mirror of
https://github.com/jekip/naive-ui-admin.git
synced 2026-02-15 18:52:27 +08:00
Fixes bug 动态路由配置重构
This commit is contained in:
@@ -13,7 +13,7 @@ export const ErrorPageRoute: AppRouteRecordRaw = {
|
||||
children: [
|
||||
{
|
||||
path: '/:path(.*)*',
|
||||
name: 'ErrorPage',
|
||||
name: 'ErrorPageSon',
|
||||
component: ErrorPage,
|
||||
meta: {
|
||||
title: 'ErrorPage',
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import { renderIcon } from '@/utils/index';
|
||||
import { DashboardOutlined } from '@vicons/antd';
|
||||
// import { RouterTransition } from '@/components/transition'
|
||||
|
||||
//前端路由映射表
|
||||
export const constantRouterComponents = {
|
||||
Layout: () => import('@/layout/index.vue'), //布局
|
||||
DashboardConsole: () => import('@/views/dashboard/console/console.vue'), // 主控台
|
||||
DashboardMonitor: () => import('@/views/dashboard/monitor/monitor.vue'), // 监控页
|
||||
DashboardWorkplace: () => import('@/views/dashboard/workplace/workplace.vue'), // 工作台
|
||||
};
|
||||
|
||||
//前端路由图标映射表
|
||||
export const constantRouterIcon = {
|
||||
DashboardOutlined: renderIcon(DashboardOutlined),
|
||||
};
|
||||
@@ -1,12 +1,19 @@
|
||||
import { adminMenus } from '@/api/system/menu';
|
||||
import { constantRouterComponents, constantRouterIcon } from './constantRouterComponents';
|
||||
import { constantRouterIcon } from './router-icons';
|
||||
import router from '@/router/index';
|
||||
import { constantRouter } from '@/router/index';
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
import { Layout, ParentLayout } from '@/router/constant';
|
||||
import type { AppRouteRecordRaw } from '@/router/types';
|
||||
|
||||
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 {*}
|
||||
@@ -19,21 +26,24 @@ export const routerGenerator = (routerMap, parent?): any[] => {
|
||||
// 路由名称,建议唯一
|
||||
name: item.name || '',
|
||||
// 该路由对应页面的 组件
|
||||
component: constantRouterComponents[item.component],
|
||||
component: item.component,
|
||||
// meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
|
||||
meta: {
|
||||
...item.meta,
|
||||
label: item.meta.title,
|
||||
icon: constantRouterIcon[item.meta.icon] || null,
|
||||
permission: item.meta.permission || null,
|
||||
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.path}/${item.children[0].path}`);
|
||||
// Recursion
|
||||
currentRouter.children = routerGenerator(item.children, currentRouter);
|
||||
}
|
||||
@@ -43,7 +53,6 @@ export const routerGenerator = (routerMap, parent?): any[] => {
|
||||
|
||||
/**
|
||||
* 动态生成菜单
|
||||
* @param token
|
||||
* @returns {Promise<Router>}
|
||||
*/
|
||||
export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
||||
@@ -51,7 +60,8 @@ export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
||||
adminMenus()
|
||||
.then((result) => {
|
||||
const routeList = routerGenerator(result);
|
||||
const asyncRoutesList = [...constantRouter, ...routeList];
|
||||
asyncImportRoute(routeList);
|
||||
const asyncRoutesList = [...routeList, ...constantRouter];
|
||||
asyncRoutesList.forEach((item) => {
|
||||
router.addRoute(item);
|
||||
});
|
||||
@@ -62,3 +72,56 @@ export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查找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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { App } from 'vue';
|
||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
|
||||
import { ErrorPageRoute, RedirectRoute } from '@/router/base';
|
||||
import { RedirectRoute } from '@/router/base';
|
||||
import { PageEnum } from '@/enums/pageEnum';
|
||||
import { createRouterGuards } from './router-guards';
|
||||
|
||||
@@ -40,7 +40,7 @@ export const LoginRoute: RouteRecordRaw = {
|
||||
};
|
||||
|
||||
//需要验证权限
|
||||
export const asyncRoutes = [ErrorPageRoute, ...routeModuleList];
|
||||
export const asyncRoutes = [...routeModuleList];
|
||||
|
||||
//普通路由 无需验证权限
|
||||
export const constantRouter: any[] = [LoginRoute, RootRoute, RedirectRoute];
|
||||
|
||||
@@ -24,7 +24,7 @@ const routes: Array<RouteRecordRaw> = [
|
||||
meta: {
|
||||
title: 'Dashboard',
|
||||
icon: renderIcon(DashboardOutlined),
|
||||
permission: ['dashboard_console', 'dashboard_console', 'dashboard_workplace'],
|
||||
permissions: ['dashboard_console', 'dashboard_console', 'dashboard_workplace'],
|
||||
sort: 0,
|
||||
},
|
||||
children: [
|
||||
@@ -33,7 +33,7 @@ const routes: Array<RouteRecordRaw> = [
|
||||
name: `${routeName}_console`,
|
||||
meta: {
|
||||
title: '主控台',
|
||||
permission: ['dashboard_console'],
|
||||
permissions: ['dashboard_console'],
|
||||
},
|
||||
component: () => import('@/views/dashboard/console/console.vue'),
|
||||
},
|
||||
@@ -42,7 +42,7 @@ const routes: Array<RouteRecordRaw> = [
|
||||
// name: `${ routeName }_monitor`,
|
||||
// meta: {
|
||||
// title: '监控页',
|
||||
// permission: ['dashboard_monitor']
|
||||
// permissions: ['dashboard_monitor']
|
||||
// },
|
||||
// component: () => import('@/views/dashboard/monitor/monitor.vue')
|
||||
// },
|
||||
@@ -52,7 +52,7 @@ const routes: Array<RouteRecordRaw> = [
|
||||
meta: {
|
||||
title: '工作台',
|
||||
keepAlive: true,
|
||||
permission: ['dashboard_workplace'],
|
||||
permissions: ['dashboard_workplace'],
|
||||
},
|
||||
component: () => import('@/views/dashboard/workplace/workplace.vue'),
|
||||
},
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { isNavigationFailure, Router } from 'vue-router';
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||
import { useAsyncRouteStoreWidthOut } from '@/store/modules/asyncRoute';
|
||||
import { ACCESS_TOKEN } from '@/store/mutation-types';
|
||||
import { storage } from '@/utils/Storage';
|
||||
import { PageEnum } from '@/enums/pageEnum';
|
||||
import { ErrorPageRoute } from '@/router/base';
|
||||
|
||||
const LOGIN_PATH = PageEnum.BASE_LOGIN;
|
||||
|
||||
@@ -29,7 +31,7 @@ export function createRouterGuards(router: Router) {
|
||||
const token = storage.get(ACCESS_TOKEN);
|
||||
|
||||
if (!token) {
|
||||
// You can access without permission. You need to set the routing meta.ignoreAuth to true
|
||||
// You can access without permissions. You need to set the routing meta.ignoreAuth to true
|
||||
if (to.meta.ignoreAuth) {
|
||||
next();
|
||||
return;
|
||||
@@ -60,9 +62,15 @@ export function createRouterGuards(router: Router) {
|
||||
|
||||
// 动态添加可访问路由表
|
||||
routes.forEach((item) => {
|
||||
router.addRoute(item);
|
||||
router.addRoute(item as unknown as RouteRecordRaw);
|
||||
});
|
||||
|
||||
//添加404
|
||||
const isErrorPage = router.getRoutes().findIndex((item) => item.name === ErrorPageRoute.name);
|
||||
if (isErrorPage === -1) {
|
||||
router.addRoute(ErrorPageRoute as unknown as RouteRecordRaw);
|
||||
}
|
||||
|
||||
const redirectPath = (from.query.redirect || to.path) as string;
|
||||
const redirect = decodeURIComponent(redirectPath);
|
||||
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect };
|
||||
|
||||
7
src/router/router-icons.ts
Normal file
7
src/router/router-icons.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { renderIcon } from '@/utils/index';
|
||||
import { DashboardOutlined } from '@vicons/antd';
|
||||
|
||||
//前端路由图标映射表
|
||||
export const constantRouterIcon = {
|
||||
DashboardOutlined: renderIcon(DashboardOutlined),
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { RouteRecordRaw, RouteMeta } from 'vue-router';
|
||||
import { defineComponent } from 'vue';
|
||||
import { RoleEnum } from '@/enums/roleEnum';
|
||||
|
||||
export type Component<T extends any = any> =
|
||||
| ReturnType<typeof defineComponent>
|
||||
@@ -23,7 +22,7 @@ export interface Meta {
|
||||
title: string;
|
||||
// 是否忽略权限
|
||||
ignoreAuth?: boolean;
|
||||
roles?: RoleEnum[];
|
||||
permissions?: string[];
|
||||
// 是否不缓存
|
||||
noKeepAlive?: boolean;
|
||||
// 是否固定在tab上
|
||||
|
||||
Reference in New Issue
Block a user