import React, { useState } from "react"; import { Link, useLocation } from "react-router-dom"; import { BarChart3, Bot, Brain, ChevronLeft, ChevronRight, CircleHelp, Compass, Database, FileBox, FileOutput, FileText, Folder, FolderOpen, Grid3X3, HelpCircle, History, Layers, Layout, Library, ListTodo, MessageSquare, MoreHorizontal, Network, PlayCircle, Plus, Scale, Target, TrendingUp, Users, Workflow, } from "lucide-react"; import { useTheme } from "../contexts/ThemeContext"; export type PageType = string; type MenuItem = { id: PageType; label: string; icon: React.ElementType; children?: MenuItem[]; path?: string; activePath?: string; }; type Props = { currentPage: PageType; isCollapsed?: boolean; onToggleCollapse?: () => void; }; type Level1MenuId = | "qa-center" | "light-app-center" | "task-management" | "agent-list" | "result-management" | "resource-management"; type TaskGroupId = string; const taskGroups: TaskGroupId[] = [ "xk-task", "plan-task", "mnty-task", "effect-task", ]; const collapsibleMenus = new Set([ "qa-center", "light-app-center", "task-management", "agent-list", "result-management", "resource-management", ]); const taskPages = new Set([ "dashboard", "task-create", "task-single", "task-scene", "task-consult-create", "task-consult", "task-consult-result", "task-list", ]); const qaPages = new Set([ "new-qa", "general-qa", "agent-qa", "multi-agent-qa", "qa-records", "sixstep-chat", "topic-research", "task-chat", "action-chat", "qa-from", "qa-from-6bf" ]); const lightAppPages = new Set([ "light-app-square", "light-app-records", "light-app-run", ]); const agentPages = new Set(["agent-trial"]); const resultPages = new Set([ "result-planning", "result-mnty", "result-effect-pg", "result-xk", "result-dq", "result-other", "result-detail", ]); const resourcePages = new Set([ "resource-zz", "resource-network-actor", "resource-knowledge-base", "resource-evaluation-index", ]); const menuItems: MenuItem[] = [ { id: "qa-center", label: "问答管理", icon: HelpCircle, children: [ { id: "qa-from", label: "通用问答", icon: Bot }, // general-qa // { id: 'sixstep-chat', label: 'zz决策支持', icon: Layers }, { id: "qa-from-6bf", label: "zz决策支持", icon: Layers }, { id: "action-chat", label: "zzXD应用", icon: History }, { id: "topic-research", label: "课题研究", icon: CircleHelp }, // { id: 'agent-qa', label: '智能体问答', icon: Bot }, // { id: 'multi-agent-qa', label: '多智能体协同', icon: Layers }, // { id: 'qa-records', label: '问答记录', icon: History }, ], }, { id: "task-management", label: "任务管理", icon: Target, children: [ // { id: "dashboard", label: "任务统计", icon: BarChart3 }, { id: "xk-task", label: "XK中任务", icon: Folder, children: [ { id: "xk-task-jc", label: "任务JC", icon: ListTodo }, { id: "xk-task-dispatch", label: "任务调度", icon: ListTodo }, ], }, { id: "plan-task", label: "COH中任务", icon: Folder, children: [ { id: "plan-task-sentiment", label: "三情FX", icon: ListTodo }, { id: "plan-task-fx", label: "任务FX", icon: ListTodo }, { id: "plan-task-action", label: "行动CE", icon: ListTodo }, ], }, { id: "effect-task", label: "PG中任务", icon: Folder, children: [ { id: "effect-task-pg", label: "任务PG", icon: ListTodo }, { id: "effect-action-pg", label: "行动PG", icon: ListTodo }, { id: "effect-info-pg", label: "信息PG", icon: ListTodo }, // { id: "effect-account-pg", label: "账号PG", icon: ListTodo }, ], }, { id: "mnty-task", label: "TY中任务", icon: Folder, children: [ { id: "mnty-task-mechanism", label: "XDTY任务", icon: ListTodo }, { id: "mnty-task-plan", label: "方案TY任务", icon: ListTodo }, { id: "mnty-task-zsty", label: "XXTY任务", icon: ListTodo }, ], }, ], }, // { // id: 'light-app-center', label: '工具管理', icon: Grid3X3, // children: [ // { id: 'light-app-square', label: '应用广场', icon: Layout }, // { id: 'light-app-records', label: '运行记录', icon: History }, // { id: 'scene-list', label: '场景管理', icon: Layers }, // ] // }, { id: "agent-list", label: " 综合管理", icon: Bot, children: [ // { id: 'agent-list', label: '业务链条管理', icon: Users }, // { id: 'agent-list', label: '智能体管理', icon: Users }, { id: "agent-expert-center", label: "智能体管理", icon: Users }, { id: 'scene-list', label: '业务链条管理', icon: Layers }, // { id: "skills-workshop", label: "技能列表", icon: Users }, // { id: "sixstep-agents", label: "mcp管理", icon: Layers }, // { id: "file-skills", label: "skills管理", icon: Layers }, // { id: 'agent-trial', label: '单智能体试用', icon: PlayCircle } ], }, // { id: 'result-management', label: '结果管理', icon: BarChart3, children: [ // { id: 'result-planning', label: '规划任务', icon: Target, children: [ // { id: 'result-planning-all', label: '全部', icon: BarChart3, path: '/result-management/result-planning', activePath: '/result-management/result-planning' }, // { id: 'result-planning-goal', label: '目标分析', icon: Target, path: '/result-management/result-planning?subCategory=目标分析' }, // { id: 'result-planning-brand', label: '品牌策略', icon: Target, path: '/result-management/result-planning?subCategory=品牌策略' }, // { id: 'result-planning-content', label: '内容规划', icon: Target, path: '/result-management/result-planning?subCategory=内容规划' }, // { id: 'result-planning-channel', label: '渠道规划', icon: Target, path: '/result-management/result-planning?subCategory=渠道规划' }, // { id: 'result-planning-narrative', label: '叙事策略', icon: Target, path: '/result-management/result-planning?subCategory=叙事策略' }, // ] }, // { id: 'result-mnty', label: 'MNTY任务', icon: Brain, children: [ // { id: 'result-mnty-all', label: '全部', icon: BarChart3, path: '/result-management/result-mnty', activePath: '/result-management/result-mnty' }, // { id: 'result-mnty-mechanism', label: '机制研究', icon: Brain, path: '/result-management/result-mnty?subCategory=机制研究' }, // { id: 'result-mnty-plan', label: '方案设计', icon: Brain, path: '/result-management/result-mnty?subCategory=方案设计' }, // { id: 'result-mnty-zsty', label: 'ZSTY分析', icon: Brain, path: '/result-management/result-mnty?subCategory=ZSTY分析' }, // ] }, // { id: 'result-effect-pg', label: '效果PG任务', icon: TrendingUp, children: [ // { id: 'result-effect-pg-all', label: '全部', icon: BarChart3, path: '/result-management/result-effect-pg', activePath: '/result-management/result-effect-pg' }, // { id: 'result-effect-pg-behavior', label: '行为PG', icon: TrendingUp, path: '/result-management/result-effect-pg?subCategory=行为PG' }, // { id: 'result-effect-pg-evaluation', label: '效果评估', icon: TrendingUp, path: '/result-management/result-effect-pg?subCategory=效果评估' }, // { id: 'result-effect-pg-info', label: '信息PG', icon: TrendingUp, path: '/result-management/result-effect-pg?subCategory=信息PG' }, // { id: 'result-effect-pg-account', label: '账号PG', icon: TrendingUp, path: '/result-management/result-effect-pg?subCategory=账号PG' }, // ] }, // { id: 'result-xk', label: 'XK任务', icon: Compass, children: [ // { id: 'result-xk-all', label: '全部', icon: BarChart3, path: '/result-management/result-xk', activePath: '/result-management/result-xk' }, // { id: 'result-xk-jc', label: '任务JC', icon: Compass, path: '/result-management/result-xk?subCategory=任务JC' }, // { id: 'result-xk-dispatch', label: '任务调度', icon: Compass, path: '/result-management/result-xk?subCategory=任务调度' }, // ] }, // { id: 'result-dq', label: 'DQ研究类任务', icon: Database, children: [ // { id: 'result-dq-all', label: '全部', icon: BarChart3, path: '/result-management/result-dq', activePath: '/result-management/result-dq' }, // { id: 'result-dq-audience', label: '受众分析', icon: Database, path: '/result-management/result-dq?subCategory=受众分析' }, // { id: 'result-dq-kb', label: '知识库研究', icon: Database, path: '/result-management/result-dq?subCategory=知识库研究' }, // { id: 'result-dq-trend', label: '趋势研究', icon: Database, path: '/result-management/result-dq?subCategory=趋势研究' }, // ] }, // { id: 'result-other', label: '其他类任务', icon: MoreHorizontal, children: [ // { id: 'result-other-all', label: '全部', icon: BarChart3, path: '/result-management/result-other', activePath: '/result-management/result-other' }, // { id: 'result-other-general', label: '通用分析', icon: MoreHorizontal, path: '/result-management/result-other?subCategory=通用分析' }, // { id: 'result-other-temp', label: '临时任务', icon: MoreHorizontal, path: '/result-management/result-other?subCategory=临时任务' }, // { id: 'result-other-other', label: '其他', icon: MoreHorizontal, path: '/result-management/result-other?subCategory=其他' }, // ] }, // ] }, { id: "resource-management", label: "资源管理", icon: Database, children: [ // { id: "resource-zz", label: "ZZ资源管理", icon: FileBox }, { id: "resource-network-actor", label: "网络行为体资源管理", icon: Network, }, { id: "resource-knowledge-base", label: "知识库资源管理", icon: Library }, { id: "resource-evaluation-index", label: "作战资源管理", icon: Library }, // { // id: "resource-evaluation-index", // label: "评估指标体系资源管理", // icon: Scale, // }, ], }, ]; const subEntries = [ // { id: 'task-create', label: '新建任务', icon: ListTodo, parent: 'task-management' }, // { id: 'task-single', label: '单智能体任务', icon: Bot, parent: 'task-management' }, // { id: 'task-scene', label: '场景任务', icon: Workflow, parent: 'task-management' }, // { id: 'task-consult-create', label: '多智能体会商', icon: MessageSquare, parent: 'task-management' }, // { id: 'final-plan', label: '方案输出', icon: FileOutput, parent: 'strategy-result' }, ]; const getPath = (id: PageType) => { if (taskGroups.includes(id as TaskGroupId)) { console.log('----task-management', id); return `/task-management/${id}`; } if (taskGroups.some((group) => id.startsWith(group))) { return `/task-management/${id.split("-").slice(0, 2).join("-")}/${id}`; } // 特殊处理 effect-task 下的子菜单项(effect-action-pg, effect-info-pg, effect-account-pg) if (id.startsWith("effect-") && !id.startsWith("effect-task")) { return `/task-management/effect-task/${id}`; } if (taskPages.has(id)) return `/task-management/${id}`; if (qaPages.has(id)) return `/qa-center/${id}`; if (id === "qa-center") return "/qa-center"; if (lightAppPages.has(id)) return `/light-app-center/${id}`; if (agentPages.has(id)) return `/agent-list/${id}`; if (resultPages.has(id)) return `/result-management/${id}`; if (resourcePages.has(id)) return `/resource-management/${id}`; return `/${id}`; }; const toggleSet = (set: Set, item: T) => { const next = new Set(set); next.has(item) ? next.delete(item) : next.add(item); return next; }; export default function Sidebar({ currentPage, isCollapsed = false, onToggleCollapse, }: Props) { const { theme } = useTheme(); const location = useLocation(); const isDark = theme === "dark"; const [collapsedMenus, setCollapsedMenus] = useState>( new Set() ); const [expandedTaskGroups, setExpandedTaskGroups] = useState>( () => new Set([ ...taskGroups.filter((group) => currentPage.startsWith(group)), ...(currentPage.startsWith("result-") ? [currentPage] : []), ]) ); const panel = `ml-4 pl-4 border-l space-y-1 theme-transition ${ isDark ? "border-blue-800/30" : "border-red-100" }`; const iconBtn = `rounded-lg transition-all duration-200 ${ isDark ? "text-slate-400 hover:text-white hover:bg-slate-800/50" : "text-gray-500 hover:text-red-600 hover:bg-red-50" }`; const itemClass = (active: boolean) => `rounded-lg transition-all duration-200 theme-transition ${ active ? isDark ? "bg-blue-600/20 text-blue-400 border border-blue-500/30" : "bg-red-50 text-red-600 border border-red-200" : isDark ? "text-slate-400 hover:text-white hover:bg-slate-800/50" : "text-gray-600 hover:text-red-600 hover:bg-red-50" }`; const isTopActive = (id: PageType) => { if (id === "qa-center") return qaPages.has(currentPage); if (id === "light-app-center") return currentPage.startsWith("light-app"); if (id === "task-management") return ( currentPage === "dashboard" || taskPages.has(currentPage) || taskGroups.some((group) => currentPage.startsWith(group)) ); if (id === "scene-list") return currentPage.startsWith("scene"); if (id === "agent-list") return currentPage.startsWith("agent"); if (id === "result-management") return currentPage.startsWith("result"); if (id === "resource-management") return currentPage.startsWith("resource"); return currentPage === id; }; const hasActiveChild = (item: MenuItem): boolean => currentPage === item.id || Boolean(item.children?.some(hasActiveChild)); const renderLink = (item: MenuItem, top = false) => { const Icon = item.icon; const activePath = decodeURI(`${location.pathname}${location.search}`); const active = top ? isTopActive(item.id) : item.path ? activePath === (item.activePath ?? item.path) : currentPage === item.id; return ( top && item.id === "task-management" && expandedTaskGroups.size === 0 && setExpandedTaskGroups(new Set(["xk-task"])) } title={isCollapsed ? item.label : undefined} className={`${top ? "flex-1" : "w-full"} flex items-center ${ isCollapsed && top ? "justify-center gap-0 px-2" : "gap-2 px-3" } py-2 ${itemClass(active)}`} > {(!isCollapsed || !top) && ( {item.label} )} ); }; const renderTaskGroup = (item: MenuItem) => { const expanded = expandedTaskGroups.has(item.id); const active = hasActiveChild(item); const Icon = expanded ? FolderOpen : Folder; return (
{expanded && item.children && (
{item.children.map((child) => renderLink(child))}
)}
); }; const renderChildren = (item: MenuItem) => item.children ? (
{item.children.map((child) => child.children ? renderTaskGroup(child) : renderLink(child) )}
) : null; const renderSubEntries = (item: MenuItem) => { const entries = subEntries.filter((entry) => entry.parent === item.id); return entries.length && isTopActive(item.id) ? (
{entries.map((entry) => renderLink(entry))}
) : null; }; return ( ); }