11 changed files with 432 additions and 156 deletions
-
1.env.development
-
377src/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='http://192.168.9.52:8081/' |
|||
VITE_UPLOAD_URL=http://39.101.133.168:8828/hljw/api/aws/upload |
|||
|
@ -1,114 +1,319 @@ |
|||
import { createRouter, createWebHashHistory } from 'vue-router'; |
|||
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({ |
|||
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( |
|||
response => response, |
|||
error => { |
|||
if (error.response && error.response.status === 401) { |
|||
// 清除本地存储的token
|
|||
localStorage.removeItem('token'); |
|||
// 跳转到登录页
|
|||
router.push({ |
|||
name: 'login', |
|||
query: { machineId: localStorage.getItem('machineId'), expired: true } |
|||
query: { |
|||
machineId: localStorage.getItem('machineId'), |
|||
expired: true |
|||
} |
|||
}); |
|||
} |
|||
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 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; |
@ -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