You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

356 lines
13 KiB

2 months ago
2 months ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
  1. import {createRouter, createWebHashHistory} from 'vue-router';
  2. import axios from "axios";
  3. import {storeToRefs} from "pinia";
  4. import {useAdminStore} from "@/store/index.js";
  5. // 路由定义(包含权限映射 meta.permissionId)
  6. const routes = [
  7. {
  8. path: '/',
  9. redirect: "/login"
  10. },
  11. {
  12. path: "/login",
  13. name: "login",
  14. component: () => import("../views/login.vue"),
  15. },
  16. {
  17. meta: {requireAuth: true},
  18. path: '/',
  19. component: () => import("../views/home.vue"),
  20. children: [
  21. // 工作台
  22. {
  23. path: '/workspace',
  24. name: "workspace",
  25. component: () => import("../views/workspace/index.vue"),
  26. meta: {permissionId: 10} // 对应"工作台展示"id=10
  27. },
  28. // 审核
  29. {
  30. path: '/audit',
  31. name: "audit",
  32. component: () => import("../views/audit/audit.vue"),
  33. meta: {permissionId: 40},
  34. // redirect: '/index',
  35. children: [
  36. // 充值审核
  37. {
  38. path: 'rechargeAudit',
  39. name: "rechargeAudit",
  40. component: () => import("../views/audit/rechargeAudit.vue"),
  41. meta: {permissionId: [11, 12]} // 对应"查看充值审核"id=11、"充值审批"id=12
  42. },
  43. // 退款审核
  44. {
  45. path: 'refundAudit',
  46. name: "refundAudit",
  47. component: () => import("../views/audit/refundAudit.vue"),
  48. meta: {permissionId: [13, 14]} // 对应"查看退款审核"id=13、"退款审批"id=14
  49. },
  50. ]
  51. },
  52. // 金币消耗
  53. {
  54. path: '/coinConsume',
  55. name: "coinConsume",
  56. component: () => import("../views/consume/coinConsume.vue"),
  57. // redirect: '/coinConsume/add',
  58. meta: {permissionId: 6},
  59. children: [
  60. // 金币新增消耗
  61. {
  62. path: 'add',
  63. name: "addCoinConsume",
  64. component: () => import("../views/consume/addCoinConsume.vue"),
  65. meta: {permissionId: 19} // 对应"提交金币消耗"id=19
  66. },
  67. // 金币消耗明细详情
  68. {
  69. path: 'detail',
  70. name: "coinConsumeDetail",
  71. component: () => import("../views/consume/coinConsumeDetail.vue"),
  72. meta: {permissionId: 20} // 对应"查看金币消耗明细"id=20
  73. }
  74. ]
  75. },
  76. // 金豆消耗
  77. {
  78. path: '/beanConsume',
  79. name: "beanConsume",
  80. component: () => import("../views/consume/beanConsume.vue"),
  81. meta: {permissionId: 6},
  82. children: [
  83. // 金豆新增消耗
  84. {
  85. path: 'add',
  86. name: "addBeanConsume",
  87. component: () => import("../views/consume/addBeanConsume.vue"),
  88. meta: {permissionId: 23} // 对应"提交金豆消耗"id=?
  89. },
  90. // 直播
  91. {
  92. path: 'live',
  93. name: "liveStream",
  94. component: () => import("../views/consume/liveStream.vue"),
  95. meta: {permissionId: 24} // 对应"直播"id=?
  96. },
  97. // 铁粉
  98. {
  99. path: 'fan',
  100. name: "dieHardFan",
  101. component: () => import("../views/consume/dieHardFan.vue"),
  102. meta: {permissionId: 25} // 对应"铁粉"id=?
  103. },
  104. // 文章视频
  105. {
  106. path: 'article',
  107. name: "articleVideo",
  108. component: () => import("../views/consume/articleVideo.vue"),
  109. meta: {permissionId: 26} // 对应"文章视频"id=?
  110. }
  111. ]
  112. },
  113. // 汇率管理
  114. {
  115. path: '/rate',
  116. name: "rate",
  117. component: () => import("../views/managerecharge/rate.vue"),
  118. meta: {permissionId: [15, 16]} // 对应"汇率查看"id=15、"汇率修改"id=16
  119. },
  120. // 金币充值
  121. {
  122. path: '/coinRecharge',
  123. name: "coinRecharge",
  124. component: () => import("../views/recharge/coinRecharge.vue"),
  125. // redirect: '/coinRecharge/add',
  126. children: [
  127. // 金币新增充值
  128. {
  129. path: 'add',
  130. name: "addCoinRecharge",
  131. component: () => import("../views/recharge/addCoinRecharge.vue"),
  132. meta: {permissionId: 17} // 对应"提交金币充值"id=17
  133. },
  134. // 金币充值明细详情
  135. {
  136. path: 'detail',
  137. name: "coinRechargeDetail",
  138. component: () => import("../views/recharge/coinRechargeDetail.vue"),
  139. meta: {permissionId: 18} // 对应"查看金币充值明细"id=18
  140. }
  141. ]
  142. },
  143. // 金豆充值
  144. {
  145. path: '/beanRecharge',
  146. name: "beanRecharge",
  147. component: () => import("../views/recharge/beanRecharge.vue"),
  148. // redirect: '/coinRecharge/add',
  149. children: [
  150. // 金豆新增充值
  151. {
  152. path: 'add',
  153. name: "addBeanRecharge",
  154. component: () => import("../views/recharge/addBeanRecharge.vue"),
  155. meta: {permissionId: 46} // 对应"提交金豆充值"id=46
  156. },
  157. // 金豆系统充值
  158. {
  159. path: 'system',
  160. name: "beanSystemRecharge",
  161. component: () => import("../views/recharge/beanSystemRecharge.vue"),
  162. meta: {permissionId: 47} // 对应"查看金豆系统充值明细"id=47
  163. },
  164. // 金豆线上充值
  165. {
  166. path: 'online',
  167. name: "beanOnlineRecharge",
  168. component: () => import("../views/recharge/beanOnlineRecharge.vue"),
  169. meta: {permissionId: 48} // 对应"查看金豆线上充值明细"id=48
  170. }
  171. ]
  172. },
  173. // 金币退款
  174. {
  175. path: '/coinRefund',
  176. name: "coinRefund",
  177. component: () => import("../views/refund/coinRefund.vue"),
  178. // redirect: '/coinRefund/add',
  179. meta: {permissionId: 7},
  180. children: [
  181. // 金币新增退款
  182. {
  183. path: 'add',
  184. name: "addCoinRefund",
  185. component: () => import("../views/refund/addCoinRefund.vue"),
  186. meta: {permissionId: 21} // 对应"提交金币退款"id=21
  187. },
  188. // 金币退款明细详情
  189. {
  190. path: 'detail',
  191. name: "coinRefundDetail",
  192. component: () => import("../views/refund/coinRefundDetail.vue"),
  193. meta: {permissionId: 22} // 对应"查看金币退款明细"id=22
  194. }
  195. ]
  196. },
  197. // 客户账户明细
  198. {
  199. path: '/usergold',
  200. name: "usergold",
  201. component: () => import("../views/usergold/clientCount.vue"),
  202. // redirect: '/usergold/detail',
  203. meta: {permissionId: 8},
  204. children: [
  205. // 金币明细
  206. {
  207. path: 'detail',
  208. name: "clientCountDetail",
  209. component: () => import("../views/usergold/clientCountDetail.vue"),
  210. meta: {permissionId: 23} // 对应"查看金币明细"id=23
  211. },
  212. // 金币余额
  213. {
  214. path: 'balance',
  215. name: "clientCountBalance",
  216. component: () => import("../views/usergold/clientCountBalance.vue"),
  217. meta: {permissionId: 24} // 对应"查看金币余额"id=24
  218. },
  219. ]
  220. },
  221. // 权限管理
  222. {
  223. path: '/permissions',
  224. name: "permissions",
  225. component: () => import("../views/permissions/permission.vue"),
  226. meta: {permissionId: [25, 26, 27, 28, 29]} // 对应权限管理下的所有操作
  227. },
  228. // 没有权限
  229. {
  230. path: '/noPermission',
  231. name: "noPermission",
  232. component: () => import("../views/noPermissionPage.vue")
  233. }
  234. ]
  235. },
  236. // 跳转页面(无需权限)
  237. {
  238. path: '/PasswordSuccess',
  239. name: "PasswordSuccess",
  240. component: () => import("../components/PasswordSuccess.vue")
  241. }
  242. ];
  243. // 创建路由实例
  244. const router = createRouter({
  245. history: createWebHashHistory(),
  246. routes
  247. });
  248. // 全局拦截器:token过期处理
  249. axios.interceptors.response.use(
  250. response => response,
  251. error => {
  252. if (error.response && error.response.status === 401) {
  253. localStorage.removeItem('token');
  254. router.push({
  255. name: 'login',
  256. query: {
  257. machineId: localStorage.getItem('machineId'),
  258. expired: true
  259. }
  260. });
  261. }
  262. return Promise.reject(error);
  263. }
  264. );
  265. // 工具函数:从菜单树提取所有权限ID
  266. const getAllPermissionIds = (menuTree) => {
  267. let permissionIds = [];
  268. const traverse = (menuList) => {
  269. menuList.forEach(menu => {
  270. permissionIds.push(menu.id);
  271. if (menu.children && menu.children.length > 0) {
  272. traverse(menu.children);
  273. }
  274. });
  275. };
  276. traverse(menuTree);
  277. return permissionIds;
  278. };
  279. // 全局路由守卫
  280. router.beforeEach(async (to, from, next) => {
  281. const adminStore = useAdminStore()
  282. const { adminData, menuTree } = storeToRefs(adminStore)
  283. const token = localStorage.getItem("token");
  284. const machineId = localStorage.getItem("machineId");
  285. // 1. 未登录:强制跳转到登录页
  286. if (to.name !== "login" && !token) {
  287. next(`/login?machineId=${machineId || ''}`);
  288. return;
  289. }
  290. // 2. 已登录:处理权限验证
  291. if (token) {
  292. // 获取管理员信息
  293. let roleId = null;
  294. console.log('adminData:', adminData)
  295. try {
  296. roleId = adminData.value.roleId;
  297. if (!roleId) {
  298. localStorage.removeItem('token'); // 清除token,强制重新登录
  299. next(`/login?machineId=${machineId || ''}`);
  300. return;
  301. }
  302. } catch (error) {
  303. localStorage.removeItem('token'); // 清除token,强制重新登录
  304. adminStore.clearState()
  305. next(`/login?machineId=${machineId || ''}`);
  306. return;
  307. }
  308. let userPermissionIds = [];
  309. // 拿权限id
  310. userPermissionIds = getAllPermissionIds(menuTree.value)
  311. // 2.4 权限验证(逻辑不变)
  312. console.log('to.meta:', to.meta)
  313. const requiresPermission = to.meta && to.meta.permissionId;
  314. if (requiresPermission) {
  315. const hasPermission = Array.isArray(requiresPermission)
  316. ? requiresPermission.some(id => userPermissionIds.includes(id))
  317. : userPermissionIds.includes(requiresPermission);
  318. if (!hasPermission) {
  319. next('/noPermission');
  320. return;
  321. }
  322. }
  323. }
  324. // 3. 正常跳转
  325. next();
  326. });
  327. export default router;