import { treeToArray, addLeadingSlash } from "./tools"; export interface Module { key: string; text?: string; // topTag V1版本使用 name?: string; // topTag V2版本使用 } export interface Menu { icon: string; // 是否缓存 ignoreCache: 0 | 1; // 是否需要授权 isAuth: 0 | 1; // 是否隐藏 菜单 isHidden: 0 | 1; // 0: 不隐藏 1: 隐藏 name: string; id: number; pid?: number; productionShow: 0 | 1; serviceCode: string; status: 0 | 1; /** 接口返回的url,生成路由component使用,对应views文件夹下页面的地址 */ url: string; /** 路由地址,包括顶层模块 */ path: string; childs?: Menu[]; children?: Menu[]; // 搜索接口返回 // 属于哪个模块 module: string; routeName: string | symbol; key?: string; // 菜单搜索使用,全部置空,否则会报ts错误 disabled?: boolean; // 菜单搜索使用 tagName?: string; // 菜单搜索使用,顶部模块名称 code?: string; meta?: { title: string; icon: string; id: number; module: string; code?: string; isHidden?: 0 | 1; }; } export type ModulesMenus = Record; export interface Option { appName: string; appVersion: string; Empty: unknown; Layout: unknown; router: { addRoute: (val: unknown) => void; getRoutes: () => { path: string; redirect: string }[]; }; soa: { getResourceTreeByTopTag: ( a: string, b: string, c: string, d: string ) => { data: Menu[] }; }; getJSON: (url: string) => { id: string; data: Menu[] }; saveObjArr: (a: string, b: unknown[]) => void; _import: (url: string) => string; } let options: Option; const welcomeUrl = "/dashboard/dashboard/index"; const modulesMenus: ModulesMenus = {}; const modulesMenusArray: ModulesMenus[] = []; // 是否已生成路由 let hadGenRouter = false; /** * 菜单路径添加Module前缀 * @param list * @param module */ function urlAddModule(list: Menu[], module: string) { list?.forEach((item) => { // 添加模块,即顶部标签 item.module = module; item.url = addLeadingSlash(item.url); item.path = `/${module}${item.url}`; item.meta = { title: item.name, icon: item.icon ?? "el-icon-s-help", id: item.id, module, isHidden: item.isHidden, }; item.children = item.childs; if (Array.isArray(item.childs) && item.childs.length) { urlAddModule(item.childs, module); } }); } const handleMenuToRoute = (menus: Menu[]) => { const menuList = treeToArray(menus); const result = menuList.map((item) => { const [urlPath] = item.url.split("?"); const [path] = (item.path ?? item.url).split("?"); // 获取路由页面 const component = item.childs?.filter(el => !el.isHidden)?.length ? options.Empty : options._import(urlPath.replace("/", "")); return { path, name: item.routeName, component, meta: { title: item.name, id: item.id, module: item.module, code: item.code, }, children: [], }; }); return result; }; const route = (currentModule: string, menus: Menu[], item: Menu) => ({ path: "/" + currentModule, meta: { title: item.name, icon: item.icon, module: currentModule, }, component: options.Layout, children: handleMenuToRoute(menus), redirect: findFirstChild(item.childs![0]).path, }); /** * 动态生成路由 */ function generatorDynamicRouter({ currentModule, menus, item, }: { currentModule: string; menus: Menu[]; item: Menu; }) { try { const routers = route(currentModule, menus, item); options.router.addRoute(routers); return routers; } catch (error) { console.error("生成路由时出错", error); } } /** * 找到第一个有权限的未隐藏的菜单 * @param menu * @returns */ const findFirstChild = (menu: Menu): Menu => { if (menu?.childs?.length) { const menus = menu.childs.filter((item) => item.isHidden === 0); if (menus.length) { return findFirstChild(menus[0]); } } return menu; }; /** * 重定向到第一个有权限的菜单页面 * @param menus */ const redirectToFirstHasAuthRouter = (menus: Menu[]) => { const routers = options.router.getRoutes(); const indexRouter = routers.find((item) => item.path === welcomeUrl); if (indexRouter) { const first = findFirstChild(menus[0]); indexRouter.redirect = first?.path === welcomeUrl ? '' : first?.path; // 如果重定向到首页,则设置为'' } }; /** * 生成新权限路由 * @param option */ export async function genRoutersInNewAuth(option: Option) { options = option; const { appName, appVersion, soa, getJSON, saveObjArr } = options; const user = getJSON("user"); const resp = await soa.getResourceTreeByTopTag( user.id, appName, "0", "dashboard" ); const menus: Menu[] = resp.data; const modules: Module[] = []; if (menus.length > 0) { menus.forEach((item) => { // 需要设置不隐藏和有子路由才:显示module、添加动态路由等操作 const childs = item.childs?.filter(el => !el.isHidden) if (!item.isHidden && childs?.length) { const module = item.url.replace("/", ""); urlAddModule(childs, module); const routers = generatorDynamicRouter({ currentModule: module, menus: childs, item, }) as unknown as ModulesMenus; modulesMenus[module] = childs; saveObjArr( "child-router:" + appVersion + ":" + module + ":" + user.id, childs ); modulesMenusArray.push(routers); modules.push({ name: item.name, key: module }); } }); } redirectToFirstHasAuthRouter(menus); saveObjArr("modules:" + appVersion, modules); saveObjArr("router:" + appVersion, modulesMenusArray); hadGenRouter = true; } export const hasSubmenu = (menuInfo: Menu) => { // 有子菜单,需要同时满足以下条件 // 1. 有childs // 2. childs,中的isHidden有一个为0 return menuInfo.childs?.some(item => item.isHidden === 0) } /** 系统是否接入的是新权限体系 */ export const checkNewAuth = (newAppName: string, oldAppName: string) => { if (!newAppName || !oldAppName) { // 未传入参数时,直接返回true return true; } return newAppName === oldAppName; } /** 是否已生成路由 */ export const checkHadGenRouter = () => hadGenRouter;