fix: 修复博客菜单可见性

This commit is contained in:
sunlei 2026-06-05 15:30:28 +08:00
parent 490632c7a1
commit add0dc3a8c
2 changed files with 91 additions and 24 deletions

View File

@ -2,7 +2,6 @@ import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Repository } from 'typeorm';
import { toTree } from '@/common';
import { WordpressService } from '@/wordpress/wordpress.service';
import { AdminUser } from '../user/admin-user.entity';
import { AdminMenu } from './admin-menu.entity';
import type { AdminMenuInput, AdminMenuMeta } from '../admin.types';
@ -12,20 +11,15 @@ export class AdminMenuService {
constructor(
@InjectRepository(AdminMenu)
private readonly menuRepository: Repository<AdminMenu>,
private readonly wordpressService: WordpressService,
) {}
async getAccessCodes(user: AdminUser) {
const menus = this.filterUnavailableFeatureMenus(
await this.getAllowedMenus(user),
);
const menus = await this.getAllowedMenus(user);
return menus.map((menu) => menu.authCode).filter((authCode) => !!authCode);
}
async getRouteMenus(user: AdminUser) {
const menus = this.filterUnavailableFeatureMenus(
await this.getAllowedMenus(user),
);
const menus = await this.getAllowedMenus(user);
return this.buildMenuTree(menus.filter((menu) => menu.type !== 'button'));
}
@ -147,22 +141,6 @@ export class AdminMenuService {
return [...menuMap.values()];
}
private filterUnavailableFeatureMenus(menus: AdminMenu[]) {
if (!menus.some((menu) => this.isWordpressMenu(menu))) return menus;
if (this.wordpressService.isAdminIntegrationAvailable()) return menus;
// WordPress 是外部增强能力,远程不可用时不影响 Admin 主系统登录和系统管理菜单。
return menus.filter((menu) => !this.isWordpressMenu(menu));
}
private isWordpressMenu(menu: AdminMenu) {
return (
menu.name?.startsWith('Blog') ||
menu.path?.startsWith('/blog') ||
menu.authCode?.startsWith('Blog:')
);
}
private normalizeMenuInput(
data: AdminMenuInput,
includeEmptyMeta: boolean,

View File

@ -0,0 +1,89 @@
import { AdminMenuService } from '../../src/admin/menu/admin-menu.service';
import type { AdminMenu } from '../../src/admin/menu/admin-menu.entity';
import type { AdminUser } from '../../src/admin/user/admin-user.entity';
describe('AdminMenuService', () => {
const blogMenus = [
createMenu({
id: '2041700000000100300',
meta: { title: '博客管理' },
name: 'Blog',
path: '/blog',
pid: '0',
type: 'catalog',
}),
createMenu({
authCode: 'Blog:Theme:List',
component: '/blog/theme/config',
id: '2041700000000100304',
meta: { title: '主题配置' },
name: 'BlogTheme',
path: '/blog/theme',
pid: '2041700000000100300',
type: 'menu',
}),
createMenu({
authCode: 'Blog:Theme:Import',
id: '2041700000000120332',
meta: { title: '导入 WordPress' },
name: 'BlogThemeImport',
pid: '2041700000000100304',
type: 'button',
}),
];
it('keeps local Blog menus visible for super users', async () => {
const service = new AdminMenuService({
find: jest.fn(async () => blogMenus),
} as any);
const user = {
roles: [
{
isDeleted: false,
roleCode: 'super',
status: 1,
},
],
} as AdminUser;
const routeMenus = await service.getRouteMenus(user);
const accessCodes = await service.getAccessCodes(user);
expect(routeMenus).toEqual([
expect.objectContaining({
children: [
expect.objectContaining({
name: 'BlogTheme',
path: '/blog/theme',
}),
],
name: 'Blog',
path: '/blog',
}),
]);
expect(accessCodes).toEqual(
expect.arrayContaining(['Blog:Theme:List', 'Blog:Theme:Import']),
);
});
});
function createMenu(menu: Partial<AdminMenu>): AdminMenu {
return {
authCode: null,
component: null,
createTime: new Date('2026-06-05T00:00:00Z'),
id: '',
isDeleted: false,
meta: {},
name: '',
path: null,
pid: '0',
redirect: null,
roles: [],
sort: 0,
status: 1,
type: 'menu',
updateTime: new Date('2026-06-05T00:00:00Z'),
...menu,
} as AdminMenu;
}