From e8db9d37e2ef39e75bb49288e9e2c091df6b01d2 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期五, 29 八月 2025 17:48:02 +0800
Subject: [PATCH] 微信扫码看设备详情

---
 src/permission.js                                  |   95 +++++----
 src/views/equipmentManagement/deviceInfo/index.vue |  190 +++++++++++++++++++++
 src/api/equipmentManagement/deviceInfo.js          |   10 +
 src/views/equipmentManagement/ledger/index.vue     |    4 
 src/router/index.js                                |  187 ++++++++++----------
 5 files changed, 350 insertions(+), 136 deletions(-)

diff --git a/src/api/equipmentManagement/deviceInfo.js b/src/api/equipmentManagement/deviceInfo.js
new file mode 100644
index 0000000..d71b713
--- /dev/null
+++ b/src/api/equipmentManagement/deviceInfo.js
@@ -0,0 +1,10 @@
+import request from "@/utils/request";
+
+// 鑾峰彇璁惧鍩烘湰淇℃伅
+export function getDeviceInfo(params) {
+  return request({
+    url: "/device/ledger/scanDevice",
+    method: "get",
+    params,
+  });
+}
diff --git a/src/permission.js b/src/permission.js
index a7d9f87..5b2566b 100644
--- a/src/permission.js
+++ b/src/permission.js
@@ -1,69 +1,76 @@
-import router from './router'
-import { ElMessage } from 'element-plus'
-import NProgress from 'nprogress'
-import 'nprogress/nprogress.css'
-import { getToken } from '@/utils/auth'
-import { isHttp, isPathMatch } from '@/utils/validate'
-import { isRelogin } from '@/utils/request'
-import useUserStore from '@/store/modules/user'
-import useSettingsStore from '@/store/modules/settings'
-import usePermissionStore from '@/store/modules/permission'
+import router from "./router";
+import { ElMessage } from "element-plus";
+import NProgress from "nprogress";
+import "nprogress/nprogress.css";
+import { getToken } from "@/utils/auth";
+import { isHttp, isPathMatch } from "@/utils/validate";
+import { isRelogin } from "@/utils/request";
+import useUserStore from "@/store/modules/user";
+import useSettingsStore from "@/store/modules/settings";
+import usePermissionStore from "@/store/modules/permission";
 
-NProgress.configure({ showSpinner: false })
+NProgress.configure({ showSpinner: false });
 
