From 19c76950db69b74afb7c12afe9cd5c527b041d07 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 26 Mar 2026 17:12:16 +0800 Subject: [PATCH] feat: add collapsible workflow child settings --- .../agent-workflow-settings-client.tsx | 375 +++++++++++------- 1 file changed, 226 insertions(+), 149 deletions(-) diff --git a/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx b/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx index 9022fc6d1..98cb4a4bb 100644 --- a/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx +++ b/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx @@ -487,6 +487,12 @@ export function AgentWorkflowSettingsClient({ const [isSaving, setIsSaving] = useState(false); const [uploadingKey, setUploadingKey] = useState(null); const [expandedSteps, setExpandedSteps] = useState>(new Set()); + const [expandedWorkflowOptions, setExpandedWorkflowOptions] = useState>( + {} + ); + const [expandedPresetLibraryNodes, setExpandedPresetLibraryNodes] = useState< + Record + >({}); const [activeTab, setActiveTab] = useState("showcase"); const [brandDraft, setBrandDraft] = useState(""); const [priceBandDraft, setPriceBandDraft] = useState(""); @@ -520,6 +526,8 @@ export function AgentWorkflowSettingsClient({ setBrandModelConfig( normalizeAgentWorkflowBrandModelConfig(data.agentWorkflowBrandModelConfig) ); + setExpandedWorkflowOptions({}); + setExpandedPresetLibraryNodes({}); if (flattenedUiConfig.steps[0]) { setExpandedSteps(new Set([flattenedUiConfig.steps[0].key])); } @@ -862,6 +870,26 @@ export function AgentWorkflowSettingsClient({ }); }; + const isWorkflowOptionExpanded = (optionKey: string, depth: number) => + expandedWorkflowOptions[optionKey] ?? depth === 1; + + const toggleWorkflowOptionExpansion = (optionKey: string, depth: number) => { + setExpandedWorkflowOptions((prev) => ({ + ...prev, + [optionKey]: !(prev[optionKey] ?? depth === 1), + })); + }; + + const isPresetLibraryNodeExpanded = (nodeId: string, depth: number) => + expandedPresetLibraryNodes[nodeId] ?? depth === 1; + + const togglePresetLibraryNodeExpansion = (nodeId: string, depth: number) => { + setExpandedPresetLibraryNodes((prev) => ({ + ...prev, + [nodeId]: !(prev[nodeId] ?? depth === 1), + })); + }; + const updateStep = ( stepKey: string, updater: (step: AgentWorkflowUiConfig["steps"][number]) => AgentWorkflowUiConfig["steps"][number] @@ -1037,91 +1065,112 @@ export function AgentWorkflowSettingsClient({ const sortedChildren = [...(node.children || [])].sort( (left, right) => left.sortOrder - right.sortOrder ); + const isExpanded = isPresetLibraryNodeExpanded(node.id, depth); return (
1 && "pl-4 sm:pl-6")}> - 1 && "border-l-4 border-l-sky-500/30")}> - -
-
-
- {indexPath.join(".")} -
-
-
- - updatePresetLibraryNode(sectionId, node.id, (currentNode) => ({ - ...currentNode, - name: e.target.value, - })) - } - className="h-8 min-w-[200px] max-w-[320px] border-0 bg-transparent px-0 text-base font-medium shadow-none focus-visible:ring-0" - placeholder="分类名称" - /> - {levelLabel} - - {node.id} - + togglePresetLibraryNodeExpansion(node.id, depth)} + > + 1 && "border-l-4 border-l-sky-500/30")}> + +
+
+ + + +
+ {indexPath.join(".")} +
+
+
+ + updatePresetLibraryNode(sectionId, node.id, (currentNode) => ({ + ...currentNode, + name: e.target.value, + })) + } + className="h-8 min-w-[200px] max-w-[320px] border-0 bg-transparent px-0 text-base font-medium shadow-none focus-visible:ring-0" + placeholder="分类名称" + /> + {levelLabel} + + {node.id} + +
-
-
- {sortedChildren.length} 子分类 - {canAddChild ? ( +
+ {sortedChildren.length} 子分类 + {canAddChild ? ( + + ) : ( + 已达三级 + )} + + updatePresetLibraryNode(sectionId, node.id, (currentNode) => ({ + ...currentNode, + enabled: checked, + })) + } + /> - ) : ( - 已达三级 - )} - - updatePresetLibraryNode(sectionId, node.id, (currentNode) => ({ - ...currentNode, - enabled: checked, - })) - } - /> - +
-
- + - - {sortedChildren.length > 0 ? ( -
- {sortedChildren.map((childNode, childIndex) => - renderPresetLibraryNodeCard(sectionId, childNode, depth + 1, [ - ...indexPath, - childIndex + 1, - ]) + + + {sortedChildren.length > 0 ? ( +
+ {sortedChildren.map((childNode, childIndex) => + renderPresetLibraryNodeCard(sectionId, childNode, depth + 1, [ + ...indexPath, + childIndex + 1, + ]) + )} +
+ ) : ( +
+ 暂无子分类 +
)} -
- ) : ( -
- 暂无子分类 -
- )} -
- + + + +
); }; @@ -1261,30 +1310,94 @@ export function AgentWorkflowSettingsClient({ const selectedBlockedItems = (option.blockedOptionKeys || []) .map((blockedKey) => optionLookup.get(blockedKey)) .filter((item): item is WorkflowOptionRelation => Boolean(item)); + const isExpanded = isWorkflowOptionExpanded(option.key, depth); return (
1 && "pl-4 sm:pl-6")}> -
1 && "border-l-4 border-l-sky-500/30" - )} + toggleWorkflowOptionExpansion(option.key, depth)} > -
-
-
- - {indexPath.join(".")} - - {levelLabel} - {sortedChildren.length} 子卡片 - - {option.key} - +
1 && "border-l-4 border-l-sky-500/30" + )} + > +
+
+
+ + + + + {indexPath.join(".")} + + {levelLabel} + {sortedChildren.length} 子卡片 + + {option.buttonName || "未命名卡片"} + + + {option.key} + +
+ {depth > 1 ? ( +
+ {isExpanded ? "已展开当前子卡片配置" : "当前子卡片已折叠,点击左侧箭头展开详细设置"} +
+ ) : null}
-
+
+ {canAddChild ? ( + + ) : ( + {`已达 ${AGENT_WORKFLOW_MAX_OPTION_DEPTH} 级`} + )} + + + updateOption(step.key, option.key, (currentOption) => ({ + ...currentOption, + enabled: checked, + })) + } + className="scale-75" + /> +
+
+ + +
{option.previewImageUrl ? ( @@ -1473,70 +1586,34 @@ export function AgentWorkflowSettingsClient({
-
- -
- {canAddChild ? ( - - ) : ( - {`已达 ${AGENT_WORKFLOW_MAX_OPTION_DEPTH} 级`} - )} - - - updateOption(step.key, option.key, (currentOption) => ({ - ...currentOption, - enabled: checked, - })) - } - className="scale-75" - /> -
-
- -
-
-
-
子卡片配置
-
- {`当前卡片下可继续建立最多 ${AGENT_WORKFLOW_MAX_OPTION_DEPTH} 级卡片母子关系。`} +
+
+
+
子卡片配置
+
+ {`当前卡片下可继续建立最多 ${AGENT_WORKFLOW_MAX_OPTION_DEPTH} 级卡片母子关系。`} +
+
-
-
- {sortedChildren.length > 0 ? ( -
- {sortedChildren.map((childOption, childIndex) => - renderWorkflowOptionCard(step, childOption, depth + 1, [ - ...indexPath, - childIndex + 1, - ]) + {sortedChildren.length > 0 ? ( +
+ {sortedChildren.map((childOption, childIndex) => + renderWorkflowOptionCard(step, childOption, depth + 1, [ + ...indexPath, + childIndex + 1, + ]) + )} +
+ ) : ( +
+ 暂无子卡片 +
)}
- ) : ( -
- 暂无子卡片 -
- )} +
-
+
); };