spring
6 天以前 e8db9d37e2ef39e75bb49288e9e2c091df6b01d2
微信扫码看设备详情
已修改3个文件
已添加2个文件
486 ■■■■ 文件已修改
src/api/equipmentManagement/deviceInfo.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/permission.js 95 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 187 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/deviceInfo/index.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/ledger/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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,
  });
}
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();
});
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;
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:'正常',
  updateTime:'',
  createTime:''
})
const deviceStatusClass = computed(() => {
  return 'status-normal'
})
const deviceStatusText = computed(() => {
  return '正常'
})
const fetchDeviceInfo = async (deviceId) => {
  try {
    // èŽ·å–è®¾å¤‡ä¿¡æ¯
    const deviceResponse = await getDeviceInfo({id:deviceId})
    if (deviceResponse.code === 200) {
      Object.assign(deviceInfo, deviceResponse.data)
    }
  } catch (error) {
    ElMessage.warning('使用模拟数据,实际API调用失败')
  }
}
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>
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;