From 423facda3c0e19fb921812bffdf36d0d3459464b Mon Sep 17 00:00:00 2001 From: wzt <3847407356@qq.com> Date: Tue, 4 Aug 2026 11:24:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=80=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/tool.ts | 129 +++--- src/router/index.ts | 294 +++++--------- src/stores/user.ts | 27 +- src/utils/request.ts | 68 ++-- src/views/biz/tool/index.vue | 326 +++++++-------- src/views/biz/tool/usage.vue | 2 +- src/views/dashboard/index.vue | 740 +++++++++++++++++++++++----------- 7 files changed, 844 insertions(+), 742 deletions(-) diff --git a/src/api/tool.ts b/src/api/tool.ts index a731824..26c2916 100644 --- a/src/api/tool.ts +++ b/src/api/tool.ts @@ -1,77 +1,78 @@ -import { request } from '@/utils/request' - -export interface Tool { - id?: number - toolCode: string - toolName: string - toolType: string - toolTypeId?: number - specModel: string - material: string - manufacturer: string - purchaseDate?: string | number - lifeCycle: number - usedCount?: number - status: number - remark: string - createTime?: string - updateTime?: string -} +import request from '@/utils/request' export const toolApi = { - page(params: { - page: number - pageSize: number - toolCode?: string - toolName?: string - status?: number - }) { - return request({ - url: '/biz/tool/page', - method: 'get', - params - }) + page(params: { page: number; pageSize: number; toolCode?: string; toolName?: string; toolType?: number; brand?: string }) { + return request({ url: '/biz/tool/page', method: 'get', params }) }, - create(data: Tool) { - return request({ - url: '/biz/tool', - method: 'post', - data - }) + detail(id: number) { + return request({ url: `/biz/tool/${id}`, method: 'get' }) }, - update(data: Tool) { - return request({ - url: '/biz/tool', - method: 'put', - data - }) + create(data: any) { + return request({ url: '/biz/tool', method: 'post', data }) + }, + + update(data: any) { + return request({ url: '/biz/tool', method: 'put', data }) }, delete(ids: number[]) { - return request({ - url: `/biz/tool/${ids.join(',')}`, - method: 'delete' + return request({ url: `/biz/tool/${ids.join(',')}`, method: 'delete' }) + }, + + export(params: { toolCode?: string; toolName?: string }) { + return request({ url: '/biz/tool/export', method: 'get', params, responseType: 'blob' }) + }, + + downloadTemplate() { + return request({ url: '/biz/tool/template', method: 'get', responseType: 'blob' }) + }, + + importData(file: File) { + const formData = new FormData() + formData.append('file', file) + return request<{ success: number; fail: number; errors: string[] }>({ + url: '/biz/tool/import', + method: 'post', + data: formData, + headers: { 'Content-Type': 'multipart/form-data' } }) }, - export(params?: { - ids?: number[] - toolCode?: string - toolName?: string - status?: number - }) { - const p: Record = {} - if (params?.ids?.length) p.ids = params.ids.join(',') - if (params?.toolCode) p.toolCode = params.toolCode - if (params?.toolName) p.toolName = params.toolName - if (params?.status != null) p.status = params.status - return request({ - url: '/biz/tool/report', - method: 'get', - params: p, - responseType: 'blob' - }) + usagePage(params: { page: number; pageSize: number; toolId?: number; stationId?: number; sourceType?: string }) { + return request({ url: '/biz/tool/usage/page', method: 'get', params }) + }, + + usageDetail(id: number) { + return request({ url: `/biz/tool/usage/${id}`, method: 'get' }) + }, + + usageCreate(data: any) { + return request({ url: '/biz/tool/usage', method: 'post', data }) + }, + + usageUpdate(data: any) { + return request({ url: '/biz/tool/usage', method: 'put', data }) + }, + + usageDelete(ids: number[]) { + return request({ url: `/biz/tool/usage/${ids.join(',')}`, method: 'delete' }) + }, + + usageSync(handoverId: number) { + return request({ url: `/biz/tool/usage/sync/${handoverId}`, method: 'post' }) + }, + + usageExport(params: { toolId?: number; stationId?: number; sourceType?: string }) { + return request({ url: '/biz/tool/usage/export', method: 'get', params, responseType: 'blob' }) + }, + + deviceList() { + return request<{ value: number; label: string }[]>({ url: '/biz/tool/device/list', method: 'get' }) + }, + + userList() { + return request<{ value: number; label: string }[]>({ url: '/biz/tool/user/list', method: 'get' }) } -} \ No newline at end of file +} diff --git a/src/router/index.ts b/src/router/index.ts index 0036c26..4008c3d 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,6 +1,5 @@ import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' -import { useUserStore } from '@/stores/user' -//import type { MenuInfo } from '@/api/auth' +import type { MenuInfo } from '@/api/auth' // 动态导入所有页面组件 const modules = import.meta.glob('/src/views/**/*.vue') @@ -16,18 +15,13 @@ const routes: RouteRecordRaw[] = [ component: () => import('@/views/login/index.vue'), meta: { title: '登录', requiresAuth: false } }, + { path: '/register', name: 'Register', component: () => import('@/views/register/index.vue'), meta: { title: '注册', requiresAuth: false } }, - { - path: '/proterminal', - name: 'proterminal', - component: () => import('@/views/proterminal/index.vue'), - meta: { title: '生产终端',requiresAuth: true } - }, { path: '/', name: 'Layout', @@ -40,6 +34,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('@/views/dashboard/index.vue'), meta: { title: '首页', icon: 'HomeOutline' } }, + // 个人中心 { path: 'profile', @@ -53,6 +48,33 @@ const routes: RouteRecordRaw[] = [ name: 'SystemUser', component: () => import('@/views/system/user/index.vue'), meta: { title: '用户管理', icon: 'PersonOutline' } + }, + // 刀具管理(静态路由) + { + path: 'biz/tool', + name: 'BizTool', + component: () => import('@/views/biz/tool/index.vue'), + meta: { title: '刀具管理', icon: 'BuildOutline' } + }, + // 刀具生产管理(静态路由,确保稳定访问) + { + path: 'biz/tool/usage', + name: 'BizToolUsage', + component: () => import('@/views/biz/tool/usage/index.vue'), + meta: { title: '刀具生产管理', icon: 'BuildOutline' } + }, + { + path: 'biz/toolUsage', + name: 'BizToolUsageAlias', + component: () => import('@/views/biz/tool/usage/index.vue'), + meta: { title: '刀具生产管理', icon: 'BuildOutline' } + }, + // NC代码库 + { + path: 'biz/ncCode', + name: 'BizNcCode', + component: () => import('@/views/biz/ncCode/index.vue'), + meta: { title: 'NC代码库', icon: 'DocumentOutline' } }, { path: 'system/role', @@ -122,80 +144,6 @@ const routes: RouteRecordRaw[] = [ component: () => import('@/views/org/post/index.vue'), meta: { title: '岗位管理', icon: 'IdCardOutline' } }, - // 项目管理 - { - path: 'biz/orderProject', - name: 'OrderProject', - component: () => import('@/views/biz/orderProject/index.vue'), - meta: { title: '项目管理', icon: 'PersonOutline' } - }, - { - path: 'biz/orderProject/gantt', - name: 'OrderProjectGantt', - component: () => import('@/views/biz/orderProject/components/GanttSchedule.vue'), - meta: { title: '甘特图排产', icon: 'CalendarOutline', activeMenu: '/biz/orderProject' } - }, - //运营管理 - { - path: 'biz/orderItem', - name: 'orderItem', - component: () => import('@/views/biz/orderItem/index.vue'), - meta: { title: '生产订单', icon: 'ListOutline' } - }, - { - path: 'biz/orderProcessPlan', - name: 'orderProcessPlan', - component: () => import('@/views/biz/orderProcessPlan/index.vue'), - meta: { title: '工序计划', icon: 'ListOutline' } - }, - { - path: 'biz/orderProcessPlan/board', - name: 'orderProcessPlanBoard', - component: () => import('@/views/biz/orderProcessPlan/board.vue'), - meta: { title: '工序计划看板', icon: 'ListOutline', activeMenu: '/biz/orderProcessPlan' } - }, - { - path: 'biz/device', - name: 'device', - component: () => import('@/views/biz/device/index.vue'), - meta: { title: '设备管理', icon: 'HardwareChipOutline' } - }, - { - path: 'biz/device/board', - name: 'deviceRealtimeBoard', - component: () => import('@/views/biz/device/board.vue'), - meta: { title: '设备状态看板', icon: 'GridOutline', activeMenu: '/biz/device' } - }, - { - path: 'biz/user', - name: 'user', - component: () => import('@/views/biz/user/index.vue'), - meta: { title: '客户管理', icon: 'ListOutline' } - }, - { - path: 'biz/order', - name: 'order', - component: () => import('@/views/biz/order/index.vue'), - meta: { title: '订单管理', icon: 'ListOutline' } - }, - { - path: 'biz/orderProject', - name: 'orderProject', - component: () => import('@/views/biz/orderProject/index.vue'), - meta: { title: '项目管理', icon: 'ListOutline' } - }, - { - path: 'biz/orderProject/gantt', - name: 'OrderProjectGantt', - component: () => import('@/views/biz/orderProject/components/GanttSchedule.vue'), - meta: { title: '甘特图排产', icon: 'CalendarOutline', activeMenu: '/biz/orderProject' } - }, - { - path: 'biz/code', - name: 'code', - component: () => import('@/views/biz/code/index.vue'), - meta: { title: '邀请码配置', icon: 'SettingsSharp' } - }, // 系统日志 { path: 'log/operlog', @@ -258,57 +206,8 @@ const routes: RouteRecordRaw[] = [ component: () => import('@/views/test/test/index.vue'), meta: { title: '测试菜单', icon: 'StarOutline' } }, + // 开发工具 { - path: 'biz/submitLog', - name: 'submitLog', - component: () => import('@/views/biz/submitLog/index.vue'), - meta: { title: '派工工单汇报记录', icon: 'ListOutline' } - }, - { - path: 'biz/processRoute', - name: 'processRoute', - component: () => import('@/views/biz/processRoute/index.vue'), - meta: { title: '工艺路线主表', icon: 'ListOutline' } - }, - { - path: 'biz/processRouteStep', - name: 'processRouteStep', - component: () => import('@/views/biz/processRouteStep/index.vue'), - meta: { title: '工艺路线工序明细', icon: 'ListOutline' } - }, - { - path: 'biz/flowingAround', - name: 'flowingAround', - component: () => import('@/views/biz/flowingAround/index.vue'), - meta: { title: '流转记录表', icon: 'ListOutline' } - }, - - { - path: 'biz/outsourcing', - name: 'outsourcing', - component: () => import('@/views/biz/outsourcing/index.vue'), - meta: { title: '工序委外', icon: 'ListOutline' } - }, - // { - // path: 'biz/tool', - // name: 'tool', - // component: () => import('@/views/biz/tool/index.vue'), - // meta: { title: '刀具管理', icon: 'ToolOutline' } - // }, - // { - // path: 'biz/tool/usage', - // name: 'toolUsage', - // component: () => import('@/views/biz/tool/usage.vue'), - // meta: { title: '刀具使用记录', icon: 'ToolOutline', activeMenu: '/biz/tool' } - // }, - { - path: 'biz/errorNotification', - name: 'errorNotification', - component: () => import('@/views/biz/errorNotification/index.vue'), - meta: { title: 'ErrorNotification', icon: 'ListOutline' } - }, - { - // 开发工具 path: 'tool/gen', name: 'ToolGen', component: () => import('@/views/tool/gen/index.vue'), @@ -323,16 +222,11 @@ const routes: RouteRecordRaw[] = [ } ] }, - // { - // path: '/:pathMatch(.*)', - // name: 'NotFound', - // component: () => import('@/views/error/404.vue'), - // meta: { title: '404', requiresAuth: false } - // } { - path: '/:pathMatch(.*)', + path: '/:pathMatch(.*)*', + name: 'NotFound', component: () => import('@/views/error/404.vue'), - // meta: { title: '404', requiresAuth: false } + meta: { title: '404', requiresAuth: false } } ] @@ -344,29 +238,44 @@ const router = createRouter({ // 已添加的动态路由 const addedRouteNames = new Set() +// 动态路由是否已初始化 +let dynamicRoutesInitialized = false + /** * 根据菜单动态添加新路由(只添加静态路由中没有的) - */ -export function addDynamicRoutes(menus: any) { //MenuInfo[] - //console.log('[动态路由] 开始处理菜单:', menus) - const addRoutes = (menuList: any) => { //MenuInfo[] + */ +export function addDynamicRoutes(menus: MenuInfo[]) { + console.log('[动态路由] 开始处理菜单:', menus) + + // 获取 Layout 路由的现有子路由路径 + const getLayoutChildPaths = () => { + const layoutRoute = router.getRoutes().find(r => r.name === 'Layout') + if (layoutRoute && layoutRoute.children) { + return new Set(layoutRoute.children.map(c => c.path)) + } + return new Set() + } + + const addRoutes = (menuList: MenuInfo[]) => { for (const menu of menuList) { // 只处理菜单类型(type=2),且有 path if (menu.type === 2 && menu.path) { const routeName = 'Dynamic-' + menu.id - // 检查是否已经有同路径的静态路由 - const existingRoutes = router.getRoutes() + // 规范化路径,去掉开头的 / const menuPath = menu.path.startsWith('/') ? menu.path.slice(1) : menu.path - const pathExists = existingRoutes.some(r => r.path === '/' + menuPath || r.path === menuPath) + + // 检查是否已经有同路径的路由(检查 Layout 的子路由) + const layoutChildPaths = getLayoutChildPaths() + const pathExists = layoutChildPaths.has(menuPath) || layoutChildPaths.has('/' + menuPath) if (pathExists) { - // console.log(`[动态路由] 跳过(已存在): ${menuPath}`) + console.log(`[动态路由] 跳过(已存在): ${menuPath}`) continue } if (addedRouteNames.has(routeName)) { - //console.log(`[动态路由] 跳过(已添加): ${menuPath}`) + console.log(`[动态路由] 跳过(已添加): ${menuPath}`) continue } @@ -389,10 +298,35 @@ export function addDynamicRoutes(menus: any) { //MenuInfo[] } else if (menu.component) { // 普通菜单,加载组件 const componentName = menu.component.startsWith('/') ? menu.component.slice(1) : menu.component - const componentPath = `/src/views/${componentName}.vue` - const component = modules[componentPath] - //console.log(`[动态路由] 处理: path=${menuPath}, component=${componentPath}, 组件存在=${!!component}`) + // 组件路径映射表(解决菜单component与实际文件路径不匹配的问题) + const componentMapping: Record = { + 'biz/toolUsage': 'biz/tool/usage/index', + 'biz/toolUsage/index': 'biz/tool/usage/index', + 'biz/tool/usage': 'biz/tool/usage/index', + } + + // 查找映射关系 + const mappedComponent = componentMapping[componentName] || componentName + + // 尝试多种路径加载组件 + let component = null + const possiblePaths = [ + `/src/views/${mappedComponent}.vue`, + `/src/views/${mappedComponent}/index.vue`, + `/src/views/${componentName}.vue`, + `/src/views/${componentName}/index.vue`, + ] + + for (const path of possiblePaths) { + if (modules[path]) { + component = modules[path] + console.log(`[动态路由] 找到组件: ${path}`) + break + } + } + + console.log(`[动态路由] 处理: path=${menuPath}, componentName=${componentName}, mappedComponent=${mappedComponent}, 组件存在=${!!component}`) if (component) { router.addRoute('Layout', { @@ -406,9 +340,9 @@ export function addDynamicRoutes(menus: any) { //MenuInfo[] } }) addedRouteNames.add(routeName) - //console.log(`[动态路由] ✓ 添加成功: ${menuPath}`) + console.log(`[动态路由] ✓ 添加成功: ${menuPath}`) } else { - //console.warn(`[动态路由] ✗ 组件不存在: ${componentPath}`) + console.warn(`[动态路由] ✗ 组件不存在: ${componentName}`) } } } @@ -421,7 +355,8 @@ export function addDynamicRoutes(menus: any) { //MenuInfo[] } addRoutes(menus) - //console.log('[动态路由] 当前所有路由:', router.getRoutes().map(r => r.path)) + dynamicRoutesInitialized = true + console.log('[动态路由] 当前所有路由:', router.getRoutes().map(r => r.path)) } /** @@ -434,15 +369,16 @@ export function resetRouter() { } }) addedRouteNames.clear() + dynamicRoutesInitialized = false } - // 路由守卫 router.beforeEach(async (to, _from, next) => { - console.log('路由测试'); + const { useUserStore } = await import('@/stores/user') const userStore = useUserStore() - - //document.title = `${to.meta.title || ''} - CSY Admin` + + document.title = `${to.meta.title || ''} - mes Admin` + if (to.meta.requiresAuth === false) { next() return @@ -453,47 +389,25 @@ router.beforeEach(async (to, _from, next) => { return } - - if (userStore.init) { + if (!userStore.user || !dynamicRoutesInitialized) { try { - - await userStore.getInfo() + if (!userStore.user) { + await userStore.getInfo() + } // 添加动态路由(只添加新的,不影响已有的) addDynamicRoutes(userStore.menus) - userStore.setinit(false) - // userStore.init = false + console.log('[路由守卫] 动态路由已添加,重新导航到:', to.path) next({ ...to, replace: true }) - //return + return } catch (error) { + console.error('[路由守卫] 获取用户信息失败:', error) userStore.logout() - //userStore.init = false - userStore.setinit(true) next({ name: 'Login' }) - //return + return } - }else{ - next() } - // if (!userStore.user) { - // try { - // await userStore.getInfo() - // // 添加动态路由(只添加新的,不影响已有的) - // addDynamicRoutes(userStore.menus) - // next({ ...to, replace: true }) - // return - // } catch (error) { - // userStore.logout() - // next({ name: 'Login' }) - // return - // } - // } - - // if (to.meta.requiresAuth === false) { - // next() - // return - // } - + next() }) export default router diff --git a/src/stores/user.ts b/src/stores/user.ts index 0acc943..3b28199 100644 --- a/src/stores/user.ts +++ b/src/stores/user.ts @@ -1,7 +1,6 @@ import { defineStore } from 'pinia' import { ref, computed } from 'vue' import { authApi, type LoginParams, type UserInfo, type MenuInfo } from '@/api/auth' -import router, { resetRouter } from '@/router' export const useUserStore = defineStore('user', () => { // 状态 @@ -11,21 +10,11 @@ export const useUserStore = defineStore('user', () => { const permissions = ref([]) const menus = ref([]) - const init = ref(true) - // 计算属性 const isLogin = computed(() => !!token.value) const nickname = computed(() => user.value?.nickname || user.value?.username || '') const avatar = computed(() => user.value?.avatar || '') - - const postNames = computed(() => user.value?.postNames || '') - const userid = computed(() => user.value?.id || '') - - function setinit(v:any) { - init.value = v - } - // 登录 async function login(params: LoginParams) { const res = await authApi.login(params) @@ -56,11 +45,6 @@ export const useUserStore = defineStore('user', () => { permissions.value = [] menus.value = [] - init.value = true - - // 重置路由 - resetRouter() - // 只有之前有 token 时才发送 logout 请求 if (hadToken) { try { @@ -69,7 +53,10 @@ export const useUserStore = defineStore('user', () => { // 忽略错误 } } - + + // 动态导入 router 避免循环依赖 + const { default: router, resetRouter } = await import('@/router') + resetRouter() router.push('/login') } @@ -95,10 +82,6 @@ export const useUserStore = defineStore('user', () => { isLogin, nickname, avatar, - init, - postNames, - userid, - setinit, login, getInfo, logout, @@ -107,7 +90,7 @@ export const useUserStore = defineStore('user', () => { } }, { persist: { - key: 'mars-user', + key: 'mes-user', paths: ['token'] } }) diff --git a/src/utils/request.ts b/src/utils/request.ts index 59d5edf..bab816e 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -1,7 +1,4 @@ import axios, { type AxiosInstance, type AxiosRequestConfig, type AxiosResponse } from 'axios' -import { useUserStore } from '@/stores/user' - -const BASE_API = import.meta.env.VITE_APP_BASE_API // API响应结构 interface ApiResponse { @@ -14,12 +11,24 @@ interface ApiResponse { interface CryptoConfig { enabled: boolean publicKey: string - aesKey: string // AES密钥的Base64编码 + aesKey: string } // 加密配置缓存 let cryptoConfigCache: CryptoConfig | null = null +// 从 localStorage 安全读取 token(避免循环依赖) +function getToken(): string | null { + try { + const raw = localStorage.getItem('mes-user') + if (raw) { + const data = JSON.parse(raw) + return data?.token || null + } + } catch {} + return null +} + // 获取加密配置 export async function fetchCryptoConfig(): Promise { if (cryptoConfigCache) { @@ -42,7 +51,7 @@ export function clearCryptoConfigCache() { cryptoConfigCache = null } -// 判断是否是AES加密的响应数据(格式:iv.encryptedData) +// 判断是否是AES加密的响应数据 function isAesEncryptedData(data: any): boolean { if (typeof data !== 'string') { return false @@ -51,11 +60,9 @@ function isAesEncryptedData(data: any): boolean { if (parts.length !== 2) { return false } - // 检查两部分是否都是有效的Base64,且IV长度正确 try { atob(parts[0]) atob(parts[1]) - // IV是12字节,Base64后是16字符 return parts[0].length === 16 && parts[1].length > 10 } catch { return false @@ -73,7 +80,6 @@ async function aesDecrypt(encryptedData: string, aesKeyBase64: string): Promise< const data = Uint8Array.from(atob(parts[1]), c => c.charCodeAt(0)) const keyBytes = Uint8Array.from(atob(aesKeyBase64), c => c.charCodeAt(0)) - // 导入AES密钥 const aesKey = await crypto.subtle.importKey( 'raw', keyBytes, @@ -82,7 +88,6 @@ async function aesDecrypt(encryptedData: string, aesKeyBase64: string): Promise< ['decrypt'] ) - // 解密 const decrypted = await crypto.subtle.decrypt( { name: 'AES-GCM', iv: iv }, aesKey, @@ -105,37 +110,24 @@ async function decryptResponseData(data: string): Promise { return JSON.parse(decryptedStr) } catch (error) { console.error('响应解密失败', error) - // 解密失败可能是密钥过期,清除缓存 cryptoConfigCache = null return data } } -//axios.defaults.headers["Content-Type"] = 'application/json;charset=utf-8' //"application/x-www-form-urlencoded;charset=utf-8"; //"application/json;charset=utf-8"; - // 创建axios实例 -// 后端 API 统一使用 /api 前缀 const service: AxiosInstance = axios.create({ - //baseURL:'/api', - baseURL:BASE_API, + baseURL: '/api', timeout: 30000 }) -// 请求拦截器 +// 请求拦截器 - 直接从 localStorage 读取 token service.interceptors.request.use( (config) => { - const userStore = useUserStore() - if (userStore.token) { - config.headers['Authorization'] = userStore.token + const token = getToken() + if (token) { + config.headers['Authorization'] = token } - - if (config.data instanceof FormData) { - // 文件上传:不设置 JSON 请求头、不序列化,交给浏览器自动处理 multipart - return config - } - - config.headers["Content-Type"] = 'application/json;charset=utf-8' - config.data = config.data instanceof Object ? JSON.stringify(config.data) : config.data return config }, (error) => { @@ -149,31 +141,25 @@ let isLoggingOut = false // 响应拦截器 service.interceptors.response.use( async (response: AxiosResponse) => { - // 如果是 blob 类型响应(文件下载),直接返回 + // blob 类型响应直接返回 if (response.config.responseType === 'blob') { return response.data } - if (response.config.responseType === 'arraybuffer') { - // 二进制流不走code校验,直接完整返回ArrayBuffer - return response.data - } - const res = response.data if (res.code !== 200) { - // logout 接口返回 401 时不显示错误消息(避免干扰) const isLogoutRequest = response.config.url?.includes('/auth/logout') - // 401 未授权,弹出明确提示并跳转登录(防止重复调用) + // 401 未授权 if (res.code === 401 && !isLoggingOut && !isLogoutRequest) { - window.$message?.warning('当前用户登录已过期,请重新登录') - isLoggingOut = true - - const userStore = useUserStore() - await userStore.logout() + window.$message?.error('当前用户登录已过期,请重新登录') + // 清除本地 token + localStorage.removeItem('mes-user') isLoggingOut = false + // 跳转到登录页 + window.location.href = '/login' return Promise.reject(new Error('登录已过期')) } @@ -184,7 +170,7 @@ service.interceptors.response.use( return Promise.reject(new Error(res.message || '请求失败')) } - // 检查响应数据是否是AES加密的,自动解密 + // AES 解密 if (isAesEncryptedData(res.data)) { try { return await decryptResponseData(res.data) diff --git a/src/views/biz/tool/index.vue b/src/views/biz/tool/index.vue index 029ad53..b340532 100644 --- a/src/views/biz/tool/index.vue +++ b/src/views/biz/tool/index.vue @@ -4,25 +4,28 @@
- + - + - - + + + + + - - - - 搜索 - - - - 重置 - - + + + 搜索 + + + + + + 重置 +
@@ -52,51 +55,31 @@ :columns="columns" :data="tableData" :loading="loading" - :pagination="pagination" :row-key="(row) => row.id" - :scroll-x="1400" - @update:page="handlePageChange" - @update:page-size="handlePageSizeChange" + :scroll-x="1200" @update:checked-row-keys="handleCheck" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + @@ -141,10 +124,9 @@ \ No newline at end of file + diff --git a/src/views/biz/tool/usage.vue b/src/views/biz/tool/usage.vue index 0b99079..8203dc9 100644 --- a/src/views/biz/tool/usage.vue +++ b/src/views/biz/tool/usage.vue @@ -270,7 +270,7 @@ async function loadData() { if (searchForm.stationCode) params.stationCode = searchForm.stationCode if (searchForm.startTime) params.startTime = formatDateTime(searchForm.startTime) if (searchForm.endTime) params.endTime = formatDateTime(searchForm.endTime) - + const res = await toolUsageApi.page(params) tableData.value = res.list pagination.itemCount = res.total diff --git a/src/views/dashboard/index.vue b/src/views/dashboard/index.vue index d5bfe97..ae8396f 100644 --- a/src/views/dashboard/index.vue +++ b/src/views/dashboard/index.vue @@ -1,253 +1,337 @@ + + \ No newline at end of file +