fix:修复平台前端显示

This commit is contained in:
2026-08-03 14:03:44 +08:00
parent 4751e738b1
commit 9f19bea7ee
2 changed files with 39 additions and 3 deletions

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest';
import type { components } from '../api/schema.generated';
import { visibleNavigationPaths } from './AppLayout';
import { frontendPathForMenu, visibleNavigationPaths } from './AppLayout';
type BackofficeMenuItem = components['schemas']['BackofficeMenuItem'];
@@ -20,6 +20,25 @@ function menu(path: string, permissionCode: string, isActive = true): Backoffice
}
describe('平台导航授权', () => {
it('将后端平台菜单路径转换为当前前端路由', () => {
expect(frontendPathForMenu('/platform/dashboard')).toBe('/');
expect(frontendPathForMenu('/platform/tenants')).toBe('/tenants');
expect(frontendPathForMenu('/platform/question-banks/')).toBe('/question-banks');
expect(frontendPathForMenu('/platform/saas')).toBe('/subscriptions');
expect(frontendPathForMenu('/platform/payment-settings')).toBe('/payments');
});
it('显示后端返回的带平台前缀菜单', () => {
const granted = new Set(['platform:dashboard:view', 'platform:tenant:manage', 'platform:payment:read']);
const paths = visibleNavigationPaths([
menu('/platform/dashboard', 'platform:dashboard:view'),
menu('/platform/tenants', 'platform:tenant:manage'),
menu('/platform/payment-settings', 'platform:payment:read'),
], (...permissions) => permissions.some((permission) => granted.has(permission)));
expect(paths).toEqual(['/', '/tenants', '/payments']);
});
it('同时以 ui-bootstrap 菜单和权限作为可见性边界', () => {
const granted = new Set(['platform:dashboard:view', 'platform:tenant:manage', 'platform:audit:view']);
const paths = visibleNavigationPaths([

View File

@@ -55,11 +55,26 @@ const navigation = [
type BackofficeMenuItem = components['schemas']['BackofficeMenuItem'];
const backendMenuPathAliases: Record<string, string> = {
'/platform/dashboard': '/',
'/platform/saas': '/subscriptions',
'/platform/payment-settings': '/payments',
};
export function frontendPathForMenu(path: string): string {
const normalizedPath = path.length > 1 ? path.replace(/\/+$/, '') : path;
if (backendMenuPathAliases[normalizedPath]) return backendMenuPathAliases[normalizedPath];
if (normalizedPath.startsWith('/platform/')) return normalizedPath.slice('/platform'.length);
return normalizedPath;
}
export function visibleNavigationPaths(
menus: readonly BackofficeMenuItem[],
hasPermission: (...permissions: string[]) => boolean,
): string[] {
const enabledPaths = new Set(menus.filter((menu) => menu.isActive && menu.path).map((menu) => menu.path as string));
const enabledPaths = new Set(menus
.filter((menu) => menu.isActive && menu.path)
.map((menu) => frontendPathForMenu(menu.path as string)));
return navigation.flatMap((item) => {
if ('permission' in item && item.permission && item.key) {
return enabledPaths.has(item.key) && hasPermission(item.permission) ? [item.key] : [];
@@ -76,7 +91,9 @@ function visibleNavigation(
): MenuProps['items'] {
const items: NonNullable<MenuProps['items']> = [];
const visiblePaths = new Set(visibleNavigationPaths(menus, hasPermission));
const menuByPath = new Map(menus.filter((menu) => menu.isActive && menu.path).map((menu) => [menu.path as string, menu]));
const menuByPath = new Map(menus
.filter((menu) => menu.isActive && menu.path)
.map((menu) => [frontendPathForMenu(menu.path as string), menu]));
for (const item of navigation) {
if ('permission' in item && item.permission && item.key) {
if (visiblePaths.has(item.key)) items.push({ key: item.key, icon: item.icon, label: menuByPath.get(item.key)?.title || item.label });