|
|
@@ -1,5 +1,100 @@
|
|
|
import type { SystemModel, TransformData } from '#/api';
|
|
|
|
|
|
+import accessMenuRoutes from '../../../public/database/menu.json';
|
|
|
+
|
|
|
+export interface TreeSelectMenuNode {
|
|
|
+ id: number | string;
|
|
|
+ label: string;
|
|
|
+ children?: TreeSelectMenuNode[];
|
|
|
+}
|
|
|
+
|
|
|
+type AccessMenuRoute = TransformData & {
|
|
|
+ id?: string;
|
|
|
+ children?: AccessMenuRoute[];
|
|
|
+};
|
|
|
+
|
|
|
+const accessMenuRouteMap = buildAccessMenuRouteMap(
|
|
|
+ accessMenuRoutes as AccessMenuRoute[],
|
|
|
+);
|
|
|
+
|
|
|
+function buildAccessMenuRouteMap(
|
|
|
+ menus: AccessMenuRoute[],
|
|
|
+ map = new Map<string, AccessMenuRoute>(),
|
|
|
+) {
|
|
|
+ for (const menu of menus) {
|
|
|
+ if (menu.id != null) map.set(String(menu.id), menu);
|
|
|
+ if (menu.children?.length) buildAccessMenuRouteMap(menu.children, map);
|
|
|
+ }
|
|
|
+ return map;
|
|
|
+}
|
|
|
+
|
|
|
+/** 将 treeselect 接口数据与本地路由配置合并为可生成路由的菜单 */
|
|
|
+export function fromTreeSelectMenus(
|
|
|
+ nodes: TreeSelectMenuNode[],
|
|
|
+): SystemModel.Menu[] {
|
|
|
+ if (!Array.isArray(nodes)) return [];
|
|
|
+
|
|
|
+ return nodes
|
|
|
+ .map((node) => toAccessMenu(node))
|
|
|
+ .filter((menu): menu is SystemModel.Menu => menu != null)
|
|
|
+ .sort((a, b) => (a.meta.order ?? 999_999) - (b.meta.order ?? 999_999));
|
|
|
+}
|
|
|
+
|
|
|
+function toAccessMenu(node: TreeSelectMenuNode): SystemModel.Menu | null {
|
|
|
+ const route = accessMenuRouteMap.get(String(node.id));
|
|
|
+ if (!route) return null;
|
|
|
+
|
|
|
+ const children = node.children?.length
|
|
|
+ ? fromTreeSelectMenus(node.children)
|
|
|
+ : undefined;
|
|
|
+
|
|
|
+ const hasChildren = !!children?.length;
|
|
|
+
|
|
|
+ return {
|
|
|
+ id: String(node.id),
|
|
|
+ type: hasChildren ? 'catalog' : 'menu',
|
|
|
+ name: route.name,
|
|
|
+ path: route.path,
|
|
|
+ component: route.component,
|
|
|
+ meta: fromMenuMeta({
|
|
|
+ ...route.meta,
|
|
|
+ title: node.label || route.meta?.title,
|
|
|
+ }),
|
|
|
+ children: hasChildren ? children : undefined,
|
|
|
+ } satisfies SystemModel.Menu;
|
|
|
+}
|
|
|
+
|
|
|
+export function filterMenusByPermissions(
|
|
|
+ permissions: Array<number | string>,
|
|
|
+ menus: SystemModel.Menu[],
|
|
|
+): SystemModel.Menu[] {
|
|
|
+ const permissionSet = new Set(permissions.map(String));
|
|
|
+
|
|
|
+ const walk = (
|
|
|
+ items: SystemModel.Menu[],
|
|
|
+ parentMenu: SystemModel.Menu[] = [],
|
|
|
+ ) => {
|
|
|
+ for (const menu of items) {
|
|
|
+ const id = String(menu.id);
|
|
|
+ if (permissionSet.has(id)) {
|
|
|
+ permissionSet.delete(id);
|
|
|
+ if (menu.type === 'menu') parentMenu.push(menu);
|
|
|
+ else if (menu.type === 'catalog' && menu.children?.length) {
|
|
|
+ const parent = { ...menu, children: [] as SystemModel.Menu[] };
|
|
|
+ parentMenu.push(parent);
|
|
|
+ walk(menu.children, parent.children);
|
|
|
+ }
|
|
|
+ } else if (menu.type === 'catalog' && menu.children?.length) {
|
|
|
+ walk(menu.children, parentMenu);
|
|
|
+ }
|
|
|
+ if (permissionSet.size === 0) break;
|
|
|
+ }
|
|
|
+ return parentMenu;
|
|
|
+ };
|
|
|
+
|
|
|
+ return walk(menus);
|
|
|
+}
|
|
|
+
|
|
|
export function fromMenus(menus: TransformData[]): SystemModel.Menu[] {
|
|
|
const getType = (menu: TransformData): SystemModel.Menu['type'] => {
|
|
|
if (menu.type) return menu.type;
|