237 lines
6.4 KiB
TypeScript
237 lines
6.4 KiB
TypeScript
import { defineStore } from 'pinia';
|
|
import type {
|
|
RouteComponent,
|
|
RouteLocationRaw,
|
|
RouteMeta,
|
|
RouteRecord,
|
|
RouteRecordRaw,
|
|
} from 'vue-router';
|
|
import { getRouter } from '@/api/auth';
|
|
import BasicLayout from '@/layouts/BasicLayout.vue';
|
|
import BlankLayout from '@/layouts/BlankLayout.vue';
|
|
import LinkLayout from '@/layouts/LinkLayout.vue';
|
|
import {
|
|
MENU_COMPONENT_LAYOUT_BASIC,
|
|
MENU_COMPONENT_LAYOUT_BLANK,
|
|
MENU_COMPONENT_LAYOUT_LINK,
|
|
} from '@/constants/menu-constants';
|
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
|
import useAppStore from '@/store/modules/app';
|
|
import {
|
|
APP_SERVER_TYPE_M,
|
|
APP_SERVER_TYPE_O,
|
|
} from '@/constants/app-constants';
|
|
|
|
/**路由构建参数类型 */
|
|
type RouterStore = {
|
|
/**初始的根路由数据 */
|
|
rootRouterData: RouteRecordRaw[];
|
|
/**动态路由数据 */
|
|
buildRouterData: RouteRecordRaw[];
|
|
};
|
|
|
|
const useRouterStore = defineStore('router', {
|
|
state: (): RouterStore => ({
|
|
rootRouterData: [],
|
|
buildRouterData: [],
|
|
}),
|
|
actions: {
|
|
/**
|
|
* 记录初始根节点菜单数据
|
|
* @param data 初始数据
|
|
* @returns 初始数据
|
|
*/
|
|
setRootRouterData(data: RouteRecordRaw[]) {
|
|
if (this.rootRouterData.length <= 0) {
|
|
this.rootRouterData = data;
|
|
}
|
|
return this.rootRouterData;
|
|
},
|
|
/**
|
|
* 动态路由列表数据生成
|
|
* @returns 生成的路由菜单
|
|
*/
|
|
async generateRoutes() {
|
|
const res = await getRouter();
|
|
if (res.code === RESULT_CODE_SUCCESS) {
|
|
const buildRoutes = buildRouters(res.data.concat());
|
|
this.buildRouterData = buildRoutes;
|
|
return buildRoutes;
|
|
}
|
|
return [];
|
|
},
|
|
/**
|
|
* 根据网元类型过滤菜单
|
|
* @param routes 经过clearMenuItem(router.getRoutes())处理
|
|
* @param coreUid 核心网元uid
|
|
* @param neTypes 网元类型
|
|
* @returns 过滤后的菜单
|
|
*/
|
|
clearMenuItemByNeList(
|
|
routes: RouteRecord[] | RouteRecordRaw[],
|
|
coreUid: string,
|
|
neTypes: string[]
|
|
): RouteRecordRaw[] {
|
|
return routes
|
|
.map((item: RouteRecord | RouteRecordRaw) => {
|
|
const finalItem = { ...item };
|
|
|
|
// 过滤核心网菜单
|
|
switch (useAppStore().serverType) {
|
|
case APP_SERVER_TYPE_O:
|
|
break;
|
|
case APP_SERVER_TYPE_M:
|
|
// 过滤核心网菜单
|
|
if (coreUid.length < 8 && finalItem.meta?.core == true) {
|
|
// 全局 网元菜单
|
|
return null;
|
|
}
|
|
if (coreUid.length == 8 && finalItem.meta?.core == false) {
|
|
// 核心网 非网元菜单
|
|
return null;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// 过滤网元类型
|
|
if (
|
|
Array.isArray(finalItem.meta?.neType) &&
|
|
finalItem.meta?.neType.length > 0
|
|
) {
|
|
let metaNeType: string[] = finalItem.meta.neType;
|
|
let match = false; // 匹配
|
|
for (const netype of metaNeType) {
|
|
if (netype.indexOf('+') > -1) {
|
|
metaNeType = netype.split('+');
|
|
match = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (match && !metaNeType.every(item => neTypes.includes(item))) {
|
|
// 同时匹配
|
|
return null;
|
|
} else if (!metaNeType.some(item => neTypes.includes(item))) {
|
|
// 有一种
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// 有子菜单进行递归
|
|
if (finalItem.children && finalItem.children.length > 0) {
|
|
const children = this.clearMenuItemByNeList(
|
|
finalItem.children,
|
|
coreUid,
|
|
neTypes
|
|
);
|
|
// 如果子菜单都被过滤掉了,就不显示
|
|
if (children.length === 0) {
|
|
return null;
|
|
}
|
|
finalItem.children = children;
|
|
return finalItem;
|
|
}
|
|
|
|
delete finalItem.children;
|
|
return finalItem;
|
|
})
|
|
.filter(item => item) as RouteRecordRaw[];
|
|
},
|
|
},
|
|
});
|
|
|
|
/**异步路由类型 */
|
|
type RecordRaws = {
|
|
path: string;
|
|
name: string;
|
|
meta: RouteMeta;
|
|
redirect: RouteLocationRaw;
|
|
component: string;
|
|
children: RecordRaws[];
|
|
};
|
|
|
|
/**
|
|
* 构建动态路由
|
|
*
|
|
* 遍历后台配置的路由菜单,转换为组件路由菜单
|
|
*
|
|
* @param recordRaws 异步路由列表
|
|
* @returns 可添加的路由列表
|
|
*/
|
|
function buildRouters(recordRaws: RecordRaws[]): RouteRecordRaw[] {
|
|
const routers: RouteRecordRaw[] = [];
|
|
for (const item of recordRaws) {
|
|
// 路由页面组件
|
|
let component: RouteComponent = {};
|
|
if (item.component) {
|
|
const comp = item.component;
|
|
if (comp === MENU_COMPONENT_LAYOUT_BASIC) {
|
|
component = BasicLayout;
|
|
} else if (comp === MENU_COMPONENT_LAYOUT_BLANK) {
|
|
component = BlankLayout;
|
|
} else if (comp === MENU_COMPONENT_LAYOUT_LINK) {
|
|
component = LinkLayout;
|
|
} else {
|
|
// 指定页面视图,一般用于显示子菜单
|
|
component = findView(comp);
|
|
}
|
|
}
|
|
|
|
// 有子菜单进行递归
|
|
let children: RouteRecordRaw[] = [];
|
|
if (item.children && item.children.length > 0) {
|
|
children = buildRouters(item.children);
|
|
}
|
|
|
|
// 对元数据特殊参数进行处理
|
|
let metaIcon = (item.meta?.icon as string) || '';
|
|
if (!metaIcon.startsWith('icon-')) {
|
|
metaIcon = '';
|
|
}
|
|
item.meta = Object.assign(item.meta, {
|
|
icon: metaIcon,
|
|
});
|
|
|
|
// 构建路由
|
|
const router: RouteRecordRaw = {
|
|
path: item.path,
|
|
name: item.name,
|
|
meta: item.meta,
|
|
redirect: item.redirect,
|
|
component: component,
|
|
children: children,
|
|
};
|
|
routers.push(router);
|
|
}
|
|
return routers;
|
|
}
|
|
|
|
/**匹配views里面所有的.vue或.tsx文件 */
|
|
const views = import.meta.glob('./../../views/**/*.{vue,tsx}');
|
|
|
|
/**
|
|
* 查找页面模块
|
|
*
|
|
* 查找 `/views/system/menu/index.vue` 或 `/views/system/menu/index.tsx`
|
|
*
|
|
* 参数值为 `system/menu/index`
|
|
*
|
|
* @param dirName 组件路径
|
|
* @returns 路由懒加载函数
|
|
*/
|
|
function findView(dirName: string) {
|
|
for (const dir in views) {
|
|
let viewDirName = '';
|
|
const component = dir.match(/views\/(.+)\.(vue|tsx)/);
|
|
if (component && component.length === 3) {
|
|
viewDirName = component[1];
|
|
}
|
|
if (viewDirName === dirName) {
|
|
return () => views[dir]();
|
|
}
|
|
}
|
|
return () => import('@/views/error/404.vue');
|
|
}
|
|
|
|
export default useRouterStore;
|