feat: add breadcrumb navigation example
This commit is contained in:
@@ -53,6 +53,7 @@ describe('generateMenus', () => {
|
||||
parent: undefined,
|
||||
parents: undefined,
|
||||
path: '/home',
|
||||
show: true,
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
@@ -65,6 +66,7 @@ describe('generateMenus', () => {
|
||||
parent: undefined,
|
||||
parents: undefined,
|
||||
path: '/about',
|
||||
show: true,
|
||||
children: [],
|
||||
},
|
||||
];
|
||||
@@ -94,6 +96,7 @@ describe('generateMenus', () => {
|
||||
parent: undefined,
|
||||
parents: undefined,
|
||||
path: '/profile',
|
||||
show: true,
|
||||
children: [],
|
||||
},
|
||||
]);
|
||||
@@ -120,6 +123,7 @@ describe('generateMenus', () => {
|
||||
parent: undefined,
|
||||
parents: undefined,
|
||||
path: '/users/:userId',
|
||||
show: true,
|
||||
children: [],
|
||||
},
|
||||
]);
|
||||
@@ -155,6 +159,7 @@ describe('generateMenus', () => {
|
||||
parent: undefined,
|
||||
parents: undefined,
|
||||
path: '/old-path',
|
||||
show: true,
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
@@ -167,6 +172,7 @@ describe('generateMenus', () => {
|
||||
parent: undefined,
|
||||
parents: undefined,
|
||||
path: '/new-path',
|
||||
show: true,
|
||||
children: [],
|
||||
},
|
||||
]);
|
||||
@@ -203,6 +209,7 @@ describe('generateMenus', () => {
|
||||
parent: undefined,
|
||||
parents: undefined,
|
||||
path: '/about',
|
||||
show: true,
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
@@ -215,6 +222,7 @@ describe('generateMenus', () => {
|
||||
parent: undefined,
|
||||
parents: undefined,
|
||||
path: '/',
|
||||
show: true,
|
||||
children: [],
|
||||
},
|
||||
];
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import type { ExRouteRecordRaw, MenuRecordRaw } from '@vben-core/typings';
|
||||
import type { RouteRecordRaw, Router } from 'vue-router';
|
||||
|
||||
import { mapTree } from '@vben-core/toolkit';
|
||||
import { filterTree, mapTree } from '@vben-core/toolkit';
|
||||
|
||||
/**
|
||||
* 根据 routes 生成菜单列表
|
||||
@@ -61,13 +61,18 @@ async function generateMenus(
|
||||
parent: route.parent,
|
||||
parents: route.parents,
|
||||
path: resultPath as string,
|
||||
show: !route?.meta?.hideInMenu,
|
||||
children: resultChildren || [],
|
||||
};
|
||||
});
|
||||
|
||||
// 对菜单进行排序
|
||||
menus = menus.sort((a, b) => (a.order || 999) - (b.order || 999));
|
||||
return menus;
|
||||
|
||||
const finalMenus = filterTree(menus, (menu) => {
|
||||
return !!menu.show;
|
||||
});
|
||||
return finalMenus;
|
||||
}
|
||||
|
||||
export { generateMenus };
|
||||
|
@@ -5,7 +5,6 @@ import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
generateRoutesByFrontend,
|
||||
hasAuthority,
|
||||
hasVisible,
|
||||
} from './generate-routes-frontend';
|
||||
|
||||
// Mock 路由数据
|
||||
@@ -51,37 +50,7 @@ describe('hasAuthority', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasVisible', () => {
|
||||
it('should return true if hideInMenu is not set or false', () => {
|
||||
expect(hasVisible(mockRoutes[0])).toBe(true);
|
||||
expect(hasVisible(mockRoutes[2])).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if hideInMenu is true', () => {
|
||||
expect(hasVisible(mockRoutes[0].children?.[1])).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateRoutesByFrontend', () => {
|
||||
it('should filter routes based on authority and visibility', async () => {
|
||||
const generatedRoutes = await generateRoutesByFrontend(mockRoutes, [
|
||||
'user',
|
||||
]);
|
||||
// The user should have access to /dashboard/stats, but it should be filtered out because it's not visible
|
||||
expect(generatedRoutes).toEqual([
|
||||
{
|
||||
meta: { authority: ['admin', 'user'], hideInMenu: false },
|
||||
path: '/dashboard',
|
||||
children: [],
|
||||
},
|
||||
// Note: We expect /settings to be filtered out because the user does not have 'admin' authority
|
||||
{
|
||||
meta: { hideInMenu: false },
|
||||
path: '/profile',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle routes without children', async () => {
|
||||
const generatedRoutes = await generateRoutesByFrontend(mockRoutes, [
|
||||
'user',
|
||||
|
@@ -12,7 +12,7 @@ async function generateRoutesByFrontend(
|
||||
): Promise<RouteRecordRaw[]> {
|
||||
// 根据角色标识过滤路由表,判断当前用户是否拥有指定权限
|
||||
const finalRoutes = filterTree(routes, (route) => {
|
||||
return hasVisible(route) && hasAuthority(route, roles);
|
||||
return hasAuthority(route, roles);
|
||||
});
|
||||
|
||||
if (!forbiddenComponent) {
|
||||
@@ -43,14 +43,6 @@ function hasAuthority(route: RouteRecordRaw, access: string[]) {
|
||||
return canAccess || (!canAccess && menuHasVisibleWithForbidden(route));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断路由是否需要在菜单中显示
|
||||
* @param route
|
||||
*/
|
||||
function hasVisible(route?: RouteRecordRaw) {
|
||||
return !route?.meta?.hideInMenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断路由是否在菜单中显示,但是访问会被重定向到403
|
||||
* @param route
|
||||
@@ -63,4 +55,4 @@ function menuHasVisibleWithForbidden(route: RouteRecordRaw) {
|
||||
);
|
||||
}
|
||||
|
||||
export { generateRoutesByFrontend, hasAuthority, hasVisible };
|
||||
export { generateRoutesByFrontend, hasAuthority };
|
||||
|
Reference in New Issue
Block a user