mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 23:40:24 +08:00
165 lines
6.0 KiB
TypeScript
165 lines
6.0 KiB
TypeScript
import 'nprogress/nprogress.css';
|
||
import { clearSession, getToken } from '@/common/utils/storage';
|
||
import openApi from '@/common/openApi';
|
||
import { useUserInfo } from '@/store/userInfo';
|
||
import { useRoutesList } from '@/store/routesList';
|
||
import { useKeepALiveNames } from '@/store/keepAliveNames';
|
||
import router from '.';
|
||
import { RouteRecordRaw } from 'vue-router';
|
||
import { LAYOUT_ROUTE_NAME } from './staticRouter';
|
||
|
||
/**
|
||
* 获取目录下的 .vue、.tsx 全部文件
|
||
* @method import.meta.glob
|
||
* @link 参考:https://cn.vitejs.dev/guide/features.html#json
|
||
*/
|
||
const viewsModules: Record<string, Function> = import.meta.glob(['../views/**/*.{vue,tsx}']);
|
||
const dynamicViewsModules: Record<string, Function> = Object.assign({}, { ...viewsModules });
|
||
|
||
// 后端控制路由:执行路由数据初始化
|
||
export async function initBackendRoutes() {
|
||
const token = getToken(); // 获取浏览器缓存 token 值
|
||
if (!token) {
|
||
// 无 token 停止执行下一步
|
||
return false;
|
||
}
|
||
useUserInfo().setUserInfo({});
|
||
// 获取路由
|
||
let menuRoute = await getBackEndControlRoutes();
|
||
|
||
const cacheList: Array<string> = [];
|
||
// 处理路由(component)
|
||
const routes = backEndRouterConverter(menuRoute, (router: any) => {
|
||
// 可能为false时不存在isKeepAlive属性
|
||
if (!router.meta.isKeepAlive) {
|
||
router.meta.isKeepAlive = false;
|
||
}
|
||
if (router.meta.isKeepAlive) {
|
||
cacheList.push(router.name);
|
||
}
|
||
});
|
||
|
||
routes.forEach((item: any) => {
|
||
if (item.meta.isFull) {
|
||
// 菜单为全屏展示 (示例:数据大屏页面等)
|
||
router.addRoute(item as RouteRecordRaw);
|
||
} else {
|
||
// 要将嵌套路由添加到现有的路由中,可以将路由的 name 作为第一个参数传递给 router.addRoute(),这将有效地添加路由,就像通过 children 添加的一样
|
||
router.addRoute(LAYOUT_ROUTE_NAME, item as RouteRecordRaw);
|
||
}
|
||
});
|
||
|
||
useKeepALiveNames().setCacheKeepAlive(cacheList);
|
||
useRoutesList().setRoutesList(routes);
|
||
}
|
||
|
||
// 后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
|
||
export async function getBackEndControlRoutes() {
|
||
try {
|
||
const menuAndPermission = await openApi.getPermissions();
|
||
// 赋值权限码,用于控制按钮等
|
||
useUserInfo().userInfo.permissions = menuAndPermission.permissions;
|
||
return menuAndPermission.menus;
|
||
} catch (e: any) {
|
||
console.error('获取菜单权限信息失败', e);
|
||
clearSession();
|
||
throw e;
|
||
}
|
||
}
|
||
|
||
type RouterConvCallbackFunc = (router: any) => void;
|
||
|
||
/**
|
||
* 后端控制路由,后端返回路由 转换为vue route
|
||
*
|
||
* @description routes参数配置简介
|
||
* @param code(path) ==> route.path -> 路由菜单访问路径
|
||
* @param name ==> title,路由标题 相当于route.meta.title
|
||
*
|
||
* @param meta ==> 路由菜单元信息
|
||
* @param meta.routeName ==> route.name -> 路由 name (对应页面组件 name, 可用作 KeepAlive 缓存标识 && 按钮权限筛选)
|
||
* @param meta.redirect ==> route.redirect -> 路由重定向地址
|
||
* @param meta.component ==> 文件路径
|
||
* @param meta.icon ==> 菜单和面包屑对应的图标
|
||
* @param meta.isHide ==> 是否在菜单中隐藏 (通常列表详情页需要隐藏)
|
||
* @param meta.isFull ==> 菜单是否全屏 (示例:数据大屏页面)
|
||
* @param meta.isAffix ==> 菜单是否固定在标签页中 (首页通常是固定项)
|
||
* @param meta.isKeepAlive ==> 当前路由是否缓存
|
||
* @param meta.linkType ==> 外链类型, 内嵌: 以iframe展示、外链: 新标签打开
|
||
* @param meta.link ==> 外链地址
|
||
* */
|
||
export function backEndRouterConverter(routes: any, callbackFunc: RouterConvCallbackFunc = null as any, parentPath: string = '/') {
|
||
if (!routes) {
|
||
return [];
|
||
}
|
||
|
||
const routeItems = [];
|
||
for (let item of routes) {
|
||
if (!item.meta) {
|
||
return item;
|
||
}
|
||
// 将json字符串的meta转为对象
|
||
item.meta = JSON.parse(item.meta);
|
||
|
||
// 将meta.comoponet 解析为route.component
|
||
if (item.meta.component) {
|
||
item.component = dynamicImport(dynamicViewsModules, item.meta.component);
|
||
delete item.meta['component'];
|
||
}
|
||
|
||
let path = item.code;
|
||
// 如果不是以 / 开头,则路径需要拼接父路径
|
||
if (!path.startsWith('/')) {
|
||
path = parentPath + '/' + path;
|
||
}
|
||
item.path = path;
|
||
delete item['code'];
|
||
|
||
// route.meta.title == resource.name
|
||
item.meta.title = item.name;
|
||
delete item['name'];
|
||
|
||
// route.name == resource.meta.routeName
|
||
item.name = item.meta.routeName;
|
||
delete item.meta['routeName'];
|
||
|
||
// route.redirect == resource.meta.redirect
|
||
if (item.meta.redirect) {
|
||
item.redirect = item.meta.redirect;
|
||
delete item.meta['redirect'];
|
||
}
|
||
// 存在回调,则执行回调
|
||
callbackFunc && callbackFunc(item);
|
||
item.children && backEndRouterConverter(item.children, callbackFunc, item.path);
|
||
routeItems.push(item);
|
||
}
|
||
|
||
return routeItems;
|
||
}
|
||
|
||
/**
|
||
* 后端路由 component 转换函数
|
||
* @param dynamicViewsModules 获取目录下的 .vue、.tsx 全部文件
|
||
* @param component 当前要处理项 component
|
||
* @returns 返回处理成函数后的 component
|
||
*/
|
||
export function dynamicImport(dynamicViewsModules: Record<string, Function>, component: string) {
|
||
const keys = Object.keys(dynamicViewsModules);
|
||
const matchKeys = keys.filter((key) => {
|
||
const k = key.replace(/..\/views|../, '');
|
||
return k.startsWith(`${component}`) || k.startsWith(`/${component}`);
|
||
});
|
||
|
||
if (matchKeys?.length === 1) {
|
||
return dynamicViewsModules[matchKeys[0]];
|
||
}
|
||
|
||
if (matchKeys?.length > 1) {
|
||
console.error('匹配到多个相似组件路径, 可添加后缀.vue或.tsx进行区分或者重命名组件名, 请调整...', matchKeys);
|
||
return null;
|
||
}
|
||
|
||
console.warn(`未匹配到[${component}]组件名对应的组件文件`);
|
||
return null;
|
||
}
|