"use client"; import { useEffect, useMemo, useState } from "react"; import { Check, ChevronDown, ChevronUp, ImageIcon, Loader2, RefreshCw, Search } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { cn } from "@/lib/utils"; import type { AgentWorkflowMaterialQueryType, AgentWorkflowMaterialSearchResult, } from "@/types/agent"; interface AgentWorkflowMaterialPickerProps { title?: string; description?: string; value: string; queryMode: AgentWorkflowMaterialQueryType; placeholder: string; buttonLabel: string; searchNote?: string; disabled?: boolean; disabledHint?: string; isLoading?: boolean; errorText?: string | null; result?: AgentWorkflowMaterialSearchResult | null; selectedImageIds: string[]; selectionLimit?: number | null; selectionLimitLabel?: string; onValueChange: (value: string) => void; onQueryModeChange: (value: AgentWorkflowMaterialQueryType) => void; onSearch: () => void; onSkuOptionSelect?: (skuName: string) => void; onSelectedImageIdsChange: (next: string[]) => void; theme?: "light" | "dark"; } export function AgentWorkflowMaterialPicker({ title, description, value, queryMode, placeholder, buttonLabel, searchNote, disabled = false, disabledHint, isLoading = false, errorText, result, selectedImageIds, selectionLimit = null, selectionLimitLabel = "当前生图模式", onValueChange, onQueryModeChange, onSearch, onSkuOptionSelect, onSelectedImageIdsChange, theme = "light", }: AgentWorkflowMaterialPickerProps) { const isDark = theme === "dark"; const [isImagePreviewExpanded, setIsImagePreviewExpanded] = useState(true); const [hasManualSelectionInteraction, setHasManualSelectionInteraction] = useState(false); const [isResultDetailsExpanded, setIsResultDetailsExpanded] = useState(true); const selectedSet = useMemo( () => new Set((selectedImageIds || []).map((item) => String(item || "").trim()).filter(Boolean)), [selectedImageIds] ); const recommendedImageIds = useMemo( () => Array.isArray(result?.recommendedImageIds) ? result.recommendedImageIds.map((item) => String(item || "").trim()).filter(Boolean) : [], [result?.recommendedImageIds] ); const selectedCount = result?.images ? result.images.filter((item) => selectedSet.has(item.id)).length : 0; const resolvedSelectionLimit = typeof selectionLimit === "number" && Number.isFinite(selectionLimit) && selectionLimit > 0 ? Math.max(1, Math.round(selectionLimit)) : null; const hasSelectableImages = Boolean( result?.images?.some((item) => Boolean(String(item.imageUrl || "").trim())) ); const goodsInfoItems = [ { label: "商品名称", value: result?.goodsInfo?.productName || null, fullWidth: true, }, { label: "尺寸信息", value: result?.goodsInfo?.sizeInfo || null, }, { label: "材质信息", value: result?.goodsInfo?.materialInfo || null, }, { label: "设计师", value: result?.goodsInfo?.designer || null, }, { label: "采购负责人", value: result?.goodsInfo?.buyer || null, }, { label: "板材类型", value: result?.goodsInfo?.boardType || null, }, ].filter((item) => Boolean(item.value)); const remainingSelectableCount = resolvedSelectionLimit === null ? null : Math.max(resolvedSelectionLimit - selectedCount, 0); const hasSystemRecommendedSelection = result?.queryType === "sku" && recommendedImageIds.length > 0 && selectedImageIds.length === recommendedImageIds.length && recommendedImageIds.every((id) => selectedSet.has(id)); const isAutoSelectedResult = Boolean(hasSystemRecommendedSelection) && !hasManualSelectionInteraction; const collapsedResultSummary = useMemo(() => { const title = result?.goodsInfo?.productName || result?.matchedSku || result?.query || "当前SKU"; return `${title} · 系统已自动选中 ${selectedCount} 张图`; }, [result?.goodsInfo?.productName, result?.matchedSku, result?.query, selectedCount]); const previewResetKey = useMemo( () => JSON.stringify({ queryType: result?.queryType || "", matchedSku: result?.matchedSku || "", imageIds: result?.images?.map((image) => image.id) || [], recommendedImageIds, }), [recommendedImageIds, result?.images, result?.matchedSku, result?.queryType] ); useEffect(() => { setHasManualSelectionInteraction(false); setIsImagePreviewExpanded(!hasSystemRecommendedSelection); setIsResultDetailsExpanded(!hasSystemRecommendedSelection); }, [hasSystemRecommendedSelection, previewResetKey]); const handleToggleImage = (imageId: string) => { setHasManualSelectionInteraction(true); const next = new Set(selectedImageIds); if (next.has(imageId)) { next.delete(imageId); } else { if (resolvedSelectionLimit !== null && next.size >= resolvedSelectionLimit) { toast.error(`${selectionLimitLabel}最多可选择 ${resolvedSelectionLimit} 张图片`); return; } next.add(imageId); } onSelectedImageIdsChange(Array.from(next)); }; const handleSelectAll = () => { setHasManualSelectionInteraction(true); const allIds = result?.images ?.filter((item) => Boolean(String(item.imageUrl || "").trim())) .map((item) => item.id) || []; const nextIds = resolvedSelectionLimit !== null ? allIds.slice(0, resolvedSelectionLimit) : allIds; onSelectedImageIdsChange(nextIds); if (resolvedSelectionLimit !== null && allIds.length > resolvedSelectionLimit) { toast.message(`${selectionLimitLabel}最多可选择 ${resolvedSelectionLimit} 张图片,已按上限选取`); } }; return (
{title || description ? (
{title ? (
{title}
) : null} {description ? (
{description}
) : null}
) : null}
{(["sku", "spu"] as const).map((mode) => ( ))}
onValueChange(event.target.value)} placeholder={placeholder} disabled={disabled} className={cn( isDark && "border-white/12 bg-white/[0.04] text-white placeholder:text-white/25 focus-visible:ring-emerald-400/30" )} onKeyDown={(event) => { if (event.key === "Enter") { event.preventDefault(); if (disabled) return; onSearch(); } }} />
{searchNote ? (
{searchNote}
) : null} {resolvedSelectionLimit !== null ? (
{selectionLimitLabel}最多可选择 {resolvedSelectionLimit} 张图片 {remainingSelectableCount !== null ? `,当前还可选择 ${remainingSelectableCount} 张。` : "。"}
) : null} {disabled && disabledHint ? (
{disabledHint}
) : null} {!disabled && errorText ? (
{errorText}
) : null} {!disabled && result ? ( isAutoSelectedResult && !isResultDetailsExpanded ? (
已自动准备完成
{collapsedResultSummary}
需要检查商品信息、已选图片或手动微调时,再展开查看。
) : (
命中:{result.matchedSku || result.query} {result.matchedSpu ? ( SPU:{result.matchedSpu} ) : null} {result.productModel ? ( 型号:{result.productModel} ) : null} 共 {result.totalCount} 张 已选 {selectedCount} 张 {resolvedSelectionLimit !== null ? ( 最多 {resolvedSelectionLimit} 张 ) : null}
{isAutoSelectedResult ? ( ) : null}
{goodsInfoItems.length > 0 ? (
{goodsInfoItems.map((item) => (
{item.label}
{item.value}
))}
) : null} {result.skuOptions?.length ? (
{result.skuOptions.map((option) => (
{option.previewImageUrl ? ( {option.previewFileName ) : (
)}
{option.skuName}
{option.hasWhiteBackground ? `已有 ${option.whiteBackgroundCount} 张白底图` : "暂无白底图"}
))}
) : null} {result.images?.length ? (
{isAutoSelectedResult ? (
系统已按权重自动选中 {selectedCount} 张 SKU 图,默认收起预览;需要检查或微调时再手动展开。
) : null} {(!isAutoSelectedResult || isImagePreviewExpanded) ? (
{result.images.map((image) => { const selected = selectedSet.has(image.id); const isPlaceholder = !String(image.imageUrl || "").trim(); return ( ); })}
) : null}
) : null}
) ) : (
{disabled ? ( <> 先选择生图模式,再搜索并选择素材图。 ) : isLoading ? ( <> 正在搜索并导入图片,请稍候... ) : ( <> {value.trim() ? "输入后点击搜索,从素材库拉取白底图。" : "先输入关键词,再搜索素材图。"} )}
)} {(result?.images?.length || result?.skuOptions?.length) ? (
{result?.skuOptions?.length ? "当前是 SPU 命中结果,请先选择具体 SKU,再继续拉取白底图。" : "白底图会先按权重自动选入槽位,如需微调仍可手动调整。"}
) : null}
); }