1
0

guard.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import type { Router } from 'vue-router';
  2. import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
  3. import { preferences } from '@vben/preferences';
  4. import { useAccessStore, useUserStore } from '@vben/stores';
  5. import { startProgress, stopProgress } from '@vben/utils';
  6. import { useTitle } from '@vueuse/core';
  7. import { $t } from '#/locales';
  8. import { coreRouteNames, dynamicRoutes } from '#/router/routes';
  9. import { useAuthStore } from '#/store';
  10. import { generateAccess } from './access';
  11. /**
  12. * 通用守卫配置
  13. * @param router
  14. */
  15. function setupCommonGuard(router: Router) {
  16. // 记录已经加载的页面
  17. const loadedPaths = new Set<string>();
  18. router.beforeEach(async (to) => {
  19. to.meta.loaded = loadedPaths.has(to.path);
  20. // 页面加载进度条
  21. if (!to.meta.loaded && preferences.transition.progress) {
  22. startProgress();
  23. }
  24. return true;
  25. });
  26. router.afterEach((to) => {
  27. // 记录页面是否加载,如果已经加载,后续的页面切换动画等效果不在重复执行
  28. if (preferences.tabbar.enable) {
  29. loadedPaths.add(to.path);
  30. }
  31. // 关闭页面加载进度条
  32. if (preferences.transition.progress) {
  33. stopProgress();
  34. }
  35. // 动态修改标题
  36. if (preferences.app.dynamicTitle) {
  37. const { title } = to.meta;
  38. // useTitle(`${$t(title)} - ${preferences.app.name}`);
  39. useTitle(`${$t(title)} - ${preferences.app.name}`);
  40. }
  41. });
  42. }
  43. /**
  44. * 权限访问守卫配置
  45. * @param router
  46. */
  47. function setupAccessGuard(router: Router) {
  48. router.beforeEach(async (to, from) => {
  49. const accessStore = useAccessStore();
  50. const userStore = useUserStore();
  51. const authStore = useAuthStore();
  52. // 基本路由,这些路由不需要进入权限拦截
  53. if (coreRouteNames.includes(to.name as string)) {
  54. if (to.path === LOGIN_PATH && accessStore.accessToken) {
  55. return decodeURIComponent(
  56. (to.query?.redirect as string) || DEFAULT_HOME_PATH,
  57. );
  58. }
  59. return true;
  60. }
  61. // accessToken 检查
  62. if (!accessStore.accessToken) {
  63. // 明确声明忽略权限访问权限,则可以访问
  64. if (to.meta.ignoreAccess) {
  65. return true;
  66. }
  67. // 没有访问权限,跳转登录页面
  68. if (to.fullPath !== LOGIN_PATH) {
  69. return {
  70. path: LOGIN_PATH,
  71. // 如不需要,直接删除 query
  72. query: { redirect: encodeURIComponent(to.fullPath) },
  73. // 携带当前跳转的页面,登录后重新跳转该页面
  74. replace: true,
  75. };
  76. }
  77. return to;
  78. }
  79. const accessRoutes = accessStore.accessRoutes;
  80. // 是否已经生成过动态路由
  81. if (accessRoutes && accessRoutes.length > 0) {
  82. return true;
  83. }
  84. // 生成路由表
  85. // 当前登录用户拥有的角色标识列表
  86. const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
  87. const userRoles = userInfo.roles ?? [];
  88. // 生成菜单和路由
  89. const { accessibleMenus, accessibleRoutes } = await generateAccess({
  90. roles: userRoles,
  91. router,
  92. // 则会在菜单中显示,但是访问会被重定向到403
  93. routes: dynamicRoutes,
  94. });
  95. // 保存菜单信息和路由信息
  96. accessStore.setAccessMenus(accessibleMenus);
  97. accessStore.setAccessRoutes(accessibleRoutes);
  98. const redirectPath = (from.query.redirect ?? to.path) as string;
  99. return {
  100. path: decodeURIComponent(redirectPath),
  101. replace: true,
  102. };
  103. });
  104. }
  105. /**
  106. * 项目守卫配置
  107. * @param router
  108. */
  109. function createRouterGuard(router: Router) {
  110. /** 通用 */
  111. setupCommonGuard(router);
  112. /** 权限访问 */
  113. setupAccessGuard(router);
  114. }
  115. export { createRouterGuard };