kt-template-admin/apps/web-antdv-next/src/api/core/menu.ts

199 lines
5.2 KiB
TypeScript

import type { RouteRecordStringComponent } from '@vben/types';
import { requestClient } from '#/api/request';
const SUPPORTED_ADMIN_MENU_NAMES = new Set([
'Analytics',
'Blog',
'BlogArticle',
'BlogArticleCreate',
'BlogArticleDelete',
'BlogArticleEdit',
'BlogArticleImport',
'BlogArticlePreview',
'BlogArticlePreviewButton',
'BlogCategory',
'BlogCategoryCreate',
'BlogCategoryDelete',
'BlogCategoryEdit',
'BlogTag',
'BlogTagCreate',
'BlogTagDelete',
'BlogTagEdit',
'BlogTheme',
'BlogThemeImport',
'BlogThemeSave',
'Dashboard',
'Profile',
'QqBot',
'QqBotAccount',
'QqBotAccountConfig',
'QqBotAccountConfigButton',
'QqBotAccountCreate',
'QqBotAccountDelete',
'QqBotAccountEdit',
'QqBotAccountKick',
'QqBotAccountMessagePushCreate',
'QqBotAccountMessagePushDelete',
'QqBotAccountMessagePushList',
'QqBotAccountMessagePushToggle',
'QqBotAccountMessagePushUpdate',
'QqBotAccountNapcatWebui',
'QqBotAccountRefreshLogin',
'QqBotAccountWebUI',
'QqBotCommand',
'QqBotCommandCreate',
'QqBotCommandDelete',
'QqBotCommandEdit',
'QqBotCommandTest',
'QqBotCommandToggle',
'QqBotConversation',
'QqBotDashboard',
'QqBotMessage',
'QqBotMessageSubscription',
'QqBotMessageSubscriptionCreate',
'QqBotMessageSubscriptionDelete',
'QqBotMessageSubscriptionList',
'QqBotMessageSubscriptionToggle',
'QqBotMessageSubscriptionUpdate',
'QqBotMessageTemplate',
'QqBotMessageTemplateCreate',
'QqBotMessageTemplateDelete',
'QqBotMessageTemplateList',
'QqBotMessageTemplatePreview',
'QqBotMessageTemplateToggle',
'QqBotMessageTemplateUpdate',
'QqBotPermission',
'QqBotPermissionCreate',
'QqBotPermissionDelete',
'QqBotPermissionEdit',
'QqBotPlugin',
'QqBotPluginTask',
'QqBotPluginTaskDisable',
'QqBotPluginTaskEnable',
'QqBotPluginTaskRun',
'QqBotPluginTaskRunLog',
'QqBotPluginTaskUpdateCron',
'QqBotRule',
'QqBotRuleCreate',
'QqBotRuleDelete',
'QqBotRuleEdit',
'QqBotRuleToggle',
'QqBotSendGroup',
'QqBotSendLog',
'QqBotSendPrivate',
'System',
'SystemDept',
'SystemDeptCreate',
'SystemDeptDelete',
'SystemDeptEdit',
'SystemDict',
'SystemDictCreate',
'SystemDictDelete',
'SystemDictEdit',
'SystemKtTableDemo',
'SystemKtTableDemoCreate',
'SystemKtTableDemoDelete',
'SystemKtTableDemoEdit',
'SystemLog',
'SystemMenu',
'SystemMenuCreate',
'SystemMenuDelete',
'SystemMenuEdit',
'SystemNetwork',
'SystemNetworkDdnsCreate',
'SystemNetworkDdnsDelete',
'SystemNetworkDdnsList',
'SystemNetworkDdnsRetry',
'SystemNetworkDdnsUpdate',
'SystemNetworkPortForwardCreate',
'SystemNetworkPortForwardDelete',
'SystemNetworkPortForwardHistory',
'SystemNetworkPortForwardKeeper',
'SystemNetworkPortForwardList',
'SystemNetworkPortForwardProbe',
'SystemNetworkPortForwardRetry',
'SystemNetworkPortForwardUpdate',
'SystemNotice',
'SystemNoticeDelete',
'SystemNoticeEdit',
'SystemRole',
'SystemRoleCreate',
'SystemRoleDelete',
'SystemRoleEdit',
'SystemUser',
'SystemUserCreate',
'SystemUserDelete',
'SystemUserEdit',
]);
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 normalizedMenu = normalizeBackendMenuOrder(menu);
const children = normalizedMenu.children
? filterSupportedAdminMenus(normalizedMenu.children)
: undefined;
const menuWithoutChildren = { ...normalizedMenu };
delete menuWithoutChildren.children;
return {
...menuWithoutChildren,
...(children && children.length > 0 ? { children } : {}),
};
})
.filter(
(menu) => isSupportedAdminMenuName(menu.name) || !!menu.children?.length,
);
}
/**
* 获取用户所有菜单
*/
export async function getAllMenusApi() {
const menus =
await requestClient.get<RouteRecordStringComponent[]>('/menu/all');
// 只暴露当前前端页面和后端接口已经支撑的后台菜单。
return filterSupportedAdminMenus(menus);
}