"use client"; import { useState } from "react"; import { Sparkles } from "lucide-react"; import { AgentWorkflowMaterialPicker } from "@/components/agents/AgentWorkflowMaterialPicker"; import { createEmptyAgentWorkflowMaterialSelection } from "@/lib/agents/workflow-material-config"; import { cn } from "@/lib/utils"; import type { AgentWorkflowInputs } from "@/components/agents/AgentWorkflowPanel"; import type { AgentWorkflowMaterialQueryType, AgentWorkflowMaterialSelections, } from "@/types/agent"; interface AgentWorkflowMaterialSelectionPanelProps { inputs: AgentWorkflowInputs; onInputsChange: (next: AgentWorkflowInputs) => void; materials: AgentWorkflowMaterialSelections; onMaterialsChange: (next: AgentWorkflowMaterialSelections) => void; title?: string; description?: string; disabled?: boolean; disabledHint?: string; theme?: "light" | "dark"; } export function AgentWorkflowMaterialSelectionPanel({ inputs, onInputsChange, materials, onMaterialsChange, title = "SKU / SPU 选图", description = "先确定生图模式,再搜索主 SKU 或搭配 SKU 的白底图。选中的图片会自动进入对应槽位。", disabled = false, disabledHint = "请先在下方选择一个生图模式,再启用 SKU / SPU 搜图。", theme = "light", }: AgentWorkflowMaterialSelectionPanelProps) { const [materialSearchState, setMaterialSearchState] = useState<{ primary: { isLoading: boolean; errorText: string | null }; secondary: { isLoading: boolean; errorText: string | null }; }>({ primary: { isLoading: false, errorText: null }, secondary: { isLoading: false, errorText: null }, }); const [materialSearchMode, setMaterialSearchMode] = useState<{ primary: AgentWorkflowMaterialQueryType; secondary: AgentWorkflowMaterialQueryType; }>({ primary: "sku", secondary: "sku", }); const updateMaterialSearchState = ( source: "primary" | "secondary", updates: Partial<{ isLoading: boolean; errorText: string | null }> ) => { setMaterialSearchState((prev) => ({ ...prev, [source]: { ...prev[source], ...updates, }, })); }; const handleMaterialInputChange = (source: "primary" | "secondary", value: string) => { const inputKey = source === "primary" ? "primarySku" : "secondarySku"; const trimmedValue = value.trim().toUpperCase(); const currentQuery = String(materials[source]?.result?.query || "").trim().toUpperCase(); onInputsChange({ ...inputs, [inputKey]: value, }); if ( trimmedValue !== currentQuery && (materials[source]?.result || materials[source]?.selectedImageIds.length) ) { onMaterialsChange({ ...materials, [source]: createEmptyAgentWorkflowMaterialSelection(), }); } if (materialSearchState[source].errorText) { updateMaterialSearchState(source, { errorText: null }); } }; const handleSearchMaterials = async ( source: "primary" | "secondary", options?: { keyword?: string; queryType?: AgentWorkflowMaterialQueryType; } ) => { const keyword = String(options?.keyword || (source === "primary" ? inputs.primarySku : inputs.secondarySku)).trim(); const queryType = options?.queryType || materialSearchMode[source]; if (!keyword) { updateMaterialSearchState(source, { errorText: "请先输入搜索关键词" }); return; } try { updateMaterialSearchState(source, { isLoading: true, errorText: null }); const response = await fetch( `/api/agent-workflow/material-search?keyword=${encodeURIComponent(keyword)}&source=${source}&queryType=${queryType}`, { cache: "no-store" } ); const result = await response.json().catch(() => ({})); if (!response.ok || !result?.success || !result?.data) { throw new Error(result?.error?.message || result?.error || "搜索失败"); } onMaterialsChange({ ...materials, [source]: { result: result.data, selectedImageIds: [], }, }); } catch (error) { updateMaterialSearchState(source, { errorText: error instanceof Error ? error.message : "搜索失败", }); } finally { updateMaterialSearchState(source, { isLoading: false }); } }; const isDark = theme === "dark"; return (
{title}
{description}
handleMaterialInputChange("primary", value)} onQueryModeChange={(nextMode) => setMaterialSearchMode((prev) => ({ ...prev, primary: nextMode, })) } onSearch={() => { void handleSearchMaterials("primary"); }} onSkuOptionSelect={(skuName) => { onInputsChange({ ...inputs, primarySku: skuName, }); setMaterialSearchMode((prev) => ({ ...prev, primary: "sku", })); void handleSearchMaterials("primary", { keyword: skuName, queryType: "sku", }); }} theme={theme} onSelectedImageIdsChange={(next) => onMaterialsChange({ ...materials, primary: { ...materials.primary, selectedImageIds: next, }, }) } /> handleMaterialInputChange("secondary", value)} onQueryModeChange={(nextMode) => setMaterialSearchMode((prev) => ({ ...prev, secondary: nextMode, })) } onSearch={() => { void handleSearchMaterials("secondary"); }} onSkuOptionSelect={(skuName) => { onInputsChange({ ...inputs, secondarySku: skuName, }); setMaterialSearchMode((prev) => ({ ...prev, secondary: "sku", })); void handleSearchMaterials("secondary", { keyword: skuName, queryType: "sku", }); }} theme={theme} onSelectedImageIdsChange={(next) => onMaterialsChange({ ...materials, secondary: { ...materials.secondary, selectedImageIds: next, }, }) } />
); }