vben
2021-06-28 f9cda2e8c0eb173fab17db84852fe411294d0e63
提交 | 用户 | age
c303ec 1 import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types';
e12c58 2 import type { Router, RouteRecordNormalized } from 'vue-router';
c303ec 3
V 4 import { getParentLayout, LAYOUT } from '/@/router/constant';
df8cd8 5 import { cloneDeep, omit } from 'lodash-es';
99ac30 6 import { warn } from '/@/utils/log';
e12c58 7 import { createRouter, createWebHashHistory } from 'vue-router';
c303ec 8
c774a6 9 export type LayoutMapKey = 'LAYOUT';
c6b766 10 const IFRAME = () => import('/@/views/sys/iframe/FrameBlank.vue');
c774a6 11
327d71 12 const LayoutMap = new Map<string, () => Promise<typeof import('*.vue')>>();
c6b766 13
14 LayoutMap.set('LAYOUT', LAYOUT);
15 LayoutMap.set('IFRAME', IFRAME);
c774a6 16
e12c58 17 let dynamicViewsModules: Record<string, () => Promise<Recordable>>;
664035 18
e12c58 19 // Dynamic introduction
c303ec 20 function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
e5b2cc 21   dynamicViewsModules = dynamicViewsModules || import.meta.glob('../../views/**/*.{vue,tsx}');
c303ec 22   if (!routes) return;
V 23   routes.forEach((item) => {
c6b766 24     if (!item.component && item.meta?.frameSrc) {
25       item.component = 'IFRAME';
26     }
c303ec 27     const { component, name } = item;
V 28     const { children } = item;
29     if (component) {
327d71 30       const layoutFound = LayoutMap.get(component as string);
c6b766 31       if (layoutFound) {
32         item.component = layoutFound;
33       } else {
34         item.component = dynamicImport(dynamicViewsModules, component as string);
35       }
c303ec 36     } else if (name) {
e12c58 37       item.component = getParentLayout();
c303ec 38     }
V 39     children && asyncImportRoute(children);
40   });
41 }
42
664035 43 function dynamicImport(
e12c58 44   dynamicViewsModules: Record<string, () => Promise<Recordable>>,
664035 45   component: string
V 46 ) {
47   const keys = Object.keys(dynamicViewsModules);
99ac30 48   const matchKeys = keys.filter((key) => {
b476e1 49     let k = key.replace('../../views', '');
V 50     const lastIndex = k.lastIndexOf('.');
51     k = k.substring(0, lastIndex);
52     return k === component;
99ac30 53   });
V 54   if (matchKeys?.length === 1) {
55     const matchKey = matchKeys[0];
664035 56     return dynamicViewsModules[matchKey];
99ac30 57   }
V 58   if (matchKeys?.length > 1) {
59     warn(
60       'Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure'
61     );
62     return;
63   }
64 }
65
c303ec 66 // Turn background objects into routing objects
V 67 export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModule[]): T[] {
68   routeList.forEach((route) => {
327d71 69     const component = route.component as string;
V 70     if (component) {
71       if (component.toUpperCase() === 'LAYOUT') {
72         route.component = LayoutMap.get(component.toUpperCase());
c303ec 73       } else {
V 74         route.children = [cloneDeep(route)];
75         route.component = LAYOUT;
76         route.name = `${route.name}Parent`;
77         route.path = '';
78         const meta = route.meta || {};
79         meta.single = true;
80         meta.affix = false;
81         route.meta = meta;
82       }
83     }
84     route.children && asyncImportRoute(route.children);
85   });
df8cd8 86   return routeList as unknown as T[];
c303ec 87 }
V 88
e12c58 89 /**
V 90  * Convert multi-level routing to level 2 routing
91  */
e2cc5a 92 export function flatMultiLevelRoutes(routeModules: AppRouteModule[]) {
V 93   const modules: AppRouteModule[] = cloneDeep(routeModules);
94   for (let index = 0; index < modules.length; index++) {
95     const routeModule = modules[index];
e12c58 96     if (!isMultipleRoute(routeModule)) {
V 97       continue;
98     }
99     promoteRouteLevel(routeModule);
100   }
e2cc5a 101   return modules;
e12c58 102 }
V 103
104 // Routing level upgrade
105 function promoteRouteLevel(routeModule: AppRouteModule) {
106   // Use vue-router to splice menus
107   let router: Router | null = createRouter({
df8cd8 108     routes: [routeModule as unknown as RouteRecordNormalized],
e12c58 109     history: createWebHashHistory(),
V 110   });
111
112   const routes = router.getRoutes();
e2cc5a 113   addToChildren(routes, routeModule.children || [], routeModule);
e12c58 114   router = null;
V 115
df8cd8 116   routeModule.children = routeModule.children?.map((item) => omit(item, 'children'));
e12c58 117 }
V 118
119 // Add all sub-routes to the secondary route
120 function addToChildren(
121   routes: RouteRecordNormalized[],
122   children: AppRouteRecordRaw[],
123   routeModule: AppRouteModule
124 ) {
125   for (let index = 0; index < children.length; index++) {
126     const child = children[index];
127     const route = routes.find((item) => item.name === child.name);
e2cc5a 128     if (!route) {
V 129       continue;
130     }
131     routeModule.children = routeModule.children || [];
132     if (!routeModule.children.find((item) => item.name === route.name)) {
df8cd8 133       routeModule.children?.push(route as unknown as AppRouteModule);
e2cc5a 134     }
V 135     if (child.children?.length) {
136       addToChildren(routes, child.children, routeModule);
e12c58 137     }
V 138   }
139 }
140
141 // Determine whether the level exceeds 2 levels
142 function isMultipleRoute(routeModule: AppRouteModule) {
143   if (!routeModule || !Reflect.has(routeModule, 'children') || !routeModule.children?.length) {
144     return false;
145   }
146
147   const children = routeModule.children;
148
149   let flag = false;
150   for (let index = 0; index < children.length; index++) {
151     const child = children[index];
152     if (child.children?.length) {
153       flag = true;
154       break;
155     }
156   }
157   return flag;
c303ec 158 }