diff --git a/frontend-web/src/components/workspace/agents/agent-module-sidebar.tsx b/frontend-web/src/components/workspace/agents/agent-module-sidebar.tsx index 54a8902f..d0712ccb 100644 --- a/frontend-web/src/components/workspace/agents/agent-module-sidebar.tsx +++ b/frontend-web/src/components/workspace/agents/agent-module-sidebar.tsx @@ -107,33 +107,11 @@ function groupAgentsByTag(agents: Agent[], allowedTagIds: string[]): AgentGroup[ return groups; } -/** - * 「按类型聚合智能体 + 聊天记录」左栏(需求 0616 #3 zzJC / #4 zzXD)。 - * - * - 上半:可见智能体按标签(类型)分组、可折叠;点击进入该智能体对话(保持当前路由 - * 命名空间,全量模式下为 /page/strategy)。 - * - 下半:聊天记录 —— 仅与本模块智能体(即左栏列出的智能体)的会话,按 metadata.agent_id 过滤。 - * - 宽度与通用问答左栏一致(``--sidebar-width``)。 - */ -export function AgentModuleSidebar({ - moduleKey, - activeAgentId, - onOpenSettings, -}: { - moduleKey: string; - activeAgentId?: string; - /** 传入则在左栏顶部显示设置齿轮(admin)。 */ - onOpenSettings?: () => void; -}) { - const routeBase = useRouteBase(); - const pathname = usePathname(); - // 智能体图标配色分主题:深蓝主题用规范蓝-青系,其它(浅色)保持原高彩度色,互不影响。 - const { theme } = useTheme(); - const isDark = theme === "dark"; - const { agents } = useAgents(); +export function useAgentModuleSidebarData(moduleKey: string) { + const { agents, isLoading: agentsLoading } = useAgents(); const { data: threads = [] } = useThreads(); - const { data: moduleConfig } = useAgentModuleConfig(moduleKey); - const [collapsed, setCollapsed] = useState>(() => new Set()); + const { data: moduleConfig, isLoading: configLoading } = + useAgentModuleConfig(moduleKey); const allowedTagIds = useMemo( () => moduleConfig?.tag_ids ?? [], @@ -161,6 +139,56 @@ export function AgentModuleSidebar({ [threads, moduleAgentIds], ); + return { + groups, + moduleAgentIds, + moduleThreads, + allowedTagIds, + // admin 是否已确认该模块展示的智能体类型(配置了标签)。 + hasConfiguredType: allowedTagIds.length > 0, + isLoading: agentsLoading || configLoading, + }; +} + +/** + * 「按类型聚合智能体 + 聊天记录」左栏(需求 0616 #3 zzJC / #4 zzXD)。 + * + * - 上半:可见智能体按标签(类型)分组、可折叠;点击进入该智能体对话(保持当前路由 + * 命名空间,全量模式下为 /page/strategy)。 + * - 下半:聊天记录 —— 仅与本模块智能体(即左栏列出的智能体)的会话,按 metadata.agent_id 过滤。 + * - 宽度与通用问答左栏一致(``--sidebar-width``)。 + */ +export function AgentModuleSidebar({ + moduleKey, + activeAgentId, + activeThreadId, + routeBase: routeBaseProp, + headerTitle = "智能体", + className, + onOpenSettings, +}: { + moduleKey: string; + activeAgentId?: string; + activeThreadId?: string; + routeBase?: string; + headerTitle?: string; + className?: string; + /** 传入则在左栏顶部显示设置齿轮(admin)。 */ + onOpenSettings?: () => void; +}) { + const contextRouteBase = useRouteBase(); + const routeBase = routeBaseProp ?? contextRouteBase; + const pathname = usePathname(); + // 智能体图标配色分主题:深蓝主题用规范蓝-青系,其它(浅色)保持原高彩度色,互不影响。 + const { theme } = useTheme(); + const isDark = theme === "dark"; + const [collapsed, setCollapsed] = useState>(() => new Set()); + const { groups, moduleThreads, hasConfiguredType } = + useAgentModuleSidebarData(moduleKey); + // 已确认智能体类型时,允许把上半「智能体类型」整块收起,把空间让给下半聊天记录。 + const [agentsSectionCollapsed, setAgentsSectionCollapsed] = useState(false); + const agentsCollapsed = hasConfiguredType && agentsSectionCollapsed; + const toggleGroup = (key: string) => setCollapsed((prev) => { const next = new Set(prev); @@ -169,14 +197,68 @@ export function AgentModuleSidebar({ return next; }); + // 已确认类型时把所有分组的智能体拍平(单选类型一般只有一个分组), + // 标题行直接显示该类型名 + 数量,去掉额外的分组行。 + const flatAgents = useMemo(() => groups.flatMap((g) => g.agents), [groups]); + const configuredTypeLabel = + groups.length === 1 ? (groups[0]?.label ?? "智能体类型") : "智能体类型"; + + const renderAgentCard = (agent: Agent, keyPrefix: string) => { + const href = `${routeBase}/agents/${agent.id}/chats/new`; + const isActive = agent.id === activeAgentId; + const { from, to } = agentColor(agent.id, isDark); + return ( + + + + + + + {desensitize(agent.name)} + + + {agent.description ? desensitize(agent.description) : "智能体助手"} + + + {isActive && ( + + )} + + ); + }; + return ( // 原有布局不变,仅做配色适配:深色下左栏改为半透明深蓝玻璃面板(对齐 .sidebar-contents: // bg rgba(3,38,80,.8) + 蓝色发光边框),叠 backdrop-blur 让外壳的深蓝底图朦胧透出; // 浅色保持白底。其余颜色已走语义 token 自适配。 -