"use client"; import { useEffect, useMemo, useState, type ReactNode } from "react"; import { motion } from "framer-motion"; import { ArrowRight, Check, Copy, Sparkles, ChevronRight } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { SearchableSelect } from "@/components/ui/searchable-select"; import { Textarea } from "@/components/ui/textarea"; import { cn } from "@/lib/utils"; import { getAgentWorkflowCategoryLabels, defaultAgentWorkflowUiConfig, flattenAgentWorkflowSteps, flattenVisibleAgentWorkflowSteps, getAgentWorkflowBlockedOptionKeysForSelections, getAgentWorkflowBrandStoreEntries, getAgentWorkflowFourthCategoryOptionsByBrandStoreThirdCategory, getAgentWorkflowPriceBandOptions, getAgentWorkflowThirdCategoryOptionsByBrandStore, getAgentWorkflowSelectedOptionPath, getAgentWorkflowStoreOptionsByBrand, getEnabledAgentWorkflowOptionTree, getEnabledAgentWorkflowStepTree, getRenderableAgentWorkflowOptionTree, getRenderableAgentWorkflowStepTree, isAgentWorkflowStepSelectionComplete, serializeAgentWorkflowSelectionPath, } from "@/lib/agents/workflow-ui-config"; import { AgentCanvasTopNavDark } from "@/components/agents/AgentCanvasTopNavDark"; import { AgentWorkflowShowcaseBanner } from "@/components/agents/AgentWorkflowShowcaseBanner"; import { buildAgentWorkflowComposerContext, getAgentWorkflowProgress, } from "@/lib/agents/workflow-composer"; import { getAgentPsdTemplateCategoryTagsByBrand, normalizeAgentPsdTemplateCategoryTagIndex, type AgentPsdTemplateCategoryTagIndex, } from "@/lib/agents/psd-template-category-tag-config"; import type { AgentWorkflowComposerSelection, AgentWorkflowMaterialSelections, AgentWorkflowShowcaseConfig, AgentWorkflowStepKey, AgentWorkflowUiConfig, } from "@/types/agent"; export interface AgentWorkflowInputs { primarySku: string; secondarySku: string; brand: string; store: string; thirdCategory: string; fourthCategory: string; fifthCategory: string; priceBand: string; } interface AgentWorkflowPanelDarkV2Props { config?: AgentWorkflowUiConfig | null; inputs: AgentWorkflowInputs; onInputsChange: (next: AgentWorkflowInputs) => void; psdTemplateCategoryTagIndex?: AgentPsdTemplateCategoryTagIndex | null; materials: AgentWorkflowMaterialSelections; onMaterialsChange: (next: AgentWorkflowMaterialSelections) => void; selections: Partial>; onSelectionsChange: (next: Partial>) => void; onReset?: () => void; onNextStep?: () => void; onSkipStep?: () => void; siteName?: string | null; siteLogo?: string | null; siteLogoDark?: string | null; showcaseConfig?: AgentWorkflowShowcaseConfig | null; topNavRightSlot?: ReactNode; embedded?: boolean; showBrandStoreSection?: boolean; } interface AgentWorkflowBrandStorePanelProps { config?: AgentWorkflowUiConfig | null; inputs: AgentWorkflowInputs; onInputsChange: (next: AgentWorkflowInputs) => void; psdTemplateCategoryTagIndex?: AgentPsdTemplateCategoryTagIndex | null; theme?: "light" | "dark"; title?: string; description?: string; } function buildSelectionSummary(params: { config: AgentWorkflowUiConfig; selections: Partial>; }) { const result: AgentWorkflowComposerSelection[] = []; for (const { step } of flattenVisibleAgentWorkflowSteps(params.config.steps, params.selections)) { const selectedOptions = getAgentWorkflowSelectedOptionPath({ step, selectionValue: params.selections[step.key], }); selectedOptions.forEach((option) => { result.push({ stepKey: step.key, stepTitle: step.title, optionKey: option.key, optionName: option.buttonName, promptFragment: option.promptFragment || "", }); }); } return result; } function getWorkflowStepSelectionSummary(params: { step: AgentWorkflowUiConfig["steps"][number]; selectionValue?: string; }) { const selectedOptions = getAgentWorkflowSelectedOptionPath({ step: params.step, selectionValue: params.selectionValue, }); if (selectedOptions.length === 0) { return ""; } return selectedOptions.map((option) => option.buttonName).join(" / "); } function getWorkflowStepOptionLevels(params: { step: AgentWorkflowUiConfig["steps"][number]; selectionValue?: string; }) { const levels: Array<{ depth: number; options: AgentWorkflowUiConfig["steps"][number]["options"]; selectedKey: string; selectedOption: AgentWorkflowUiConfig["steps"][number]["options"][number] | null; }> = []; const selectedPath = getAgentWorkflowSelectedOptionPath({ step: params.step, selectionValue: params.selectionValue, }); let depth = 1; let currentOptions = getRenderableAgentWorkflowOptionTree(params.step.options || []); while (currentOptions.length > 0) { const selectedKey = selectedPath[depth - 1]?.key || ""; const selectedOption = currentOptions.find((option) => option.key === selectedKey) || null; levels.push({ depth, options: currentOptions, selectedKey, selectedOption, }); const nextOptions = getRenderableAgentWorkflowOptionTree( selectedOption?.children || [] ); if (!selectedOption || nextOptions.length === 0) { break; } currentOptions = nextOptions; depth += 1; } return levels; } function getWorkflowOptionDepthLabel(depth: number) { return depth === 1 ? "主卡片" : `${depth}级子卡片`; } function getWorkflowOptionDepthShortLabel(depth: number) { return depth === 1 ? "主" : `${depth}级`; } function StepOptionCard({ option, step, selected, disabled = false, disabledReason = null, onClick, index, }: { option: { key: string; buttonName: string; description?: string | null; previewImageUrl?: string | null }; step: { title: string }; selected: boolean; disabled?: boolean; disabledReason?: "blocked" | "developing" | null; onClick: () => void; index: number; }) { return ( {/* 背景 */}
{option.previewImageUrl ? ( <> {option.buttonName}
) : (
)}
{/* 选中标记 */} {selected && ( )} {disabled && !selected ? (
{disabledReason === "developing" ? "开发中" : "已限制"}
) : null} {/* 步骤标签 */}
{step.title}
{/* 底部信息 */}

{option.buttonName}

{option.description && (

{option.description}

)}
{/* 选中边框 */} {selected && (
)} ); } export function AgentWorkflowBrandStorePanel({ config, inputs, onInputsChange, psdTemplateCategoryTagIndex, theme = "dark", title = "品牌层级选择", description = "先选择品牌、店铺、分类层级和价格带,后续品牌模特与风格步骤会按这里的选择联动。", }: AgentWorkflowBrandStorePanelProps) { const categoryLabels = useMemo( () => getAgentWorkflowCategoryLabels(config), [config] ); const firstCategoryLabel = categoryLabels.firstCategory; const secondCategoryLabel = categoryLabels.secondCategory; const thirdCategoryLabel = categoryLabels.thirdCategory; const fourthCategoryLabel = categoryLabels.fourthCategory; const fifthCategoryLabel = categoryLabels.fifthCategory; const resolvedTitle = title === "品牌层级选择" ? `${firstCategoryLabel}层级选择` : title; const resolvedDescription = description === "先选择品牌、店铺、分类层级和价格带,后续品牌模特与风格步骤会按这里的选择联动。" ? `先选择${firstCategoryLabel}、${secondCategoryLabel}、分类层级和价格带,后续品牌模特与风格步骤会按这里的选择联动。` : description; const brandOptions = useMemo( () => config?.inputOptions?.brands || defaultAgentWorkflowUiConfig.inputOptions?.brands || [], [config?.inputOptions?.brands] ); const brandStoreEntries = useMemo( () => getAgentWorkflowBrandStoreEntries(config), [config] ); const storeOptions = useMemo( () => getAgentWorkflowStoreOptionsByBrand({ config, brand: inputs.brand }), [config, inputs.brand] ); const thirdCategoryOptions = useMemo( () => getAgentWorkflowThirdCategoryOptionsByBrandStore({ config, brand: inputs.brand, store: inputs.store, }), [config, inputs.brand, inputs.store] ); const fourthCategoryOptions = useMemo( () => getAgentWorkflowFourthCategoryOptionsByBrandStoreThirdCategory({ config, brand: inputs.brand, store: inputs.store, thirdCategory: inputs.thirdCategory, }), [config, inputs.brand, inputs.store, inputs.thirdCategory] ); const normalizedPsdTemplateCategoryTagIndex = useMemo( () => normalizeAgentPsdTemplateCategoryTagIndex(psdTemplateCategoryTagIndex), [psdTemplateCategoryTagIndex] ); const fifthCategoryOptions = useMemo( () => getAgentPsdTemplateCategoryTagsByBrand( normalizedPsdTemplateCategoryTagIndex, inputs.brand ), [inputs.brand, normalizedPsdTemplateCategoryTagIndex] ); const priceBandOptions = useMemo( () => getAgentWorkflowPriceBandOptions(config), [config] ); const hasThirdCategoryLevel = useMemo( () => brandStoreEntries.some((entry) => (entry.storeEntries || []).some( (storeEntry) => (storeEntry.thirdCategoryEntries || []).length > 0 || (storeEntry.thirdCategories || []).length > 0 ) ) || Boolean(config?.inputOptions?.thirdCategories?.length), [brandStoreEntries, config?.inputOptions?.thirdCategories] ); const hasFourthCategoryLevel = useMemo( () => hasThirdCategoryLevel && (brandStoreEntries.some((entry) => (entry.storeEntries || []).some((storeEntry) => (storeEntry.thirdCategoryEntries || []).some( (thirdEntry) => (thirdEntry.fourthCategoryEntries || []).length > 0 || (thirdEntry.fourthCategories || []).length > 0 ) ) ) || Boolean(config?.inputOptions?.fourthCategories?.length)), [brandStoreEntries, config?.inputOptions?.fourthCategories, hasThirdCategoryLevel] ); const isDark = theme === "dark"; useEffect(() => { let nextInputs = inputs; let changed = false; if (!hasThirdCategoryLevel) { if (nextInputs.thirdCategory || nextInputs.fourthCategory) { nextInputs = { ...nextInputs, thirdCategory: "", fourthCategory: "", }; changed = true; } } else if (!hasFourthCategoryLevel) { if (nextInputs.fourthCategory) { nextInputs = { ...nextInputs, fourthCategory: "", }; changed = true; } } if ( nextInputs.fifthCategory && !fifthCategoryOptions.some( (option) => option.trim().toLowerCase() === nextInputs.fifthCategory.trim().toLowerCase() ) ) { nextInputs = { ...nextInputs, fifthCategory: "", }; changed = true; } if (changed) { onInputsChange(nextInputs); } }, [ fifthCategoryOptions, hasThirdCategoryLevel, hasFourthCategoryLevel, inputs, onInputsChange, ]); return (
{resolvedTitle}
{resolvedDescription}
onInputsChange({ ...inputs, brand: value, store: value.trim().toLowerCase() === inputs.brand.trim().toLowerCase() ? inputs.store : "", thirdCategory: value.trim().toLowerCase() === inputs.brand.trim().toLowerCase() ? inputs.thirdCategory : "", fourthCategory: "", fifthCategory: "", }) } /> 0 && storeOptions.length === 0)} onValueChange={(value) => onInputsChange({ ...inputs, store: value, thirdCategory: value.trim().toLowerCase() === inputs.store.trim().toLowerCase() ? inputs.thirdCategory : "", fourthCategory: "", }) } /> {hasThirdCategoryLevel ? ( onInputsChange({ ...inputs, thirdCategory: value, fourthCategory: value.trim().toLowerCase() === inputs.thirdCategory.trim().toLowerCase() ? inputs.fourthCategory : "", }) } /> ) : null} {hasFourthCategoryLevel ? ( onInputsChange({ ...inputs, fourthCategory: value, }) } /> ) : null} onInputsChange({ ...inputs, fifthCategory: value })} /> onInputsChange({ ...inputs, priceBand: value })} />
); } export function AgentWorkflowPanelDarkV2({ config, inputs, onInputsChange, psdTemplateCategoryTagIndex, materials, onMaterialsChange, selections, onSelectionsChange, onNextStep, onSkipStep, siteName, siteLogo, siteLogoDark, showcaseConfig, topNavRightSlot, embedded = false, showBrandStoreSection = true, }: AgentWorkflowPanelDarkV2Props) { const categoryLabels = useMemo( () => getAgentWorkflowCategoryLabels(config), [config] ); const firstCategoryLabel = categoryLabels.firstCategory; const secondCategoryLabel = categoryLabels.secondCategory; const resolvedConfig = useMemo(() => { const source = config || defaultAgentWorkflowUiConfig; return { ...source, steps: getEnabledAgentWorkflowStepTree(source.steps || []), }; }, [config]); const displayConfig = useMemo(() => { const source = config || defaultAgentWorkflowUiConfig; return { ...source, steps: getRenderableAgentWorkflowStepTree(source.steps || []), }; }, [config]); const flattenedResolvedSteps = useMemo( () => flattenVisibleAgentWorkflowSteps(displayConfig.steps, selections).filter( ({ step }) => Array.isArray(step.options) && step.options.length > 0 ), [displayConfig.steps, selections] ); const summary = useMemo( () => buildSelectionSummary({ config: resolvedConfig, selections }), [resolvedConfig, selections] ); const composerContext = useMemo( () => buildAgentWorkflowComposerContext({ config: resolvedConfig, inputs, materials, selections, }), [inputs, materials, resolvedConfig, selections] ); const progress = useMemo( () => getAgentWorkflowProgress({ config: resolvedConfig, selections }), [resolvedConfig, selections] ); const stepSelectionSummaryMap = useMemo(() => { const entries = flattenAgentWorkflowSteps(resolvedConfig.steps).map(({ step }) => [ step.key, getWorkflowStepSelectionSummary({ step, selectionValue: selections[step.key], }), ]); return Object.fromEntries(entries) as Record; }, [resolvedConfig.steps, selections]); const blockedOptionKeys = useMemo( () => new Set( getAgentWorkflowBlockedOptionKeysForSelections({ config: resolvedConfig, selections, }) ), [resolvedConfig, selections] ); const [autoAdvanceNotice, setAutoAdvanceNotice] = useState<{ completedStepTitle: string; completedSummary: string; nextStepTitle: string; } | null>(null); const [activeEmbeddedStepKey, setActiveEmbeddedStepKey] = useState(""); const [activeEmbeddedOptionDepth, setActiveEmbeddedOptionDepth] = useState(1); const [pendingAutoAdvanceStepKey, setPendingAutoAdvanceStepKey] = useState(null); const activeEmbeddedStepIndex = Math.max( flattenedResolvedSteps.findIndex(({ step }) => step.key === activeEmbeddedStepKey), 0 ); const activeEmbeddedStepEntry = flattenedResolvedSteps[activeEmbeddedStepIndex] || flattenedResolvedSteps[0] || null; const activeEmbeddedOptionLevels = useMemo( () => activeEmbeddedStepEntry ? getWorkflowStepOptionLevels({ step: activeEmbeddedStepEntry.step, selectionValue: selections[activeEmbeddedStepEntry.step.key], }) : [], [activeEmbeddedStepEntry, selections] ); const activeEmbeddedSelectedPath = useMemo( () => activeEmbeddedStepEntry ? getAgentWorkflowSelectedOptionPath({ step: activeEmbeddedStepEntry.step, selectionValue: selections[activeEmbeddedStepEntry.step.key], }) : [], [activeEmbeddedStepEntry, selections] ); const activeEmbeddedOptionLevel = activeEmbeddedOptionLevels.find((level) => level.depth === activeEmbeddedOptionDepth) || activeEmbeddedOptionLevels[activeEmbeddedOptionLevels.length - 1] || activeEmbeddedOptionLevels[0] || null; const activeEmbeddedDeepestSelectedOption = useMemo( () => [...activeEmbeddedOptionLevels] .reverse() .find((level) => level.selectedOption)?.selectedOption || null, [activeEmbeddedOptionLevels] ); const activeEmbeddedSelectedOptionHasDevelopingChildren = useMemo(() => { if (!activeEmbeddedDeepestSelectedOption) { return false; } const renderableChildren = getRenderableAgentWorkflowOptionTree( activeEmbeddedDeepestSelectedOption.children || [] ); if (renderableChildren.length === 0) { return false; } return getEnabledAgentWorkflowOptionTree(activeEmbeddedDeepestSelectedOption.children || []).length === 0; }, [activeEmbeddedDeepestSelectedOption]); useEffect(() => { if (!embedded) { return; } if (flattenedResolvedSteps.length === 0) { if (activeEmbeddedStepKey) { setActiveEmbeddedStepKey(""); } return; } if ( activeEmbeddedStepKey && flattenedResolvedSteps.some(({ step }) => step.key === activeEmbeddedStepKey) ) { return; } setActiveEmbeddedStepKey(flattenedResolvedSteps[0]?.step.key || ""); }, [activeEmbeddedStepKey, embedded, flattenedResolvedSteps]); useEffect(() => { if (!embedded) { return; } if (!activeEmbeddedStepEntry) { if (activeEmbeddedOptionDepth !== 1) { setActiveEmbeddedOptionDepth(1); } return; } const firstIncompleteDepth = activeEmbeddedOptionLevels.find((level) => !level.selectedKey)?.depth || activeEmbeddedOptionLevels[activeEmbeddedOptionLevels.length - 1]?.depth || 1; setActiveEmbeddedOptionDepth((current) => { const maxDepth = activeEmbeddedOptionLevels[activeEmbeddedOptionLevels.length - 1]?.depth || 1; if (current < 1 || current > maxDepth) { return firstIncompleteDepth; } return current; }); }, [activeEmbeddedOptionDepth, activeEmbeddedOptionLevels, activeEmbeddedStepEntry, embedded]); useEffect(() => { if (!embedded || !activeEmbeddedStepEntry) { return; } if (pendingAutoAdvanceStepKey !== activeEmbeddedStepEntry.step.key) { return; } const currentStepComplete = isAgentWorkflowStepSelectionComplete({ step: activeEmbeddedStepEntry.step, selectionValue: selections[activeEmbeddedStepEntry.step.key], }); if (!currentStepComplete) { return; } if (activeEmbeddedSelectedOptionHasDevelopingChildren) { setPendingAutoAdvanceStepKey(null); return; } const nextStep = flattenedResolvedSteps .slice(activeEmbeddedStepIndex + 1) .find( ({ step }) => !isAgentWorkflowStepSelectionComplete({ step, selectionValue: selections[step.key], }) ); if (nextStep && nextStep.step.key !== activeEmbeddedStepKey) { setAutoAdvanceNotice({ completedStepTitle: activeEmbeddedStepEntry.step.title, completedSummary: stepSelectionSummaryMap[activeEmbeddedStepEntry.step.key] || "已完成当前步骤选择", nextStepTitle: nextStep.step.title, }); setActiveEmbeddedStepKey(nextStep.step.key); setActiveEmbeddedOptionDepth(1); } setPendingAutoAdvanceStepKey(null); }, [ activeEmbeddedStepEntry, activeEmbeddedStepIndex, activeEmbeddedStepKey, activeEmbeddedSelectedOptionHasDevelopingChildren, embedded, flattenedResolvedSteps, pendingAutoAdvanceStepKey, selections, stepSelectionSummaryMap, ]); useEffect(() => { if (!autoAdvanceNotice) { return; } const timer = window.setTimeout(() => { setAutoAdvanceNotice(null); }, 3200); return () => window.clearTimeout(timer); }, [autoAdvanceNotice]); const renderOptionLevels = ( step: AgentWorkflowUiConfig["steps"][number], options: AgentWorkflowUiConfig["steps"][number]["options"], depth = 1, parentPath: string[] = [] ): ReactNode => { const selectedPathKeys = getAgentWorkflowSelectedOptionPath({ step, selectionValue: selections[step.key], }).map((option) => option.key); const currentSelectedKey = selectedPathKeys[depth - 1] || ""; const currentSelectedOption = options.find((option) => option.key === currentSelectedKey) || null; const visibleChildren = getRenderableAgentWorkflowOptionTree( currentSelectedOption?.children || [] ); const levelLabel = depth === 1 ? "主卡片" : depth === 2 ? "二级卡片" : "三级卡片"; return (
{levelLabel} {depth > 1 ? ( 该层卡片从上一级已选卡片中继续展开 ) : null}
{options.map((option, optionIndex) => { const isDeveloping = option.enabled === false; const isBlocked = !isDeveloping && currentSelectedKey !== option.key && blockedOptionKeys.has(option.key); const isDisabled = isDeveloping || isBlocked; return ( { if (isDisabled) { return; } const prefix = parentPath.slice(0, depth - 1); const nextKeys = currentSelectedKey === option.key ? prefix : [...prefix, option.key]; setPendingAutoAdvanceStepKey(step.key); onSelectionsChange({ ...selections, [step.key]: nextKeys.length > 0 ? serializeAgentWorkflowSelectionPath(nextKeys) : undefined, }); }} index={optionIndex} /> ); })}
{currentSelectedOption && visibleChildren.length > 0 ? renderOptionLevels(step, visibleChildren, depth + 1, [ ...parentPath.slice(0, depth - 1), currentSelectedOption.key, ]) : null}
); }; const handleCopyPrompt = async () => { if (!composerContext?.promptText) { toast.error("当前还没有可复制的 Prompt"); return; } try { await navigator.clipboard.writeText(composerContext.promptText); toast.success("Prompt 已复制"); } catch { toast.error("复制失败"); } }; const workflowContent = (
{showBrandStoreSection ? (

1 {firstCategoryLabel}和{secondCategoryLabel}选择

) : null} {/* 工作流步骤 */} {embedded ? ( activeEmbeddedStepEntry ? ( 1 && "border-l-4 border-l-emerald-500/30" )} initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} >
{flattenedResolvedSteps.map(({ step }, stepIndex) => { const completed = isAgentWorkflowStepSelectionComplete({ step, selectionValue: selections[step.key], }); const active = step.key === activeEmbeddedStepEntry.step.key; const stepSelectedPath = getAgentWorkflowSelectedOptionPath({ step, selectionValue: selections[step.key], }); const primarySelectedOption = stepSelectedPath[0] || null; const selectedCountLabel = stepSelectedPath.length > 0 ? `${stepSelectedPath.length} 项已选` : "待选择"; return (
); })}
当前步骤路径 {activeEmbeddedStepEntry.step.title}
{activeEmbeddedSelectedPath.length > 0 ? `已选 ${activeEmbeddedSelectedPath.length} 项` : "还未选择主卡片"}
{activeEmbeddedSelectedPath.length > 0 ? (
{activeEmbeddedSelectedPath.map((option, optionIndex) => { const optionDepth = optionIndex + 1; const optionLevelActive = (activeEmbeddedOptionLevel?.depth || 1) === optionDepth; return ( ); })}
) : (
先选择当前步骤的主卡片,完整子节点路径会显示在这里,顶部步骤条只保留紧凑摘要。
)}
{activeEmbeddedOptionLevel ? (
{autoAdvanceNotice ? (
已完成「{autoAdvanceNotice.completedStepTitle}」 已自动切换到「{autoAdvanceNotice.nextStepTitle}」
刚刚完成的内容:{autoAdvanceNotice.completedSummary}
) : null}
{activeEmbeddedOptionLevel.depth === 1 ? "主卡片" : `${activeEmbeddedOptionLevel.depth}级子卡片`} {activeEmbeddedOptionLevel.depth === 1 ? "先选择当前步骤的主卡片" : "当前层级只展示这一层的子节点卡片,选完再进入下一层"}
{activeEmbeddedOptionLevel.options.map((option, optionIndex) => { const currentSelectedKey = activeEmbeddedOptionLevel.selectedKey; const isDeveloping = option.enabled === false; const isBlocked = !isDeveloping && currentSelectedKey !== option.key && blockedOptionKeys.has(option.key); const isDisabled = isDeveloping || isBlocked; const nextChildren = getRenderableAgentWorkflowOptionTree( option.children || [] ); return ( { if (isDisabled) { return; } const selectedPathKeys = activeEmbeddedOptionLevels .slice(0, activeEmbeddedOptionLevel.depth - 1) .map((level) => level.selectedKey) .filter(Boolean); const nextKeys = currentSelectedKey === option.key ? selectedPathKeys : [...selectedPathKeys, option.key]; setPendingAutoAdvanceStepKey(activeEmbeddedStepEntry.step.key); onSelectionsChange({ ...selections, [activeEmbeddedStepEntry.step.key]: nextKeys.length > 0 ? serializeAgentWorkflowSelectionPath(nextKeys) : undefined, }); if (currentSelectedKey !== option.key && nextChildren.length > 0) { setActiveEmbeddedOptionDepth( activeEmbeddedOptionLevel.depth + 1 ); } else { setActiveEmbeddedOptionDepth( activeEmbeddedOptionLevel.depth ); } }} index={optionIndex} /> ); })}
) : null}
) : null ) : ( flattenedResolvedSteps.map(({ step, depth }, stepIndex) => ( 1 && "ml-3 border-l-4 border-l-emerald-500/30 sm:ml-6" )} initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: 0.15 + stepIndex * 0.05 }} >

{stepIndex + 2} {step.title} {depth > 1 ? ( {`${depth}级模块`} ) : null}

{stepSelectionSummaryMap[step.key] ? `已选:${stepSelectionSummaryMap[step.key]}` : "待选择:先确定这一组风格卡片,系统再继续组合 Prompt"}
{step.description && (

{step.description}

)} {renderOptionLevels(step, getRenderableAgentWorkflowOptionTree(step.options || []))}
)) )} {/* Prompt 预览 */}

Prompt 预览