mirror of
				https://github.com/pure-admin/vue-pure-admin.git
				synced 2025-11-03 13:44:47 +08:00 
			
		
		
		
	refactor: router (#145)
* refactor: router * perf: router * perf: router * perf: router Co-authored-by: lrl <742798240@qq.com>
This commit is contained in:
		
							parent
							
								
									7811f6bdeb
								
							
						
					
					
						commit
						d57e0e379e
					
				@ -62,7 +62,7 @@
 | 
				
			|||||||
    "sortablejs": "1.13.0",
 | 
					    "sortablejs": "1.13.0",
 | 
				
			||||||
    "typescript-cookie": "^1.0.0",
 | 
					    "typescript-cookie": "^1.0.0",
 | 
				
			||||||
    "v-contextmenu": "3.0.0",
 | 
					    "v-contextmenu": "3.0.0",
 | 
				
			||||||
    "vue": "^3.2.21",
 | 
					    "vue": "^3.2.24",
 | 
				
			||||||
    "vue-i18n": "^9.2.0-beta.3",
 | 
					    "vue-i18n": "^9.2.0-beta.3",
 | 
				
			||||||
    "vue-json-pretty": "^2.0.2",
 | 
					    "vue-json-pretty": "^2.0.2",
 | 
				
			||||||
    "vue-router": "^4.0.11",
 | 
					    "vue-router": "^4.0.11",
 | 
				
			||||||
@ -87,7 +87,7 @@
 | 
				
			|||||||
    "@typescript-eslint/parser": "4.31.0",
 | 
					    "@typescript-eslint/parser": "4.31.0",
 | 
				
			||||||
    "@vitejs/plugin-vue": "^1.10.2",
 | 
					    "@vitejs/plugin-vue": "^1.10.2",
 | 
				
			||||||
    "@vitejs/plugin-vue-jsx": "^1.3.1",
 | 
					    "@vitejs/plugin-vue-jsx": "^1.3.1",
 | 
				
			||||||
    "@vue/compiler-sfc": "^3.2.21",
 | 
					    "@vue/compiler-sfc": "^3.2.24",
 | 
				
			||||||
    "@vue/eslint-config-prettier": "6.0.0",
 | 
					    "@vue/eslint-config-prettier": "6.0.0",
 | 
				
			||||||
    "@vue/eslint-config-typescript": "7.0.0",
 | 
					    "@vue/eslint-config-typescript": "7.0.0",
 | 
				
			||||||
    "@zougt/vite-plugin-theme-preprocessor": "^1.3.12",
 | 
					    "@zougt/vite-plugin-theme-preprocessor": "^1.3.12",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4825
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4825
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -13,7 +13,6 @@
 | 
				
			|||||||
  "HideTabs": false,
 | 
					  "HideTabs": false,
 | 
				
			||||||
  "MapConfigure": {
 | 
					  "MapConfigure": {
 | 
				
			||||||
    "amapKey": "97b3248d1553172e81f168cf94ea667e",
 | 
					    "amapKey": "97b3248d1553172e81f168cf94ea667e",
 | 
				
			||||||
    "baiduKey": "wTHbkkEweiFqZLKunMIjcrb2RcqNXkhc",
 | 
					 | 
				
			||||||
    "options": {
 | 
					    "options": {
 | 
				
			||||||
      "resizeEnable": true,
 | 
					      "resizeEnable": true,
 | 
				
			||||||
      "center": [113.6401, 34.72468],
 | 
					      "center": [113.6401, 34.72468],
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,6 @@ const title =
 | 
				
			|||||||
  getCurrentInstance().appContext.config.globalProperties.$config?.Title;
 | 
					  getCurrentInstance().appContext.config.globalProperties.$config?.Title;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const menuRef = templateRef<ElRef | null>("menu", null);
 | 
					const menuRef = templateRef<ElRef | null>("menu", null);
 | 
				
			||||||
const routeStore = usePermissionStoreHook();
 | 
					 | 
				
			||||||
const route = useRoute();
 | 
					const route = useRoute();
 | 
				
			||||||
const router = useRouter();
 | 
					const router = useRouter();
 | 
				
			||||||
const routers = useRouter().options.routes;
 | 
					const routers = useRouter().options.routes;
 | 
				
			||||||
@ -133,7 +132,7 @@ onMounted(() => {
 | 
				
			|||||||
      @select="menuSelect"
 | 
					      @select="menuSelect"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <sidebar-item
 | 
					      <sidebar-item
 | 
				
			||||||
        v-for="route in routeStore.wholeRoutes"
 | 
					        v-for="route in usePermissionStoreHook().wholeMenus"
 | 
				
			||||||
        :key="route.path"
 | 
					        :key="route.path"
 | 
				
			||||||
        :item="route"
 | 
					        :item="route"
 | 
				
			||||||
        :base-path="route.path"
 | 
					        :base-path="route.path"
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,6 @@ import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
				
			|||||||
const route = useRoute();
 | 
					const route = useRoute();
 | 
				
			||||||
const pureApp = useAppStoreHook();
 | 
					const pureApp = useAppStoreHook();
 | 
				
			||||||
const router = useRouter().options.routes;
 | 
					const router = useRouter().options.routes;
 | 
				
			||||||
const routeStore = usePermissionStoreHook();
 | 
					 | 
				
			||||||
const showLogo = ref(storageLocal.getItem("logoVal") || "1");
 | 
					const showLogo = ref(storageLocal.getItem("logoVal") || "1");
 | 
				
			||||||
const isCollapse = computed(() => {
 | 
					const isCollapse = computed(() => {
 | 
				
			||||||
  return !pureApp.getSidebarStatus;
 | 
					  return !pureApp.getSidebarStatus;
 | 
				
			||||||
@ -72,7 +71,7 @@ onBeforeMount(() => {
 | 
				
			|||||||
        @select="menuSelect"
 | 
					        @select="menuSelect"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <sidebar-item
 | 
					        <sidebar-item
 | 
				
			||||||
          v-for="route in routeStore.wholeRoutes"
 | 
					          v-for="route in usePermissionStoreHook().wholeMenus"
 | 
				
			||||||
          :key="route.path"
 | 
					          :key="route.path"
 | 
				
			||||||
          :item="route"
 | 
					          :item="route"
 | 
				
			||||||
          class="outer-most"
 | 
					          class="outer-most"
 | 
				
			||||||
 | 
				
			|||||||
@ -22,11 +22,12 @@ import { transformI18n } from "/@/plugins/i18n";
 | 
				
			|||||||
import { storageLocal } from "/@/utils/storage";
 | 
					import { storageLocal } from "/@/utils/storage";
 | 
				
			||||||
import { useRoute, useRouter } from "vue-router";
 | 
					import { useRoute, useRouter } from "vue-router";
 | 
				
			||||||
import { RouteConfigs, tagsViewsType } from "../../types";
 | 
					import { RouteConfigs, tagsViewsType } from "../../types";
 | 
				
			||||||
import { handleAliveRoute, delAliveRoutes } from "/@/router";
 | 
					 | 
				
			||||||
import { useSettingStoreHook } from "/@/store/modules/settings";
 | 
					import { useSettingStoreHook } from "/@/store/modules/settings";
 | 
				
			||||||
 | 
					import { handleAliveRoute, delAliveRoutes } from "/@/router/utils";
 | 
				
			||||||
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
 | 
					import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
 | 
				
			||||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
					import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
				
			||||||
import { toggleClass, removeClass, hasClass } from "/@/utils/operate";
 | 
					import { toggleClass, removeClass, hasClass } from "/@/utils/operate";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { templateRef, useResizeObserver, useDebounceFn } from "@vueuse/core";
 | 
					import { templateRef, useResizeObserver, useDebounceFn } from "@vueuse/core";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const route = useRoute();
 | 
					const route = useRoute();
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										15
									
								
								src/layout/routerView/parent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/layout/routerView/parent.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <router-view>
 | 
				
			||||||
 | 
					    <template #default="{ Component, route }">
 | 
				
			||||||
 | 
					      <transition appear name="fade-transform" mode="out-in">
 | 
				
			||||||
 | 
					        <component :is="Component" :key="route.fullPath" />
 | 
				
			||||||
 | 
					      </transition>
 | 
				
			||||||
 | 
					    </template>
 | 
				
			||||||
 | 
					  </router-view>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  name: "layoutParentView"
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@ -20,7 +20,9 @@ export type RouteConfigs = {
 | 
				
			|||||||
    icon?: string;
 | 
					    icon?: string;
 | 
				
			||||||
    showLink?: boolean;
 | 
					    showLink?: boolean;
 | 
				
			||||||
    savedPosition?: boolean;
 | 
					    savedPosition?: boolean;
 | 
				
			||||||
 | 
					    authority?: Array<string>;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					  children?: RouteConfigs[];
 | 
				
			||||||
  name?: string;
 | 
					  name?: string;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2,145 +2,30 @@ import {
 | 
				
			|||||||
  Router,
 | 
					  Router,
 | 
				
			||||||
  RouteMeta,
 | 
					  RouteMeta,
 | 
				
			||||||
  createRouter,
 | 
					  createRouter,
 | 
				
			||||||
  RouteComponent,
 | 
					 | 
				
			||||||
  RouteRecordName,
 | 
					  RouteRecordName,
 | 
				
			||||||
  createWebHashHistory,
 | 
					  createWebHashHistory
 | 
				
			||||||
  RouteRecordNormalized
 | 
					 | 
				
			||||||
} from "vue-router";
 | 
					} from "vue-router";
 | 
				
			||||||
 | 
					import { toRouteType } from "./types";
 | 
				
			||||||
import { openLink } from "/@/utils/link";
 | 
					import { openLink } from "/@/utils/link";
 | 
				
			||||||
import NProgress from "/@/utils/progress";
 | 
					import NProgress from "/@/utils/progress";
 | 
				
			||||||
import { split, uniqBy } from "lodash-es";
 | 
					import { split, uniqBy } from "lodash-es";
 | 
				
			||||||
import { useTimeoutFn } from "@vueuse/core";
 | 
					import { constantRoutes } from "./modules";
 | 
				
			||||||
import { RouteConfigs } from "/@/layout/types";
 | 
					 | 
				
			||||||
import { transformI18n } from "/@/plugins/i18n";
 | 
					import { transformI18n } from "/@/plugins/i18n";
 | 
				
			||||||
import { storageSession, storageLocal } from "/@/utils/storage";
 | 
					 | 
				
			||||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
					 | 
				
			||||||
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 静态路由
 | 
					 | 
				
			||||||
import tabsRouter from "./modules/tabs";
 | 
					 | 
				
			||||||
import homeRouter from "./modules/home";
 | 
					 | 
				
			||||||
import Layout from "/@/layout/index.vue";
 | 
					 | 
				
			||||||
import errorRouter from "./modules/error";
 | 
					 | 
				
			||||||
import editorRouter from "./modules/editor";
 | 
					 | 
				
			||||||
import nestedRouter from "./modules/nested";
 | 
					 | 
				
			||||||
import externalLink from "./modules/externalLink";
 | 
					 | 
				
			||||||
import remainingRouter from "./modules/remaining";
 | 
					import remainingRouter from "./modules/remaining";
 | 
				
			||||||
import flowChartRouter from "./modules/flowchart";
 | 
					import { storageSession, storageLocal } from "/@/utils/storage";
 | 
				
			||||||
import componentsRouter from "./modules/components";
 | 
					import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
 | 
				
			||||||
 | 
					import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
				
			||||||
// 动态路由
 | 
					import {
 | 
				
			||||||
import { getAsyncRoutes } from "/@/api/routes";
 | 
					  initRouter,
 | 
				
			||||||
 | 
					  getParentPaths,
 | 
				
			||||||
// https://cn.vitejs.dev/guide/features.html#glob-import
 | 
					  findRouteByPath,
 | 
				
			||||||
const modulesRoutes = import.meta.glob("/src/views/*/*/*.vue");
 | 
					  handleAliveRoute
 | 
				
			||||||
 | 
					} from "./utils";
 | 
				
			||||||
const constantRoutes: Array<RouteComponent> = [
 | 
					 | 
				
			||||||
  tabsRouter,
 | 
					 | 
				
			||||||
  homeRouter,
 | 
					 | 
				
			||||||
  flowChartRouter,
 | 
					 | 
				
			||||||
  editorRouter,
 | 
					 | 
				
			||||||
  componentsRouter,
 | 
					 | 
				
			||||||
  nestedRouter,
 | 
					 | 
				
			||||||
  externalLink,
 | 
					 | 
				
			||||||
  errorRouter
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 按照路由中meta下的rank等级升序来排序路由
 | 
					 | 
				
			||||||
export const ascending = arr => {
 | 
					 | 
				
			||||||
  return arr.sort((a: any, b: any) => {
 | 
					 | 
				
			||||||
    return a?.meta?.rank - b?.meta?.rank;
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 将所有静态路由导出
 | 
					 | 
				
			||||||
export const constantRoutesArr: Array<RouteComponent> = ascending(
 | 
					 | 
				
			||||||
  constantRoutes
 | 
					 | 
				
			||||||
).concat(...remainingRouter);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 过滤meta中showLink为false的路由
 | 
					 | 
				
			||||||
export const filterTree = data => {
 | 
					 | 
				
			||||||
  const newTree = data.filter(v => v.meta.showLink);
 | 
					 | 
				
			||||||
  newTree.forEach(v => v.children && (v.children = filterTree(v.children)));
 | 
					 | 
				
			||||||
  return newTree;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 从路由中提取keepAlive为true的name组成数组(此处本项目中并没有用到,只是暴露个方法)
 | 
					 | 
				
			||||||
export const getAliveRoute = () => {
 | 
					 | 
				
			||||||
  const alivePageList = [];
 | 
					 | 
				
			||||||
  const recursiveSearch = treeLists => {
 | 
					 | 
				
			||||||
    if (!treeLists || !treeLists.length) {
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for (let i = 0; i < treeLists.length; i++) {
 | 
					 | 
				
			||||||
      if (treeLists[i]?.meta?.keepAlive) alivePageList.push(treeLists[i].name);
 | 
					 | 
				
			||||||
      recursiveSearch(treeLists[i].children);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  recursiveSearch(router.options.routes);
 | 
					 | 
				
			||||||
  return alivePageList;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 批量删除缓存路由
 | 
					 | 
				
			||||||
export const delAliveRoutes = (delAliveRouteList: Array<RouteConfigs>) => {
 | 
					 | 
				
			||||||
  delAliveRouteList.forEach(route => {
 | 
					 | 
				
			||||||
    usePermissionStoreHook().cacheOperate({
 | 
					 | 
				
			||||||
      mode: "delete",
 | 
					 | 
				
			||||||
      name: route?.name
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 处理缓存路由(添加、删除、刷新)
 | 
					 | 
				
			||||||
export const handleAliveRoute = (
 | 
					 | 
				
			||||||
  matched: RouteRecordNormalized[],
 | 
					 | 
				
			||||||
  mode?: string
 | 
					 | 
				
			||||||
) => {
 | 
					 | 
				
			||||||
  switch (mode) {
 | 
					 | 
				
			||||||
    case "add":
 | 
					 | 
				
			||||||
      matched.forEach(v => {
 | 
					 | 
				
			||||||
        usePermissionStoreHook().cacheOperate({ mode: "add", name: v.name });
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case "delete":
 | 
					 | 
				
			||||||
      usePermissionStoreHook().cacheOperate({
 | 
					 | 
				
			||||||
        mode: "delete",
 | 
					 | 
				
			||||||
        name: matched[matched.length - 1].name
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      usePermissionStoreHook().cacheOperate({
 | 
					 | 
				
			||||||
        mode: "delete",
 | 
					 | 
				
			||||||
        name: matched[matched.length - 1].name
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      useTimeoutFn(() => {
 | 
					 | 
				
			||||||
        matched.forEach(v => {
 | 
					 | 
				
			||||||
          usePermissionStoreHook().cacheOperate({ mode: "add", name: v.name });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      }, 100);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 过滤后端传来的动态路由 重新生成规范路由
 | 
					 | 
				
			||||||
export const addAsyncRoutes = (arrRoutes: Array<RouteComponent>) => {
 | 
					 | 
				
			||||||
  if (!arrRoutes || !arrRoutes.length) return;
 | 
					 | 
				
			||||||
  arrRoutes.forEach((v: any) => {
 | 
					 | 
				
			||||||
    if (v.redirect) {
 | 
					 | 
				
			||||||
      v.component = Layout;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      v.component = modulesRoutes[`/src/views${v.path}/index.vue`];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (v.children) {
 | 
					 | 
				
			||||||
      addAsyncRoutes(v.children);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  return arrRoutes;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 创建路由实例
 | 
					// 创建路由实例
 | 
				
			||||||
export const router: Router = createRouter({
 | 
					export const router: Router = createRouter({
 | 
				
			||||||
  history: createWebHashHistory(),
 | 
					  history: createWebHashHistory(),
 | 
				
			||||||
  routes: ascending(constantRoutes).concat(...remainingRouter),
 | 
					  routes: constantRoutes.concat(...remainingRouter),
 | 
				
			||||||
  scrollBehavior(to, from, savedPosition) {
 | 
					  scrollBehavior(to, from, savedPosition) {
 | 
				
			||||||
    return new Promise(resolve => {
 | 
					    return new Promise(resolve => {
 | 
				
			||||||
      if (savedPosition) {
 | 
					      if (savedPosition) {
 | 
				
			||||||
@ -156,96 +41,10 @@ export const router: Router = createRouter({
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 初始化路由
 | 
					 | 
				
			||||||
export const initRouter = name => {
 | 
					 | 
				
			||||||
  return new Promise(resolve => {
 | 
					 | 
				
			||||||
    getAsyncRoutes({ name }).then(({ info }) => {
 | 
					 | 
				
			||||||
      if (info.length === 0) {
 | 
					 | 
				
			||||||
        usePermissionStoreHook().changeSetting(info);
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        addAsyncRoutes(info).map((v: any) => {
 | 
					 | 
				
			||||||
          // 防止重复添加路由
 | 
					 | 
				
			||||||
          if (
 | 
					 | 
				
			||||||
            router.options.routes.findIndex(value => value.path === v.path) !==
 | 
					 | 
				
			||||||
            -1
 | 
					 | 
				
			||||||
          ) {
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            // 切记将路由push到routes后还需要使用addRoute,这样路由才能正常跳转
 | 
					 | 
				
			||||||
            router.options.routes.push(v);
 | 
					 | 
				
			||||||
            // 最终路由进行升序
 | 
					 | 
				
			||||||
            ascending(router.options.routes);
 | 
					 | 
				
			||||||
            router.addRoute(v.name, v);
 | 
					 | 
				
			||||||
            usePermissionStoreHook().changeSetting(info);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          resolve(router);
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      router.addRoute({
 | 
					 | 
				
			||||||
        path: "/:pathMatch(.*)",
 | 
					 | 
				
			||||||
        redirect: "/error/404"
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 重置路由
 | 
					 | 
				
			||||||
export function resetRouter() {
 | 
					 | 
				
			||||||
  router.getRoutes().forEach(route => {
 | 
					 | 
				
			||||||
    const { name } = route;
 | 
					 | 
				
			||||||
    if (name) {
 | 
					 | 
				
			||||||
      router.hasRoute(name) && router.removeRoute(name);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function findRouteByPath(path, routes) {
 | 
					 | 
				
			||||||
  let res = routes.find(item => item.path == path);
 | 
					 | 
				
			||||||
  if (res) {
 | 
					 | 
				
			||||||
    return res;
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    for (let i = 0; i < routes.length; i++) {
 | 
					 | 
				
			||||||
      if (
 | 
					 | 
				
			||||||
        routes[i].children instanceof Array &&
 | 
					 | 
				
			||||||
        routes[i].children.length > 0
 | 
					 | 
				
			||||||
      ) {
 | 
					 | 
				
			||||||
        res = findRouteByPath(path, routes[i].children);
 | 
					 | 
				
			||||||
        if (res) {
 | 
					 | 
				
			||||||
          return res;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return null;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function getParentPaths(path, routes) {
 | 
					 | 
				
			||||||
  // 深度遍历查找
 | 
					 | 
				
			||||||
  function dfs(routes, path, parents) {
 | 
					 | 
				
			||||||
    for (let i = 0; i < routes.length; i++) {
 | 
					 | 
				
			||||||
      const item = routes[i];
 | 
					 | 
				
			||||||
      // 找到path则返回父级path
 | 
					 | 
				
			||||||
      if (item.path === path) return parents;
 | 
					 | 
				
			||||||
      // children不存在或为空则不递归
 | 
					 | 
				
			||||||
      if (!item.children || !item.children.length) continue;
 | 
					 | 
				
			||||||
      // 往下查找时将当前path入栈
 | 
					 | 
				
			||||||
      parents.push(item.path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (dfs(item.children, path, parents).length) return parents;
 | 
					 | 
				
			||||||
      // 深度遍历查找未找到时当前path 出栈
 | 
					 | 
				
			||||||
      parents.pop();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // 未找到时返回空数组
 | 
					 | 
				
			||||||
    return [];
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return dfs(routes, path, []);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 路由白名单
 | 
					// 路由白名单
 | 
				
			||||||
const whiteList = ["/login"];
 | 
					const whiteList = ["/login"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router.beforeEach((to, _from, next) => {
 | 
					router.beforeEach((to: toRouteType, _from, next) => {
 | 
				
			||||||
  if (to.meta?.keepAlive) {
 | 
					  if (to.meta?.keepAlive) {
 | 
				
			||||||
    const newMatched = to.matched;
 | 
					    const newMatched = to.matched;
 | 
				
			||||||
    handleAliveRoute(newMatched, "add");
 | 
					    handleAliveRoute(newMatched, "add");
 | 
				
			||||||
@ -277,7 +76,7 @@ router.beforeEach((to, _from, next) => {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // 刷新
 | 
					      // 刷新
 | 
				
			||||||
      if (usePermissionStoreHook().wholeRoutes.length === 0)
 | 
					      if (usePermissionStoreHook().wholeMenus.length === 0)
 | 
				
			||||||
        initRouter(name.username).then((router: Router) => {
 | 
					        initRouter(name.username).then((router: Router) => {
 | 
				
			||||||
          if (!useMultiTagsStoreHook().getMultiTagsCache) {
 | 
					          if (!useMultiTagsStoreHook().getMultiTagsCache) {
 | 
				
			||||||
            const handTag = (
 | 
					            const handTag = (
 | 
				
			||||||
@ -293,14 +92,27 @@ router.beforeEach((to, _from, next) => {
 | 
				
			|||||||
                meta
 | 
					                meta
 | 
				
			||||||
              });
 | 
					              });
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            const parentPath = to.matched[0]?.path;
 | 
					            // 未开启标签页缓存,刷新页面重定向到顶级路由(参考标签页操作例子)
 | 
				
			||||||
            if (to.meta?.realPath) {
 | 
					            if (to.meta?.realPath) {
 | 
				
			||||||
              const { path, name, meta } = to.matched[0]?.children[0];
 | 
					              const routes = router.options.routes;
 | 
				
			||||||
              handTag(path, parentPath, name, meta);
 | 
					              const { refreshRedirect } = to.meta;
 | 
				
			||||||
              return router.push(path);
 | 
					              const { name, meta } = findRouteByPath(refreshRedirect, routes);
 | 
				
			||||||
 | 
					              handTag(
 | 
				
			||||||
 | 
					                refreshRedirect,
 | 
				
			||||||
 | 
					                getParentPaths(refreshRedirect, routes)[1],
 | 
				
			||||||
 | 
					                name,
 | 
				
			||||||
 | 
					                meta
 | 
				
			||||||
 | 
					              );
 | 
				
			||||||
 | 
					              return router.push(refreshRedirect);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              const { path } = to;
 | 
					              const { path } = to;
 | 
				
			||||||
              const routes = router.options.routes;
 | 
					              const index = remainingRouter.findIndex(v => {
 | 
				
			||||||
 | 
					                return v.path == path;
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					              const routes =
 | 
				
			||||||
 | 
					                index === -1
 | 
				
			||||||
 | 
					                  ? router.options.routes[0].children
 | 
				
			||||||
 | 
					                  : router.options.routes;
 | 
				
			||||||
              const route = findRouteByPath(path, routes);
 | 
					              const route = findRouteByPath(path, routes);
 | 
				
			||||||
              const routePartent = getParentPaths(path, routes);
 | 
					              const routePartent = getParentPaths(path, routes);
 | 
				
			||||||
              handTag(
 | 
					              handTag(
 | 
				
			||||||
@ -315,7 +127,7 @@ router.beforeEach((to, _from, next) => {
 | 
				
			|||||||
          router.push(to.path);
 | 
					          router.push(to.path);
 | 
				
			||||||
          // 刷新页面更新标签栏与页面路由匹配
 | 
					          // 刷新页面更新标签栏与页面路由匹配
 | 
				
			||||||
          const localRoutes = storageLocal.getItem("responsive-tags");
 | 
					          const localRoutes = storageLocal.getItem("responsive-tags");
 | 
				
			||||||
          const optionsRoutes = router.options?.routes;
 | 
					          const optionsRoutes = router.options?.routes[0].children;
 | 
				
			||||||
          const newLocalRoutes = [];
 | 
					          const newLocalRoutes = [];
 | 
				
			||||||
          optionsRoutes.forEach(ors => {
 | 
					          optionsRoutes.forEach(ors => {
 | 
				
			||||||
            localRoutes.forEach(lrs => {
 | 
					            localRoutes.forEach(lrs => {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										39
									
								
								src/router/modules/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/router/modules/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					// 静态路由
 | 
				
			||||||
 | 
					import tabsRouter from "./tabs";
 | 
				
			||||||
 | 
					import homeRouter from "./home";
 | 
				
			||||||
 | 
					import errorRouter from "./error";
 | 
				
			||||||
 | 
					import editorRouter from "./editor";
 | 
				
			||||||
 | 
					import nestedRouter from "./nested";
 | 
				
			||||||
 | 
					import externalLink from "./externalLink";
 | 
				
			||||||
 | 
					import flowChartRouter from "./flowchart";
 | 
				
			||||||
 | 
					import remainingRouter from "./remaining";
 | 
				
			||||||
 | 
					import componentsRouter from "./components";
 | 
				
			||||||
 | 
					import { RouteRecordRaw, RouteComponent } from "vue-router";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  ascending,
 | 
				
			||||||
 | 
					  formatTwoStageRoutes,
 | 
				
			||||||
 | 
					  formatFlatteningRoutes
 | 
				
			||||||
 | 
					} from "../utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 原始静态路由(未做任何处理)
 | 
				
			||||||
 | 
					const routes = [
 | 
				
			||||||
 | 
					  tabsRouter,
 | 
				
			||||||
 | 
					  homeRouter,
 | 
				
			||||||
 | 
					  errorRouter,
 | 
				
			||||||
 | 
					  nestedRouter,
 | 
				
			||||||
 | 
					  externalLink,
 | 
				
			||||||
 | 
					  editorRouter,
 | 
				
			||||||
 | 
					  flowChartRouter,
 | 
				
			||||||
 | 
					  componentsRouter
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 导出处理后的静态路由(三级及以上的路由全部拍成二级)
 | 
				
			||||||
 | 
					export const constantRoutes: Array<RouteRecordRaw> = formatTwoStageRoutes(
 | 
				
			||||||
 | 
					  formatFlatteningRoutes(ascending(routes))
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 用于渲染菜单,保持原始层级
 | 
				
			||||||
 | 
					export const constantMenus: Array<RouteComponent> = ascending(routes).concat(
 | 
				
			||||||
 | 
					  ...remainingRouter
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
@ -15,7 +15,7 @@ const nestedRouter = {
 | 
				
			|||||||
  children: [
 | 
					  children: [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      path: "/nested/menu1",
 | 
					      path: "/nested/menu1",
 | 
				
			||||||
      component: () => import("/@/views/nested/menu1/index.vue"),
 | 
					      component: () => import("/@/layout/routerView/parent.vue"),
 | 
				
			||||||
      name: "Menu1",
 | 
					      name: "Menu1",
 | 
				
			||||||
      meta: {
 | 
					      meta: {
 | 
				
			||||||
        title: "message.hsmenu1",
 | 
					        title: "message.hsmenu1",
 | 
				
			||||||
@ -38,7 +38,7 @@ const nestedRouter = {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          path: "/nested/menu1/menu1-2",
 | 
					          path: "/nested/menu1/menu1-2",
 | 
				
			||||||
          component: () => import("/@/views/nested/menu1/menu1-2/index.vue"),
 | 
					          component: () => import("/@/layout/routerView/parent.vue"),
 | 
				
			||||||
          name: "Menu1-2",
 | 
					          name: "Menu1-2",
 | 
				
			||||||
          redirect: "/nested/menu1/menu1-2/menu1-2-1",
 | 
					          redirect: "/nested/menu1/menu1-2/menu1-2-1",
 | 
				
			||||||
          meta: {
 | 
					          meta: {
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@ const tabsRouter = {
 | 
				
			|||||||
  path: "/tabs",
 | 
					  path: "/tabs",
 | 
				
			||||||
  name: "reTabs",
 | 
					  name: "reTabs",
 | 
				
			||||||
  component: Layout,
 | 
					  component: Layout,
 | 
				
			||||||
  redirect: "/tags/index",
 | 
					  redirect: "/tabs/index",
 | 
				
			||||||
  meta: {
 | 
					  meta: {
 | 
				
			||||||
    icon: "IF-team-icontabs",
 | 
					    icon: "IF-team-icontabs",
 | 
				
			||||||
    title: "message.hstabs",
 | 
					    title: "message.hstabs",
 | 
				
			||||||
@ -32,7 +32,8 @@ const tabsRouter = {
 | 
				
			|||||||
        showLink: false,
 | 
					        showLink: false,
 | 
				
			||||||
        i18n: false,
 | 
					        i18n: false,
 | 
				
			||||||
        dynamicLevel: 3,
 | 
					        dynamicLevel: 3,
 | 
				
			||||||
        realPath: "/tabs/detail"
 | 
					        realPath: "/tabs/detail",
 | 
				
			||||||
 | 
					        refreshRedirect: "/tabs/index"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										9
									
								
								src/router/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/router/types.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import { RouteLocationNormalized } from "vue-router";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface toRouteType extends RouteLocationNormalized {
 | 
				
			||||||
 | 
					  meta: {
 | 
				
			||||||
 | 
					    keepAlive: boolean;
 | 
				
			||||||
 | 
					    refreshRedirect: string;
 | 
				
			||||||
 | 
					    realPath: string;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										236
									
								
								src/router/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								src/router/utils.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,236 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					  RouteRecordRaw,
 | 
				
			||||||
 | 
					  RouteComponent,
 | 
				
			||||||
 | 
					  RouteRecordNormalized
 | 
				
			||||||
 | 
					} from "vue-router";
 | 
				
			||||||
 | 
					import { router } from "./index";
 | 
				
			||||||
 | 
					import Layout from "/@/layout/index.vue";
 | 
				
			||||||
 | 
					import { useTimeoutFn } from "@vueuse/core";
 | 
				
			||||||
 | 
					import { RouteConfigs } from "/@/layout/types";
 | 
				
			||||||
 | 
					import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
				
			||||||
 | 
					// https://cn.vitejs.dev/guide/features.html#glob-import
 | 
				
			||||||
 | 
					const modulesRoutes = import.meta.glob("/src/views/*/*/*.vue");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 动态路由
 | 
				
			||||||
 | 
					import { getAsyncRoutes } from "/@/api/routes";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 按照路由中meta下的rank等级升序来排序路由
 | 
				
			||||||
 | 
					const ascending = (arr: any[]) => {
 | 
				
			||||||
 | 
					  return arr.sort(
 | 
				
			||||||
 | 
					    (a: { meta: { rank: number } }, b: { meta: { rank: number } }) => {
 | 
				
			||||||
 | 
					      return a?.meta?.rank - b?.meta?.rank;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 过滤meta中showLink为false的路由
 | 
				
			||||||
 | 
					const filterTree = (data: RouteComponent[]) => {
 | 
				
			||||||
 | 
					  const newTree = data.filter(
 | 
				
			||||||
 | 
					    (v: { meta: { showLink: boolean } }) => v.meta.showLink
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  newTree.forEach(
 | 
				
			||||||
 | 
					    (v: { children }) => v.children && (v.children = filterTree(v.children))
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  return newTree;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 批量删除缓存路由(keepalive)
 | 
				
			||||||
 | 
					const delAliveRoutes = (delAliveRouteList: Array<RouteConfigs>) => {
 | 
				
			||||||
 | 
					  delAliveRouteList.forEach(route => {
 | 
				
			||||||
 | 
					    usePermissionStoreHook().cacheOperate({
 | 
				
			||||||
 | 
					      mode: "delete",
 | 
				
			||||||
 | 
					      name: route?.name
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 通过path获取父级路径
 | 
				
			||||||
 | 
					const getParentPaths = (path: string, routes: RouteRecordRaw[]) => {
 | 
				
			||||||
 | 
					  // 深度遍历查找
 | 
				
			||||||
 | 
					  function dfs(routes: RouteRecordRaw[], path: string, parents: string[]) {
 | 
				
			||||||
 | 
					    for (let i = 0; i < routes.length; i++) {
 | 
				
			||||||
 | 
					      const item = routes[i];
 | 
				
			||||||
 | 
					      // 找到path则返回父级path
 | 
				
			||||||
 | 
					      if (item.path === path) return parents;
 | 
				
			||||||
 | 
					      // children不存在或为空则不递归
 | 
				
			||||||
 | 
					      if (!item.children || !item.children.length) continue;
 | 
				
			||||||
 | 
					      // 往下查找时将当前path入栈
 | 
				
			||||||
 | 
					      parents.push(item.path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (dfs(item.children, path, parents).length) return parents;
 | 
				
			||||||
 | 
					      // 深度遍历查找未找到时当前path 出栈
 | 
				
			||||||
 | 
					      parents.pop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 未找到时返回空数组
 | 
				
			||||||
 | 
					    return [];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return dfs(routes, path, []);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 查找对应path的路由信息
 | 
				
			||||||
 | 
					const findRouteByPath = (path: string, routes: RouteRecordRaw[]) => {
 | 
				
			||||||
 | 
					  let res = routes.find((item: { path: string }) => item.path == path);
 | 
				
			||||||
 | 
					  if (res) {
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    for (let i = 0; i < routes.length; i++) {
 | 
				
			||||||
 | 
					      if (
 | 
				
			||||||
 | 
					        routes[i].children instanceof Array &&
 | 
				
			||||||
 | 
					        routes[i].children.length > 0
 | 
				
			||||||
 | 
					      ) {
 | 
				
			||||||
 | 
					        res = findRouteByPath(path, routes[i].children);
 | 
				
			||||||
 | 
					        if (res) {
 | 
				
			||||||
 | 
					          return res;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 重置路由
 | 
				
			||||||
 | 
					const resetRouter = (): void => {
 | 
				
			||||||
 | 
					  router.getRoutes().forEach(route => {
 | 
				
			||||||
 | 
					    const { name } = route;
 | 
				
			||||||
 | 
					    if (name) {
 | 
				
			||||||
 | 
					      router.hasRoute(name) && router.removeRoute(name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 初始化路由
 | 
				
			||||||
 | 
					const initRouter = (name: string) => {
 | 
				
			||||||
 | 
					  return new Promise(resolve => {
 | 
				
			||||||
 | 
					    getAsyncRoutes({ name }).then(({ info }) => {
 | 
				
			||||||
 | 
					      if (info.length === 0) {
 | 
				
			||||||
 | 
					        usePermissionStoreHook().changeSetting(info);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        formatFlatteningRoutes(addAsyncRoutes(info)).map(
 | 
				
			||||||
 | 
					          (v: RouteRecordRaw) => {
 | 
				
			||||||
 | 
					            // 防止重复添加路由
 | 
				
			||||||
 | 
					            if (
 | 
				
			||||||
 | 
					              router.options.routes[0].children.findIndex(
 | 
				
			||||||
 | 
					                value => value.path === v.path
 | 
				
			||||||
 | 
					              ) !== -1
 | 
				
			||||||
 | 
					            ) {
 | 
				
			||||||
 | 
					              return;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              // 切记将路由push到routes后还需要使用addRoute,这样路由才能正常跳转
 | 
				
			||||||
 | 
					              router.options.routes[0].children.push(v);
 | 
				
			||||||
 | 
					              // 最终路由进行升序
 | 
				
			||||||
 | 
					              ascending(router.options.routes[0].children);
 | 
				
			||||||
 | 
					              router.addRoute("home", v);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            resolve(router);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        usePermissionStoreHook().changeSetting(info);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      router.addRoute({
 | 
				
			||||||
 | 
					        path: "/:pathMatch(.*)",
 | 
				
			||||||
 | 
					        redirect: "/error/404"
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 将多级嵌套路由处理成一维数组
 | 
				
			||||||
 | 
					 * @param routesList 传入路由
 | 
				
			||||||
 | 
					 * @returns 返回处理后的一维路由
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const formatFlatteningRoutes = (routesList: RouteRecordRaw[]) => {
 | 
				
			||||||
 | 
					  if (routesList.length <= 0) return routesList;
 | 
				
			||||||
 | 
					  for (let i = 0; i < routesList.length; i++) {
 | 
				
			||||||
 | 
					    if (routesList[i].children) {
 | 
				
			||||||
 | 
					      routesList = routesList
 | 
				
			||||||
 | 
					        .slice(0, i + 1)
 | 
				
			||||||
 | 
					        .concat(routesList[i].children, routesList.slice(i + 1));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return routesList;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 一维数组处理成多级嵌套数组(三级及以上的路由全部拍成二级,keep-alive 只支持到二级缓存)
 | 
				
			||||||
 | 
					 * https://github.com/xiaoxian521/vue-pure-admin/issues/67
 | 
				
			||||||
 | 
					 * @param routesList 处理后的一维路由菜单数组
 | 
				
			||||||
 | 
					 * @returns 返回将一维数组重新处理成规定路由的格式
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const formatTwoStageRoutes = (routesList: RouteRecordRaw[]) => {
 | 
				
			||||||
 | 
					  if (routesList.length <= 0) return routesList;
 | 
				
			||||||
 | 
					  const newRoutesList: RouteRecordRaw[] = [];
 | 
				
			||||||
 | 
					  routesList.forEach((v: RouteRecordRaw) => {
 | 
				
			||||||
 | 
					    if (v.path === "/") {
 | 
				
			||||||
 | 
					      newRoutesList.push({
 | 
				
			||||||
 | 
					        component: v.component,
 | 
				
			||||||
 | 
					        name: v.name,
 | 
				
			||||||
 | 
					        path: v.path,
 | 
				
			||||||
 | 
					        redirect: v.redirect,
 | 
				
			||||||
 | 
					        meta: v.meta,
 | 
				
			||||||
 | 
					        children: []
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      newRoutesList[0].children.push({ ...v });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  return newRoutesList;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 处理缓存路由(添加、删除、刷新)
 | 
				
			||||||
 | 
					const handleAliveRoute = (matched: RouteRecordNormalized[], mode?: string) => {
 | 
				
			||||||
 | 
					  switch (mode) {
 | 
				
			||||||
 | 
					    case "add":
 | 
				
			||||||
 | 
					      matched.forEach(v => {
 | 
				
			||||||
 | 
					        usePermissionStoreHook().cacheOperate({ mode: "add", name: v.name });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case "delete":
 | 
				
			||||||
 | 
					      usePermissionStoreHook().cacheOperate({
 | 
				
			||||||
 | 
					        mode: "delete",
 | 
				
			||||||
 | 
					        name: matched[matched.length - 1].name
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      usePermissionStoreHook().cacheOperate({
 | 
				
			||||||
 | 
					        mode: "delete",
 | 
				
			||||||
 | 
					        name: matched[matched.length - 1].name
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      useTimeoutFn(() => {
 | 
				
			||||||
 | 
					        matched.forEach(v => {
 | 
				
			||||||
 | 
					          usePermissionStoreHook().cacheOperate({ mode: "add", name: v.name });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }, 100);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 过滤后端传来的动态路由 重新生成规范路由
 | 
				
			||||||
 | 
					const addAsyncRoutes = (arrRoutes: Array<RouteRecordRaw>) => {
 | 
				
			||||||
 | 
					  if (!arrRoutes || !arrRoutes.length) return;
 | 
				
			||||||
 | 
					  arrRoutes.forEach((v: RouteRecordRaw) => {
 | 
				
			||||||
 | 
					    if (v.redirect) {
 | 
				
			||||||
 | 
					      v.component = Layout;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      v.component = modulesRoutes[`/src/views${v.path}/index.vue`];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (v.children) {
 | 
				
			||||||
 | 
					      addAsyncRoutes(v.children);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  return arrRoutes;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export {
 | 
				
			||||||
 | 
					  ascending,
 | 
				
			||||||
 | 
					  filterTree,
 | 
				
			||||||
 | 
					  initRouter,
 | 
				
			||||||
 | 
					  resetRouter,
 | 
				
			||||||
 | 
					  addAsyncRoutes,
 | 
				
			||||||
 | 
					  delAliveRoutes,
 | 
				
			||||||
 | 
					  getParentPaths,
 | 
				
			||||||
 | 
					  findRouteByPath,
 | 
				
			||||||
 | 
					  handleAliveRoute,
 | 
				
			||||||
 | 
					  formatTwoStageRoutes,
 | 
				
			||||||
 | 
					  formatFlatteningRoutes
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,28 +1,32 @@
 | 
				
			|||||||
import { defineStore } from "pinia";
 | 
					import { defineStore } from "pinia";
 | 
				
			||||||
import { store } from "/@/store";
 | 
					import { store } from "/@/store";
 | 
				
			||||||
import { cacheType } from "./types";
 | 
					import { cacheType } from "./types";
 | 
				
			||||||
import { constantRoutesArr, ascending, filterTree } from "/@/router/index";
 | 
					import { RouteConfigs } from "/@/layout/types";
 | 
				
			||||||
 | 
					import { constantMenus } from "/@/router/modules";
 | 
				
			||||||
 | 
					import { ascending, filterTree } from "/@/router/utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const usePermissionStore = defineStore({
 | 
					export const usePermissionStore = defineStore({
 | 
				
			||||||
  id: "pure-permission",
 | 
					  id: "pure-permission",
 | 
				
			||||||
  state: () => ({
 | 
					  state: () => ({
 | 
				
			||||||
    // 静态路由
 | 
					    // 静态路由生成的菜单
 | 
				
			||||||
    constantRoutes: constantRoutesArr,
 | 
					    constantMenus,
 | 
				
			||||||
    wholeRoutes: [],
 | 
					    // 整体路由生成的菜单(静态、动态)
 | 
				
			||||||
 | 
					    wholeMenus: [],
 | 
				
			||||||
    buttonAuth: [],
 | 
					    buttonAuth: [],
 | 
				
			||||||
    // 缓存页面keepAlive
 | 
					    // 缓存页面keepAlive
 | 
				
			||||||
    cachePageList: []
 | 
					    cachePageList: []
 | 
				
			||||||
  }),
 | 
					  }),
 | 
				
			||||||
  actions: {
 | 
					  actions: {
 | 
				
			||||||
 | 
					    // 获取异步路由菜单
 | 
				
			||||||
    asyncActionRoutes(routes) {
 | 
					    asyncActionRoutes(routes) {
 | 
				
			||||||
      if (this.wholeRoutes.length > 0) return;
 | 
					      if (this.wholeMenus.length > 0) return;
 | 
				
			||||||
      this.wholeRoutes = filterTree(
 | 
					      this.wholeMenus = filterTree(
 | 
				
			||||||
        ascending(this.constantRoutes.concat(routes))
 | 
					        ascending(this.constantMenus.concat(routes))
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const getButtonAuth = (arrRoutes: Array<string>) => {
 | 
					      const getButtonAuth = (arrRoutes: Array<RouteConfigs>) => {
 | 
				
			||||||
        if (!arrRoutes || !arrRoutes.length) return;
 | 
					        if (!arrRoutes || !arrRoutes.length) return;
 | 
				
			||||||
        arrRoutes.forEach((v: any) => {
 | 
					        arrRoutes.forEach((v: RouteConfigs) => {
 | 
				
			||||||
          if (v.meta && v.meta.authority) {
 | 
					          if (v.meta && v.meta.authority) {
 | 
				
			||||||
            this.buttonAuth.push(...v.meta.authority);
 | 
					            this.buttonAuth.push(...v.meta.authority);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
@ -32,7 +36,7 @@ export const usePermissionStore = defineStore({
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      getButtonAuth(this.wholeRoutes);
 | 
					      getButtonAuth(this.wholeMenus);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    async changeSetting(routes) {
 | 
					    async changeSetting(routes) {
 | 
				
			||||||
      await this.asyncActionRoutes(routes);
 | 
					      await this.asyncActionRoutes(routes);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { ref, computed } from "vue";
 | 
					import { ref, computed } from "vue";
 | 
				
			||||||
import { useRouter } from "vue-router";
 | 
					import { useRouter } from "vue-router";
 | 
				
			||||||
import { initRouter } from "/@/router";
 | 
					import { initRouter } from "/@/router/utils";
 | 
				
			||||||
import { storageSession } from "/@/utils/storage";
 | 
					import { storageSession } from "/@/utils/storage";
 | 
				
			||||||
import { addClass, removeClass } from "/@/utils/operate";
 | 
					import { addClass, removeClass } from "/@/utils/operate";
 | 
				
			||||||
import bg from "/@/assets/login/bg.png";
 | 
					import bg from "/@/assets/login/bg.png";
 | 
				
			||||||
 | 
				
			|||||||
@ -1,35 +0,0 @@
 | 
				
			|||||||
<template>
 | 
					 | 
				
			||||||
  <div>
 | 
					 | 
				
			||||||
    <p>{{ $t("message.hsmenu1") }}</p>
 | 
					 | 
				
			||||||
    <router-view>
 | 
					 | 
				
			||||||
      <template #default="{ Component, route }">
 | 
					 | 
				
			||||||
        <transition appear name="fade-transform" mode="out-in">
 | 
					 | 
				
			||||||
          <keep-alive
 | 
					 | 
				
			||||||
            v-if="keepAlive"
 | 
					 | 
				
			||||||
            :include="usePermissionStoreHook().cachePageList"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <component :is="Component" :key="route.fullPath" />
 | 
					 | 
				
			||||||
          </keep-alive>
 | 
					 | 
				
			||||||
          <component v-else :is="Component" :key="route.fullPath" />
 | 
					 | 
				
			||||||
        </transition>
 | 
					 | 
				
			||||||
      </template>
 | 
					 | 
				
			||||||
    </router-view>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script lang="ts">
 | 
					 | 
				
			||||||
import { ref, getCurrentInstance } from "vue";
 | 
					 | 
				
			||||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
					 | 
				
			||||||
export default {
 | 
					 | 
				
			||||||
  name: "Menu1",
 | 
					 | 
				
			||||||
  setup() {
 | 
					 | 
				
			||||||
    const keepAlive: Boolean = ref(
 | 
					 | 
				
			||||||
      getCurrentInstance().appContext.config.globalProperties.$config?.KeepAlive
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      keepAlive,
 | 
					 | 
				
			||||||
      usePermissionStoreHook
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
@ -1,35 +0,0 @@
 | 
				
			|||||||
<template>
 | 
					 | 
				
			||||||
  <div>
 | 
					 | 
				
			||||||
    <p style="text-indent: 2em">{{ $t("message.hsmenu1-2") }}</p>
 | 
					 | 
				
			||||||
    <router-view>
 | 
					 | 
				
			||||||
      <template #default="{ Component, route }">
 | 
					 | 
				
			||||||
        <transition appear name="fade-transform" mode="out-in">
 | 
					 | 
				
			||||||
          <keep-alive
 | 
					 | 
				
			||||||
            v-if="keepAlive"
 | 
					 | 
				
			||||||
            :include="usePermissionStoreHook().cachePageList"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <component :is="Component" :key="route.fullPath" />
 | 
					 | 
				
			||||||
          </keep-alive>
 | 
					 | 
				
			||||||
          <component v-else :is="Component" :key="route.fullPath" />
 | 
					 | 
				
			||||||
        </transition>
 | 
					 | 
				
			||||||
      </template>
 | 
					 | 
				
			||||||
    </router-view>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script lang="ts">
 | 
					 | 
				
			||||||
import { ref, getCurrentInstance } from "vue";
 | 
					 | 
				
			||||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
					 | 
				
			||||||
export default {
 | 
					 | 
				
			||||||
  name: "Menu1-2",
 | 
					 | 
				
			||||||
  setup() {
 | 
					 | 
				
			||||||
    const keepAlive: Boolean = ref(
 | 
					 | 
				
			||||||
      getCurrentInstance().appContext.config.globalProperties.$config?.KeepAlive
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      keepAlive,
 | 
					 | 
				
			||||||
      usePermissionStoreHook
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								types/global.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								types/global.d.ts
									
									
									
									
										vendored
									
									
								
							@ -85,7 +85,6 @@ declare global {
 | 
				
			|||||||
    HideTabs?: boolean;
 | 
					    HideTabs?: boolean;
 | 
				
			||||||
    MapConfigure?: {
 | 
					    MapConfigure?: {
 | 
				
			||||||
      amapKey?: string;
 | 
					      amapKey?: string;
 | 
				
			||||||
      baiduKey?: string;
 | 
					 | 
				
			||||||
      options: {
 | 
					      options: {
 | 
				
			||||||
        resizeEnable?: boolean;
 | 
					        resizeEnable?: boolean;
 | 
				
			||||||
        center?: number[];
 | 
					        center?: number[];
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user