Commit e12c588c0abb8d639babd7f4b62abec111187302

Authored by Vben
1 parent 37320160

refactor(route): refactoring the routing multi-layer model close #215

.eslintrc.js
@@ -38,15 +38,15 @@ module.exports = { @@ -38,15 +38,15 @@ module.exports = {
38 '@typescript-eslint/no-unused-vars': [ 38 '@typescript-eslint/no-unused-vars': [
39 'error', 39 'error',
40 { 40 {
41 - argsIgnorePattern: '^h$',  
42 - varsIgnorePattern: '^h$', 41 + argsIgnorePattern: '^_',
  42 + varsIgnorePattern: '^_',
43 }, 43 },
44 ], 44 ],
45 'no-unused-vars': [ 45 'no-unused-vars': [
46 'error', 46 'error',
47 { 47 {
48 - argsIgnorePattern: '^h$',  
49 - varsIgnorePattern: '^h$', 48 + argsIgnorePattern: '^_',
  49 + varsIgnorePattern: '^_',
50 }, 50 },
51 ], 51 ],
52 'space-before-function-paren': 'off', 52 'space-before-function-paren': 'off',
.vscode/settings.json
@@ -8,7 +8,6 @@ @@ -8,7 +8,6 @@
8 "explorer.openEditors.visible": 0, 8 "explorer.openEditors.visible": 0,
9 "editor.tabSize": 2, 9 "editor.tabSize": 2,
10 "editor.renderControlCharacters": true, 10 "editor.renderControlCharacters": true,
11 - "window.zoomLevel": -1,  
12 "editor.minimap.renderCharacters": false, 11 "editor.minimap.renderCharacters": false,
13 "editor.minimap.maxColumn": 300, 12 "editor.minimap.maxColumn": 300,
14 "editor.minimap.showSlider": "always", 13 "editor.minimap.showSlider": "always",
CHANGELOG.zh_CN.md
  1 +## Wip
  2 +
  3 +### ✨ Refactor
  4 +
  5 +- 重构路由多层模式,解决嵌套 keepalive 执行多次问题
  6 +
1 ## 2.1.0 (2021-03-15) 7 ## 2.1.0 (2021-03-15)
2 8
3 ### ✨ Features 9 ### ✨ Features
build/vite/plugin/hmr.ts 0 → 100644
  1 +import type { Plugin } from 'vite';
  2 +
  3 +/**
  4 + * TODO
  5 + * Temporarily solve the Vite circular dependency problem, and wait for a better solution to fix it later. I don't know what problems this writing will bring.
  6 + * @returns
  7 + */
  8 +
  9 +export function configHmrPlugin(): Plugin {
  10 + return {
  11 + name: 'singleHMR',
  12 + handleHotUpdate({ modules, file }) {
  13 + if (file.match(/xml$/)) return [];
  14 + modules.forEach((m) => {
  15 + m.importedModules = new Set();
  16 + m.importers = new Set();
  17 + });
  18 + return modules;
  19 + },
  20 + };
  21 +}
build/vite/plugin/index.ts
@@ -17,6 +17,7 @@ import { configThemePlugin } from './theme'; @@ -17,6 +17,7 @@ import { configThemePlugin } from './theme';
17 import { configImageminPlugin } from './imagemin'; 17 import { configImageminPlugin } from './imagemin';
18 import { configWindiCssPlugin } from './windicss'; 18 import { configWindiCssPlugin } from './windicss';
19 import { configSvgIconsPlugin } from './svgSprite'; 19 import { configSvgIconsPlugin } from './svgSprite';
  20 +import { configHmrPlugin } from './hmr';
20 21
21 export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) { 22 export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
22 const { VITE_USE_IMAGEMIN, VITE_USE_MOCK, VITE_LEGACY, VITE_BUILD_COMPRESS } = viteEnv; 23 const { VITE_USE_IMAGEMIN, VITE_USE_MOCK, VITE_LEGACY, VITE_BUILD_COMPRESS } = viteEnv;
@@ -28,6 +29,9 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) { @@ -28,6 +29,9 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
28 vueJsx(), 29 vueJsx(),
29 ]; 30 ];
30 31
  32 + // TODO
  33 + !isBuild && vitePlugins.push(configHmrPlugin());
  34 +
31 // @vitejs/plugin-legacy 35 // @vitejs/plugin-legacy
32 VITE_LEGACY && isBuild && vitePlugins.push(legacy()); 36 VITE_LEGACY && isBuild && vitePlugins.push(legacy());
33 37
src/layouts/default/header/components/Breadcrumb.vue
@@ -33,6 +33,7 @@ @@ -33,6 +33,7 @@
33 import { useGo } from '/@/hooks/web/usePage'; 33 import { useGo } from '/@/hooks/web/usePage';
34 import { isString } from '/@/utils/is'; 34 import { isString } from '/@/utils/is';
35 import { useI18n } from '/@/hooks/web/useI18n'; 35 import { useI18n } from '/@/hooks/web/useI18n';
  36 + import { getMenus } from '/@/router/menus';
