import type { MenuNode } from "@/api/admin"; function normPath(p: string | undefined): string { if (!p) return ""; const s = p.trim(); return s.startsWith("/") ? s : `/${s}`.replace(/^\/+/, "/"); } function hasMpUserMenu(nodes: MenuNode[]): boolean { for (const n of nodes) { if (normPath(n.path) === "/system/mp-user") return true; if (n.children?.length && hasMpUserMenu(n.children)) return true; } return false; } function hasDownloadAssetsMenu(nodes: MenuNode[]): boolean { for (const n of nodes) { if (normPath(n.path) === "/content/download-assets") return true; if (n.children?.length && hasDownloadAssetsMenu(n.children)) return true; } return false; } /** 去掉「内容管理」目录,子项(作品审核、轮播等)提升为侧栏一级 */ export function flattenContentMenus(list: MenuNode[]): MenuNode[] { if (!list.length) return list; const out: MenuNode[] = []; for (const n of list) { const p = normPath(n.path); const isContentDir = n.type === 1 && (p === "/content" || n.name === "内容管理"); if (isContentDir && n.children?.length) { const parentSort = n.sort ?? 10; const sorted = [...n.children].sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0)); sorted.forEach((ch, idx) => { out.push({ ...ch, parent_id: 0, sort: parentSort + idx + 1, }); }); continue; } out.push(n); } out.sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0)); return out; } /** 将「用户管理」从系统管理下提升为侧栏一级(排在内容菜单后、系统管理前) */ export function flattenMpUserMenu(list: MenuNode[]): MenuNode[] { if (!list.length) return list; const hoisted: MenuNode[] = []; const out: MenuNode[] = []; const hoistSort = 15; for (const n of list) { const p = normPath(n.path); const isSystemDir = n.type === 1 && (p === "/system" || n.name === "系统管理"); if (isSystemDir && n.children?.length) { const rest: MenuNode[] = []; for (const ch of n.children) { if (normPath(ch.path) === "/system/mp-user") { hoisted.push({ ...ch, parent_id: 0, sort: hoistSort, }); } else { rest.push(ch); } } out.push({ ...n, children: rest.length ? rest : undefined, }); continue; } out.push(n); } const merged = [...out, ...hoisted]; merged.sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0)); return merged; } /** 接口未返回用户管理菜单时,在根级补一项(一级侧栏) */ export function withMpUserMenu(list: MenuNode[]): MenuNode[] { if (!list.length || hasMpUserMenu(list)) { return list; } const item: MenuNode = { id: 999001, parent_id: 0, name: "用户管理", type: 2, path: "/system/mp-user", component: "", perms: "", icon: "avatar", sort: 15, }; return [...list, item].sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0)); } /** 接口未返回下载素材菜单时,在根级补一项(一级侧栏) */ export function withDownloadAssetsMenu(list: MenuNode[]): MenuNode[] { if (!list.length || hasDownloadAssetsMenu(list)) { return list; } const item: MenuNode = { id: 999002, parent_id: 0, name: "下载素材", type: 2, path: "/content/download-assets", component: "", perms: "", icon: "picture", sort: 11, }; return [...list, item].sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0)); } /** * 保证轮播图、作品审核排在「系统管理」之上(避免库中 sort 相同时按 id 把系统顶到前面) */ export function ensureContentBeforeSystem(list: MenuNode[]): MenuNode[] { if (!list.length) return list; const contentOrder: Record = { "/content/download-assets": 10, "/content/banner": 11, "/content/work": 12, }; const patched = list.map((n) => { const p = normPath(n.path); if (n.type === 1 && (p === "/system" || n.name === "系统管理")) { const s = n.sort ?? 0; return { ...n, sort: s < 20 ? 20 : s }; } if (contentOrder[p] !== undefined) { return { ...n, sort: contentOrder[p] }; } return n; }); patched.sort((a, b) => { const sa = a.sort ?? 0; const sb = b.sort ?? 0; if (sa !== sb) return sa - sb; return (a.id ?? 0) - (b.id ?? 0); }); return patched; } /** 接口未配置「工作台」菜单时,前置仪表盘入口 */ export function withDashboardMenu(list: MenuNode[]): MenuNode[] { const dash: MenuNode = { id: 0, parent_id: 0, name: "工作台", type: 2, path: "/dashboard", component: "", perms: "", icon: "odometer", sort: -999, }; const has = list.some( (m) => m.path === "/dashboard" || m.children?.some((c) => c.path === "/dashboard") ); if (has) { return list; } return [dash, ...list]; }