11 changed files with 432 additions and 156 deletions
-
1.env.development
-
379src/router/index.js
-
80src/utils/menu-utils.ts
-
66src/views/audit/audit.vue
-
6src/views/consume/coinConsume.vue
-
2src/views/home.vue
-
4src/views/login.vue
-
6src/views/recharge/coinRecharge.vue
-
6src/views/refund/coinRefund.vue
-
7src/views/usergold/clientCount.vue
-
31src/views/workspace/index.vue
@ -1,3 +1,4 @@ |
|||||
VITE_API_BASE='https://hwjb.homilychart.com/dev/admin' |
VITE_API_BASE='https://hwjb.homilychart.com/dev/admin' |
||||
|
# VITE_API_BASE='http://192.168.9.52:8081/' |
||||
VITE_UPLOAD_URL=http://39.101.133.168:8828/hljw/api/aws/upload |
VITE_UPLOAD_URL=http://39.101.133.168:8828/hljw/api/aws/upload |
||||
|
|
@ -1,114 +1,319 @@ |
|||||
import { createRouter, createWebHashHistory } from 'vue-router'; |
import { createRouter, createWebHashHistory } from 'vue-router'; |
||||
import axios from "axios"; |
import axios from "axios"; |
||||
|
import request from "@/util/http.js"; |
||||
|
import {ref} from "vue"; |
||||
|
|
||||
|
// 路由定义(包含权限映射 meta.permissionId)
|
||||
|
const routes = [ |
||||
|
// {
|
||||
|
// path: '/workspace',
|
||||
|
// name: "workspace",
|
||||
|
// component: () => import("../views/workspace/audit.vue"),
|
||||
|
// meta: { permissionId: 10 } // 对应"工作台展示"id=10
|
||||
|
// },
|
||||
|
{ |
||||
|
path: '/', |
||||
|
redirect: "/login" |
||||
|
}, |
||||
|
{ |
||||
|
path: "/login", |
||||
|
name: "login", |
||||
|
component: () => import("../views/login.vue"), |
||||
|
}, |
||||
|
{ |
||||
|
meta: { requireAuth: true }, |
||||
|
path: '/', |
||||
|
component: () => import("../views/home.vue"), |
||||
|
children: [ |
||||
|
// 工作台
|
||||
|
{ |
||||
|
path: '/workspace', |
||||
|
name: "workspace", |
||||
|
component: () => import("../views/workspace/index.vue"), |
||||
|
meta: { permissionId: 10 } // 对应"工作台展示"id=10
|
||||
|
}, |
||||
|
|
||||
|
|
||||
|
// 审核
|
||||
|
{ |
||||
|
path: '/audit', |
||||
|
name: "audit", |
||||
|
component: () => import("../views/audit/audit.vue"), |
||||
|
meta: { permissionId: 40 }, |
||||
|
// redirect: '/index',
|
||||
|
children: [ |
||||
|
// 充值审核
|
||||
|
{ |
||||
|
path: 'rechargeAudit', |
||||
|
name: "rechargeAudit", |
||||
|
component: () => import("../views/audit/rechargeAudit.vue"), |
||||
|
meta: { permissionId: [11, 12] } // 对应"查看充值审核"id=11、"充值审批"id=12
|
||||
|
}, |
||||
|
// 退款审核
|
||||
|
{ |
||||
|
path: 'refundAudit', |
||||
|
name: "refundAudit", |
||||
|
component: () => import("../views/audit/refundAudit.vue"), |
||||
|
meta: { permissionId: [13, 14] } // 对应"查看退款审核"id=13、"退款审批"id=14
|
||||
|
}, |
||||
|
] |
||||
|
}, |
||||
|
|
||||
|
|
||||
|
|
||||
|
// 金币消耗
|
||||
|
{ |
||||
|
path: '/coinConsume', |
||||
|
name: "coinConsume", |
||||
|
component: () => import("../views/consume/coinConsume.vue"), |
||||
|
// redirect: '/coinConsume/add',
|
||||
|
meta: { permissionId: 6 }, |
||||
|
children: [ |
||||
|
// 金币新增消耗
|
||||
|
{ |
||||
|
path: 'add', |
||||
|
name: "addCoinConsume", |
||||
|
component: () => import("../views/consume/addCoinConsume.vue"), |
||||
|
meta: { permissionId: 19 } // 对应"提交金币消耗"id=19
|
||||
|
}, |
||||
|
// 金币消耗明细详情
|
||||
|
{ |
||||
|
path: 'detail', |
||||
|
name: "coinConsumeDetail", |
||||
|
component: () => import("../views/consume/coinConsumeDetail.vue"), |
||||
|
meta: { permissionId: 20 } // 对应"查看金币消耗明细"id=20
|
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
|
||||
|
// 汇率管理
|
||||
|
{ |
||||
|
path: '/rate', |
||||
|
name: "rate", |
||||
|
component: () => import("../views/managerecharge/rate.vue"), |
||||
|
meta: { permissionId: [15, 16] } // 对应"汇率查看"id=15、"汇率修改"id=16
|
||||
|
}, |
||||
|
// 金币充值
|
||||
|
{ |
||||
|
path: '/coinRecharge', |
||||
|
name: "coinRecharge", |
||||
|
component: () => import("../views/recharge/coinRecharge.vue"), |
||||
|
// redirect: '/coinRecharge/add',
|
||||
|
children: [ |
||||
|
// 金币新增充值
|
||||
|
{ |
||||
|
path: 'add', |
||||
|
name: "addCoinRecharge", |
||||
|
component: () => import("../views/recharge/addCoinRecharge.vue"), |
||||
|
meta: { permissionId: 17 } // 对应"提交金币充值"id=17
|
||||
|
}, |
||||
|
// 金币充值明细详情
|
||||
|
{ |
||||
|
path: 'detail', |
||||
|
name: "coinRechargeDetail", |
||||
|
component: () => import("../views/recharge/coinRechargeDetail.vue"), |
||||
|
meta: { permissionId: 18 } // 对应"查看金币充值明细"id=18
|
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
|
||||
|
// 金币退款
|
||||
|
{ |
||||
|
path: '/coinRefund', |
||||
|
name: "coinRefund", |
||||
|
component: () => import("../views/refund/coinRefund.vue"), |
||||
|
// redirect: '/coinRefund/add',
|
||||
|
meta: { permissionId: 7 }, |
||||
|
children: [ |
||||
|
// 金币新增退款
|
||||
|
{ |
||||
|
path: 'add', |
||||
|
name: "addCoinRefund", |
||||
|
component: () => import("../views/refund/addCoinRefund.vue"), |
||||
|
meta: { permissionId: 21 } // 对应"提交金币退款"id=21
|
||||
|
}, |
||||
|
// 金币退款明细详情
|
||||
|
{ |
||||
|
path: 'detail', |
||||
|
name: "coinRefundDetail", |
||||
|
component: () => import("../views/refund/coinRefundDetail.vue"), |
||||
|
meta: { permissionId: 22 } // 对应"查看金币退款明细"id=22
|
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
|
||||
|
// 客户账户明细
|
||||
|
{ |
||||
|
path: '/usergold', |
||||
|
name: "usergold", |
||||
|
component: () => import("../views/usergold/clientCount.vue"), |
||||
|
// redirect: '/usergold/detail',
|
||||
|
meta: { permissionId: 8 }, |
||||
|
children: [ |
||||
|
// 金币明细
|
||||
|
{ |
||||
|
path: 'detail', |
||||
|
name: "clientCountDetail", |
||||
|
component: () => import("../views/usergold/clientCountDetail.vue"), |
||||
|
meta: { permissionId: 23 } // 对应"查看金币明细"id=23
|
||||
|
}, |
||||
|
// 金币余额
|
||||
|
{ |
||||
|
path: 'balance', |
||||
|
name: "clientCountBalance", |
||||
|
component: () => import("../views/usergold/clientCountBalance.vue"), |
||||
|
meta: { permissionId: 24 } // 对应"查看金币余额"id=24
|
||||
|
}, |
||||
|
] |
||||
|
}, |
||||
|
// 权限管理
|
||||
|
{ |
||||
|
path: '/permissions', |
||||
|
name: "permissions", |
||||
|
component: () => import("../views/permissions/permission.vue"), |
||||
|
meta: { permissionId: [25, 26, 27, 28, 29] } // 对应权限管理下的所有操作
|
||||
|
}, |
||||
|
// 没有权限
|
||||
|
{ |
||||
|
path: '/noPermission', |
||||
|
name: "noPermission", |
||||
|
component: () => import("../views/noPermissionPage.vue") |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
// 跳转页面(无需权限)
|
||||
|
{ |
||||
|
path: '/PasswordSuccess', |
||||
|
name: "PasswordSuccess", |
||||
|
component: () => import("../components/PasswordSuccess.vue") |
||||
|
} |
||||
|
]; |
||||
|
|
||||
|
// 创建路由实例
|
||||
const router = createRouter({ |
const router = createRouter({ |
||||
history: createWebHashHistory(), |
history: createWebHashHistory(), |
||||
routes: [ |
|
||||
{ path: '/workspace', name: "workspace", component: () => import("../views/workspace/index.vue") }, |
|
||||
{ path: '/', redirect: "/login" }, |
|
||||
{path: "/login",name: "login",component: () => import("../views/login.vue"),}, |
|
||||
// { path: '/test', component: () => import("../views/z.vue") },
|
|
||||
{ |
|
||||
meta: { requireAuth: true }, |
|
||||
path: '/', component: () => import("../views/home.vue"), |
|
||||
children: [ |
|
||||
// 工作台
|
|
||||
{ path: '/workspace/:area?', name: "workspace", component: () => import("../views/workspace/index.vue") }, |
|
||||
// 充值审核
|
|
||||
{ path: '/rechargeAudit', name: "rechargeAudit", component: () => import("../views/audit/rechargeAudit.vue") }, |
|
||||
// 退款审核
|
|
||||
{ path: '/refundAudit', name: "refundAudit", component: () => import("../views/audit/refundAudit.vue") }, |
|
||||
// 金币消耗
|
|
||||
{ path: '/coinConsume', name: "coinConsume", component: () => import("../views/consume/coinConsume.vue"), |
|
||||
redirect: '/coinConsume/add',// 重定向到新增消耗页面
|
|
||||
children: [ |
|
||||
// 金币新增消耗
|
|
||||
{ path: 'add', name: "addCoinConsume", component: () => import("../views/consume/addCoinConsume.vue") }, |
|
||||
// 金币消耗明细详情
|
|
||||
{ path: 'detail', name: "coinConsumeDetail", component: () => import("../views/consume/coinConsumeDetail.vue") } |
|
||||
] |
|
||||
}, |
|
||||
// 金豆消耗
|
|
||||
{ path: '/beanConsume', name: "beanConsume", component: () => import("../views/consume/beanConsume.vue") }, |
|
||||
// 汇率管理
|
|
||||
{ path: '/rate', name: "rate", component: () => import("../views/managerecharge/rate.vue") }, |
|
||||
// 金币充值
|
|
||||
{ path: '/coinRecharge', name: "coinRecharge", component: () => import("../views/recharge/coinRecharge.vue"), |
|
||||
redirect: '/coinRecharge/add',// 重定向到新增充值页面
|
|
||||
children: [ |
|
||||
// 金币新增充值
|
|
||||
{ path: 'add', name: "addCoinRecharge", component: () => import("../views/recharge/addCoinRecharge.vue") }, |
|
||||
// 金币充值明细详情
|
|
||||
{ path: 'detail', name: "coinRechargeDetail", component: () => import("../views/recharge/coinRechargeDetail.vue") } |
|
||||
] |
|
||||
}, |
|
||||
// 金豆充值
|
|
||||
{ path: '/beanRecharge', name: "beanRecharge", component: () => import("../views/recharge/beanRecharge.vue") }, |
|
||||
// 金币退款
|
|
||||
{ path: '/coinRefund', name: "coinRefund", component: () => import("../views/refund/coinRefund.vue"), |
|
||||
redirect: '/coinRefund/add',// 重定向到新增退款页面
|
|
||||
children: [ |
|
||||
// 金币新增消耗
|
|
||||
{ path: 'add', name: "addCoinRefund", component: () => import("../views/refund/addCoinRefund.vue") }, |
|
||||
// 金币消耗明细详情
|
|
||||
{ path: 'detail', name: "coinRefundDetail", component: () => import("../views/refund/coinRefundDetail.vue") } |
|
||||
] |
|
||||
}, |
|
||||
// 金豆退款
|
|
||||
{ path: '/beanRefund', name: "beanRefund", component: () => import("../views/refund/beanRefund.vue") }, |
|
||||
// 客户账户明细
|
|
||||
{ path: '/usergold', name: "usergold", component: () => import("../views/usergold/clientCount.vue"), |
|
||||
redirect: '/usergold/detail',// 重定向到客户账户明细页面
|
|
||||
children: [ |
|
||||
// 金币明细
|
|
||||
{ path: 'detail', name: "clientCountDetail", component: () => import("../views/usergold/clientCountDetail.vue") }, |
|
||||
// 金币余额
|
|
||||
{ path: 'balance', name: "clientCountBalance", component: () => import("../views/usergold/clientCountBalance.vue") }, |
|
||||
] |
|
||||
}, |
|
||||
// 权限管理
|
|
||||
{ path: '/permissions', name: "permissions", component: () => import("../views/permissions/permission.vue") }, |
|
||||
// 没有权限
|
|
||||
{ path: '/noPermission', name: "noPermission", component: () => import("../views/noPermissionPage.vue") } |
|
||||
] |
|
||||
|
|
||||
}, |
|
||||
// 跳转页面
|
|
||||
{ path: '/PasswordSuccess', name: "PasswordSuccess", component: () => import("../components/PasswordSuccess.vue") }, |
|
||||
|
|
||||
|
|
||||
|
|
||||
] |
|
||||
|
routes |
||||
}); |
}); |
||||
|
|
||||
|
|
||||
// 全局拦截器 token 过期拦截
|
|
||||
|
// 全局拦截器:token过期处理
|
||||
axios.interceptors.response.use( |
axios.interceptors.response.use( |
||||
response => response, |
response => response, |
||||
error => { |
error => { |
||||
if (error.response && error.response.status === 401) { |
if (error.response && error.response.status === 401) { |
||||
// 清除本地存储的token
|
|
||||
localStorage.removeItem('token'); |
localStorage.removeItem('token'); |
||||
// 跳转到登录页
|
|
||||
router.push({ |
router.push({ |
||||
name: 'login', |
name: 'login', |
||||
query: { machineId: localStorage.getItem('machineId'), expired: true } |
|
||||
|
query: { |
||||
|
machineId: localStorage.getItem('machineId'), |
||||
|
expired: true |
||||
|
} |
||||
}); |
}); |
||||
} |
} |
||||
return Promise.reject(error); |
return Promise.reject(error); |
||||
} |
} |
||||
); |
); |
||||
|
|
||||
|
// 工具函数:从菜单树提取所有权限ID
|
||||
|
const getAllPermissionIds = (menuTree) => { |
||||
|
let permissionIds = []; |
||||
|
const traverse = (menuList) => { |
||||
|
menuList.forEach(menu => { |
||||
|
permissionIds.push(menu.id); |
||||
|
if (menu.children && menu.children.length > 0) { |
||||
|
traverse(menu.children); |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
traverse(menuTree); |
||||
|
return permissionIds; |
||||
|
}; |
||||
|
|
||||
|
// 存储管理员信息(全局可访问)
|
||||
|
const adminData = ref(null); |
||||
|
|
||||
router.beforeEach((to, from, next) => { |
|
||||
|
// 获取管理员信息(返回Promise,方便路由守卫中使用)
|
||||
|
export const getAdminData = async function () { |
||||
|
try { |
||||
|
const result = await request({ |
||||
|
url: "/admin/userinfo", |
||||
|
|
||||
|
}); |
||||
|
adminData.value = result; // 存储管理员信息(包含roleId)
|
||||
|
return result; // 返回结果,供路由守卫使用
|
||||
|
} catch (error) { |
||||
|
console.log("获取管理员信息失败", error); |
||||
|
throw error; // 抛出错误,让路由守卫捕获
|
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 全局路由守卫
|
||||
|
router.beforeEach(async (to, from, next) => { |
||||
const token = localStorage.getItem("token"); |
const token = localStorage.getItem("token"); |
||||
const machineId = localStorage.getItem("machineId"); |
const machineId = localStorage.getItem("machineId"); |
||||
if (to.name != "login" && !token) { |
|
||||
next('/login?machineId=' + machineId); |
|
||||
|
|
||||
|
// 1. 未登录:强制跳转到登录页
|
||||
|
if (to.name !== "login" && !token) { |
||||
|
next(`/login?machineId=${machineId || ''}`); |
||||
|
return; |
||||
} |
} |
||||
next(); |
|
||||
}) |
|
||||
|
|
||||
|
// 2. 已登录:处理权限验证
|
||||
|
if (token) { |
||||
|
|
||||
|
// 获取管理员信息
|
||||
|
let roleId = null; |
||||
|
console.log('adminData:', adminData) |
||||
|
try { |
||||
|
await getAdminData(); // 等待管理员信息获取完成
|
||||
|
roleId = adminData.value.roleId; |
||||
|
if (!roleId) { |
||||
|
throw new Error("未获取到roleId"); |
||||
|
} |
||||
|
} catch (error) { |
||||
|
localStorage.removeItem('token'); // 清除token,强制重新登录
|
||||
|
next(`/login?machineId=${machineId || ''}`); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
let userPermissionIds = []; |
||||
|
try { |
||||
|
const response = await request( {url: "/menu/tree", |
||||
|
data:{id: roleId} |
||||
|
}); |
||||
|
console.log('roleId:', roleId) |
||||
|
console.log('response:', response) |
||||
|
console.log('userPermissionIds:', userPermissionIds) |
||||
|
if (response.code === 200 && response.data) { |
||||
|
userPermissionIds = getAllPermissionIds(response.data); // 提取权限id
|
||||
|
console.log('userPermissionIds:', userPermissionIds) |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.error('获取菜单树失败:', error); |
||||
|
localStorage.removeItem('token'); |
||||
|
next(`/login?machineId=${machineId || ''}`); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 2.4 权限验证(逻辑不变)
|
||||
|
console.log('to.meta:',to.meta) |
||||
|
|
||||
|
|
||||
|
const requiresPermission = to.meta && to.meta.permissionId; |
||||
|
if (requiresPermission) { |
||||
|
const hasPermission = Array.isArray(requiresPermission) |
||||
|
? requiresPermission.some(id => userPermissionIds.includes(id)) |
||||
|
: userPermissionIds.includes(requiresPermission); |
||||
|
|
||||
|
if (!hasPermission) { |
||||
|
next('/noPermission'); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 3. 正常跳转
|
||||
|
next(); |
||||
|
}); |
||||
|
|
||||
export default router; |
|
||||
|
export default router; |
@ -0,0 +1,66 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<!-- 这里放置标签切换的按钮 --> |
||||
|
<el-button-group> |
||||
|
<!-- 切换后状态显示 primary 样式否则是默认样式 --> |
||||
|
<el-button |
||||
|
:type="activeTab === 'rechargeAudit' ? 'primary' : 'default'" |
||||
|
@click="goRechargeAudit" |
||||
|
> |
||||
|
充值审核 |
||||
|
</el-button> |
||||
|
<el-button |
||||
|
:type="activeTab === 'refundAudit' ? 'primary' : 'default'" |
||||
|
@click="goRefundAudit" |
||||
|
> |
||||
|
退款审核 |
||||
|
</el-button> |
||||
|
</el-button-group> |
||||
|
<!-- 渲染子路由组件 --> |
||||
|
<router-view></router-view> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup > |
||||
|
import {onMounted, ref, watch} from 'vue'; |
||||
|
import { useRouter, useRoute } from 'vue-router'; |
||||
|
|
||||
|
const router = useRouter();// 获取路由实例 |
||||
|
const route = useRoute();// 获取当前路由信息 |
||||
|
// 定义响应式变量 activeTab 来跟踪当前激活的标签 |
||||
|
const activeTab = ref(route.name === 'rechargeAudit' ? 'rechargeAudit' : 'refundAudit'); |
||||
|
//也就是说如果当前在clientCountBalance页面,那么就是balance,否则默认情况都展示detail页面 |
||||
|
//此时获取到的路由信息是clientCountDetail,所以默认是detail |
||||
|
|
||||
|
|
||||
|
const goRechargeAudit = () => { |
||||
|
// 点击按钮时更新 activeTab 为 detail |
||||
|
activeTab.value = 'rechargeAudit'; |
||||
|
router.push({ name: 'rechargeAudit' }); |
||||
|
}; |
||||
|
|
||||
|
const goRefundAudit = () => { |
||||
|
// 点击按钮时更新 activeTab 为balance |
||||
|
activeTab.value = 'refundAudit'; |
||||
|
router.push({ name: 'refundAudit' }); |
||||
|
}; |
||||
|
|
||||
|
// 监听路由变化,更新 activeTab |
||||
|
watch(() => route.name, (newName) => { |
||||
|
if (newName === 'rechargeAudit') { |
||||
|
activeTab.value = 'rechargeAudit'; |
||||
|
} else if (newName === 'refundAudit') { |
||||
|
activeTab.value = 'refundAudit'; |
||||
|
}}); |
||||
|
|
||||
|
// 当进入父路由时,默认跳转到金币明细页面 |
||||
|
// if (route.name === 'usergold') { |
||||
|
// router.push({ name: 'clientCountDetail' }); |
||||
|
// } |
||||
|
|
||||
|
|
||||
|
onMounted(async function () { |
||||
|
console.log("@@@@@@@@@@@@",route.name) |
||||
|
}); |
||||
|
|
||||
|
</script> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue