"use client"; import { useMemo } from "react"; import { Check, ImageIcon, Loader2, RefreshCw, Search } from "lucide-react"; 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[]; 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, onValueChange, onQueryModeChange, onSearch, onSkuOptionSelect, onSelectedImageIdsChange, theme = "light", }: AgentWorkflowMaterialPickerProps) { const isDark = theme === "dark"; const selectedSet = useMemo( () => new Set((selectedImageIds || []).map((item) => String(item || "").trim()).filter(Boolean)), [selectedImageIds] ); const selectedCount = result?.images ? result.images.filter((item) => selectedSet.has(item.id)).length : 0; const hasSelectableImages = Boolean( result?.images?.some((item) => Boolean(String(item.imageUrl || "").trim())) ); const handleToggleImage = (imageId: string) => { const next = new Set(selectedImageIds); if (next.has(imageId)) { next.delete(imageId); } else { next.add(imageId); } onSelectedImageIdsChange(Array.from(next)); }; const handleSelectAll = () => { onSelectedImageIdsChange( result?.images ?.filter((item) => Boolean(String(item.imageUrl || "").trim())) .map((item) => item.id) || [] ); }; 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} {disabled && disabledHint ? (
{disabledHint}
) : null} {!disabled && errorText ? (
{errorText}
) : null} {!disabled && result ? (
命中:{result.matchedSku || result.query} {result.matchedSpu ? ( SPU:{result.matchedSpu} ) : null} {result.productModel ? ( 型号:{result.productModel} ) : null} 共 {result.totalCount} 张 已选 {selectedCount} 张
{result.skuOptions?.length ? (
{result.skuOptions.map((option) => (
{option.previewImageUrl ? ( {option.previewFileName ) : (
)}
{option.skuName}
{option.hasWhiteBackground ? `已有 ${option.whiteBackgroundCount} 张白底图` : "暂无白底图"}
))}
) : null} {result.images?.length ? (
{result.images.map((image) => { const selected = selectedSet.has(image.id); const isPlaceholder = !String(image.imageUrl || "").trim(); return ( ); })}
) : null}
) : (
{disabled ? ( <> 先选择生图模式,再搜索并选择素材图。 ) : isLoading ? ( <> 正在搜索并导入图片,请稍候... ) : ( <> {value.trim() ? "输入后点击搜索,从素材库拉取白底图。" : "先输入关键词,再搜索素材图。"} )}
)} {(result?.images?.length || result?.skuOptions?.length) ? (
{result?.skuOptions?.length ? "当前是 SPU 命中结果,请先选择具体 SKU,再继续拉取白底图。" : "已选中的图片会在下一步优先带入右侧“生图模式”槽位,你也可以进入后继续替换。"}
) : null}
); }