36 37
37 export default defineComponent({ 38 export default defineComponent({
38 name: 'LayoutBreadcrumb', 39 name: 'LayoutBreadcrumb',
@@ -47,7 +48,7 @@ @@ -47,7 +48,7 @@
47 const { getShowBreadCrumbIcon } = useRootSetting(); 48 const { getShowBreadCrumbIcon } = useRootSetting();
48 49
49 const { t } = useI18n(); 50 const { t } = useI18n();
50 - watchEffect(() => { 51 + watchEffect(async () => {
51 if (currentRoute.value.name === REDIRECT_NAME) return; 52 if (currentRoute.value.name === REDIRECT_NAME) return;
52 53
53 const matched = currentRoute.value?.matched; 54 const matched = currentRoute.value?.matched;
src/layouts/page/ParentView.vue deleted 100644 → 0
1 -<!--  
2 - * @Description: The reason is that tsx will report warnings under multi-level nesting.  
3 --->  
4 -<template>  
5 - <div>  
6 - <RouterView>  
7 - <template #default="{ Component, route }">  
8 - <transition  
9 - :name="  
10 - getTransitionName({  
11 - route,  
12 - openCache: openCache,  
13 - enableTransition: getEnableTransition,  
14 - cacheTabs: getCaches,  
15 - def: getBasicTransition,  
16 - })  
17 - "  
18 - mode="out-in"  
19 - appear  
20 - >  
21 - <keep-alive v-if="openCache" :include="getCaches">  
22 - <component :is="Component" v-bind="getKey(Component, route)" />  
23 - </keep-alive>  
24 - <component v-else :is="Component" v-bind="getKey(Component, route)" />  
25 - </transition>  
26 - </template>  
27 - </RouterView>  
28 - </div>  
29 -</template>  
30 -<script lang="ts">  
31 - import { computed, defineComponent, unref } from 'vue';  
32 -  
33 - import { useRootSetting } from '/@/hooks/setting/useRootSetting';  
34 - import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';  
35 -  
36 - import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';  
37 - import { useCache, getKey } from './useCache';  
38 - import { getTransitionName } from './transition';  
39 -  
40 - export default defineComponent({  
41 - parentView: true,  
42 - setup() {  
43 - const { getCaches } = useCache(false);  
44 -  
45 - const { getShowMultipleTab } = useMultipleTabSetting();  
46 -  
47 - const { getOpenKeepAlive } = useRootSetting();  
48 -  
49 - const { getBasicTransition, getEnableTransition } = useTransitionSetting();  
50 -  
51 - const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab));  
52 -  
53 - return {  
54 - getCaches,  
55 - getBasicTransition,  
56 - openCache,  
57 - getEnableTransition,  
58 - getTransitionName,  
59 - getKey,  
60 - };  
61 - },  
62 - });  
63 -</script>  
src/layouts/page/index.vue
@@ -16,9 +16,9 @@ @@ -16,9 +16,9 @@
16 appear 16 appear
17 > 17 >
18 <keep-alive v-if="openCache" :include="getCaches"> 18 <keep-alive v-if="openCache" :include="getCaches">
19 - <component :is="Component" v-bind="getKey(Component, route)" /> 19 + <component :is="Component" :key="route.fullPath" />
20 </keep-alive> 20 </keep-alive>
21 - <component v-else :is="Component" v-bind="getKey(Component, route)" /> 21 + <component v-else :is="Component" :key="route.fullPath" />
22 </transition> 22 </transition>
23 </template> 23 </template>
24 </RouterView> 24 </RouterView>
@@ -34,15 +34,15 @@ @@ -34,15 +34,15 @@
34 import { useRootSetting } from '/@/hooks/setting/useRootSetting'; 34 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
35 35
36 import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'; 36 import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
37 - import { useCache, getKey } from './useCache';  
38 import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; 37 import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
39 import { getTransitionName } from './transition'; 38 import { getTransitionName } from './transition';
40 39
  40 + import { useStore } from 'vuex';
  41 +
41 export default defineComponent({ 42 export default defineComponent({
42 name: 'PageLayout', 43 name: 'PageLayout',
43 components: { FrameLayout }, 44 components: { FrameLayout },
44 setup() { 45 setup() {
45 - const { getCaches } = useCache(true);  
46 const { getShowMultipleTab } = useMultipleTabSetting(); 46 const { getShowMultipleTab } = useMultipleTabSetting();
47 47
48 const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting(); 48 const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting();
@@ -51,6 +51,17 @@ @@ -51,6 +51,17 @@
51 51
52 const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab)); 52 const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab));
53 53
  54 + const { getters } = useStore();
  55 +
  56 + const getCaches = computed((): string[] => {
  57 + if (!unref(getOpenKeepAlive)) {
  58 + return [];
  59 + }
  60 + // TODO The useStore is used here mainly to solve the problem of circular dependency hot update
  61 + const cacheTabs = getters['app-tab/getCachedTabsState'];
  62 + return cacheTabs;
  63 + });
  64 +
54 return { 65 return {
55 getTransitionName, 66 getTransitionName,
56 openCache, 67 openCache,
@@ -58,7 +69,6 @@ @@ -58,7 +69,6 @@
58 getBasicTransition, 69 getBasicTransition,
59 getCaches, 70 getCaches,
60 getCanEmbedIFramePage, 71 getCanEmbedIFramePage,
61 - getKey,  
62 }; 72 };
63 }, 73 },
64 }); 74 });
src/layouts/page/useCache.ts deleted 100644 → 0
1 -import type { FunctionalComponent } from 'vue';  
2 -import type { RouteLocation } from 'vue-router';  
3 -import { computed, ref, unref, getCurrentInstance } from 'vue';  
4 -import { useRootSetting } from '/@/hooks/setting/useRootSetting';  
5 -  
6 -import { useRouter } from 'vue-router';  
7 -import { useStore } from 'vuex';  
8 -  
9 -const ParentLayoutName = 'ParentLayout';  
10 -  
11 -const PAGE_LAYOUT_KEY = '__PAGE_LAYOUT__';  
12 -  
13 -export function getKey(component: FunctionalComponent & { type: Indexable }, route: RouteLocation) {  
14 - return !!component?.type.parentView ? {} : { key: route.fullPath };  
15 -}  
16 -  
17 -export function useCache(isPage: boolean) {  
18 - const { getters } = useStore();  
19 -  
20 - const name = ref('');  
21 - const { currentRoute } = useRouter();  
22 - const instance = getCurrentInstance();  
23 - const routeName = instance?.type.name;  
24 - if (routeName && ![ParentLayoutName].includes(routeName)) {  
25 - name.value = routeName;  
26 - } else {  
27 - const matched = currentRoute.value?.matched;  
28 - if (!matched) {  
29 - return;  
30 - }  
31 - const len = matched.length;  
32 - if (len < 2) return;  
33 - name.value = matched[len - 2].name as string;  
34 - }  
35 -  
36 - const { getOpenKeepAlive } = useRootSetting();  
37 -  
38 - const getCaches = computed((): string[] => {  
39 - if (!unref(getOpenKeepAlive)) {  
40 - return [];  
41 - }  
42 - const cached = getters['app-tab/getCachedMapState'];  
43 -  
44 - if (isPage) {  
45 - // page Layout  
46 - return cached.get(PAGE_LAYOUT_KEY) || [];  
47 - }  
48 - const cacheSet = new Set<string>();  
49 - cacheSet.add(unref(name));  
50 -  
51 - const list = cached.get(unref(name));  
52 -  
53 - if (!list) {  
54 - return Array.from(cacheSet);  
55 - }  
56 - list.forEach((item) => {  
57 - cacheSet.add(item);  
58 - });  
59 -  
60 - return Array.from(cacheSet);  
61 - });  
62 - return { getCaches };  
63 -}  
src/logics/mitt/tabChange.ts
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 4
5 import Mitt from '/@/utils/mitt'; 5 import Mitt from '/@/utils/mitt';
6 import type { RouteLocationNormalized } from 'vue-router'; 6 import type { RouteLocationNormalized } from 'vue-router';
7 -import { getRoute } from '/@/router/helper/routeHelper'; 7 +import { getRawRoute } from '/@/utils';
8 8
9 const mitt = new Mitt(); 9 const mitt = new Mitt();
10 10
@@ -13,7 +13,7 @@ const key = Symbol(); @@ -13,7 +13,7 @@ const key = Symbol();
13 let lastChangeTab: RouteLocationNormalized; 13 let lastChangeTab: RouteLocationNormalized;
14 14
15 export function setLastChangeTab(lastChangeRoute: RouteLocationNormalized) { 15 export function setLastChangeTab(lastChangeRoute: RouteLocationNormalized) {
16 - const r = getRoute(lastChangeRoute); 16 + const r = getRawRoute(lastChangeRoute);
17 mitt.emit(key, r); 17 mitt.emit(key, r);
18 lastChangeTab = r; 18 lastChangeTab = r;
19 } 19 }
src/router/constant.ts
1 -import type { AppRouteRecordRaw } from '/@/router/types';  
2 -import ParentLayout from '/@/layouts/page/ParentView.vue';  
3 -import { t } from '/@/hooks/web/useI18n';  
4 -  
5 export const REDIRECT_NAME = 'Redirect'; 1 export const REDIRECT_NAME = 'Redirect';
6 2
  3 +export const PARENT_LAYOUT_NAME = 'ParentLayout';
  4 +
7 export const EXCEPTION_COMPONENT = () => import('../views/sys/exception/Exception.vue'); 5 export const EXCEPTION_COMPONENT = () => import('../views/sys/exception/Exception.vue');
8 6
9 /** 7 /**
@@ -12,78 +10,23 @@ export const EXCEPTION_COMPONENT = () =&gt; import(&#39;../views/sys/exception/Exceptio @@ -12,78 +10,23 @@ export const EXCEPTION_COMPONENT = () =&gt; import(&#39;../views/sys/exception/Exceptio
12 export const LAYOUT = () => import('/@/layouts/default/index.vue'); 10 export const LAYOUT = () => import('/@/layouts/default/index.vue');
13 11
14 /** 12 /**
15 - * @description: page-layout 13 + * @description: parent-layout
16 */ 14 */
17 -export const getParentLayout = (name: string) => { 15 +export const getParentLayout = (_name?: string) => {
18 return () => 16 return () =>
19 new Promise((resolve) => { 17 new Promise((resolve) => {
20 resolve({ 18 resolve({
21 - ...ParentLayout,  
22 - name, 19 + name: PARENT_LAYOUT_NAME,
23 }); 20 });
24 }); 21 });
25 }; 22 };
26 23
27 -// 404 on a page  
28 -export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {  
29 - path: '/:path(.*)*',  
30 - name: 'ErrorPage',  
31 - component: LAYOUT,  
32 - meta: {  
33 - title: 'ErrorPage',  
34 - hideBreadcrumb: true,  
35 - },  
36 - children: [  
37 - {  
38 - path: '/:path(.*)*',  
39 - name: 'ErrorPage',  
40 - component: EXCEPTION_COMPONENT,  
41 - meta: {  
42 - title: 'ErrorPage',  
43 - hideBreadcrumb: true,  
44 - },  
45 - },  
46 - ],  
47 -};  
48 -  
49 -export const REDIRECT_ROUTE: AppRouteRecordRaw = {  
50 - path: '/redirect',  
51 - name: REDIRECT_NAME,  
52 - component: LAYOUT,  
53 - meta: {  
54 - title: REDIRECT_NAME,  
55 - hideBreadcrumb: true,  
56 - },  
57 - children: [  
58 - {  
59 - path: '/redirect/:path(.*)',  
60 - name: REDIRECT_NAME,  
61 - component: () => import('/@/views/sys/redirect/index.vue'),  
62 - meta: {  
63 - title: REDIRECT_NAME,  
64 - hideBreadcrumb: true,  
65 - },  
66 - },  
67 - ],  
68 -};  
69 -  
70 -export const ERROR_LOG_ROUTE: AppRouteRecordRaw = {  
71 - path: '/error-log',  
72 - name: 'errorLog',  
73 - component: LAYOUT,  
74 - meta: {  
75 - title: 'ErrorLog',  
76 - hideBreadcrumb: true,  
77 - },  
78 - children: [  
79 - {  
80 - path: 'list',  
81 - name: 'errorLogList',  
82 - component: () => import('/@/views/sys/error-log/index.vue'),  
83 - meta: {  
84 - title: t('routes.basic.errorLogList'),  
85 - hideBreadcrumb: true,  
86 - },  
87 - },  
88 - ],  
89 -}; 24 +// export const getParentLayout = (name: string) => {
  25 +// return () =>
  26 +// new Promise((resolve) => {
  27 +// resolve({
  28 +// ...ParentLayout,
  29 +// name,
  30 +// });
  31 +// });
  32 +// };
src/router/guard/permissionGuard.ts
@@ -5,7 +5,7 @@ import { permissionStore } from &#39;/@/store/modules/permission&#39;; @@ -5,7 +5,7 @@ import { permissionStore } from &#39;/@/store/modules/permission&#39;;
5 import { PageEnum } from '/@/enums/pageEnum'; 5 import { PageEnum } from '/@/enums/pageEnum';
6 import { userStore } from '/@/store/modules/user'; 6 import { userStore } from '/@/store/modules/user';
7 7
8 -import { PAGE_NOT_FOUND_ROUTE } from '/@/router/constant'; 8 +import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
9 9
10 const LOGIN_PATH = PageEnum.BASE_LOGIN; 10 const LOGIN_PATH = PageEnum.BASE_LOGIN;
11 11
src/router/helper/menuHelper.ts
1 import { AppRouteModule } from '/@/router/types'; 1 import { AppRouteModule } from '/@/router/types';
2 import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types'; 2 import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types';
3 3
4 -import { findPath, forEach, treeMap } from '/@/utils/helper/treeHelper'; 4 +import { findPath, treeMap } from '/@/utils/helper/treeHelper';
5 import { cloneDeep } from 'lodash-es'; 5 import { cloneDeep } from 'lodash-es';
6 import { isUrl } from '/@/utils/is'; 6 import { isUrl } from '/@/utils/is';
7 7
8 -export function getAllParentPath(treeData: any[], path: string) { 8 +export function getAllParentPath<T = Recordable>(treeData: T[], path: string) {
9 const menuList = findPath(treeData, (n) => n.path === path) as Menu[]; 9 const menuList = findPath(treeData, (n) => n.path === path) as Menu[];
10 return (menuList || []).map((item) => item.path); 10 return (menuList || []).map((item) => item.path);
11 } 11 }
12 12
13 -// 拼接父级路径  
14 -function joinParentPath(list: any, node: any) {  
15 - let allPaths = getAllParentPath(list, node.path);  
16 -  
17 - allPaths = allPaths.slice(0, allPaths.length - 1);  
18 - let parentPath = '';  
19 - if (Array.isArray(allPaths) && allPaths.length >= 2) {  
20 - parentPath = allPaths[allPaths.length - 1];  
21 - } else {  
22 - allPaths.forEach((p) => {  
23 - parentPath += /^\//.test(p) ? p : `/${p}`;  
24 - }); 13 +function joinParentPath(menus: Menu[], parentPath = '') {
  14 + for (let index = 0; index < menus.length; index++) {
  15 + const menu = menus[index];
  16 + const p = menu.path.startsWith('/') ? menu.path : `/${menu.path}`;
  17 + const parent = isUrl(menu.path) ? menu.path : `${parentPath}${p}`;
  18 + menus[index].path = parent;
  19 + if (menu?.children?.length) {
  20 + joinParentPath(menu.children, parent);
  21 + }
25 } 22 }
26 - node.path = `${/^\//.test(node.path) ? node.path : `${parentPath}/${node.path}`}`.replace(  
27 - /\/\//g,  
28 - '/'  
29 - );  
30 - return node;  
31 } 23 }
32 24
33 -// 解析菜单模块 25 +// Parsing the menu module
34 export function transformMenuModule(menuModule: MenuModule): Menu { 26 export function transformMenuModule(menuModule: MenuModule): Menu {
35 const { menu } = menuModule; 27 const { menu } = menuModule;
36 28
37 const menuList = [menu]; 29 const menuList = [menu];
38 - forEach(menuList, (m) => {  
39 - !isUrl(m.path) && joinParentPath(menuList, m);  
40 - });  
41 30
  31 + joinParentPath(menuList);
42 return menuList[0]; 32 return menuList[0];
43 } 33 }
44 34
@@ -54,17 +44,16 @@ export function transformRouteToMenu(routeModList: AppRouteModule[]) { @@ -54,17 +44,16 @@ export function transformRouteToMenu(routeModList: AppRouteModule[]) {
54 routeList.push(item); 44 routeList.push(item);
55 } 45 }
56 }); 46 });
57 - return treeMap(routeList, { 47 + const list = treeMap(routeList, {
58 conversion: (node: AppRouteRecordRaw) => { 48 conversion: (node: AppRouteRecordRaw) => {
59 - const { meta: { title, icon, hideMenu = false } = {} } = node;  
60 -  
61 - !isUrl(node.path) && joinParentPath(routeList, node); 49 + const { meta: { title, hideMenu = false } = {} } = node;
62 return { 50 return {
  51 + ...(node.meta || {}),
63 name: title, 52 name: title,
64 - icon,  
65 - path: node.path,  
66 hideMenu, 53 hideMenu,
67 }; 54 };
68 }, 55 },
69 }); 56 });
  57 + joinParentPath(list);
  58 + return list;
