fix: move material fetch success state into input
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-03-28 18:00:08 +08:00
parent 37b22b583f
commit f8900a0d72

View File

@ -1,7 +1,7 @@
"use client";
import { useEffect, useMemo, useState } from "react";
import { Check, ChevronDown, ChevronUp, ImageIcon, Loader2, RefreshCw, Search } from "lucide-react";
import { Check, ImageIcon, Loader2, RefreshCw, Search } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@ -61,7 +61,6 @@ export function AgentWorkflowMaterialPicker({
const isDark = theme === "dark";
const [previewDisplayMode, setPreviewDisplayMode] = useState<"selected" | "all">("all");
const [hasManualSelectionInteraction, setHasManualSelectionInteraction] = useState(false);
const [isResultDetailsExpanded, setIsResultDetailsExpanded] = useState(true);
const selectedSet = useMemo(
() => new Set((selectedImageIds || []).map((item) => String(item || "").trim()).filter(Boolean)),
[selectedImageIds]
@ -127,20 +126,6 @@ export function AgentWorkflowMaterialPicker({
const isAutoSelectedResult =
Boolean(hasSystemRecommendedSelection) && !hasManualSelectionInteraction;
const canTogglePreviewMode = totalImageCount > 0 && selectedCount > 0 && selectedCount < totalImageCount;
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 collapsedGoodsInfoSummary = useMemo(
() =>
[
result?.goodsInfo?.sizeInfo ? `尺寸:${result.goodsInfo.sizeInfo}` : "",
result?.goodsInfo?.materialInfo ? `材质:${result.goodsInfo.materialInfo}` : "",
]
.filter(Boolean)
.join(" · "),
[result?.goodsInfo?.materialInfo, result?.goodsInfo?.sizeInfo]
);
const visibleImages = useMemo(() => {
if (!result?.images?.length) {
return [];
@ -170,9 +155,10 @@ export function AgentWorkflowMaterialPicker({
return;
}
setPreviewDisplayMode(hasSystemRecommendedSelection ? "selected" : "all");
setIsResultDetailsExpanded(!hasSystemRecommendedSelection);
}, [hasManualSelectionInteraction, hasSystemRecommendedSelection, previewResetKey]);
const hasFetchSuccess = !disabled && !isLoading && !errorText && Boolean(result);
const handleToggleImage = (imageId: string) => {
setHasManualSelectionInteraction(true);
const next = new Set(selectedImageIds);
@ -247,23 +233,31 @@ export function AgentWorkflowMaterialPicker({
</div>
<div className="flex flex-col gap-2 md:flex-row">
<Input
value={value}
onChange={(event) => 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();
}
}}
/>
<div className="relative flex-1">
<Input
value={value}
onChange={(event) => onValueChange(event.target.value)}
placeholder={placeholder}
disabled={disabled}
className={cn(
hasFetchSuccess && "pr-11",
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();
}
}}
/>
{hasFetchSuccess ? (
<span className="pointer-events-none absolute right-3 top-1/2 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded-full bg-emerald-500/18 text-emerald-300">
<Check className="h-3.5 w-3.5" />
</span>
) : null}
</div>
<Button
type="button"
onClick={onSearch}
@ -320,47 +314,6 @@ export function AgentWorkflowMaterialPicker({
) : null}
{!disabled && result ? (
isAutoSelectedResult && !isResultDetailsExpanded ? (
<div
className={cn(
"flex flex-wrap items-center justify-between gap-3 rounded-[22px] border px-4 py-3",
isDark
? "border-emerald-500/18 bg-emerald-500/[0.06] text-emerald-100"
: "border-emerald-200 bg-emerald-50 text-emerald-700"
)}
>
<div className="min-w-0">
<div className="text-[11px] uppercase tracking-[0.12em] text-emerald-200/70">
已自动准备完成
</div>
<div className="mt-1 truncate text-sm font-medium text-white/92">
{collapsedResultSummary}
</div>
<div className="mt-1 text-xs text-emerald-100/72">
默认先替你收起结果区,需要检查商品信息、已选图片或手动微调时再展开查看。
</div>
{collapsedGoodsInfoSummary ? (
<div className="mt-2 text-xs text-emerald-100/82">
{collapsedGoodsInfoSummary}
</div>
) : null}
</div>
<Button
type="button"
variant="outline"
size="sm"
onClick={() => setIsResultDetailsExpanded(true)}
className={cn(
"shrink-0",
isDark &&
"border-white/12 bg-white/[0.04] text-white/82 hover:bg-white/[0.10] hover:text-white"
)}
>
<ChevronDown className="mr-2 h-4 w-4" />
查看已选内容
</Button>
</div>
) : (
<div className="space-y-3">
<div className="flex flex-wrap items-center justify-between gap-2">
<div className={cn("flex flex-wrap gap-2 text-xs", isDark ? "text-white/52" : "text-muted-foreground")}>
@ -491,21 +444,6 @@ export function AgentWorkflowMaterialPicker({
>
清空已选
</Button>
{isAutoSelectedResult ? (
<Button
type="button"
variant="outline"
size="sm"
onClick={() => setIsResultDetailsExpanded(false)}
className={cn(
isDark &&
"border-white/12 bg-white/[0.04] text-white/82 hover:bg-white/[0.10] hover:text-white disabled:text-white/35"
)}
>
<ChevronUp className="mr-2 h-4 w-4" />
收起
</Button>
) : null}
</div>
</div>
@ -745,7 +683,6 @@ export function AgentWorkflowMaterialPicker({
</div>
) : null}
</div>
)
) : (
<div
className={cn(