代码修改

This commit is contained in:
fengxiangdebaozi committed 2026-05-27 19:43:15 +08:00
1 parent 8f5af46ec2
commit 8f75e12871
168 files changed
+76575

No files matched your search

+572
View File
@@ -0,0 +1,572 @@
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<PageType>([
"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 = <T,>(set: Set<T>, 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<Set<Level1MenuId>>(
new Set()
);
const [expandedTaskGroups, setExpandedTaskGroups] = useState<Set<string>>(
() =>
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 (
<Link
key={item.id}
to={item.path ?? getPath(item.id)}
onClick={() =>
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)}`}
>
<Icon
className={`${top ? "w-5 h-5" : "w-4 h-4"} flex-shrink-0 ${
active ? (isDark ? "text-blue-400" : "text-red-500") : ""
}`}
/>
{(!isCollapsed || !top) && (
<span
className={`${
top ? "text-sm" : "text-xs"
} font-medium flex-1 text-left`}
>
{item.label}
</span>
)}
</Link>
);
};
const renderTaskGroup = (item: MenuItem) => {
const expanded = expandedTaskGroups.has(item.id);
const active = hasActiveChild(item);
const Icon = expanded ? FolderOpen : Folder;
return (
<div key={item.id} className="space-y-1">
<button
type="button"
onClick={() =>
setExpandedTaskGroups((prev) => toggleSet(prev, item.id))
}
className={`w-full flex items-center gap-2 px-3 py-2 ${itemClass(
active
)}`}
>
<Icon
className={`w-4 h-4 flex-shrink-0 ${
active ? (isDark ? "text-blue-400" : "text-red-500") : ""
}`}
/>
<span className="text-xs font-medium flex-1 text-left">
{item.label}
</span>
<ChevronRight
className={`w-4 h-4 transition-transform duration-200 ${
expanded ? "rotate-90" : ""
}`}
/>
</button>
{expanded && item.children && (
<div className={panel}>
{item.children.map((child) => renderLink(child))}
</div>
)}
</div>
);
};
const renderChildren = (item: MenuItem) =>
item.children ? (
<div className={panel}>
{item.children.map((child) =>
child.children ? renderTaskGroup(child) : renderLink(child)
)}
</div>
) : null;
const renderSubEntries = (item: MenuItem) => {
const entries = subEntries.filter((entry) => entry.parent === item.id);
return entries.length && isTopActive(item.id) ? (
<div className={panel}>{entries.map((entry) => renderLink(entry))}</div>
) : null;
};
return (
<aside
className={`fixed left-0 top-0 h-screen ${
isCollapsed ? "w-16" : "w-64"
} z-50 theme-transition overflow-y-auto ${
isDark
? "bg-slate-900/80 backdrop-blur-xl border-r border-blue-800/30"
: "bg-white border-r border-red-100 shadow-sm"
}`}
>
<div
className={`h-16 flex items-center ${
isCollapsed ? "justify-center px-2" : "justify-between px-6"
} border-b theme-transition flex-shrink-0 ${
isDark ? "border-blue-800/30" : "border-red-100"
}`}
>
<div className="flex items-center gap-3 min-w-0">
<div
className={`w-8 h-8 rounded-lg flex items-center justify-center flex-shrink-0 ${
isDark
? "bg-gradient-to-br from-blue-500 to-cyan-400"
: "bg-gradient-to-br from-red-500 to-red-400"
}`}
>
<FileText className="w-4 h-4 text-white" />
</div>
{!isCollapsed && (
<div>
<h1
className={`font-semibold text-sm ${
isDark ? "text-white" : "text-gray-900"
}`}
>
智能CM系统
</h1>
<p
className={`text-xs ${
isDark ? "text-blue-400/60" : "text-red-400/80"
}`}
>
Smart CM Platform
</p>
</div>
)}
</div>
{!isCollapsed && (
<button
type="button"
onClick={onToggleCollapse}
className={`p-2 ${iconBtn}`}
title="收起侧边栏"
>
<ChevronLeft className="w-4 h-4" />
</button>
)}
</div>
<nav className={`${isCollapsed ? "p-2" : "p-4"} space-y-2`}>
{isCollapsed && (
<button
type="button"
onClick={onToggleCollapse}
className={`w-full flex items-center justify-center p-2.5 ${iconBtn}`}
title="展开侧边栏"
>
<ChevronRight className="w-5 h-5" />
</button>
)}
{menuItems.map((item) => {
const canCollapse = collapsibleMenus.has(item.id);
const childrenCollapsed =
canCollapse && collapsedMenus.has(item.id as Level1MenuId);
return (
<div key={item.id} className="space-y-1">
<div className="flex items-center gap-2">
{renderLink(item, true)}
{!isCollapsed && item.children && canCollapse && (
<button
type="button"
onClick={() =>
setCollapsedMenus((prev) =>
toggleSet(prev, item.id as Level1MenuId)
)
}
className={`p-1.5 ${iconBtn}`}
title={childrenCollapsed ? "展开菜单" : "折叠菜单"}
>
<ChevronRight
className={`w-4 h-4 transition-transform duration-200 ${
childrenCollapsed ? "" : "rotate-90"
}`}
/>
</button>
)}
</div>
{!isCollapsed &&
item.children &&
!childrenCollapsed &&
renderChildren(item)}
{!isCollapsed && !childrenCollapsed && renderSubEntries(item)}
</div>
);
})}
</nav>
{isDark ? (
<>
<div className="absolute top-0 right-0 w-32 h-32 bg-blue-500/10 rounded-full blur-3xl pointer-events-none" />
<div className="absolute bottom-20 right-0 w-24 h-24 bg-cyan-500/10 rounded-full blur-3xl pointer-events-none" />
</>
) : (
<>
<div className="absolute top-0 right-0 w-32 h-32 bg-red-500/5 rounded-full blur-3xl pointer-events-none" />
<div className="absolute bottom-20 right-0 w-24 h-24 bg-red-400/5 rounded-full blur-3xl pointer-events-none" />
</>
)}
</aside>
);
}