Files
fe.ems.vue3/src/store/modules/router.ts
2024-06-12 14:36:16 +08:00

158 lines
4.0 KiB
TypeScript

import { defineStore } from 'pinia';
import type {
RouteComponent,
RouteLocationRaw,
RouteMeta,
RouteRecordRaw,
} from 'vue-router';
import { getRouters } from '@/api/router';
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';
/**路由构建参数类型 */
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 getRouters();
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
const buildRoutes = buildRouters(res.data.concat());
this.buildRouterData = buildRoutes;
return buildRoutes;
}
return [];
},
},
});
/**异步路由类型 */
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) {
// 过滤旧前端菜单 是layui的菜单跳过
if (['', '/page"'].includes(item.path)) {
continue;
}
// 路由页面组件
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;