import type { AdminMenuNode } from '../types/admin' export interface SidebarItem { key: string name: string route: string } /** 侧边栏渲染项:分组(含子页面)或单页面项(含顶级路由叶节点)。 */ export type SidebarEntry = | { kind: 'group'; key: string; name: string; children: SidebarItem[] } | { kind: 'item'; key: string; name: string; route: string } /** * 后端菜单树 -> 侧边栏节点映射规则(任务 6): * - 有可路由子节点的节点渲染为分组,只保留带 route 的子项; * - 无子节点但有 route 的节点渲染为单页面项(不丢顶级叶菜单); * - 既无子节点也无 route 的节点跳过(点不进去的纯占位不展示)。 */ export function toSidebarEntries(nodes: AdminMenuNode[] | null | undefined): SidebarEntry[] { const entries: SidebarEntry[] = [] for (const node of nodes || []) { const name = node.name || '' const key = node.key || '' const children: SidebarItem[] = (node.children || []) .filter((child): child is AdminMenuNode & { route: string } => Boolean(child.route)) .map((child) => ({ key: child.key || '', name: child.name || '', route: child.route })) if (children.length > 0) { entries.push({ kind: 'group', key, name, children }) } else if (node.route) { entries.push({ kind: 'item', key, name, route: node.route }) } } return entries } /** 计算需默认展开的分组 key:分组下含当前激活路由子项时返回该分组 key。 */ export function groupKeysForActive(entries: SidebarEntry[], activeRoute: string): string[] { const keys: string[] = [] for (const entry of entries) { if (entry.kind === 'group' && entry.children.some((child) => child.route === activeRoute)) { keys.push(entry.key) } } return keys }