-const whiteList = ['/login', '/register']
+const whiteList = ["/login", "/register", "/device-info"];
 
 const isWhiteList = (path) => {
-  return whiteList.some(pattern => isPathMatch(pattern, path))
-}
+  return whiteList.some((pattern) => isPathMatch(pattern, path));
+};
 
 router.beforeEach((to, from, next) => {
-  NProgress.start()
+  NProgress.start();
   if (getToken()) {
-    to.meta.title && useSettingsStore().setTitle(to.meta.title)
+    to.meta.title && useSettingsStore().setTitle(to.meta.title);
     /* has token*/
-    if (to.path === '/login') {
-      next({ path: '/' })
-      NProgress.done()
+    if (to.path === "/login") {
+      next({ path: "/" });
+      NProgress.done();
     } else if (isWhiteList(to.path)) {
-      next()
+      next();
     } else {
       if (useUserStore().roles.length === 0) {
-        isRelogin.show = true
+        isRelogin.show = true;
         // 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁宸叉媺鍙栧畬user_info淇℃伅
-        useUserStore().getInfo().then(() => {
-          isRelogin.show = false
-          usePermissionStore().generateRoutes().then(accessRoutes => {
-            // 鏍规嵁roles鏉冮檺鐢熸垚鍙闂殑璺敱琛�
-            accessRoutes.forEach(route => {
-              if (!isHttp(route.path)) {
-                router.addRoute(route) // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
-              }
-            })
-            next({ ...to, replace: true }) // hack鏂规硶 纭繚addRoutes宸插畬鎴�
+        useUserStore()
+          .getInfo()
+          .then(() => {
+            isRelogin.show = false;
+            usePermissionStore()
+              .generateRoutes()
+              .then((accessRoutes) => {
+                // 鏍规嵁roles鏉冮檺鐢熸垚鍙闂殑璺敱琛�
+                accessRoutes.forEach((route) => {
+                  if (!isHttp(route.path)) {
+                    router.addRoute(route); // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
+                  }
+                });
+                next({ ...to, replace: true }); // hack鏂规硶 纭繚addRoutes宸插畬鎴�
+              });
           })
-        }).catch(err => {
-          useUserStore().logOut().then(() => {
-            ElMessage.error(err)
-            next({ path: '/' })
-          })
-        })
+          .catch((err) => {
+            useUserStore()
+              .logOut()
+              .then(() => {
+                ElMessage.error(err);
+                next({ path: "/" });
+              });
+          });
       } else {
-        next()
+        next();
       }
     }
   } else {
     // 娌℃湁token
     if (isWhiteList(to.path)) {
       // 鍦ㄥ厤鐧诲綍鐧藉悕鍗曪紝鐩存帴杩涘叆
-      next()
+      next();
     } else {
-      next(`/login?redirect=${to.fullPath}`) // 鍚﹀垯鍏ㄩ儴閲嶅畾鍚戝埌鐧诲綍椤�
-      NProgress.done()
+      next(`/login?redirect=${to.fullPath}`); // 鍚﹀垯鍏ㄩ儴閲嶅畾鍚戝埌鐧诲綍椤�
+      NProgress.done();
     }
   }
-})
+});
 
 router.afterEach(() => {
-  NProgress.done()
-})
+  NProgress.done();
+});
diff --git a/src/router/index.js b/src/router/index.js
index 10adf72..340409e 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -1,6 +1,6 @@
-import { createWebHistory, createRouter } from 'vue-router'
+import { createWebHistory, createRouter } from "vue-router";
 /* Layout */
