diff --git a/package-lock.json b/package-lock.json index 1d5f867..4d7c7c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "axios": "^1.9.0", + "echarts": "^5.6.0", "element-plus": "^2.9.11", "escpos": "^3.0.0-alpha.6", "escpos-usb": "^3.0.0-alpha.4", @@ -668,6 +669,22 @@ "safer-buffer": "^2.1.0" } }, + "node_modules/echarts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", + "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.6.1" + } + }, + "node_modules/echarts/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" + }, "node_modules/element-plus": { "version": "2.9.11", "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.9.11.tgz", @@ -2186,6 +2203,21 @@ "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", "dev": true, "license": "MIT" + }, + "node_modules/zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "license": "BSD-3-Clause", + "dependencies": { + "tslib": "2.3.0" + } + }, + "node_modules/zrender/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" } }, "dependencies": { @@ -2635,6 +2667,22 @@ "safer-buffer": "^2.1.0" } }, + "echarts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", + "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", + "requires": { + "tslib": "2.3.0", + "zrender": "5.6.1" + }, + "dependencies": { + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + } + }, "element-plus": { "version": "2.9.11", "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.9.11.tgz", @@ -3646,6 +3694,21 @@ "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", "dev": true + }, + "zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "requires": { + "tslib": "2.3.0" + }, + "dependencies": { + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + } } } } diff --git a/package.json b/package.json index 5940618..3f9c267 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ }, "dependencies": { "axios": "^1.9.0", + "echarts": "^5.6.0", "element-plus": "^2.9.11", "escpos": "^3.0.0-alpha.6", "escpos-usb": "^3.0.0-alpha.4", diff --git a/src/api/index.js b/src/api/index.js index e4930aa..a23a371 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -10,4 +10,5 @@ setupResponseInterceptors(instance) export { adminApi } from './modules/admin' export { invitationApi } from './modules/invitation' export { depotApi } from './modules/depot' -export { userApi } from './modules/user' \ No newline at end of file +export { userApi } from './modules/user' +export { userLoginApi } from './modules/userLogin' \ No newline at end of file diff --git a/src/api/interceptors/response.js b/src/api/interceptors/response.js index 7708482..de52564 100644 --- a/src/api/interceptors/response.js +++ b/src/api/interceptors/response.js @@ -54,11 +54,11 @@ export function setupResponseInterceptors(instance) { return Promise.reject(error); } - // 调用刷新接口 + // 调用用户刷新接口 const formData = new FormData(); formData.append('refreshToken', refreshToken); - const response = await axiosInstance.post('/admin/refreshToken', formData); + const response = await axiosInstance.post('/userLogin/refreshToken', formData); console.log('刷新token响应:', response); // 后端返回格式: { code: 200, data: { accessToken: "xxx", refreshToken: "xxx" } } diff --git a/src/api/modules/user.js b/src/api/modules/user.js index 3d70d3e..9e0c056 100644 --- a/src/api/modules/user.js +++ b/src/api/modules/user.js @@ -2,8 +2,8 @@ import instance from '../../utils/axios.js' // 用户相关API const userApi = { - // 获取用户列表 - getUserList: () => instance.get('/user/list'), + // 获取用户列表(支持分页和搜索) + getUserList: (params) => instance.get('/user/list', { params }), // 获取单个用户信息 getUserById: (id) => instance.get(`/user/get/${id}`), diff --git a/src/api/permission.js b/src/api/permission.js index 2d75805..c2be567 100644 --- a/src/api/permission.js +++ b/src/api/permission.js @@ -1,7 +1,37 @@ import axios from '@/utils/axios' /** - * 获取权限树 + * 获取当前用户权限树 + */ +export function getUserPermissionTree() { + return axios({ + url: '/admin/permission/user/tree', + method: 'get' + }) +} + +/** + * 获取当前用户菜单树(用于侧边栏显示) + */ +export function getUserMenuTree() { + return axios({ + url: '/admin/permission/user/tree', + method: 'get' + }) +} + +/** + * 获取当前用户权限编码列表 + */ +export function getUserPermissionCodes() { + return axios({ + url: '/admin/permission/user/codes', + method: 'get' + }) +} + +/** + * 获取权限树(管理用) */ export function getPermissionTree() { return axios({ @@ -40,4 +70,4 @@ export function deletePermission(id) { url: `/admin/permission/delete/${id}`, method: 'delete' }) -} \ No newline at end of file +} diff --git a/src/layout/Index.vue b/src/layout/Index.vue index 80cf3c5..cff85f0 100644 --- a/src/layout/Index.vue +++ b/src/layout/Index.vue @@ -4,7 +4,7 @@ - + diff --git a/src/layout/Sidebar.vue b/src/layout/Sidebar.vue index 22d65db..6471567 100644 --- a/src/layout/Sidebar.vue +++ b/src/layout/Sidebar.vue @@ -1,7 +1,8 @@ \ No newline at end of file +} + diff --git a/src/main.js b/src/main.js index 6021e3f..6e0c91c 100644 --- a/src/main.js +++ b/src/main.js @@ -2,17 +2,32 @@ import { createApp } from 'vue' import App from './App.vue' import router from './router' import store from './store' -import axios from './utils/axios' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' -import './styles/global.css' -import { globalConfig } from './config/global' -import zhCn from 'element-plus/es/locale/lang/zh-cn' -import globalComponents from './components' +import { permission, permissionAll } from '@/directives/permission' +import { initUserPermissions } from '@/utils/permission' const app = createApp(App) -app.config.globalProperties.$axios = axios -app.config.globalProperties.$global = globalConfig +// 过滤 Element Plus 的 slot 警告 +app.config.warnHandler = (msg, instance, trace) => { + // 忽略 Element Plus 组件的 slot 警告 + if (msg.includes('Slot "default" invoked outside of the render function')) { + return + } + // 其他警告正常显示 + console.warn(`[Vue warn]: ${msg}`, instance, trace) +} -app.use(store).use(router).use(ElementPlus, { locale: zhCn }).use(globalComponents).mount('#app') +// 注册权限指令 +app.directive('permission', permission) +app.directive('permission-all', permissionAll) + +app.use(store) +app.use(router) +app.use(ElementPlus) + +// 初始化用户权限 +initUserPermissions().then(() => { + app.mount('#app') +}) diff --git a/src/router/index.js b/src/router/index.js index f2c8cb2..6717821 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,5 +1,5 @@ -import { createRouter,createWebHistory } from 'vue-router' -import store from '@/store' +import { createRouter, createWebHistory } from 'vue-router' +import { getUserPermissions } from '@/utils/permission' const routes = [{ path: '/', @@ -8,91 +8,113 @@ const routes = [{ path: '', component: () => import('@/components/TabsView.vue'), meta: {noLayout: true}, - children: [{ + children: [ + { path: '/welcome', component: () => import('@/views/Welcome/Index.vue'), meta: { title: '欢迎' } }, + // 入驻配置 { path: '/SettledConfig/list', component: () => import('@/views/SettledConfig/List.vue'), - meta: { title: '配置列表' } + meta: { title: '配置列表', permission: 'settled:config:list' } }, { path: '/SettledConfig/memberRecord', component: () => import('@/views/SettledConfig/MemberRecord.vue'), - meta: { title: '会员开通记录' } + meta: { title: '会员开通记录', permission: 'settled:member:record' } }, + // 用户管理 { path: '/user/list', component: () => import('@/views/User/List.vue'), - meta: { title: '用户列表' } + meta: { title: '用户列表', permission: 'user:list:view' } }, { path: '/user/role', component: () => import('@/views/User/Role.vue'), - meta: { title: '角色管理' } + meta: { title: '角色管理', permission: 'user:role:manage' } }, { path: '/user/permission', component: () => import('@/views/User/Permission.vue'), - meta: { title: '权限管理' } + meta: { title: '权限管理', permission: 'user:permission:manage' } }, + // 邀请管理 + { + path: '/invitation/list', + component: () => import('@/views/Invitation/List/index.vue'), + meta: { title: '邀请列表', permission: 'invitation:list:view' } + }, + // 店铺管理 { path: '/shop/list', component: () => import('@/views/Shop/index.vue'), - meta: { title: '店铺列表' } + meta: { title: '店铺列表', permission: 'shop:list:view' } }, + // 选品管理 + { + path: '/book/selection/center', + component: () => import('@/views/baseInfo/index.vue'), + meta: { title: '选品中心', permission: 'book:selection:view' } + }, + // 仓库管理 + { + path: '/warehouse/depot/list', + component: () => import('@/views/Warehouse/Depot/List.vue'), + meta: { title: '货区管理', permission: 'warehouse:depot:view' } + }, + // 工具管理 { path: '/tools/cards/list', component: () => import('@/views/Tools/Cards/List.vue'), - meta: { title: '卡密列表' } + meta: { title: '卡密列表', permission: 'cards:list:view' } }, { path: '/tools/cards/activeCardsList', component: () => import('@/views/Tools/Cards/ActiveCardsList.vue'), - meta: { title: '活跃卡密列表' } + meta: { title: '活跃卡密列表', permission: 'cards:active:view' } }, + // 审核管理 { path: '/examine/violation/list', component: () => import('@/views/Examine/Violation/List.vue'), meta: { title: '违规列表' } }, + // 日志管理 { path: '/log/runningLog/list', - component: () => import('@/views/log/RunningLog/List.vue'), - meta: { title: '日志列表' } - }, - { - path: '/useModule/vas/list', - component: () => import('@/views/UseModule/Vas/List.vue'), - meta: { title: '订阅服务' } - }, - { - path: '/invitation/list', - component: () => import('@/views/Invitation/List/index.vue'), - meta: { title: '邀请列表' } - }, - { - path: '/order/wechat/list', - component: () => import('@/views/order/wechat/list.vue'), - meta: { title: '订单列表' } - }, - { - path: '/book/selection/center', - component: () => import('@/views/baseInfo/index.vue'), - meta: { title: '选品中心' } - }, - { - path: '/warehouse/depot/list', - component: () => import('@/views/Warehouse/Depot/List.vue'), - meta: { title: '货区管理' } + component: () => import('@/views/Log/RunningLog/List.vue'), + meta: { title: '运行日志', permission: 'log:running:view' } }, + // 任务管理 { path: '/task/list', component: () => import('@/views/Task/List.vue'), - meta: { title: '任务列表' } + meta: { title: '任务列表', permission: 'task:list:view' } + }, + // 功能模块 + { + path: '/useModule/vas/list', + component: () => import('@/views/UseModule/Vas/List.vue'), + meta: { title: '服务列表', permission: 'vas:list:view' } + }, + // 监控中心 + { + path: '/monitor/dashboard', + component: () => import('@/views/Monitor/Dashboard.vue'), + meta: { title: '监控大屏', permission: 'monitor:dashboard:view' } + }, + // 物流模板 + { + path: '/warehouse/logistics', + component: () => import('@/views/logistics/index.vue'), + // meta: { title: '物流模板', permission: 'logistics:view' } + meta: { title: '物流模板' } + } + ] }] @@ -102,28 +124,32 @@ const routes = [{ component: () => import('@/views/Login/Index.vue'), meta: { noLayout: true,public: true } }, + { + path: '/redirectUrl', + component: () => import('@/views/redirectUrl/index.vue'), + meta: { noLayout: true, title: '用户注册', public: true } + }, ] // 定义 路由 const router = createRouter({history: createWebHistory(),routes}) -// 路由守卫 +// 路由权限守卫 router.beforeEach((to, from, next) => { - // 定义 是否为公开 - const isPublic = to.meta.public - // 定义 是否已认证 - const isAuthenticated = store.getters.isAuthenticated - // 如果访问根路径, 重定向到welcome页 - if (to.path === '/' && isAuthenticated) return next('/welcome') - // 已认证用户访问登录页自动跳转首页 - if (to.path === '/login' && isAuthenticated) return next('/welcome') - // 需要认证且未登录 - if (!isPublic && !isAuthenticated) { - // 跳转到登录 并且带上属性 - return next({ path: '/login',query: { redirect: to.fullPath } }) + // 检查路由是否需要权限 + if (to.meta && to.meta.permission) { + const userPermissions = getUserPermissions() + const requiredPermission = to.meta.permission + + if (userPermissions.includes(requiredPermission)) { + next() + } else { + // 没有权限,跳转到403页面或首页 + next('/403') + } + } else { + next() } - // 正常跳转 - next() }) // 返回 模块 -export default router \ No newline at end of file +export default router diff --git a/src/store/Index.js b/src/store/Index.js index 536a9b8..2ad1577 100644 --- a/src/store/Index.js +++ b/src/store/Index.js @@ -1,6 +1,7 @@ import { createStore } from 'vuex' -import { adminApi } from '../api/index.js' +import { userLoginApi } from '../api/index.js' import webSocketService from '../utils/webSocket.js' +import { initUserPermissions } from '../utils/permission.js' export default createStore({ state: { @@ -32,7 +33,7 @@ export default createStore({ localStorage.removeItem('refreshToken') // 清除本地缓存 localStorage.removeItem('userInfo') - + // 断开WebSocket连接 webSocketService.disconnect() }, @@ -44,21 +45,47 @@ export default createStore({ } }, actions: { - async login({commit}, data) { + async login({ commit }, data) { try { - // 调用登录接口 - const response = await adminApi.login(data) - console.log("响应",response) + // 转换字段名:username -> phonenumber(因为userLogin接口使用phonenumber) + let loginData = data; + if (data instanceof FormData) { + const newFormData = new FormData(); + for (let [key, value] of data.entries()) { + if (key === 'username') { + newFormData.append('phonenumber', value); + } else if (key === 'captcha') { + newFormData.append('code', value); + } else { + newFormData.append(key, value); + } + } + loginData = newFormData; + + // 调试日志:查看转换后的数据 + console.log('转换后的FormData内容:'); + for (let [key, value] of loginData.entries()) { + console.log(`${key}: ${value}`); + } + } + + // 调用用户登录接口 + const response = await userLoginApi.userLogin(loginData) + console.log("用户登录响应", response) + // 检查响应状态 if (response.code !== 200) { throw new Error(response.message || '登录失败') } - - // 设置 状态 - commit('SET_TOKEN', response.data) + + // 设置 token 状态 + commit('SET_TOKEN', { + accessToken: response.data.accessToken, + refreshToken: response.data.refreshToken + }) // 添加更多日志,确保token存在 - console.log("登录成功,准备连接WebSocket") + console.log("用户登录成功,准备连接WebSocket") console.log("accessToken值:", response.data.accessToken) // 登录成功后连接WebSocket @@ -67,26 +94,29 @@ export default createStore({ } else { console.error("无法连接WebSocket: accessToken不存在") } - - try { - // 调用查询接口获取用户信息 - const admin = await adminApi.getAdmin() - - // 检查响应状态 - if (admin.code !== 200) { - console.error('获取用户信息失败:', admin.message) - // 不清空认证信息,仅返回警告 - return Promise.resolve('登录成功,但获取用户信息失败') - } - - // 设置 管理员信息 - commit('SET_USER_INFO', admin.data) - } catch (adminError) { - // 记录错误但不清空认证信息 - console.error('获取用户信息出错:', adminError) - return Promise.resolve('登录成功,但获取用户信息失败') + + // 设置用户信息(userLogin接口直接返回用户信息) + const userInfo = { + userId: response.data.userId, + username: response.data.userName, + nickName: response.data.nickName, + phonenumber: response.data.phonenumber, + email: response.data.email, + sex: response.data.sex, + userType: response.data.userType, + status: response.data.status } - + commit('SET_USER_INFO', userInfo) + + // 初始化用户权限 + try { + await initUserPermissions() + console.log("用户权限初始化成功") + } catch (permissionError) { + console.error("用户权限初始化失败:", permissionError) + // 权限初始化失败不影响登录,只记录错误 + } + // 抛出 消息 return Promise.resolve('登录成功') } catch (error) { @@ -96,7 +126,7 @@ export default createStore({ return Promise.reject(error) } }, - logout({commit}) { + logout({ commit }) { // 清空 状态 commit('CLEAR_AUTH') } diff --git a/src/utils/axios.js b/src/utils/axios.js index 9b80b3b..59f8f0a 100644 --- a/src/utils/axios.js +++ b/src/utils/axios.js @@ -3,11 +3,27 @@ import axios from 'axios' const instance = axios.create({ baseURL: '/api', timeout: 30000, // 增加超时时间到30秒 - // headers: { - // 'Content-Type': 'multipart/form-data' - // } }) - +// 添加请求拦截器来处理Content-Type和Authorization +instance.interceptors.request.use(config => { + // 添加Authorization头 + const token = localStorage.getItem('accessToken') + if (token) { + config.headers['Authorization'] = `Bearer ${token}` + } + + // 如果是FormData,让浏览器自动设置Content-Type + if (config.data instanceof FormData) { + // 删除Content-Type,让浏览器自动设置(包括boundary) + delete config.headers['Content-Type'] + } else if (config.data && typeof config.data === 'object') { + // 对于普通对象,设置为JSON格式 + config.headers['Content-Type'] = 'application/json' + } + return config +}, error => { + return Promise.reject(error) +}) export default instance \ No newline at end of file diff --git a/src/views/Examine/Violation/List.vue b/src/views/Examine/Violation/List.vue index 16efec9..9629af0 100644 --- a/src/views/Examine/Violation/List.vue +++ b/src/views/Examine/Violation/List.vue @@ -24,8 +24,8 @@ - - + + @@ -39,37 +39,29 @@ - +
- + - - + + @@ -80,7 +72,7 @@ - + @@ -95,33 +87,16 @@
- +
- + - - + + @@ -172,10 +147,10 @@ const remark = ref('') // 搜索表单 const searchForm = reactive({ - type:'', - name:'', - review:'', - status:'' + type: '', + name: '', + review: '', + status: '' }) // 分页配置 @@ -194,12 +169,12 @@ const single = ref(true); const multiple = ref(true); /** 多选框选中数据 */ const handleSelectionChange = (selection) => { - ids.value = selection.map(item => item.id); - names.value = selection.map(item => item.name); - reviews.value = selection.map(item => item.review); - sorts.value = selection.map(item => item.sort); - single.value = selection.length != 1; - multiple.value = !selection.length; + ids.value = selection.map(item => item.id); + names.value = selection.map(item => item.name); + reviews.value = selection.map(item => item.review); + sorts.value = selection.map(item => item.sort); + single.value = selection.length != 1; + multiple.value = !selection.length; } @@ -215,23 +190,23 @@ onMounted(() => { const fetchData = async () => { loading.value = true try { - + // 构建查询参数 const params = { - page: pagination.current, - size: pagination.size, + pageNum: pagination.current, // 后端期望 pageNum + pageSize: pagination.size, // 后端期望 pageSize type: searchForm.type !== null ? searchForm.type : undefined, name: searchForm.name || undefined, status: searchForm.status || undefined, review: searchForm.review !== null ? searchForm.review : undefined, } - + // 使用API模块获取数据 const res = await violationApi.pageQuery(params) // 由于响应拦截器已经提取了response.data,所以直接使用res if (res.code === 200) { - - tableData.value = res.data.list || [] + // 适配后端返回的数据结构:data.rows 而不是 data.list + tableData.value = res.data.rows || [] pagination.total = res.data.total || 0 } else { ElMessage.error(res.message || '获取数据失败') @@ -248,7 +223,7 @@ const fetchData = async () => { } else { ElMessage.error(`请求错误: ${error.message}`) } - + // 设置空数据 tableData.value = [] pagination.total = 0 @@ -260,12 +235,12 @@ const fetchData = async () => { //驳回 const btnError = () => { - for(var i=0;i { //通过 const btnSuccess = async () => { - for(var i=0;i { const res = await violationApi.successSubmit(ids.value); - if(res.code == '200'){ + if (res.code == '200') { ElMessage.success('审核成功'); fetchData() - }else{ + } else { ElMessage.error('系统异常,请联系管理员'); } } const setReviewCellStyle = ({ row, column }) => { - if (row.review == 1) { - return 'shenhe-row'; // 返回自定义的 class 名称 - } + if (row.review == 1) { + return 'shenhe-row'; // 返回自定义的 class 名称 + } } @@ -370,31 +345,31 @@ const getReview = (review) => { const getSort = (sort) => { const map = { - 0:'拼多多', - 1:'孔夫子', - 2:'淘宝', - 3:'咸鱼' + 0: '拼多多', + 1: '孔夫子', + 2: '淘宝', + 3: '咸鱼' } return map[sort] || 'info' } -const getSortContent = () =>{ - return [ +const getSortContent = () => { + return [ { - "label":"拼多多", - "value":"0" + "label": "拼多多", + "value": "0" }, { - "label":"孔夫子", - "value":"1" + "label": "孔夫子", + "value": "1" }, { - "label":"淘宝", - "value":"2" + "label": "淘宝", + "value": "2" }, { - "label":"咸鱼", - "value":"3" + "label": "咸鱼", + "value": "3" }, ] @@ -418,35 +393,35 @@ const formatDateTime = (timestamp) => { return date.toLocaleString() } // 驳回提交 -const submit = async () =>{ - if(!remark.value){ +const submit = async () => { + if (!remark.value) { ElMessage.error('请填写驳回原因!!!'); return } - const res = await violationApi.submit(ids.value,remark.value); + const res = await violationApi.submit(ids.value, remark.value); - if(res.code == '200'){ + if (res.code == '200') { violationVisible.value = false; ElMessage.success('驳回成功'); remark.value = ''; fetchData() - }else{ + } else { ElMessage.error('系统异常,请联系管理员'); } } //修改违规平台提交 -const editSubmit = async() =>{ +const editSubmit = async () => { - const res = await violationApi.editSubmit(ids.value,sortArr.value); + const res = await violationApi.editSubmit(ids.value, sortArr.value); - if(res.code == '200'){ + if (res.code == '200') { violtaionEditVisible.value = false; ElMessage.success('修改成功'); sortArr.value = []; fetchData() - }else{ + } else { ElMessage.error('系统异常,请联系管理员'); } } @@ -504,7 +479,7 @@ const editSubmit = async() =>{ .card-secret-content { text-align: left; - + p { margin-bottom: 15px; font-size: 16px; @@ -513,7 +488,7 @@ const editSubmit = async() =>{ .card-params-content { text-align: left; - + p { margin-bottom: 15px; font-size: 16px; @@ -533,4 +508,4 @@ const editSubmit = async() =>{ .unit-label { margin-left: 5px; } - \ No newline at end of file + \ No newline at end of file diff --git a/src/views/Home/Index.vue b/src/views/Home/Index.vue index 81a9f7d..62ff740 100644 --- a/src/views/Home/Index.vue +++ b/src/views/Home/Index.vue @@ -1,9 +1,811 @@ - + + + \ No newline at end of file diff --git a/src/views/Login/index.vue b/src/views/Login/index.vue index edca692..3ba9105 100644 --- a/src/views/Login/index.vue +++ b/src/views/Login/index.vue @@ -7,7 +7,7 @@ - + { - captchaUrl.value = `https://newadmin.buzhiyushu.cn/admin/generateCaptcha?t=${Date.now()}` + captchaUrl.value = `/api/userLogin/generateCaptcha?t=${Date.now()}` } // 处理登录 diff --git a/src/views/Task/List.vue b/src/views/Task/List.vue index dbca112..1d081e9 100644 --- a/src/views/Task/List.vue +++ b/src/views/Task/List.vue @@ -166,6 +166,12 @@ const logsList = ref([]) const logsMessage = ref('') const currentTaskId = ref('') +// 详细日志相关数据 +const detailLogsVisible = ref(false) +const detailLogsLoading = ref(false) +const detailLogsList = ref([]) +const currentDetailShopLog = ref(null) + // 获取任务列表 const fetchTaskList = async () => { loading.value = true @@ -394,18 +400,46 @@ const refreshLogs = () => { // 查看详细日志 const handleViewDetail = async (row) => { try { + // 保存当前选中的店铺日志 + currentDetailShopLog.value = row + + // 显示加载状态 + detailLogsLoading.value = true + detailLogsVisible.value = true + + // 调用API获取详细日志数据 const res = await taskApi.getLogsDetailList(row.taskId, row.shopId) console.log('详细日志响应:', res) if (res.code === 200) { - // 这里可以打开一个新的弹窗显示详细日志,或者跳转到详细页面 - ElMessage.success('查看详细日志功能待实现') + // 处理返回的数据 + if (res.data && typeof res.data === 'object') { + // 如果返回的是嵌套对象,尝试获取数据数组 + if (Array.isArray(res.data.data)) { + detailLogsList.value = res.data.data + } else if (Array.isArray(res.data.list)) { + detailLogsList.value = res.data.list + } else if (Array.isArray(res.data.records)) { + detailLogsList.value = res.data.records + } else if (Array.isArray(res.data)) { + detailLogsList.value = res.data + } else { + detailLogsList.value = [] + console.warn('未能识别的详细日志数据格式:', res.data) + } + } else { + detailLogsList.value = [] + } } else { + detailLogsList.value = [] ElMessage.error('获取详细日志失败: ' + (res.message || '未知错误')) } } catch (error) { console.error('获取详细日志出错:', error) ElMessage.error('获取详细日志失败: ' + (error.message || '未知错误')) + detailLogsList.value = [] + } finally { + detailLogsLoading.value = false } } @@ -449,6 +483,41 @@ const formatLogMessage = (message) => { return lines } +// 处理API错误 +const handleApiError = (error, operation, defaultMessage = '操作失败') => { + console.error(`${operation}出错:`, error) + + // 确定错误消息 + let errorMessage = defaultMessage + + if (error.response) { + // 服务器返回了错误状态码 + const status = error.response.status + if (status === 404) { + errorMessage = `${operation}: 资源不存在 (404)` + } else if (status === 403) { + errorMessage = `${operation}: 权限不足 (403)` + } else if (status === 401) { + errorMessage = `${operation}: 未授权,请重新登录 (401)` + } else if (status >= 500) { + errorMessage = `${operation}: 服务器错误 (${status})` + } else { + errorMessage = `${operation}: ${error.response.data?.message || error.message || '未知错误'}` + } + } else if (error.request) { + // 请求已发送但没有收到响应 + errorMessage = `${operation}: 网络错误,请检查网络连接` + } else { + // 请求设置时出错 + errorMessage = `${operation}: ${error.message || '未知错误'}` + } + + // 显示错误消息 + ElMessage.error(errorMessage) + + return errorMessage +} + // 组件挂载时获取任务列表 onMounted(() => { fetchTaskList() diff --git a/src/views/User/List.vue b/src/views/User/List.vue index e574b36..a103dc2 100644 --- a/src/views/User/List.vue +++ b/src/views/User/List.vue @@ -3,7 +3,7 @@
- - - - + + + + - + + + + + + +