diff --git a/frontend-web/src/components/page-sidebar-dark.tsx b/frontend-web/src/components/page-sidebar-dark.tsx index 17238017..c9dc31c3 100644 --- a/frontend-web/src/components/page-sidebar-dark.tsx +++ b/frontend-web/src/components/page-sidebar-dark.tsx @@ -1,272 +1,23 @@ import { useEffect, useMemo, useRef, useState } from "react"; -import type { ElementType } from "react"; import { useNavigate, useLocation } from "react-router-dom"; -import { - Bell, - Bot, - Brain, - CalendarClock, - ChevronLeft, - ChevronRight, - ChevronsUpDown, - CircleHelp, - Database, - FileBox, - FileText, - Folder, - FolderOpen, - Gauge, - Grid3X3, - HelpCircle, - History, - Layout, - Library, - List, - ListChecks, - ListTodo, - MessageSquareCode, - MessageSquarePlus, - Network, - NotebookPen, - Plus, - Settings, - Sparkles, - Target, - User, - Users, - Wrench, -} from "lucide-react"; import { getStoredAuth } from "@/core/auth"; +import { + defaultExpandedIds, + filterMenuItemsByRole, + sidebarMenuItems, + type MenuItem, +} from "@/core/page-layout/sidebar-menu"; import './page-sdebar.css' -type MenuItem = { - id: string; - label: string; - icon: ElementType; - path?: string; - adminOnly?: boolean; - children?: MenuItem[]; -}; - -const menuItems: MenuItem[] = [ - { - id: "qa-center", - label: "问答中心", - icon: HelpCircle, - children: [ - { id: "general-qa", label: "通用问答", icon: CircleHelp, path: "/page/workspace/chats/new" }, - { id: "expert-qa", label: "专家问答", icon: Brain, path: "/page/strategy/qa/expert-qa" }, - { id: "qa-zzjc", label: "zzjc支持", icon: Bot }, - { id: "qa-zzxd", label: "zzXD应用", icon: Layout }, - { id: "qa-research", label: "课题研究", icon: FileText, path: "/page/canvas/ai-writing" }, - ], - }, - { - id: "light-app-center", - label: "轻应用", - icon: Grid3X3, - children: [ - { - id: "light-app-note-management", - label: "笔记管理", - icon: NotebookPen, - children: [ - { - id: "light-app-new-note", - label: "新建笔记", - icon: Plus, - path: "/page/strategy/light-app/new-note", - }, - { - id: "light-app-note-list", - label: "笔记列表", - icon: List, - path: "/page/strategy/light-app/notes", - }, - { - id: "light-app-note-qa", - label: "笔记问答", - icon: MessageSquareCode, - path: "/page/strategy/light-app/note-qa", - }, - ], - }, - { id: "light-app-square", label: "应用广场", icon: Layout }, - { id: "light-app-records", label: "运行记录", icon: History }, - ], - }, - { - id: "task-management", - label: "任务管理", - icon: Target, - children: [ - { - id: "xk-center-task", - label: "XK中任务", - icon: Folder, - children: [ - { id: "xk-task-jc", label: "任务JC", icon: ListTodo, path: "/page/strategy/task-management/xk-task-jc" }, - { id: "xk-task-dispatch", label: "任务调度", icon: ListTodo, path: "/page/strategy/task-management/xk-task-dispatch" }, - ], - }, - { - id: "coh-center-task", - label: "COH中任务", - icon: Folder, - children: [ - { - id: "coh-task-3qfx", - label: "3QFX", - icon: ListTodo, - path: "/page/strategy/task-management/plan-task-sentiment", - }, - { - id: "coh-task-fx", - label: "任务FX", - icon: ListTodo, - path: "/page/strategy/task-management/plan-task/plan-task-fx", - }, - { - id: "coh-task-xdfx", - label: "XDFX", - icon: ListTodo, - path: "/page/strategy/task-management/plan-task/plan-task-action", - }, - ], - }, - { - id: "pg-center-task", - label: "PG中任务", - icon: Folder, - children: [ - { id: "pg-task-pg", label: "任务PG", icon: ListTodo, path: "/page/strategy/task-management/effect-task-pg" }, - { id: "pg-task-xdpg", label: "XDPG", icon: ListTodo, path: "/page/strategy/task-management/effect-action-pg" }, - { id: "pg-task-info-pg", label: "信息PG", icon: ListTodo, path: "/page/strategy/task-management/effect-info-pg" }, - ], - }, - { - id: "ty-center-task", - label: "TY中任务", - icon: Folder, - children: [ - { id: "ty-task-xdty", label: "XDTY任务", icon: ListTodo, path: "/page/strategy/task-management/mnty-task-mechanism" }, - { id: "ty-task-plan", label: "方案TY任务", icon: ListTodo, path: "/page/strategy/task-management/mnty-task-plan" }, - { id: "ty-task-xxty", label: "XXTY任务", icon: ListTodo, path: "/page/strategy/task-management/mnty-task-zsty" }, - ], - }, - ], - }, - { - id: "comprehensive-management", - label: "综合管理", - icon: Settings, - children: [ - { id: "mgmt-agents", label: "智能体管理", icon: Bot, path: "/page/strategy/agents" }, - { id: "mgmt-skills", label: "技能管理", icon: Sparkles, path: "/page/strategy/skills" }, - { id: "mgmt-memory", label: "记忆管理", icon: Brain, path: "/page/strategy/memory" }, - { - id: "mgmt-tasks", - label: "任务管理", - icon: ListChecks, - path: "/page/strategy/scheduled/tasks", - }, - { - id: "mgmt-recommended-questions", - label: "推荐问题配置", - icon: MessageSquarePlus, - path: "/page/strategy/settings/recommended-questions", - adminOnly: true, - }, - { - id: "mgmt-prompt-prefix", - label: "问答前缀配置", - icon: MessageSquareCode, - path: "/page/strategy/settings/prompt-prefix", - adminOnly: true, - }, - { - id: "mgmt-llm-metrics", - label: "大模型调用统计", - icon: Gauge, - path: "/page/strategy/settings/llm-metrics", - adminOnly: true, - }, - { - id: "mgmt-users", - label: "用户管理", - icon: Users, - path: "/page/strategy/admin/users", - adminOnly: true, - }, - { - id: "mgmt-admin-scheduled-tasks", - label: "定时任务管理", - icon: CalendarClock, - path: "/page/strategy/admin/scheduled-tasks", - adminOnly: true, - }, - { - id: "mgmt-user-activity", - label: "用户活动审计", - icon: History, - path: "/page/strategy/admin/user-activity", - adminOnly: true, - }, - ], - }, - { - id: "resource-management", - label: "资源管理", - icon: Database, - children: [ - { - id: "resource-network-xwt", - label: "网络xwt资源管理", - icon: Network, - path: "/page/strategy/resource-management/resource-network-actor", - }, - { - id: "resource-knowledge-base", - label: "知识库资源管理", - icon: Library, - path: "/page/strategy/resource-management/resource-knowledge-base", - }, - { - id: "resource-evaluation-index", - label: "作战资源管理", - icon: FileBox, - path: "/page/strategy/resource-management/resource-evaluation-index", - }, - ], - }, -]; - -const defaultExpandedIds = new Set([ - "qa-center", - "light-app-center", - "light-app-note-management", - "task-management", - "xk-center-task", -]); - -function filterMenuItemsByRole(items: MenuItem[], isAdmin: boolean): MenuItem[] { - return items - .filter((item) => !item.adminOnly || isAdmin) - .map((item) => - item.children - ? { ...item, children: filterMenuItemsByRole(item.children, isAdmin) } - : item, - ); -} - export function PageSidebarDark() { const isAdmin = getStoredAuth()?.system_role === "admin"; const visibleMenuItems = useMemo( - () => filterMenuItemsByRole(menuItems, !!isAdmin), + () => filterMenuItemsByRole(sidebarMenuItems, !!isAdmin), [isAdmin], ); - const [expandedIds, setExpandedIds] = useState>(defaultExpandedIds); + // defaultExpandedIds 是共享的 ReadonlySet,复制一份给 useState(避免外部突变) + const [expandedIds, setExpandedIds] = useState>(() => new Set(defaultExpandedIds)); const navigate = useNavigate(); const { pathname } = useLocation(); diff --git a/frontend-web/src/components/page-sidebar.tsx b/frontend-web/src/components/page-sidebar.tsx index 11dec345..10512957 100644 --- a/frontend-web/src/components/page-sidebar.tsx +++ b/frontend-web/src/components/page-sidebar.tsx @@ -1,40 +1,14 @@ import { useEffect, useState } from "react"; -import type { ElementType } from "react"; import { useNavigate, useLocation } from "react-router-dom"; import { Bell, - Bot, - Brain, - CalendarClock, ChevronLeft, ChevronRight, ChevronsUpDown, - CircleHelp, - Database, - FileBox, - FileText, Folder, FolderOpen, - Gauge, - Grid3X3, - HelpCircle, - History, - Layout, - Library, - List, - ListChecks, - ListTodo, - MessageSquareCode, - MessageSquarePlus, - ShieldCheck, - Network, - NotebookPen, - Plus, Settings, - Sparkles, - Target, User, - Users, Wrench, } from "lucide-react"; @@ -50,14 +24,12 @@ import { useTheme } from "@/contexts/ThemeContext"; import { getStoredAuth } from "@/core/auth"; import { useI18n } from "@/core/i18n/hooks"; import { useUnreadCount } from "@/core/notifications"; -type MenuItem = { - id: string; - label: string; - icon: ElementType; - path?: string; - adminOnly?: boolean; - children?: MenuItem[]; -}; +import { + defaultExpandedIds, + filterMenuItemsByRole, + sidebarMenuItems, + type MenuItem, +} from "@/core/page-layout/sidebar-menu"; type PageSidebarProps = { collapsed: boolean; @@ -66,272 +38,6 @@ type PageSidebarProps = { type SettingsSection = "account" | "appearance" | "memory" | "tools" | "about"; -const menuItems: MenuItem[] = [ - { - id: "qa-center", - label: "问答中心", - icon: HelpCircle, - children: [ - { id: "general-qa", label: "通用问答", icon: CircleHelp, path: "/page/workspace/chats/new" }, - { id: "expert-qa", label: "专家问答", icon: Brain, path: "/page/strategy/qa/expert-qa" }, - // 「圆桌规划」入口暂时隐藏 —— 功能仍在 /page/roundtable/planning,只是不在侧边栏出现。 - // 需要重新开放时取消注释即可。 - // { - // id: "qa-roundtable", - // label: "圆桌规划", - // icon: Bot, - // path: "/page/roundtable/planning", - // }, - { id: "qa-zzjc", label: "zzjc支持", icon: Bot }, - { id: "qa-zzxd", label: "zzXD应用", icon: Layout }, - { id: "qa-research", label: "课题研究", icon: FileText, path: "/page/canvas/ai-writing" }, - ], - }, - { - id: "light-app-center", - label: "轻应用", - icon: Grid3X3, - children: [ - { - id: "light-app-note-management", - label: "笔记管理", - icon: NotebookPen, - children: [ - { - id: "light-app-new-note", - label: "新建笔记", - icon: Plus, - path: "/page/strategy/light-app/new-note", - }, - { - id: "light-app-note-list", - label: "笔记列表", - icon: List, - path: "/page/strategy/light-app/notes", - }, - { - id: "light-app-note-qa", - label: "笔记问答", - icon: MessageSquareCode, - path: "/page/strategy/light-app/note-qa", - }, - ], - }, - { id: "light-app-square", label: "应用广场", icon: Layout }, - { id: "light-app-records", label: "运行记录", icon: History }, - ], - }, - { - id: "task-management", - label: "任务管理", - icon: Target, - children: [ - { - id: "xk-center-task", - label: "XK中任务", - icon: Folder, - children: [ - { - id: "xk-task-jc", - label: "任务JC", - icon: ListTodo, - path: "/page/strategy/task-management/xk-task-jc", - }, - { - id: "xk-task-dispatch", - label: "任务调度", - icon: ListTodo, - path: "/page/strategy/task-management/xk-task-dispatch", - }, - ], - }, - { - id: "coh-center-task", - label: "COH中任务", - icon: Folder, - children: [ - { - id: "coh-task-3qfx", - label: "3QFX", - icon: ListTodo, - path: "/page/strategy/task-management/plan-task-sentiment", - }, - { - id: "coh-task-fx", - label: "任务FX", - icon: ListTodo, - path: "/page/strategy/task-management/plan-task/plan-task-fx", - }, - { - id: "coh-task-xdfx", - label: "XDFX", - icon: ListTodo, - path: "/page/strategy/task-management/plan-task/plan-task-action", - }, - ], - }, - { - id: "pg-center-task", - label: "PG中任务", - icon: Folder, - children: [ - { - id: "pg-task-pg", - label: "任务PG", - icon: ListTodo, - path: "/page/strategy/task-management/effect-task-pg", - }, - { - id: "pg-task-xdpg", - label: "XDPG", - icon: ListTodo, - path: "/page/strategy/task-management/effect-action-pg", - }, - { - id: "pg-task-info-pg", - label: "信息PG", - icon: ListTodo, - path: "/page/strategy/task-management/effect-info-pg", - }, - ], - }, - { - id: "ty-center-task", - label: "TY中任务", - icon: Folder, - children: [ - { - id: "ty-task-xdty", - label: "XDTY任务", - icon: ListTodo, - path: "/page/strategy/task-management/mnty-task-mechanism", - }, - { - id: "ty-task-plan", - label: "方案TY任务", - icon: ListTodo, - path: "/page/strategy/task-management/mnty-task-plan", - }, - { - id: "ty-task-xxty", - label: "XXTY任务", - icon: ListTodo, - path: "/page/strategy/task-management/mnty-task-zsty", - }, - ], - }, - ], - }, - { - id: "comprehensive-management", - label: "综合管理", - icon: Settings, - children: [ - { id: "mgmt-agents", label: "智能体管理", icon: Bot, path: "/page/strategy/agents" }, - { id: "mgmt-skills", label: "技能管理", icon: Sparkles, path: "/page/strategy/skills" }, - { id: "mgmt-memory", label: "记忆管理", icon: Brain, path: "/page/strategy/memory" }, - { - id: "mgmt-tasks", - label: "定时任务", - icon: ListChecks, - path: "/page/strategy/scheduled/tasks", - }, - { - id: "mgmt-recommended-questions", - label: "推荐问题配置", - icon: MessageSquarePlus, - path: "/page/strategy/settings/recommended-questions", - adminOnly: true, - }, - { - id: "mgmt-prompt-prefix", - label: "问答前缀配置", - icon: MessageSquareCode, - path: "/page/strategy/settings/prompt-prefix", - adminOnly: true, - }, - { - id: "mgmt-private-square", - label: "私密广场配置", - icon: ShieldCheck, - path: "/page/strategy/settings/private-square", - adminOnly: true, - }, - { - id: "mgmt-llm-metrics", - label: "大模型调用统计", - icon: Gauge, - path: "/page/strategy/settings/llm-metrics", - adminOnly: true, - }, - { - id: "mgmt-users", - label: "用户管理", - icon: Users, - path: "/page/strategy/admin/users", - adminOnly: true, - }, - { - id: "mgmt-admin-scheduled-tasks", - label: "定时任务管理", - icon: CalendarClock, - path: "/page/strategy/admin/scheduled-tasks", - adminOnly: true, - }, - { - id: "mgmt-user-activity", - label: "用户活动审计", - icon: History, - path: "/page/strategy/admin/user-activity", - adminOnly: true, - }, - ], - }, - { - id: "resource-management", - label: "资源管理", - icon: Database, - children: [ - { - id: "resource-network-xwt", - label: "网络xwt资源管理", - icon: Network, - path: "/page/strategy/resource-management/resource-network-actor", - }, - { - id: "resource-knowledge-base", - label: "知识库资源管理", - icon: Library, - path: "/page/strategy/resource-management/resource-knowledge-base", - }, - { - id: "resource-evaluation-index", - label: "作战资源管理", - icon: FileBox, - path: "/page/strategy/resource-management/resource-evaluation-index", - }, - ], - }, -]; - -const defaultExpandedIds = new Set([ - "qa-center", - "light-app-center", - "light-app-note-management", - "task-management", - "xk-center-task", -]); - -function filterMenuItemsByRole(items: MenuItem[], isAdmin: boolean): MenuItem[] { - return items - .filter((item) => !item.adminOnly || isAdmin) - .map((item) => - item.children - ? { ...item, children: filterMenuItemsByRole(item.children, isAdmin) } - : item, - ); -} - export function PageSidebar({ collapsed, onToggleCollapsed, @@ -339,10 +45,11 @@ export function PageSidebar({ const { theme } = useTheme(); const isDark = theme === "dark"; const isAdmin = getStoredAuth()?.system_role === "admin"; - const visibleMenuItems = filterMenuItemsByRole(menuItems, !!isAdmin); + const visibleMenuItems = filterMenuItemsByRole(sidebarMenuItems, !!isAdmin); const { t } = useI18n(); const { data: unreadCount = 0 } = useUnreadCount(); - const [expandedIds, setExpandedIds] = useState>(defaultExpandedIds); + // defaultExpandedIds 是共享的 ReadonlySet,复制一份给 useState(避免外部突变) + const [expandedIds, setExpandedIds] = useState>(() => new Set(defaultExpandedIds)); const [settingsOpen, setSettingsOpen] = useState(false); const [settingsDefaultSection, setSettingsDefaultSection] = useState("appearance"); diff --git a/frontend-web/src/core/page-layout/sidebar-menu.ts b/frontend-web/src/core/page-layout/sidebar-menu.ts new file mode 100644 index 00000000..446d6be8 --- /dev/null +++ b/frontend-web/src/core/page-layout/sidebar-menu.ts @@ -0,0 +1,316 @@ +/** + * 全局侧边栏菜单数据与权限过滤逻辑。 + * + * 浅色 ``PageSidebar`` 和深色 ``PageSidebarDark`` 共用这份数据 —— 菜单结构与 + * adminOnly 权限策略对两种皮肤完全一致;UI 渲染(icon 显示/折叠样式/hover flyout) + * 在各自组件里实现。 + * + * 修改菜单只需改这一处,两个 sidebar 自动同步。 + */ +import type { ElementType } from "react"; +import { + Bot, + Brain, + CalendarClock, + CircleHelp, + Database, + FileBox, + FileText, + Folder, + Gauge, + Grid3X3, + HelpCircle, + History, + Layout, + Library, + List, + ListChecks, + ListTodo, + MessageSquareCode, + MessageSquarePlus, + Network, + NotebookPen, + Plus, + Settings, + ShieldCheck, + Sparkles, + Target, + Users, +} from "lucide-react"; + +export type MenuItem = { + id: string; + label: string; + icon: ElementType; + path?: string; + adminOnly?: boolean; + children?: MenuItem[]; +}; + +export const sidebarMenuItems: MenuItem[] = [ + { + id: "qa-center", + label: "问答中心", + icon: HelpCircle, + children: [ + { id: "general-qa", label: "通用问答", icon: CircleHelp, path: "/page/workspace/chats/new" }, + { id: "expert-qa", label: "专家问答", icon: Brain, path: "/page/strategy/qa/expert-qa" }, + // 「圆桌规划」入口暂时隐藏 —— 功能仍在 /page/roundtable/planning,只是不在侧边栏出现。 + // 需要重新开放时取消注释即可。 + // { + // id: "qa-roundtable", + // label: "圆桌规划", + // icon: Bot, + // path: "/page/roundtable/planning", + // }, + { id: "qa-zzjc", label: "zzjc支持", icon: Bot }, + { id: "qa-zzxd", label: "zzXD应用", icon: Layout }, + { id: "qa-research", label: "课题研究", icon: FileText, path: "/page/canvas/ai-writing" }, + ], + }, + { + id: "light-app-center", + label: "轻应用", + icon: Grid3X3, + children: [ + { + id: "light-app-note-management", + label: "笔记管理", + icon: NotebookPen, + children: [ + { + id: "light-app-new-note", + label: "新建笔记", + icon: Plus, + path: "/page/strategy/light-app/new-note", + }, + { + id: "light-app-note-list", + label: "笔记列表", + icon: List, + path: "/page/strategy/light-app/notes", + }, + { + id: "light-app-note-qa", + label: "笔记问答", + icon: MessageSquareCode, + path: "/page/strategy/light-app/note-qa", + }, + ], + }, + { id: "light-app-square", label: "应用广场", icon: Layout }, + { id: "light-app-records", label: "运行记录", icon: History }, + ], + }, + { + id: "task-management", + label: "任务管理", + icon: Target, + children: [ + { + id: "xk-center-task", + label: "XK中任务", + icon: Folder, + children: [ + { + id: "xk-task-jc", + label: "任务JC", + icon: ListTodo, + path: "/page/strategy/task-management/xk-task-jc", + }, + { + id: "xk-task-dispatch", + label: "任务调度", + icon: ListTodo, + path: "/page/strategy/task-management/xk-task-dispatch", + }, + ], + }, + { + id: "coh-center-task", + label: "COH中任务", + icon: Folder, + children: [ + { + id: "coh-task-3qfx", + label: "3QFX", + icon: ListTodo, + path: "/page/strategy/task-management/plan-task-sentiment", + }, + { + id: "coh-task-fx", + label: "任务FX", + icon: ListTodo, + path: "/page/strategy/task-management/plan-task/plan-task-fx", + }, + { + id: "coh-task-xdfx", + label: "XDFX", + icon: ListTodo, + path: "/page/strategy/task-management/plan-task/plan-task-action", + }, + ], + }, + { + id: "pg-center-task", + label: "PG中任务", + icon: Folder, + children: [ + { + id: "pg-task-pg", + label: "任务PG", + icon: ListTodo, + path: "/page/strategy/task-management/effect-task-pg", + }, + { + id: "pg-task-xdpg", + label: "XDPG", + icon: ListTodo, + path: "/page/strategy/task-management/effect-action-pg", + }, + { + id: "pg-task-info-pg", + label: "信息PG", + icon: ListTodo, + path: "/page/strategy/task-management/effect-info-pg", + }, + ], + }, + { + id: "ty-center-task", + label: "TY中任务", + icon: Folder, + children: [ + { + id: "ty-task-xdty", + label: "XDTY任务", + icon: ListTodo, + path: "/page/strategy/task-management/mnty-task-mechanism", + }, + { + id: "ty-task-plan", + label: "方案TY任务", + icon: ListTodo, + path: "/page/strategy/task-management/mnty-task-plan", + }, + { + id: "ty-task-xxty", + label: "XXTY任务", + icon: ListTodo, + path: "/page/strategy/task-management/mnty-task-zsty", + }, + ], + }, + ], + }, + { + id: "comprehensive-management", + label: "综合管理", + icon: Settings, + children: [ + { id: "mgmt-agents", label: "智能体管理", icon: Bot, path: "/page/strategy/agents" }, + { id: "mgmt-skills", label: "技能管理", icon: Sparkles, path: "/page/strategy/skills" }, + { id: "mgmt-memory", label: "记忆管理", icon: Brain, path: "/page/strategy/memory" }, + { + id: "mgmt-tasks", + label: "定时任务", + icon: ListChecks, + path: "/page/strategy/scheduled/tasks", + }, + { + id: "mgmt-recommended-questions", + label: "推荐问题配置", + icon: MessageSquarePlus, + path: "/page/strategy/settings/recommended-questions", + adminOnly: true, + }, + { + id: "mgmt-prompt-prefix", + label: "问答前缀配置", + icon: MessageSquareCode, + path: "/page/strategy/settings/prompt-prefix", + adminOnly: true, + }, + { + id: "mgmt-private-square", + label: "私密广场配置", + icon: ShieldCheck, + path: "/page/strategy/settings/private-square", + adminOnly: true, + }, + { + id: "mgmt-llm-metrics", + label: "大模型调用统计", + icon: Gauge, + path: "/page/strategy/settings/llm-metrics", + adminOnly: true, + }, + { + id: "mgmt-users", + label: "用户管理", + icon: Users, + path: "/page/strategy/admin/users", + adminOnly: true, + }, + { + id: "mgmt-admin-scheduled-tasks", + label: "定时任务管理", + icon: CalendarClock, + path: "/page/strategy/admin/scheduled-tasks", + adminOnly: true, + }, + { + id: "mgmt-user-activity", + label: "用户活动审计", + icon: History, + path: "/page/strategy/admin/user-activity", + adminOnly: true, + }, + ], + }, + { + id: "resource-management", + label: "资源管理", + icon: Database, + children: [ + { + id: "resource-network-xwt", + label: "网络xwt资源管理", + icon: Network, + path: "/page/strategy/resource-management/resource-network-actor", + }, + { + id: "resource-knowledge-base", + label: "知识库资源管理", + icon: Library, + path: "/page/strategy/resource-management/resource-knowledge-base", + }, + { + id: "resource-evaluation-index", + label: "作战资源管理", + icon: FileBox, + path: "/page/strategy/resource-management/resource-evaluation-index", + }, + ], + }, +]; + +/** 默认展开的菜单 id 集合(浅色版可折叠交互的初始状态) */ +export const defaultExpandedIds: ReadonlySet = new Set([ + "qa-center", + "light-app-center", + "light-app-note-management", + "task-management", + "xk-center-task", +]); + +/** 按 admin 角色过滤菜单:非 admin 不展示 ``adminOnly: true`` 的项及其子项 */ +export function filterMenuItemsByRole(items: MenuItem[], isAdmin: boolean): MenuItem[] { + return items + .filter((item) => !item.adminOnly || isAdmin) + .map((item) => + item.children + ? { ...item, children: filterMenuItemsByRole(item.children, isAdmin) } + : item, + ); +}