70 } 59 }
src/router/helper/routeHelper.ts
1 import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types'; 1 import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types';
2 -import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router'; 2 +import type { Router, RouteRecordNormalized } from 'vue-router';
3 3
4 import { getParentLayout, LAYOUT } from '/@/router/constant'; 4 import { getParentLayout, LAYOUT } from '/@/router/constant';
5 import { cloneDeep } from 'lodash-es'; 5 import { cloneDeep } from 'lodash-es';
6 import { warn } from '/@/utils/log'; 6 import { warn } from '/@/utils/log';
  7 +import { createRouter, createWebHashHistory } from 'vue-router';
7 8
8 export type LayoutMapKey = 'LAYOUT'; 9 export type LayoutMapKey = 'LAYOUT';
9 10
10 const LayoutMap = new Map<LayoutMapKey, () => Promise<typeof import('*.vue')>>(); 11 const LayoutMap = new Map<LayoutMapKey, () => Promise<typeof import('*.vue')>>();
11 12
12 -let dynamicViewsModules: Record<  
13 - string,  
14 - () => Promise<{  
15 - [key: string]: any;  
16 - }>  
17 ->; 13 +let dynamicViewsModules: Record<string, () => Promise<Recordable>>;
18 14
19 -// 动态引入 15 +// Dynamic introduction
20 function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) { 16 function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
21 dynamicViewsModules = dynamicViewsModules || import.meta.glob('../../views/**/*.{vue,tsx}'); 17 dynamicViewsModules = dynamicViewsModules || import.meta.glob('../../views/**/*.{vue,tsx}');
22 if (!routes) return; 18 if (!routes) return;
@@ -26,19 +22,14 @@ function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) { @@ -26,19 +22,14 @@ function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
26 if (component) { 22 if (component) {
27 item.component = dynamicImport(dynamicViewsModules, component as string); 23 item.component = dynamicImport(dynamicViewsModules, component as string);
28 } else if (name) { 24 } else if (name) {
29 - item.component = getParentLayout(name); 25 + item.component = getParentLayout();
30 } 26 }
31 children && asyncImportRoute(children); 27 children && asyncImportRoute(children);
32 }); 28 });
33 } 29 }
34 30
35 function dynamicImport( 31 function dynamicImport(
36 - dynamicViewsModules: Record<  
37 - string,  
38 - () => Promise<{  
39 - [key: string]: any;  
40 - }>  
41 - >, 32 + dynamicViewsModules: Record<string, () => Promise<Recordable>>,
42 component: string 33 component: string
43 ) { 34 ) {
44 const keys = Object.keys(dynamicViewsModules); 35 const keys = Object.keys(dynamicViewsModules);
@@ -84,18 +75,69 @@ export function transformObjToRoute&lt;T = AppRouteModule&gt;(routeList: AppRouteModul @@ -84,18 +75,69 @@ export function transformObjToRoute&lt;T = AppRouteModule&gt;(routeList: AppRouteModul
84 return (routeList as unknown) as T[]; 75 return (routeList as unknown) as T[];
85 } 76 }
86 77
87 -// Return to the new routing structure, not affected by the original example  
88 -export function getRoute(route: RouteLocationNormalized): RouteLocationNormalized {  
89 - if (!route) return route;  
90 - const { matched, ...opt } = route;  
91 - return {  
92 - ...opt,  
93 - matched: (matched  
94 - ? matched.map((item) => ({  
95 - meta: item.meta,  
96 - name: item.name,  
97 - path: item.path,  
98 - }))  
99 - : undefined) as RouteRecordNormalized[],  
100 - }; 78 +/**
  79 + * Convert multi-level routing to level 2 routing
  80 + */
  81 +export function flatRoutes(routeModules: AppRouteModule[]) {
  82 + for (let index = 0; index < routeModules.length; index++) {
  83 + const routeModule = routeModules[index];
  84 + if (!isMultipleRoute(routeModule)) {
  85 + continue;
  86 + }
  87 + promoteRouteLevel(routeModule);
  88 + }
  89 +}
  90 +
  91 +// Routing level upgrade
  92 +function promoteRouteLevel(routeModule: AppRouteModule) {
  93 + // Use vue-router to splice menus
  94 + let router: Router | null = createRouter({
  95 + routes: [routeModule as any],
  96 + history: createWebHashHistory(),
  97 + });
  98 +
  99 + const routes = router.getRoutes();
  100 + const children = cloneDeep(routeModule.children);
  101 + addToChildren(routes, children || [], routeModule);
  102 + router = null;
  103 +
  104 + routeModule.children = routeModule.children?.filter((item) => !item.children?.length);
  105 +}
  106 +
  107 +// Add all sub-routes to the secondary route
  108 +function addToChildren(
  109 + routes: RouteRecordNormalized[],
  110 + children: AppRouteRecordRaw[],
  111 + routeModule: AppRouteModule
  112 +) {
  113 + for (let index = 0; index < children.length; index++) {
  114 + const child = children[index];
  115 + const route = routes.find((item) => item.name === child.name);
  116 + if (route) {
  117 + routeModule.children = routeModule.children || [];
  118 + routeModule.children?.push(route as any);
  119 + if (child.children?.length) {
  120 + addToChildren(routes, child.children, routeModule);
  121 + }
  122 + }
  123 + }
  124 +}
  125 +
  126 +// Determine whether the level exceeds 2 levels
  127 +function isMultipleRoute(routeModule: AppRouteModule) {
  128 + if (!routeModule || !Reflect.has(routeModule, 'children') || !routeModule.children?.length) {
  129 + return false;
  130 + }
  131 +
  132 + const children = routeModule.children;
  133 +
  134 + let flag = false;
  135 + for (let index = 0; index < children.length; index++) {
  136 + const child = children[index];
  137 + if (child.children?.length) {
  138 + flag = true;
  139 + break;
  140 + }
  141 + }
  142 + return flag;
101 } 143 }
src/router/menus/index.ts
@@ -5,6 +5,7 @@ import { appStore } from &#39;/@/store/modules/app&#39;; @@ -5,6 +5,7 @@ import { appStore } from &#39;/@/store/modules/app&#39;;
5 import { permissionStore } from '/@/store/modules/permission'; 5 import { permissionStore } from '/@/store/modules/permission';
6 import { transformMenuModule, getAllParentPath } from '/@/router/helper/menuHelper'; 6 import { transformMenuModule, getAllParentPath } from '/@/router/helper/menuHelper';
7 import { filter } from '/@/utils/helper/treeHelper'; 7 import { filter } from '/@/utils/helper/treeHelper';
  8 +import { isUrl } from '/@/utils/is';
8 import router from '/@/router'; 9 import router from '/@/router';
9 import { PermissionModeEnum } from '/@/enums/appEnum'; 10 import { PermissionModeEnum } from '/@/enums/appEnum';
10 import { pathToRegexp } from 'path-to-regexp'; 11 import { pathToRegexp } from 'path-to-regexp';
@@ -19,8 +20,6 @@ Object.keys(modules).forEach((key) =&gt; { @@ -19,8 +20,6 @@ Object.keys(modules).forEach((key) =&gt; {
19 menuModules.push(...modList); 20 menuModules.push(...modList);
20 }); 21 });
21 22
22 -const reg = /(((https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;  
23 -  
24 // =========================== 23 // ===========================
25 // ==========Helper=========== 24 // ==========Helper===========
26 // =========================== 25 // ===========================
@@ -40,18 +39,15 @@ const staticMenus: Menu[] = []; @@ -40,18 +39,15 @@ const staticMenus: Menu[] = [];
40 })(); 39 })();
41 40
42 async function getAsyncMenus() { 41 async function getAsyncMenus() {
43 - // 前端角色控制菜单 直接取菜单文件  
44 return !isBackMode() ? staticMenus : permissionStore.getBackMenuListState; 42 return !isBackMode() ? staticMenus : permissionStore.getBackMenuListState;
45 } 43 }
46 44
47 -// 获取菜单 树级  
48 export const getMenus = async (): Promise<Menu[]> => { 45 export const getMenus = async (): Promise<Menu[]> => {
49 const menus = await getAsyncMenus(); 46 const menus = await getAsyncMenus();
50 const routes = router.getRoutes(); 47 const routes = router.getRoutes();
51 return !isBackMode() ? filter(menus, basicFilter(routes)) : menus; 48 return !isBackMode() ? filter(menus, basicFilter(routes)) : menus;
52 }; 49 };
53 50
54 -// 获取当前路径的顶级路径  
55 export async function getCurrentParentPath(currentPath: string) { 51 export async function getCurrentParentPath(currentPath: string) {
56 const menus = await getAsyncMenus(); 52 const menus = await getAsyncMenus();
57 53
@@ -60,7 +56,7 @@ export async function getCurrentParentPath(currentPath: string) { @@ -60,7 +56,7 @@ export async function getCurrentParentPath(currentPath: string) {
60 return allParentPath?.[0]; 56 return allParentPath?.[0];
61 } 57 }
62 58
63 -// 获取1级菜单,删除children 59 +// Get the level 1 menu, delete children
64 export async function getShallowMenus(): Promise<Menu[]> { 60 export async function getShallowMenus(): Promise<Menu[]> {
65 const menus = await getAsyncMenus(); 61 const menus = await getAsyncMenus();
66 const routes = router.getRoutes(); 62 const routes = router.getRoutes();
@@ -68,7 +64,7 @@ export async function getShallowMenus(): Promise&lt;Menu[]&gt; { @@ -68,7 +64,7 @@ export async function getShallowMenus(): Promise&lt;Menu[]&gt; {
68 return !isBackMode() ? shallowMenuList.filter(basicFilter(routes)) : shallowMenuList; 64 return !isBackMode() ? shallowMenuList.filter(basicFilter(routes)) : shallowMenuList;
69 } 65 }
70 66
71 -// 获取菜单的children 67 +// Get the children of the menu
72 export async function getChildrenMenus(parentPath: string) { 68 export async function getChildrenMenus(parentPath: string) {
73 const menus = await getAsyncMenus(); 69 const menus = await getAsyncMenus();
74 const parent = menus.find((item) => item.path === parentPath); 70 const parent = menus.find((item) => item.path === parentPath);
@@ -78,14 +74,10 @@ export async function getChildrenMenus(parentPath: string) { @@ -78,14 +74,10 @@ export async function getChildrenMenus(parentPath: string) {
78 return !isBackMode() ? filter(parent.children, basicFilter(routes)) : parent.children; 74 return !isBackMode() ? filter(parent.children, basicFilter(routes)) : parent.children;
79 } 75 }
80 76
81 -// 通用过滤方法  
82 function basicFilter(routes: RouteRecordNormalized[]) { 77 function basicFilter(routes: RouteRecordNormalized[]) {
83 return (menu: Menu) => { 78 return (menu: Menu) => {
84 const matchRoute = routes.find((route) => { 79 const matchRoute = routes.find((route) => {
85 - const match = route.path.match(reg)?.[0];  
86 - if (match && match === menu.path) {  
87 - return true;  
88 - } 80 + if (isUrl(menu.path)) return true;
89 81
90 if (route.meta?.carryParam) { 82 if (route.meta?.carryParam) {
91 return pathToRegexp(route.path).test(menu.path); 83 return pathToRegexp(route.path).test(menu.path);
src/router/routes/basic.ts 0 → 100644
  1 +import type { AppRouteRecordRaw } from '/@/router/types';
  2 +import { t } from '/@/hooks/web/useI18n';
  3 +import { REDIRECT_NAME, LAYOUT, EXCEPTION_COMPONENT } from '/@/router/constant';
  4 +
  5 +// 404 on a page
  6 +export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
  7 + path: '/:path(.*)*',
  8 + name: 'ErrorPage',
  9 + component: LAYOUT,
  10 + meta: {
  11 + title: 'ErrorPage',
  12 + hideBreadcrumb: true,
  13 + },
  14 + children: [
  15 + {
  16 + path: '/:path(.*)*',
  17 + name: 'ErrorPage',
  18 + component: EXCEPTION_COMPONENT,
  19 + meta: {
  20 + title: 'ErrorPage',
  21 + hideBreadcrumb: true,
  22 + },
  23 + },
  24 + ],
  25 +};
  26 +
  27 +export const REDIRECT_ROUTE: AppRouteRecordRaw = {
  28 + path: '/redirect',
  29 + name: REDIRECT_NAME,
  30 + component: LAYOUT,
  31 + meta: {
  32 + title: REDIRECT_NAME,
  33 + hideBreadcrumb: true,
  34 + },
  35 + children: [
  36 + {
  37 + path: '/redirect/:path(.*)',
  38 + name: REDIRECT_NAME,
  39 + component: () => import('/@/views/sys/redirect/index.vue'),
  40 + meta: {
  41 + title: REDIRECT_NAME,
  42 + hideBreadcrumb: true,
  43 + },
  44 + },
  45 + ],
  46 +};
  47 +
  48 +export const ERROR_LOG_ROUTE: AppRouteRecordRaw = {
  49 + path: '/error-log',
  50 + name: 'errorLog',
  51 + component: LAYOUT,
  52 + meta: {
  53 + title: 'ErrorLog',
  54 + hideBreadcrumb: true,
  55 + },
  56 + children: [
  57 + {
  58 + path: 'list',
  59 + name: 'errorLogList',
  60 + component: () => import('/@/views/sys/error-log/index.vue'),
  61 + meta: {
  62 + title: t('routes.basic.errorLogList'),
  63 + hideBreadcrumb: true,
  64 + },
  65 + },
  66 + ],
  67 +};
src/router/routes/index.ts
1 import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types'; 1 import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types';
2 2
3 -import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '../constant'; 3 +import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/routes/basic';
4 4
5 import { mainOutRoutes } from './mainOut'; 5 import { mainOutRoutes } from './mainOut';
6 import { PageEnum } from '/@/enums/pageEnum'; 6 import { PageEnum } from '/@/enums/pageEnum';
7 import { t } from '/@/hooks/web/useI18n'; 7 import { t } from '/@/hooks/web/useI18n';
  8 +import { flatRoutes } from '/@/router/helper/routeHelper';
8 9
9 const modules = import.meta.globEager('./modules/**/*.ts'); 10 const modules = import.meta.globEager('./modules/**/*.ts');
10 11
@@ -16,6 +17,9 @@ Object.keys(modules).forEach((key) =&gt; { @@ -16,6 +17,9 @@ Object.keys(modules).forEach((key) =&gt; {
16 routeModuleList.push(...modList); 17 routeModuleList.push(...modList);
17 }); 18 });
18 19
  20 +// Multi-level routing conversion
  21 +flatRoutes(routeModuleList);
  22 +
19 export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList]; 23 export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList];
20 24
21 export const RootRoute: AppRouteRecordRaw = { 25 export const RootRoute: AppRouteRecordRaw = {
src/store/modules/permission.ts
@@ -14,12 +14,12 @@ import { filter } from &#39;/@/utils/helper/treeHelper&#39;; @@ -14,12 +14,12 @@ import { filter } from &#39;/@/utils/helper/treeHelper&#39;;
14 import { toRaw } from 'vue'; 14 import { toRaw } from 'vue';
15 import { getMenuListById } from '/@/api/sys/menu'; 15 import { getMenuListById } from '/@/api/sys/menu';
16 16
17 -import { transformObjToRoute } from '/@/router/helper/routeHelper'; 17 +import { transformObjToRoute, flatRoutes } from '/@/router/helper/routeHelper';
18 import { transformRouteToMenu } from '/@/router/helper/menuHelper'; 18 import { transformRouteToMenu } from '/@/router/helper/menuHelper';
19 19
20 import { useMessage } from '/@/hooks/web/useMessage'; 20 import { useMessage } from '/@/hooks/web/useMessage';
21 import { useI18n } from '/@/hooks/web/useI18n'; 21 import { useI18n } from '/@/hooks/web/useI18n';
22 -import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/constant'; 22 +import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
23 23
24 const { createMessage } = useMessage(); 24 const { createMessage } = useMessage();
25 const NAME = 'app-permission'; 25 const NAME = 'app-permission';
@@ -113,11 +113,12 @@ class Permission extends VuexModule { @@ -113,11 +113,12 @@ class Permission extends VuexModule {
113 113
114 // Dynamically introduce components 114 // Dynamically introduce components
115 routeList = transformObjToRoute(routeList); 115 routeList = transformObjToRoute(routeList);
  116 +
116 // Background routing to menu structure 117 // Background routing to menu structure
117 const backMenuList = transformRouteToMenu(routeList); 118 const backMenuList = transformRouteToMenu(routeList);
118 -  
119 this.commitBackMenuListState(backMenuList); 119 this.commitBackMenuListState(backMenuList);
120 120
  121 + flatRoutes(routeList);
121 routes = [PAGE_NOT_FOUND_ROUTE, ...routeList]; 122 routes = [PAGE_NOT_FOUND_ROUTE, ...routeList];
122 } 123 }
123 routes.push(ERROR_LOG_ROUTE); 124 routes.push(ERROR_LOG_ROUTE);
src/store/modules/tab.ts
@@ -8,8 +8,8 @@ import { PageEnum } from &#39;/@/enums/pageEnum&#39;; @@ -8,8 +8,8 @@ import { PageEnum } from &#39;/@/enums/pageEnum&#39;;
8 8
9 import store from '/@/store'; 9 import store from '/@/store';
10 import router from '/@/router'; 10 import router from '/@/router';
11 -import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/constant';  
12 -import { getRoute } from '/@/router/helper/routeHelper'; 11 +import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/routes/basic';
  12 +import { getRawRoute } from '/@/utils';
13 13
14 import { useGo, useRedo } from '/@/hooks/web/usePage'; 14 import { useGo, useRedo } from '/@/hooks/web/usePage';
15 import { cloneDeep } from 'lodash-es'; 15 import { cloneDeep } from 'lodash-es';
@@ -18,8 +18,6 @@ const NAME = &#39;app-tab&#39;; @@ -18,8 +18,6 @@ const NAME = &#39;app-tab&#39;;
18 18
19 hotModuleUnregisterModule(NAME); 19 hotModuleUnregisterModule(NAME);
20 20
21 -export const PAGE_LAYOUT_KEY = '__PAGE_LAYOUT__';  
22 -  
23 function isGotoPage() { 21 function isGotoPage() {
24 const go = useGo(); 22 const go = useGo();
25 go(unref(router.currentRoute).path, true); 23 go(unref(router.currentRoute).path, true);
@@ -27,7 +25,7 @@ function isGotoPage() { @@ -27,7 +25,7 @@ function isGotoPage() {
27 25
28 @Module({ namespaced: true, name: NAME, dynamic: true, store }) 26 @Module({ namespaced: true, name: NAME, dynamic: true, store })
29 class Tab extends VuexModule { 27 class Tab extends VuexModule {
30 - cachedMapState = new Map<string, string[]>(); 28 + cachedTabsState: Set<string> = new Set();
31 29
32 // tab list 30 // tab list
33 tabsState: RouteLocationNormalized[] = []; 31 tabsState: RouteLocationNormalized[] = [];
@@ -43,8 +41,8 @@ class Tab extends VuexModule { @@ -43,8 +41,8 @@ class Tab extends VuexModule {
43 return this.tabsState.find((item) => item.path === route.path)!; 41 return this.tabsState.find((item) => item.path === route.path)!;
44 } 42 }
45 43
46 - get getCachedMapState(): Map<string, string[]> {  
47 - return this.cachedMapState; 44 + get getCachedTabsState(): string[] {
  45 + return Array.from(this.cachedTabsState);
48 } 46 }
49 47
50 get getLastDragEndIndexState(): number { 48 get getLastDragEndIndexState(): number {
@@ -53,7 +51,7 @@ class Tab extends VuexModule { @@ -53,7 +51,7 @@ class Tab extends VuexModule {
53 51
54 @Mutation 52 @Mutation
55 commitClearCache(): void { 53 commitClearCache(): void {
56 - this.cachedMapState = new Map(); 54 + this.cachedTabsState = new Set();
57 } 55 }
58 56
59 @Mutation 57 @Mutation
@@ -77,46 +75,16 @@ class Tab extends VuexModule { @@ -77,46 +75,16 @@ class Tab extends VuexModule {
77 75
78 @Mutation 76 @Mutation
79 commitCachedMapState(): void { 77 commitCachedMapState(): void {
80 - const cacheMap = new Map<string, string[]>(); 78 + const cacheMap: Set<string> = new Set();
81 79
82 - const pageCacheSet = new Set<string>();  
83 this.tabsState.forEach((tab) => { 80 this.tabsState.forEach((tab) => {
84 - const item = getRoute(tab); 81 + const item = getRawRoute(tab);
85 const needCache = !item.meta?.ignoreKeepAlive; 82 const needCache = !item.meta?.ignoreKeepAlive;
86 if (!needCache) return; 83 if (!needCache) return;
87 -  
88 - if (item.meta?.affix) {  
89 - const name = item.name as string;  
90 - pageCacheSet.add(name);  
91 - } else if (item?.matched && needCache) {  
92 - const matched = item?.matched;  
93 - if (!matched) return;  
94 - const len = matched.length;  
95 -  
96 - if (len < 2) return;  
97 -  
98 - for (let i = 0; i < matched.length; i++) {  
99 - const key = matched[i].name as string;  
100 -  
101 - if (i < 2) {  
102 - pageCacheSet.add(key);  
103 - }  
104 - if (i < len - 1) {  
105 - const { meta, name } = matched[i + 1];  
106 - if (meta && (meta.affix || needCache)) {  
107 - const mapList = cacheMap.get(key) || [];  
108 - if (!mapList.includes(name as string)) {  
109 - mapList.push(name as string);  
110 - }  
111 - cacheMap.set(key, mapList);  
112 - }  
113 - }  
114 - }  
115 - } 84 + const name = item.name as string;
  85 + cacheMap.add(name);
116 }); 86 });
117 -  
118 - cacheMap.set(PAGE_LAYOUT_KEY, Array.from(pageCacheSet));  
119 - this.cachedMapState = cacheMap; 87 + this.cachedTabsState = cacheMap;
120 } 88 }
121 89
122 @Mutation 90 @Mutation
@@ -162,7 +130,7 @@ class Tab extends VuexModule { @@ -162,7 +130,7 @@ class Tab extends VuexModule {
162 @Mutation 130 @Mutation
163 commitResetState(): void { 131 commitResetState(): void {
164 this.tabsState = []; 132 this.tabsState = [];
165 - this.cachedMapState = new Map(); 133 + this.cachedTabsState = new Set();
166 } 134 }
167 135
168 @Mutation 136 @Mutation
@@ -190,7 +158,7 @@ class Tab extends VuexModule { @@ -190,7 +158,7 @@ class Tab extends VuexModule {
190 ) { 158 ) {
191 return; 159 return;
192 } 160 }
193 - this.commitTabRoutesState(getRoute(route)); 161 + this.commitTabRoutesState(getRawRoute(route));
194 162
195 this.commitCachedMapState(); 163 this.commitCachedMapState();
196 } 164 }
@@ -198,17 +166,12 @@ class Tab extends VuexModule { @@ -198,17 +166,12 @@ class Tab extends VuexModule {
198 @Mutation 166 @Mutation
199 async commitRedoPage() { 167 async commitRedoPage() {
200 const route = router.currentRoute.value; 168 const route = router.currentRoute.value;
201 - for (const [key, value] of this.cachedMapState) {  
202 - const index = value.findIndex((item) => item === (route.name as string));  
203 - if (index === -1) {  
204 - continue;  
205 - }  
206 - if (value.length === 1) {  
207 - this.cachedMapState.delete(key);  
208 - continue;  
209 - }  
210 - value.splice(index, 1);  
211 - this.cachedMapState.set(key, value); 169 + const name = route.name;
  170 +
  171 + const findVal = Array.from(this.cachedTabsState).find((item) => item === name);
  172 + if (findVal) {
  173 + this.cachedTabsState.delete(findVal);
  174 + // this.cachedTabsState.splice(index, 1);
212 } 175 }
213 const redo = useRedo(); 176 const redo = useRedo();
214 await redo(); 177 await redo();
src/utils/index.ts
1 -export const timestamp = () => +Date.now(); 1 +import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router';
2 import { unref } from 'vue'; 2 import { unref } from 'vue';
3 import { isObject } from '/@/utils/is'; 3 import { isObject } from '/@/utils/is';
4 -export const clamp = (n: number, min: number, max: number) => Math.min(max, Math.max(min, n)); 4 +
5 export const noop = () => {}; 5 export const noop = () => {};
6 -export const now = () => Date.now();  
7 6
8 /** 7 /**
9 * @description: Set ui mount node 8 * @description: Set ui mount node
@@ -91,3 +90,18 @@ export function setTitle(title: string, appTitle?: string) { @@ -91,3 +90,18 @@ export function setTitle(title: string, appTitle?: string) {
91 setDocumentTitle(_title); 90 setDocumentTitle(_title);
92 } 91 }
93 } 92 }
  93 +
  94 +export function getRawRoute(route: RouteLocationNormalized): RouteLocationNormalized {
  95 + if (!route) return route;
  96 + const { matched, ...opt } = route;
  97 + return {
  98 + ...opt,
  99 + matched: (matched
  100 + ? matched.map((item) => ({
  101 + meta: item.meta,
  102 + name: item.name,
  103 + path: item.path,
  104 + }))
  105 + : undefined) as RouteRecordNormalized[],
  106 + };
  107 +}
vite.config.ts
@@ -43,7 +43,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig =&gt; { @@ -43,7 +43,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig =&gt; {
43 }, 43 },
44 44
45 build: { 45 build: {
46 - minify: 'esbuild', 46 + // minify: 'esbuild',
47 outDir: OUTPUT_DIR, 47 outDir: OUTPUT_DIR,
48 polyfillDynamicImport: VITE_LEGACY, 48 polyfillDynamicImport: VITE_LEGACY,
49 terserOptions: { 49 terserOptions: {