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.

296 lines
8.5 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. import {
  2. RouterHistory,
  3. RouteRecordRaw,
  4. RouteComponent,
  5. createWebHistory,
  6. createWebHashHistory,
  7. RouteRecordNormalized
  8. } from "vue-router";
  9. import { router } from "./index";
  10. import { loadEnv } from "../../build";
  11. import { useTimeoutFn } from "@vueuse/core";
  12. import { RouteConfigs } from "/@/layout/types";
  13. import { buildHierarchyTree } from "/@/utils/tree";
  14. import { usePermissionStoreHook } from "/@/store/modules/permission";
  15. const Layout = () => import("/@/layout/index.vue");
  16. const IFrame = () => import("/@/layout/frameView.vue");
  17. // https://cn.vitejs.dev/guide/features.html#glob-import
  18. const modulesRoutes = import.meta.glob("/src/views/**/*.{vue,tsx}");
  19. // 动态路由
  20. import { getAsyncRoutes } from "/@/api/routes";
  21. // 按照路由中meta下的rank等级升序来排序路由
  22. function ascending(arr: any[]) {
  23. return arr.sort(
  24. (a: { meta: { rank: number } }, b: { meta: { rank: number } }) => {
  25. return a?.meta?.rank - b?.meta?.rank;
  26. }
  27. );
  28. }
  29. // 过滤meta中showLink为false的路由
  30. function filterTree(data: RouteComponent[]) {
  31. const newTree = data.filter(
  32. (v: { meta: { showLink: boolean } }) => v.meta?.showLink !== false
  33. );
  34. newTree.forEach(
  35. (v: { children }) => v.children && (v.children = filterTree(v.children))
  36. );
  37. return newTree;
  38. }
  39. // 批量删除缓存路由(keepalive)
  40. function delAliveRoutes(delAliveRouteList: Array<RouteConfigs>) {
  41. delAliveRouteList.forEach(route => {
  42. usePermissionStoreHook().cacheOperate({
  43. mode: "delete",
  44. name: route?.name
  45. });
  46. });
  47. }
  48. // 通过path获取父级路径
  49. function getParentPaths(path: string, routes: RouteRecordRaw[]) {
  50. // 深度遍历查找
  51. function dfs(routes: RouteRecordRaw[], path: string, parents: string[]) {
  52. for (let i = 0; i < routes.length; i++) {
  53. const item = routes[i];
  54. // 找到path则返回父级path
  55. if (item.path === path) return parents;
  56. // children不存在或为空则不递归
  57. if (!item.children || !item.children.length) continue;
  58. // 往下查找时将当前path入栈
  59. parents.push(item.path);
  60. if (dfs(item.children, path, parents).length) return parents;
  61. // 深度遍历查找未找到时当前path 出栈
  62. parents.pop();
  63. }
  64. // 未找到时返回空数组
  65. return [];
  66. }
  67. return dfs(routes, path, []);
  68. }
  69. // 查找对应path的路由信息
  70. function findRouteByPath(path: string, routes: RouteRecordRaw[]) {
  71. let res = routes.find((item: { path: string }) => item.path == path);
  72. if (res) {
  73. return res;
  74. } else {
  75. for (let i = 0; i < routes.length; i++) {
  76. if (
  77. routes[i].children instanceof Array &&
  78. routes[i].children.length > 0
  79. ) {
  80. res = findRouteByPath(path, routes[i].children);
  81. if (res) {
  82. return res;
  83. }
  84. }
  85. }
  86. return null;
  87. }
  88. }
  89. // 重置路由
  90. function resetRouter(): void {
  91. router.getRoutes().forEach(route => {
  92. const { name } = route;
  93. if (name) {
  94. router.hasRoute(name) && router.removeRoute(name);
  95. }
  96. });
  97. }
  98. // 初始化路由
  99. function initRouter(name: string) {
  100. return new Promise(resolve => {
  101. getAsyncRoutes({ name }).then(({ info }) => {
  102. if (info.length === 0) {
  103. usePermissionStoreHook().changeSetting(info);
  104. } else {
  105. formatFlatteningRoutes(addAsyncRoutes(info)).map(
  106. (v: RouteRecordRaw) => {
  107. // 防止重复添加路由
  108. if (
  109. router.options.routes[0].children.findIndex(
  110. value => value.path === v.path
  111. ) !== -1
  112. ) {
  113. return;
  114. } else {
  115. // 切记将路由push到routes后还需要使用addRoute,这样路由才能正常跳转
  116. router.options.routes[0].children.push(v);
  117. // 最终路由进行升序
  118. ascending(router.options.routes[0].children);
  119. if (!router.hasRoute(v?.name)) router.addRoute(v);
  120. const flattenRouters = router
  121. .getRoutes()
  122. .find(n => n.path === "/");
  123. router.addRoute(flattenRouters);
  124. }
  125. resolve(router);
  126. }
  127. );
  128. usePermissionStoreHook().changeSetting(info);
  129. }
  130. router.addRoute({
  131. path: "/:pathMatch(.*)",
  132. redirect: "/error/404"
  133. });
  134. });
  135. });
  136. }
  137. /**
  138. *
  139. * @param routesList
  140. * @returns
  141. */
  142. function formatFlatteningRoutes(routesList: RouteRecordRaw[]) {
  143. if (routesList.length === 0) return routesList;
  144. let hierarchyList = buildHierarchyTree(routesList);
  145. for (let i = 0; i < hierarchyList.length; i++) {
  146. if (hierarchyList[i].children) {
  147. hierarchyList = hierarchyList
  148. .slice(0, i + 1)
  149. .concat(hierarchyList[i].children, hierarchyList.slice(i + 1));
  150. }
  151. }
  152. return hierarchyList;
  153. }
  154. /**
  155. * keep-alive
  156. * https://github.com/xiaoxian521/vue-pure-admin/issues/67
  157. * @param routesList
  158. * @returns
  159. */
  160. function formatTwoStageRoutes(routesList: RouteRecordRaw[]) {
  161. if (routesList.length === 0) return routesList;
  162. const newRoutesList: RouteRecordRaw[] = [];
  163. routesList.forEach((v: RouteRecordRaw) => {
  164. if (v.path === "/") {
  165. newRoutesList.push({
  166. component: v.component,
  167. name: v.name,
  168. path: v.path,
  169. redirect: v.redirect,
  170. meta: v.meta,
  171. children: []
  172. });
  173. } else {
  174. newRoutesList[0].children.push({ ...v });
  175. }
  176. });
  177. return newRoutesList;
  178. }
  179. // 处理缓存路由(添加、删除、刷新)
  180. function handleAliveRoute(matched: RouteRecordNormalized[], mode?: string) {
  181. switch (mode) {
  182. case "add":
  183. matched.forEach(v => {
  184. usePermissionStoreHook().cacheOperate({ mode: "add", name: v.name });
  185. });
  186. break;
  187. case "delete":
  188. usePermissionStoreHook().cacheOperate({
  189. mode: "delete",
  190. name: matched[matched.length - 1].name
  191. });
  192. break;
  193. default:
  194. usePermissionStoreHook().cacheOperate({
  195. mode: "delete",
  196. name: matched[matched.length - 1].name
  197. });
  198. useTimeoutFn(() => {
  199. matched.forEach(v => {
  200. usePermissionStoreHook().cacheOperate({ mode: "add", name: v.name });
  201. });
  202. }, 100);
  203. }
  204. }
  205. // 过滤后端传来的动态路由 重新生成规范路由
  206. function addAsyncRoutes(arrRoutes: Array<RouteRecordRaw>) {
  207. if (!arrRoutes || !arrRoutes.length) return;
  208. const modulesRoutesKeys = Object.keys(modulesRoutes);
  209. arrRoutes.forEach((v: RouteRecordRaw) => {
  210. if (v.redirect) {
  211. v.component = Layout;
  212. } else if (v.meta?.frameSrc) {
  213. v.component = IFrame;
  214. } else {
  215. const index = modulesRoutesKeys.findIndex(ev => ev.includes(v.path));
  216. v.component = modulesRoutes[modulesRoutesKeys[index]];
  217. }
  218. if (v.children) {
  219. addAsyncRoutes(v.children);
  220. }
  221. });
  222. return arrRoutes;
  223. }
  224. // 获取路由历史模式 https://next.router.vuejs.org/zh/guide/essentials/history-mode.html
  225. function getHistoryMode(): RouterHistory {
  226. const routerHistory = loadEnv().VITE_ROUTER_HISTORY;
  227. // len为1 代表只有历史模式 为2 代表历史模式中存在base参数 https://next.router.vuejs.org/zh/api/#%E5%8F%82%E6%95%B0-1
  228. const historyMode = routerHistory.split(",");
  229. const leftMode = historyMode[0];
  230. const rightMode = historyMode[1];
  231. // no param
  232. if (historyMode.length === 1) {
  233. if (leftMode === "hash") {
  234. return createWebHashHistory("");
  235. } else if (leftMode === "h5") {
  236. return createWebHistory("");
  237. }
  238. } //has param
  239. else if (historyMode.length === 2) {
  240. if (leftMode === "hash") {
  241. return createWebHashHistory(rightMode);
  242. } else if (leftMode === "h5") {
  243. return createWebHistory(rightMode);
  244. }
  245. }
  246. }
  247. // 是否有权限
  248. function hasPermissions(value: Array<string>): boolean {
  249. if (value && value instanceof Array && value.length > 0) {
  250. const roles = usePermissionStoreHook().buttonAuth;
  251. const permissionRoles = value;
  252. const hasPermission = roles.some(role => {
  253. return permissionRoles.includes(role);
  254. });
  255. if (!hasPermission) {
  256. return false;
  257. }
  258. return true;
  259. } else {
  260. return false;
  261. }
  262. }
  263. export {
  264. ascending,
  265. filterTree,
  266. initRouter,
  267. resetRouter,
  268. hasPermissions,
  269. getHistoryMode,
  270. addAsyncRoutes,
  271. delAliveRoutes,
  272. getParentPaths,
  273. findRouteByPath,
  274. handleAliveRoute,
  275. formatTwoStageRoutes,
  276. formatFlatteningRoutes
  277. };