- 当前参考图查询:
- SPU /
- {detailReplacementSearchState.lastQuery ||
- detailReplacementQueryInput.trim().toUpperCase()}
- {workflowStoreName ? (
- {`店铺 / ${workflowStoreName}`}
- ) : null}
-
- {`已接入真实${detailReferenceSourceLabel}参考图接口`}
-
-
- ) : null}
-
- {detailReplacementCandidates.length > 0 ? (
-
-
-
- 候选整套素材 {detailReplacementCandidates.length} 套
-
-
- 默认载入最新一套,可随时切换
-
-
-
- {detailReplacementCandidates.map((candidate) => {
- const isSelected = detailReplacementSelectedCandidateId === candidate.id;
- const previewUrls = getCandidatePreviewUrls(
- candidate,
- detailReferenceTarget,
- 4
- );
- const primaryPreviewUrl = previewUrls[0] || getCandidatePreviewUrl(candidate, detailReferenceTarget);
- const uploadedAtText = (() => {
- const raw = candidate.uploadedAt ? new Date(candidate.uploadedAt) : null;
- if (!raw || Number.isNaN(raw.getTime())) return "未记录";
- return raw.toLocaleString("zh-CN", {
- timeZone: "Asia/Shanghai",
- month: "2-digit",
- day: "2-digit",
- hour: "2-digit",
- minute: "2-digit",
- });
- })();
- const summaryBadges = [
- `${detailReferenceSourceLabel}`,
- `${getCandidateTargetCount(candidate, detailReferenceTarget)}张`,
- candidate.categoryName || null,
- ].filter((item): item is string => Boolean(item));
- return (
-
- );
- })}
-
-
- ) : null}
-
{detailReplacementReferenceCards.length > 0 ? (
detailReplacementReferenceCards.map((card, index) => (
diff --git a/components/agents/AgentWorkflowMaterialPicker.tsx b/components/agents/AgentWorkflowMaterialPicker.tsx
index 085933339..2e601f33b 100644
--- a/components/agents/AgentWorkflowMaterialPicker.tsx
+++ b/components/agents/AgentWorkflowMaterialPicker.tsx
@@ -1,7 +1,7 @@
"use client";
-import { useMemo } from "react";
-import { Check, ImageIcon, Loader2, RefreshCw, Search } from "lucide-react";
+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";
@@ -59,10 +59,19 @@ export function AgentWorkflowMaterialPicker({
theme = "light",
}: AgentWorkflowMaterialPickerProps) {
const isDark = theme === "dark";
+ const [isImagePreviewExpanded, setIsImagePreviewExpanded] = useState(true);
+ const [hasManualSelectionInteraction, setHasManualSelectionInteraction] = useState(false);
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;
@@ -102,8 +111,31 @@ export function AgentWorkflowMaterialPicker({
].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 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);
+ }, [hasSystemRecommendedSelection, previewResetKey]);
const handleToggleImage = (imageId: string) => {
+ setHasManualSelectionInteraction(true);
const next = new Set(selectedImageIds);
if (next.has(imageId)) {
next.delete(imageId);
@@ -118,6 +150,7 @@ export function AgentWorkflowMaterialPicker({
};
const handleSelectAll = () => {
+ setHasManualSelectionInteraction(true);
const allIds =
result?.images
?.filter((item) => Boolean(String(item.imageUrl || "").trim()))
@@ -324,7 +357,10 @@ export function AgentWorkflowMaterialPicker({
type="button"
variant="outline"
size="sm"
- onClick={() => onSelectedImageIdsChange([])}
+ onClick={() => {
+ setHasManualSelectionInteraction(true);
+ onSelectedImageIdsChange([]);
+ }}
disabled={selectedCount === 0 && !hasSelectableImages}
className={cn(
isDark &&
@@ -429,91 +465,133 @@ export function AgentWorkflowMaterialPicker({
) : null}
{result.images?.length ? (
-
- {result.images.map((image) => {
- const selected = selectedSet.has(image.id);
- const isPlaceholder = !String(image.imageUrl || "").trim();
- return (
-
) : null}
diff --git a/components/agents/AgentWorkflowMaterialSelectionPanel.tsx b/components/agents/AgentWorkflowMaterialSelectionPanel.tsx
index 70c9b6b74..980ef2891 100644
--- a/components/agents/AgentWorkflowMaterialSelectionPanel.tsx
+++ b/components/agents/AgentWorkflowMaterialSelectionPanel.tsx
@@ -102,38 +102,6 @@ export function AgentWorkflowMaterialSelectionPanel({
typeof productSelectionLimit === "number" && Number.isFinite(productSelectionLimit) && productSelectionLimit > 0
? Math.max(productSelectionLimit - primarySelectedCount, secondarySelectedCount, 0)
: null;
- const hasAnyQueryInput =
- Boolean(String(inputs.primarySku || "").trim()) ||
- Boolean(String(inputs.secondarySku || "").trim());
- const hasSkuSelectionPending =
- Boolean(materials.primary.result?.skuOptions?.length) ||
- Boolean(materials.secondary.result?.skuOptions?.length);
- const hasAnyMaterialResult =
- Boolean(materials.primary.result?.images?.length) ||
- Boolean(materials.secondary.result?.images?.length) ||
- hasSkuSelectionPending;
- const hasAnySelectedImages =
- materials.primary.selectedImageIds.length > 0 || materials.secondary.selectedImageIds.length > 0;
- const materialGuideSteps = [
- {
- badge: "01",
- label: "输入型号",
- description: "先选择按 SPU 或 SKU 搜索,再输入商品型号。",
- status: hasAnyQueryInput ? "completed" : "current",
- },
- {
- badge: "02",
- label: "选择SKU",
- description: "如果是 SPU 查询,先从返回的 SKU 列表里点选具体 SKU。",
- status: hasSkuSelectionPending ? "current" : hasAnyMaterialResult ? "completed" : "pending",
- },
- {
- badge: "03",
- label: "自动选图",
- description: "系统会按角度权重自动选图并映射到产品槽位,你也可以手动微调。",
- status: hasAnySelectedImages ? "completed" : hasAnyMaterialResult ? "current" : "pending",
- },
- ] as const;
useEffect(() => {
if (hasSecondaryMaterialContent) {
@@ -273,71 +241,6 @@ export function AgentWorkflowMaterialSelectionPanel({
) : null}
-