diff --git a/src/api/interceptors/response.js b/src/api/interceptors/response.js index 38df3d4..8a5e4d3 100644 --- a/src/api/interceptors/response.js +++ b/src/api/interceptors/response.js @@ -1,11 +1,27 @@ //响应拦截器 import axios from 'axios'; // 引入axios用于创建新请求 +import { ElMessage } from 'element-plus'; // 引入Element Plus的消息组件 +import store from '../../store'; // 引入store用于统一处理登出 export function setupResponseInterceptors(instance) { // 用于存储正在刷新token的Promise let isRefreshing = false; // 存储等待token刷新的请求队列 let requests = []; + + // 统一处理登录过期的函数 + const handleTokenExpired = (message = '登录已过期,请重新登录') => { + // 显示提示消息 + ElMessage.error(message); + + // 使用store的logout action清除认证状态 + store.dispatch('logout'); + + // 延迟跳转,让用户有时间看到提示 + setTimeout(() => { + window.location.href = '/login'; + }, 1500); + }; instance.interceptors.response.use( response => { @@ -20,70 +36,110 @@ export function setupResponseInterceptors(instance) { return data; }, async error => { + console.log('响应错误:', error); + // 获取原始请求配置 const originalRequest = error.config; - - // 判断是否401错误(token过期)且没有在刷新中 - if (error.response?.status === 401 && !originalRequest._retry) { - // 标记该请求已尝试过重试 - originalRequest._retry = true; - - // 如果当前没有在刷新token - if (!isRefreshing) { - isRefreshing = true; + + // 检查是否有响应 + if (!error.response) { + // 网络错误或请求被中断 + return Promise.reject(error); + } + + // 检查错误响应中的各种可能的错误信息位置 + const errorResponse = error.response; + console.log('错误响应:', errorResponse); + const errorData = errorResponse.data || {}; + const errorMessage = errorData.message || errorData.error || errorResponse.statusText || ''; + const errorStack = errorData.stack || ''; + const statusCode = errorResponse.status; + + // 处理403错误(权限不足) + if (errorResponse.status === "403") { + // 显示权限不足提示,但不重定向 + ElMessage.error(errorMessage || '您没有权限执行此操作'); + return Promise.reject("您没有权限执行此操作"); + } + + // 检查是否为令牌错误(检查多种可能的错误信息格式) + const isTokenError = + statusCode === 401 || + (statusCode === 500 && ( + errorMessage.includes('令牌') || + errorMessage.includes('token') || + errorMessage.includes('Token') || + errorStack.includes('TokenIllegal') || + errorStack.includes('TheTokenIllegalException') || + (typeof errorData === 'string' && errorData.includes('令牌')) + )); + + // 如果是令牌错误,尝试刷新令牌或直接跳转登录页 + if (isTokenError) { + // 如果是401错误且没有在刷新中,尝试刷新令牌 + if (statusCode === 401 && !originalRequest._retry) { + // 标记该请求已尝试过重试 + originalRequest._retry = true; - try { - // 从localStorage获取refreshToken - const refreshToken = localStorage.getItem('refreshToken'); + // 如果当前没有在刷新token + if (!isRefreshing) { + isRefreshing = true; - if (!refreshToken) { - // 无refreshToken,跳转到登录页 - window.location.href = '/login'; - return Promise.reject(error); + try { + // 从localStorage获取refreshToken + const refreshToken = localStorage.getItem('refreshToken'); + + if (!refreshToken) { + // 无refreshToken,跳转到登录页 + handleTokenExpired(); + return Promise.reject(error); + } + + // 创建表单数据 + const formData = new FormData(); + formData.append('refreshToken', refreshToken); + + // 调用刷新token接口 + const response = await axios.post('/admin/getAccessToken', formData); + + // 获取新的token + const { accessToken, refreshToken: newRefreshToken } = response.data.data; + + // 更新本地存储 + localStorage.setItem('accessToken', accessToken); + if (newRefreshToken) { + localStorage.setItem('refreshToken', newRefreshToken); + } + + // 更新当前请求的Authorization头 + originalRequest.headers.Authorization = accessToken; + + // 执行队列中的所有请求 + requests.forEach(cb => cb(accessToken)); + requests = []; + + // 重新发送之前失败的请求 + return instance(originalRequest); + } catch (refreshError) { + // 刷新token失败,清除token并跳转到登录页 + handleTokenExpired(); + return Promise.reject(refreshError); + } finally { + isRefreshing = false; } - - // 创建表单数据 - const formData = new FormData(); - formData.append('refreshToken', refreshToken); - - // 调用刷新token接口 - const response = await axios.post('/admin/getAccessToken', formData); - - // 获取新的token - const { accessToken, refreshToken: newRefreshToken } = response.data.data; - - // 更新本地存储 - localStorage.setItem('accessToken', accessToken); - if (newRefreshToken) { - localStorage.setItem('refreshToken', newRefreshToken); - } - - // 更新当前请求的Authorization头 - originalRequest.headers.Authorization = accessToken; - - // 执行队列中的所有请求 - requests.forEach(cb => cb(accessToken)); - requests = []; - - // 重新发送之前失败的请求 - return instance(originalRequest); - } catch (refreshError) { - // 刷新token失败,清除token并跳转到登录页 - localStorage.removeItem('accessToken'); - localStorage.removeItem('refreshToken'); - window.location.href = '/login'; - return Promise.reject(refreshError); - } finally { - isRefreshing = false; + } else { + // 如果已经在刷新中,将请求加入队列 + return new Promise(resolve => { + requests.push(token => { + originalRequest.headers.Authorization = token; + resolve(instance(originalRequest)); + }); + }); } } else { - // 如果已经在刷新中,将请求加入队列 - return new Promise(resolve => { - requests.push(token => { - originalRequest.headers.Authorization = token; - resolve(instance(originalRequest)); - }); - }); + // 其他令牌错误,直接处理登录过期 + handleTokenExpired(); + return Promise.reject(error); } } diff --git a/src/api/modules/task.js b/src/api/modules/task.js new file mode 100644 index 0000000..ac79878 --- /dev/null +++ b/src/api/modules/task.js @@ -0,0 +1,13 @@ +import instance from '../../utils/axios.js' + +// 任务相关API +const taskApi = { + // 获取运行中的任务列表 + getRunningTasks: () => instance.get('/task/test'), + + // 停止指定任务 + stopTask: (taskId) => instance.get(`/task/stopTask?taskId=${taskId}`), +}; + +// 导出模块 +export { taskApi }; \ No newline at end of file diff --git a/src/layout/Sidebar.vue b/src/layout/Sidebar.vue index 06f232c..50910e2 100644 --- a/src/layout/Sidebar.vue +++ b/src/layout/Sidebar.vue @@ -57,10 +57,6 @@ { title: '权限管理', path: '/user/permission' - }, - { - title: '用户角色管理', - path: '/user/userRole' } ] }, @@ -164,6 +160,19 @@ }] }] }, + { + title: '任务管理', + path: '/task', + icon: TrendCharts, + children:[{ + title: '任务列表', + path: '/task/list', + children:[{ + title: '任务列表', + path: '/task/list' + }] + }] + }, { title: '功能模块', path: '/useModule', diff --git a/src/router/index.js b/src/router/index.js index 1bd2893..566d884 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -28,11 +28,6 @@ const routes = [{ component: () => import('@/views/User/List.vue'), meta: { title: '用户列表' } }, - { - path: '/user/edit', - component: () => import('@/views/User/Edit.vue'), - meta: { title: '新增用户' } - }, { path: '/user/role', component: () => import('@/views/User/Role.vue'), @@ -43,11 +38,6 @@ const routes = [{ component: () => import('@/views/User/Permission.vue'), meta: { title: '权限管理' } }, - { - path: '/user/userRole', - component: () => import('@/views/User/UserRole.vue'), - meta: { title: '用户角色管理' } - }, { path: '/shop/list', component: () => import('@/views/Shop/index.vue'), @@ -83,11 +73,6 @@ const routes = [{ component: () => import('@/views/order/wechat/list.vue'), meta: { title: '订单列表' } }, - { - path: '/websocket/demo', - component: () => import('@/views/websocket/index.vue'), - meta: { title: 'WebSocket演示' } - }, { path: '/book/selection/center', component: () => import('@/views/baseInfo/index.vue'), @@ -97,6 +82,11 @@ const routes = [{ path: '/warehouse/depot/list', component: () => import('@/views/Warehouse/Depot/List.vue'), meta: { title: '货区管理' } + }, + { + path: '/task/list', + component: () => import('@/views/Task/List.vue'), + meta: { title: '任务列表' } } ] }] diff --git a/src/views/Task/List.vue b/src/views/Task/List.vue new file mode 100644 index 0000000..af0cf90 --- /dev/null +++ b/src/views/Task/List.vue @@ -0,0 +1,219 @@ + + + + + \ No newline at end of file diff --git a/src/views/User/Role.vue b/src/views/User/Role.vue index 143e47d..01462ad 100644 --- a/src/views/User/Role.vue +++ b/src/views/User/Role.vue @@ -119,8 +119,13 @@ export default { const res = await getRoleList() roleList.value = res.data || [] } catch (error) { - console.error('获取角色列表失败', error) - ElMessage.error('获取角色列表失败') + console.log(error) + if(error.status === 403){ + ElMessage.error("您没有权限执行此操作") + }else{ + console.error('获取角色列表失败', error) + ElMessage.error('获取角色列表失败') + } } finally { loading.value = false }