guard.ts 3.4 KB

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