177 lines
5.6 KiB
Plaintext
177 lines
5.6 KiB
Plaintext
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';
|
|
import { ProfileOutlined } from '@ant-design/icons-vue';
|
|
import { renderIcon } from '@/utils/index';
|
|
|
|
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): any[] => {
|
|
return routerMap.map((item) => {
|
|
const names = /http(s)?:/.test(item.component)?item.component:item.path.replaceAll('/','')
|
|
item.meta = {
|
|
title:item.parentId==0 && item.children.length==0?'':item.name,
|
|
icon:constantRouterIcon[item.icon2]|| null,
|
|
sort:item.sort,
|
|
permissions:item.permission,
|
|
hidden: item.hide?true:false,
|
|
isRoot:item.parentId==0 && item.children.length==0?true:false,
|
|
alwaysShow: item.parentId==0 && item.children.length==0?true:false,
|
|
frameSrc: item.target==1?item.component:'',
|
|
target:item.target==2?true:false
|
|
}
|
|
let components = ''
|
|
if(item.parentId==0 && (item.children.length==0 || item.children.length>0) ) {
|
|
components ='LAYOUT'
|
|
} else if(item.target==0) {
|
|
components = item.component
|
|
} else if(item.target==1) {
|
|
components ='IFRAME'
|
|
}
|
|
const currentRouter: any = {
|
|
path:item.target==2?'':item.path,
|
|
// 路由名称,建议唯一
|
|
name: names,
|
|
// 该路由对应页面的 组件
|
|
component: components,
|
|
// meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
|
|
meta: {
|
|
...item.meta,
|
|
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.children[0].path}`);
|
|
// Recursion
|
|
currentRouter.children = routerGenerator(item.children, currentRouter);
|
|
} else {
|
|
if(item.parentId==0 && item.children.length==0) {
|
|
currentRouter.children =[]
|
|
if(item.target==1 && (/http(s)?:/.test(item.component))){
|
|
currentRouter.children.push({
|
|
path: item.path,
|
|
name: names,
|
|
meta: {
|
|
title: item.name,
|
|
frameSrc: item.component,
|
|
icon:constantRouterIcon[item.icon2],
|
|
hidden: item.hide?true:false,
|
|
},
|
|
component: 'IFRAME',
|
|
})
|
|
} else {
|
|
currentRouter.children.push({
|
|
path: item.path,
|
|
name: names,
|
|
meta: {
|
|
title: item.name,
|
|
icon:constantRouterIcon[item.icon2],
|
|
activeMenu: names,
|
|
target:item.target==2?true:false,
|
|
hidden: item.hide?true:false,
|
|
},
|
|
component: item.component,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
};
|
|
/**
|
|
* 查找第一个路由
|
|
* */
|
|
export const findFirstRoutePath = (routes)=>{
|
|
return routes.length > 0?(routes[0].redirect?routes[0].redirect:routes[0].path):''
|
|
}
|