-import Layout from '@/layout'
+import Layout from "@/layout";
 
 /**
  * Note: 璺敱閰嶇疆椤�
@@ -27,163 +27,170 @@
 // 鍏叡璺敱
 export const constantRoutes = [
   {
-    path: '/redirect',
+    path: "/redirect",
     component: Layout,
     hidden: true,
     children: [
       {
-        path: '/redirect/:path(.*)',
-        component: () => import('@/views/redirect/index.vue')
-      }
-    ]
+        path: "/redirect/:path(.*)",
+        component: () => import("@/views/redirect/index.vue"),
+      },
+    ],
   },
   {
-    path: '/login',
-    component: () => import('@/views/login'),
-    hidden: true
+    path: "/login",
+    component: () => import("@/views/login"),
+    hidden: true,
   },
   {
-    path: '/register',
-    component: () => import('@/views/register'),
-    hidden: true
+    path: "/register",
+    component: () => import("@/views/register"),
+    hidden: true,
   },
   {
     path: "/:pathMatch(.*)*",
-    component: () => import('@/views/error/404'),
-    hidden: true
+    component: () => import("@/views/error/404"),
+    hidden: true,
   },
   {
-    path: '/401',
-    component: () => import('@/views/error/401'),
-    hidden: true
+    path: "/401",
+    component: () => import("@/views/error/401"),
+    hidden: true,
   },
 
   {
-    path: '',
+    path: "",
     component: Layout,
-    redirect: '/index',
+    redirect: "/index",
     children: [
       {
-        path: '/index',
-        component: () => import('@/views/index'),
-        name: 'Index',
-        meta: { title: '棣栭〉', icon: 'dashboard', affix: true }
-      }
-    ]
+        path: "/index",
+        component: () => import("@/views/index"),
+        name: "Index",
+        meta: { title: "棣栭〉", icon: "dashboard", affix: true },
+      },
+    ],
   },
   {
-    path: '/main/MobileChat',
+    path: "/main/MobileChat",
     component: Layout,
-    redirect: '',
+    redirect: "",
     hidden: true,
     children: [
       {
-        path: '',
-        component: () => import('@/views/chatHome/chatHomeIndex/MobileChat'),
-        name: 'MobileChat',
-        meta: { title: 'AI瀵硅瘽', icon: 'dashboard', affix: true}
-      }
-    ]
+        path: "",
+        component: () => import("@/views/chatHome/chatHomeIndex/MobileChat"),
+        name: "MobileChat",
+        meta: { title: "AI瀵硅瘽", icon: "dashboard", affix: true },
+      },
+    ],
   },
   {
-    path: '/user',
+    path: "/user",
     component: Layout,
     hidden: true,
-    redirect: 'noredirect',
+    redirect: "noredirect",
     children: [
       {
-        path: 'profile',
-        component: () => import('@/views/system/user/profile/index'),
-        name: 'Profile',
-        meta: { title: '涓汉涓績', icon: 'user' }
-      }
-    ]
-  }
-]
+        path: "profile",
+        component: () => import("@/views/system/user/profile/index"),
+        name: "Profile",
+        meta: { title: "涓汉涓績", icon: "user" },
+      },
+    ],
+  },
+  {
+    path: "/device-info",
+    component: () => import("@/views/equipmentManagement/deviceInfo/index.vue"),
+    hidden: true,
+    name: "DeviceInfo",
+    meta: { title: "璁惧淇℃伅", icon: "monitor" },
+  },
+];
 
 // 鍔ㄦ�佽矾鐢憋紝鍩轰簬鐢ㄦ埛鏉冮檺鍔ㄦ�佸幓鍔犺浇
 export const dynamicRoutes = [
   {
-    path: '/system/user-auth',
+    path: "/system/user-auth",
     component: Layout,
     hidden: true,
-    permissions: ['system:user:edit'],
+    permissions: ["system:user:edit"],
     children: [
       {
-        path: 'role/:userId(\\d+)',
-        component: () => import('@/views/system/user/authRole'),
-        name: 'AuthRole',
-        meta: { title: '鍒嗛厤瑙掕壊', activeMenu: '/system/user' }
-      }
-    ]
+        path: "role/:userId(\\d+)",
+        component: () => import("@/views/system/user/authRole"),
+        name: "AuthRole",
+        meta: { title: "鍒嗛厤瑙掕壊", activeMenu: "/system/user" },
+      },
+    ],
   },
   {
-    path: '/system/role-auth',
+    path: "/system/role-auth",
     component: Layout,
     hidden: true,
-    permissions: ['system:role:edit'],
+    permissions: ["system:role:edit"],
     children: [
       {
-        path: 'user/:roleId(\\d+)',
-        component: () => import('@/views/system/role/authUser'),
-        name: 'AuthUser',
-        meta: { title: '鍒嗛厤鐢ㄦ埛', activeMenu: '/system/role' }
-      }
-    ]
+        path: "user/:roleId(\\d+)",
+        component: () => import("@/views/system/role/authUser"),
+        name: "AuthUser",
+        meta: { title: "鍒嗛厤鐢ㄦ埛", activeMenu: "/system/role" },
+      },
+    ],
   },
   {
-    path: '/system/dict-data',
+    path: "/system/dict-data",
     component: Layout,
     hidden: true,
-    permissions: ['system:dict:list'],
+    permissions: ["system:dict:list"],
     children: [
       {
-        path: 'index/:dictId(\\d+)',
-        component: () => import('@/views/system/dict/data'),
-        name: 'Data',
-        meta: { title: '瀛楀吀鏁版嵁', activeMenu: '/system/dict' }
-      }
-    ]
+        path: "index/:dictId(\\d+)",
+        component: () => import("@/views/system/dict/data"),
+        name: "Data",
+        meta: { title: "瀛楀吀鏁版嵁", activeMenu: "/system/dict" },
+      },
+    ],
   },
   {
-    path: '/monitor/job-log',
+    path: "/monitor/job-log",
     component: Layout,
     hidden: true,
-    permissions: ['monitor:job:list'],
+    permissions: ["monitor:job:list"],
     children: [
       {
-        path: 'index/:jobId(\\d+)',
-        component: () => import('@/views/monitor/job/log'),
-        name: 'JobLog',
-        meta: { title: '璋冨害鏃ュ織', activeMenu: '/monitor/job' }
-      }
-    ]
+        path: "index/:jobId(\\d+)",
+        component: () => import("@/views/monitor/job/log"),
+        name: "JobLog",
+        meta: { title: "璋冨害鏃ュ織", activeMenu: "/monitor/job" },
+      },
+    ],
   },
   {
-    path: '/tool/gen-edit',
+    path: "/tool/gen-edit",
     component: Layout,
     hidden: true,
-    permissions: ['tool:gen:edit'],
+    permissions: ["tool:gen:edit"],
     children: [
       {
-        path: 'index/:tableId(\\d+)',
-        component: () => import('@/views/tool/gen/editTable'),
-        name: 'GenEdit',
-        meta: { title: '淇敼鐢熸垚閰嶇疆', activeMenu: '/tool/gen' }
-      }
-    ]
-  }
-]
+        path: "index/:tableId(\\d+)",
+        component: () => import("@/views/tool/gen/editTable"),
+        name: "GenEdit",
+        meta: { title: "淇敼鐢熸垚閰嶇疆", activeMenu: "/tool/gen" },
+      },
+    ],
+  },
+];
 
 const router = createRouter({
   history: createWebHistory(),
   routes: constantRoutes,
   scrollBehavior(to, from, savedPosition) {
     if (savedPosition) {
-      return savedPosition
+      return savedPosition;
     }
-    return { top: 0 }
+    return { top: 0 };
   },
-})
+});
 
-export default router
+export default router;
diff --git a/src/views/equipmentManagement/deviceInfo/index.vue b/src/views/equipmentManagement/deviceInfo/index.vue
new file mode 100644
index 0000000..de162cc
--- /dev/null
+++ b/src/views/equipmentManagement/deviceInfo/index.vue
@@ -0,0 +1,190 @@
+<template>
+  <div class="device-info-container">
+    <div class="page-header">
+      <h1>璁惧淇℃伅</h1>
+      <div class="device-status" :class="deviceStatusClass">
+        {{ deviceStatusText }}
+      </div>
+    </div>
+
+    <div class="info-card">
+      <div class="card-header">鍩烘湰淇℃伅</div>
+      <div class="card-content">
+        <div class="info-row">
+          <span class="label">璁惧鍚嶇О锛�</span>
+          <span class="value">{{ deviceInfo.deviceName }}</span>
+        </div>
+        <div class="info-row">
+          <span class="label">瑙勬牸鍨嬪彿锛�</span>
+          <span class="value">{{ deviceInfo.deviceModel }}</span>
+        </div>
+        <div class="info-row">
+          <span class="label">鐢熶骇鍘傚锛�</span>
+          <span class="value">{{ deviceInfo.supplierName }}</span>
+        </div>
+        <div class="info-row">
+          <span class="label">鍗曚綅锛�</span>
+          <span class="value">{{ deviceInfo.unit }}</span>
+        </div>
+      </div>
+    </div>
+
+         <div class="info-card">
+       <div class="card-header">缁存姢淇℃伅</div>
+       <div class="card-content">
+         <div class="maintenance-info">
+           <div class="maintenance-item">
+             <span class="label">鏈�鍚庣淮鎶わ細</span>
+             <span class="value">{{ deviceInfo.updateTime }}</span>
+           </div>
+           <div class="maintenance-item">
+             <span class="label">涓嬫缁存姢锛�</span>
+             <span class="value">{{ deviceInfo.createTime }}</span>
+           </div>
+           <div class="maintenance-item">
+             <span class="label">缁存姢鐘舵�侊細</span>
+             <span class="value status-normal">{{ deviceInfo.statusText }}</span>
+           </div>
+         </div>
+       </div>
+     </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, computed } from 'vue'
+import { useRoute } from 'vue-router'
+import { ElMessage } from 'element-plus'
+import { 
+  getDeviceInfo, 
+} from '@/api/equipmentManagement/deviceInfo'
+
+const route = useRoute()
+
+const deviceInfo = reactive({
+  deviceName: '',
+  deviceModel: '',
+  supplierName: '',
+  unit: '',
+  statusText:'姝e父',
+  updateTime:'',
+  createTime:''
+})
+
+const deviceStatusClass = computed(() => {
+  return 'status-normal'
+})
+
+const deviceStatusText = computed(() => {
+  return '姝e父'
+})
+
+const fetchDeviceInfo = async (deviceId) => {
+  try {
+    // 鑾峰彇璁惧淇℃伅
+    const deviceResponse = await getDeviceInfo({id:deviceId})
+    if (deviceResponse.code === 200) {
+      Object.assign(deviceInfo, deviceResponse.data)
+    }
+    
+    
+  } catch (error) {
+    
+    ElMessage.warning('浣跨敤妯℃嫙鏁版嵁锛屽疄闄匒PI璋冪敤澶辫触')
+  }
+}
+
+onMounted(() => {
+  const deviceId = route.query.deviceId || route.params.deviceId || ''
+  fetchDeviceInfo(deviceId)
+})
+</script>
+
+<style scoped>
+.device-info-container {
+  min-height: 100vh;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  padding: 20px;
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+}
+
+.page-header {
+  background: rgba(255, 255, 255, 0.95);
+  border-radius: 16px;
+  padding: 20px;
+  margin-bottom: 20px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.page-header h1 {
+  margin: 0;
+  color: #2c3e50;
+  font-size: 24px;
+}
+
+.device-status {
+  padding: 8px 16px;
+  border-radius: 20px;
+  font-size: 14px;
+  color: white;
+  background: #52c41a;
+}
+
+.info-card {
+  background: rgba(255, 255, 255, 0.95);
+  border-radius: 16px;
+  margin-bottom: 20px;
+  overflow: hidden;
+}
+
+.card-header {
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  color: white;
+  padding: 16px 20px;
+  font-weight: 500;
+}
+
+.card-content {
+  padding: 20px;
+}
+
+.info-row, .maintenance-item {
+  display: flex;
+  margin-bottom: 12px;
+  align-items: center;
+}
+
+.label {
+  width: 100px;
+  color: #666;
+  font-size: 14px;
+}
+
+.value {
+  flex: 1;
+  color: #2c3e50;
+  font-weight: 500;
+}
+
+.status-normal {
+  color: #52c41a;
+}
+
+
+
+@media (max-width: 768px) {
+  .device-info-container {
+    padding: 16px;
+  }
+  
+  .page-header h1 {
+    font-size: 20px;
+  }
+  
+  .label {
+    width: 80px;
+  }
+}
+</style>
diff --git a/src/views/equipmentManagement/ledger/index.vue b/src/views/equipmentManagement/ledger/index.vue
index 16fbbc6..9b4f802 100644
--- a/src/views/equipmentManagement/ledger/index.vue
+++ b/src/views/equipmentManagement/ledger/index.vue
@@ -270,8 +270,8 @@
 };
 
 const showQRCode = async (row) => {
-  // 浣犲彲浠ヨ嚜瀹氫箟浜岀淮鐮佸唴瀹癸紝姣斿 row.id 鎴� row.deviceName
-  const qrContent = JSON.stringify(row); // 鎴� `${row.id}`
+  // 鐩存帴浣跨敤URL锛屼笉瑕佺敤JSON.stringify鍖呰
+  const qrContent = proxy.javaApi + '/device-info?deviceId=' + row.id;
   qrCodeUrl.value = await QRCode.toDataURL(qrContent);
   qrRowData.value = row;
   qrDialogVisible.value = true;

--
Gitblit v1.9.3