index.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import "@/utils/sso";
  2. import { getConfig } from "@/config";
  3. import NProgress from "@/utils/progress";
  4. import { transformI18n } from "@/plugins/i18n";
  5. import { sessionKey, type DataInfo } from "@/utils/auth";
  6. import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
  7. import { usePermissionStoreHook } from "@/store/modules/permission";
  8. import {
  9. Router,
  10. createRouter,
  11. RouteRecordRaw,
  12. RouteComponent
  13. } from "vue-router";
  14. import {
  15. ascending,
  16. initRouter,
  17. isOneOfArray,
  18. getHistoryMode,
  19. findRouteByPath,
  20. handleAliveRoute,
  21. formatTwoStageRoutes,
  22. formatFlatteningRoutes
  23. } from "./utils";
  24. import { buildHierarchyTree } from "@/utils/tree";
  25. import { isUrl, openLink, storageSession } from "@pureadmin/utils";
  26. import remainingRouter from "./modules/remaining";
  27. /** 自动导入全部静态路由,无需再手动引入!匹配 src/router/modules 目录(任何嵌套级别)中具有 .ts 扩展名的所有文件,除了 remaining.ts 文件
  28. * 如何匹配所有文件请看:https://github.com/mrmlnc/fast-glob#basic-syntax
  29. * 如何排除文件请看:https://cn.vitejs.dev/guide/features.html#negative-patterns
  30. */
  31. const modules: Record<string, any> = import.meta.glob(
  32. ["./modules/**/*.ts", "!./modules/**/remaining.ts"],
  33. {
  34. eager: true
  35. }
  36. );
  37. /** 原始静态路由(未做任何处理) */
  38. const routes = [];
  39. Object.keys(modules).forEach(key => {
  40. routes.push(modules[key].default);
  41. });
  42. /** 导出处理后的静态路由(三级及以上的路由全部拍成二级) */
  43. export const constantRoutes: Array<RouteRecordRaw> = formatTwoStageRoutes(
  44. formatFlatteningRoutes(buildHierarchyTree(ascending(routes)))
  45. );
  46. /** 用于渲染菜单,保持原始层级 */
  47. export const constantMenus: Array<RouteComponent> = ascending(routes).concat(
  48. ...remainingRouter
  49. );
  50. /** 不参与菜单的路由 */
  51. export const remainingPaths = Object.keys(remainingRouter).map(v => {
  52. return remainingRouter[v].path;
  53. });
  54. /** 创建路由实例 */
  55. export const router: Router = createRouter({
  56. history: getHistoryMode(),
  57. routes: constantRoutes.concat(...(remainingRouter as any)),
  58. strict: true,
  59. scrollBehavior(to, from, savedPosition) {
  60. return new Promise(resolve => {
  61. if (savedPosition) {
  62. return savedPosition;
  63. } else {
  64. if (from.meta.saveSrollTop) {
  65. const top: number =
  66. document.documentElement.scrollTop || document.body.scrollTop;
  67. resolve({ left: 0, top });
  68. }
  69. }
  70. });
  71. }
  72. });
  73. /** 重置路由 */
  74. export function resetRouter() {
  75. router.getRoutes().forEach(route => {
  76. const { name, meta } = route;
  77. if (name && router.hasRoute(name) && meta?.backstage) {
  78. router.removeRoute(name);
  79. router.options.routes = formatTwoStageRoutes(
  80. formatFlatteningRoutes(buildHierarchyTree(ascending(routes)))
  81. );
  82. }
  83. });
  84. usePermissionStoreHook().clearAllCachePage();
  85. }
  86. /** 路由白名单 */
  87. const whiteList = ["/login"];
  88. router.beforeEach((to: toRouteType, _from, next) => {
  89. if (to.meta?.keepAlive) {
  90. const newMatched = to.matched;
  91. handleAliveRoute(newMatched, "add");
  92. // 页面整体刷新和点击标签页刷新
  93. if (_from.name === undefined || _from.name === "Redirect") {
  94. handleAliveRoute(newMatched);
  95. }
  96. }
  97. const userInfo = storageSession().getItem<DataInfo<number>>(sessionKey);
  98. NProgress.start();
  99. const externalLink = isUrl(to?.name as string);
  100. if (!externalLink) {
  101. to.matched.some(item => {
  102. if (!item.meta.title) return "";
  103. const Title = getConfig().Title;
  104. if (Title)
  105. document.title = `${transformI18n(item.meta.title)} | ${Title}`;
  106. else document.title = transformI18n(item.meta.title);
  107. });
  108. }
  109. /** 如果已经登录并存在登录信息后不能跳转到路由白名单,而是继续保持在当前页面 */
  110. function toCorrectRoute() {
  111. whiteList.includes(to.fullPath) ? next(_from.fullPath) : next();
  112. }
  113. if (userInfo) {
  114. // 无权限跳转403页面
  115. if (to.meta?.roles && !isOneOfArray(to.meta?.roles, userInfo?.roles)) {
  116. next({ path: "/error/403" });
  117. }
  118. if (_from?.name) {
  119. // name为超链接
  120. if (externalLink) {
  121. openLink(to?.name as string);
  122. NProgress.done();
  123. } else {
  124. toCorrectRoute();
  125. }
  126. } else {
  127. // 刷新
  128. if (
  129. usePermissionStoreHook().wholeMenus.length === 0 &&
  130. to.path !== "/login"
  131. )
  132. initRouter().then((router: Router) => {
  133. if (!useMultiTagsStoreHook().getMultiTagsCache) {
  134. const { path } = to;
  135. const route = findRouteByPath(
  136. path,
  137. router.options.routes[0].children
  138. );
  139. // query、params模式路由传参数的标签页不在此处处理
  140. if (route && route.meta?.title) {
  141. useMultiTagsStoreHook().handleTags("push", {
  142. path: route.path,
  143. name: route.name,
  144. meta: route.meta
  145. });
  146. }
  147. }
  148. router.push(to.fullPath);
  149. });
  150. toCorrectRoute();
  151. }
  152. } else {
  153. if (to.path !== "/login") {
  154. if (whiteList.indexOf(to.path) !== -1) {
  155. next();
  156. } else {
  157. next({ path: "/login" });
  158. }
  159. } else {
  160. next();
  161. }
  162. }
  163. });
  164. router.afterEach(() => {
  165. NProgress.done();
  166. });
  167. export default router;