123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- import { adminMenus } from '@/api/system/menu';
- import { constantRouterIcon } from './router-icons';
- import { RouteRecordRaw } from 'vue-router';
- import { Layout, ParentLayout } from '@/router/constant';
- import type { AppRouteRecordRaw } from '@/router/types';
- const Iframe = () => import('@/views/iframe/index.vue');
- const LayoutMap = new Map<string, () => Promise<typeof import('*.vue')>>();
- LayoutMap.set('LAYOUT', Layout);
- LayoutMap.set('IFRAME', Iframe);
- /**
- * 格式化 后端 结构信息并递归生成层级路由表
- * @param routerMap
- * @param parent
- * @returns {*}
- */
- export const routerGenerator = (routerMap, parent?): any[] => {
- return routerMap.map((item) => {
- const currentRouter: any = {
- // 路由地址 动态拼接生成如 /dashboard/workplace
- path: `${(parent && parent.path) || ''}/${item.path}`,
- // 路由名称,建议唯一
- name: item.name || '',
- // 该路由对应页面的 组件
- component: item.component,
- // meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
- meta: {
- ...item.meta,
- label: item.meta.title,
- icon: constantRouterIcon[item.meta.icon] || null,
- permissions: item.meta.permissions || null,
- },
- };
- // 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
- currentRouter.path = currentRouter.path.replace('//', '/');
- // 重定向
- item.redirect && (currentRouter.redirect = item.redirect);
- // 是否有子菜单,并递归处理
- if (item.children && item.children.length > 0) {
- //如果未定义 redirect 默认第一个子路由为 redirect
- !item.redirect && (currentRouter.redirect = `${item.path}/${item.children[0].path}`);
- // Recursion
- currentRouter.children = routerGenerator(item.children, currentRouter);
- }
- return currentRouter;
- });
- };
- /**
- * 动态生成菜单
- * @returns {Promise<Router>}
- */
- export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
- return new Promise((resolve, reject) => {
- adminMenus()
- .then((result) => {
- const routeList = routerGenerator(result);
- asyncImportRoute(routeList);
- resolve(routeList);
- })
- .catch((err) => {
- reject(err);
- });
- });
- };
- /**
- * 查找views中对应的组件文件
- * */
- let viewsModules: Record<string, () => Promise<Recordable>>;
- export const asyncImportRoute = (routes: AppRouteRecordRaw[] | undefined): void => {
- viewsModules = viewsModules || import.meta.glob('../views/**/*.{vue,tsx}');
- if (!routes) return;
- routes.forEach((item) => {
- if (!item.component && item.meta?.frameSrc) {
- item.component = 'IFRAME';
- }
- const { component, name } = item;
- const { children } = item;
- if (component) {
- const layoutFound = LayoutMap.get(component as string);
- if (layoutFound) {
- item.component = layoutFound;
- } else {
- item.component = dynamicImport(viewsModules, component as string);
- }
- } else if (name) {
- item.component = ParentLayout;
- }
- children && asyncImportRoute(children);
- });
- };
- /**
- * 动态导入
- * */
- export const dynamicImport = (
- viewsModules: Record<string, () => Promise<Recordable>>,
- component: string
- ) => {
- const keys = Object.keys(viewsModules);
- const matchKeys = keys.filter((key) => {
- let k = key.replace('../views', '');
- const lastIndex = k.lastIndexOf('.');
- k = k.substring(0, lastIndex);
- return k === component;
- });
- if (matchKeys?.length === 1) {
- const matchKey = matchKeys[0];
- return viewsModules[matchKey];
- }
- if (matchKeys?.length > 1) {
- console.warn(
- 'Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure'
- );
- return;
- }
- };
|