fix: 修复后台菜单排序生效
This commit is contained in:
parent
4ba24f2b60
commit
083d5a4720
@ -46,7 +46,7 @@ pnpm run build:antdv-next
|
||||
|
||||
## 业务页面
|
||||
|
||||
- 系统管理 / 菜单管理维护后端 `admin_menu.sort` 排序字段,菜单树展示仍以后端返回顺序为准;默认首页入口收敛到环境总览 `/analytics`,不再保留假工作台 `/workspace` 页面。
|
||||
- 系统管理 / 菜单管理维护后端 `admin_menu.sort` 排序字段;`/menu/all` caller 会把后端 `sort` 映射到 Vben 菜单生成器读取的 `meta.order`,保证侧边栏菜单展示以后端返回顺序为准。默认首页入口收敛到环境总览 `/analytics`,不再保留假工作台 `/workspace` 页面。
|
||||
- 系统管理 / 站内信是日志级通知列表,只展示 API 错误、QQBot 下线、NapCat 离线等后端自动捕获事件;页面提供筛选、处理/重新打开、置顶和删除,不提供人工新增或编辑。
|
||||
- QQBot / 账号连接页拆分 OneBot 连接、QQ 登录、NapCat 运行和运行说明列;更新登录通过 SSE 展示 quick / password / captcha / new-device / qrcode 每步中文进度,密码登录触发 QQ 安全验证时在弹窗内完成腾讯验证码并回交 API,新设备验证二维码和腾讯验证码分开展示;行操作“运行态”打开只读抽屉,展示 NapCat runtime/protocol/session behavior profile、风险模式和登录事件证据。
|
||||
- QQBot / 插件平台页保留在线命令能力表,并提供 manifest 校验、本地插件安装、安装记录、运行事件和账号绑定抽屉,接口走 `/qqbot/plugin-platform/*`。
|
||||
|
||||
@ -109,4 +109,52 @@ describe('core menu api', () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('uses backend sort as the authoritative menu order before menu generation', async () => {
|
||||
requestClientGet.mockResolvedValue([
|
||||
{
|
||||
name: 'Dashboard',
|
||||
path: '/dashboard',
|
||||
sort: 200,
|
||||
meta: {
|
||||
order: -1,
|
||||
title: 'Dashboard',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'QqBot',
|
||||
path: '/qqbot',
|
||||
sort: 1,
|
||||
meta: {
|
||||
title: 'QQBot',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'QqBotAccount',
|
||||
path: '/qqbot/account',
|
||||
component: '/qqbot/account/list',
|
||||
sort: 1,
|
||||
meta: {
|
||||
title: '账号连接',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Blog',
|
||||
path: '/blog',
|
||||
sort: 0,
|
||||
meta: {
|
||||
order: 100,
|
||||
title: '博客管理',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const { getAllMenusApi } = await import('./menu');
|
||||
const menus = await getAllMenusApi();
|
||||
|
||||
expect(menus.map((menu) => menu.meta?.order)).toEqual([200, 1, 0]);
|
||||
expect(menus[1]?.children?.[0]?.meta?.order).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
@ -97,15 +97,49 @@ export function isSupportedAdminMenuName(name?: null | string | symbol) {
|
||||
return typeof name === 'string' && SUPPORTED_ADMIN_MENU_NAMES.has(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将后端数据库排序字段对齐到 Vben 菜单生成器实际读取的 `meta.order`。
|
||||
* @param menu - `/menu/all` 返回的后端菜单节点;节点可能同时带有历史路由 `meta.order` 和 DB `sort`。
|
||||
* @returns 克隆后的菜单节点;当后端提供有限数字 `sort` 时以 DB 排序为准,否则保留原节点。
|
||||
*/
|
||||
function normalizeBackendMenuOrder(
|
||||
menu: RouteRecordStringComponent,
|
||||
): RouteRecordStringComponent {
|
||||
const sortOrder =
|
||||
typeof menu.sort === 'number' && Number.isFinite(menu.sort)
|
||||
? menu.sort
|
||||
: undefined;
|
||||
|
||||
if (sortOrder === undefined) {
|
||||
return menu;
|
||||
}
|
||||
|
||||
const meta = menu.meta ?? { title: String(menu.name ?? '') };
|
||||
|
||||
return {
|
||||
...menu,
|
||||
meta: {
|
||||
...meta,
|
||||
order: sortOrder,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤当前 Admin 已实现的后端菜单,并保留后端排序语义给路由菜单生成器使用。
|
||||
* @param menus - `/menu/all` 返回的后端菜单树;包含页面节点、隐藏路由节点和按钮权限节点。
|
||||
* @returns 仅含当前前端支持节点的菜单树,且每个节点的 DB `sort` 已映射为权威 `meta.order`。
|
||||
*/
|
||||
function filterSupportedAdminMenus(
|
||||
menus: RouteRecordStringComponent[],
|
||||
): RouteRecordStringComponent[] {
|
||||
return menus
|
||||
.map((menu) => {
|
||||
const children = menu.children
|
||||
? filterSupportedAdminMenus(menu.children)
|
||||
const normalizedMenu = normalizeBackendMenuOrder(menu);
|
||||
const children = normalizedMenu.children
|
||||
? filterSupportedAdminMenus(normalizedMenu.children)
|
||||
: undefined;
|
||||
const menuWithoutChildren = { ...menu };
|
||||
const menuWithoutChildren = { ...normalizedMenu };
|
||||
delete menuWithoutChildren.children;
|
||||
|
||||
return {
|
||||
|
||||
@ -130,6 +130,7 @@ type RouteRecordStringComponent<T = string> = Omit<
|
||||
> & {
|
||||
children?: RouteRecordStringComponent<T>[];
|
||||
component: T;
|
||||
sort?: number;
|
||||
};
|
||||
|
||||
type ComponentRecordType = Record<string, () => Promise<Component>>;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user