import type { RouteRecordRaw } from 'vue-router' import { adminMenus } from '@/api/system/menu' import { Layout, ParentLayout } from '@/router/constant' import type { AppRouteRecordRaw } from '@/router/types' const LayoutMap = new Map Promise>() LayoutMap.set('LAYOUT', Layout) /** * 格式化 后端 结构信息并递归生成层级路由表 * @param routerMap * @param parent * @returns {*} */ export function generateRoutes(routerMap, parent?): any[] { return routerMap.map((item) => { const currentRoute: any = { // 路由地址 动态拼接生成如 /dashboard/workplace path: `${(parent && parent.path) ?? ''}/${item.path}`, // 路由名称,建议唯一 name: item.name ?? '', // 该路由对应页面的 组件 component: item.component, // meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉) meta: { ...item.meta, label: item.meta.title, // TODO add icon // icon: constantRouterIcon[item.meta.icon] || null, icon: null, permissions: item.meta.permissions || null, }, } // 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠 currentRoute.path = currentRoute.path.replace('//', '/') // 重定向 item.redirect && (currentRoute.redirect = item.redirect) // 是否有子菜单,并递归处理 if (item.children && item.children.length > 0) { // 如果未定义 redirect 默认第一个子路由为 redirect !item.redirect && (currentRoute.redirect = `${item.path}/${item.children[0].path}`) // Recursion currentRoute.children = generateRoutes(item.children, currentRoute) } return currentRoute }) } /** * 动态生成菜单 * @returns {Promise} */ export async function generateDynamicRoutes(): Promise { const result = await adminMenus() const router = generateRoutes(result) asyncImportRoute(router) return router } /** * 查找views中对应的组件文件 */ let viewsModules: Record Promise> export function 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 function dynamicImport(viewsModules: Record Promise>, 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', ) } }