修复详情替换产品图预览

This commit is contained in:
Your Name 2026-02-05 19:26:23 +08:00
parent 378900e0da
commit 35a1b75df9

View File

@ -88,6 +88,7 @@ export function SceneFusionView({ onBack, initialProductImage, initialProductNam
// 状态管理
const [productImage, setProductImage] = useState<string | null>(null);
const [productImagePreview, setProductImagePreview] = useState<string | null>(null);
const [productName, setProductName] = useState<string>(initialProductName || ""); // 产品名称(如"沙发")
const [scenes, setScenes] = useState<SceneItem[]>([]);
const [isProcessing, setIsProcessing] = useState(false);
@ -97,14 +98,41 @@ export function SceneFusionView({ onBack, initialProductImage, initialProductNam
// 文件上传 Input 引用
const productInputRef = useRef<HTMLInputElement>(null);
const sceneInputRef = useRef<HTMLInputElement>(null);
const productPreviewObjectUrlRef = useRef<string | null>(null);
// 如果外部传入了初始产品图,则在首次挂载或传入值变化时自动带入
const updateProductPreview = (previewUrl: string | null, isObjectUrl = false) => {
if (productPreviewObjectUrlRef.current) {
URL.revokeObjectURL(productPreviewObjectUrlRef.current);
productPreviewObjectUrlRef.current = null;
}
setProductImagePreview(previewUrl);
if (isObjectUrl && previewUrl) {
productPreviewObjectUrlRef.current = previewUrl;
}
};
const clearProductImage = () => {
setProductImage(null);
updateProductPreview(null);
};
useEffect(() => {
if (initialProductImage) {
setProductImage(initialProductImage);
updateProductPreview(initialProductImage);
}
}, [initialProductImage]);
useEffect(() => {
return () => {
if (productPreviewObjectUrlRef.current) {
URL.revokeObjectURL(productPreviewObjectUrlRef.current);
productPreviewObjectUrlRef.current = null;
}
};
}, []);
// 处理产品图上传
const handleProductUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
@ -115,9 +143,23 @@ export function SceneFusionView({ onBack, initialProductImage, initialProductNam
return;
}
setProductImage(null);
const previewUrl = URL.createObjectURL(file);
updateProductPreview(previewUrl, true);
const reader = new FileReader();
reader.onload = (e) => {
setProductImage(e.target?.result as string);
const result = e.target?.result;
if (typeof result === "string") {
setProductImage(result);
} else {
toast.error("图片读取失败,请重试");
clearProductImage();
}
};
reader.onerror = () => {
toast.error("图片读取失败,请重试");
clearProductImage();
};
reader.readAsDataURL(file);
// 重置 input,允许重复选择同一文件
@ -590,8 +632,8 @@ export function SceneFusionView({ onBack, initialProductImage, initialProductNam
<div className="space-y-2">
<div className="flex items-center justify-between">
<Label className="text-base font-medium">产品图 A (必须)</Label>
{productImage && (
<Button variant="ghost" size="sm" onClick={() => setProductImage(null)} className="h-6 text-xs text-muted-foreground hover:text-destructive">
{(productImagePreview || productImage) && (
<Button variant="ghost" size="sm" onClick={clearProductImage} className="h-6 text-xs text-muted-foreground hover:text-destructive">
清除
</Button>
)}
@ -600,9 +642,9 @@ export function SceneFusionView({ onBack, initialProductImage, initialProductNam
<div
className={cn(
"border-2 border-dashed rounded-lg p-4 transition-colors text-center cursor-pointer relative group",
productImage ? "border-primary/50 bg-primary/5" : "border-muted-foreground/25 hover:border-primary/50 hover:bg-muted/50"
(productImagePreview || productImage) ? "border-primary/50 bg-primary/5" : "border-muted-foreground/25 hover:border-primary/50 hover:bg-muted/50"
)}
onClick={() => !productImage && productInputRef.current?.click()}
onClick={() => !(productImagePreview || productImage) && productInputRef.current?.click()}
>
<input
type="file"
@ -612,9 +654,9 @@ export function SceneFusionView({ onBack, initialProductImage, initialProductNam
onChange={handleProductUpload}
/>
{productImage ? (
{(productImagePreview || productImage) ? (
<div className="relative aspect-square w-full max-w-[200px] mx-auto">
<img src={productImage} alt="产品图" className="w-full h-full object-contain rounded-md" />
<img src={productImagePreview || productImage || ""} alt="产品图" className="w-full h-full object-contain rounded-md" />
<div className="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center rounded-md">
<Button variant="secondary" size="sm" onClick={(e) => { e.stopPropagation(); productInputRef.current?.click(); }}>
更换图片
@ -630,7 +672,7 @@ export function SceneFusionView({ onBack, initialProductImage, initialProductNam
</div>
{/* 产品名称输入 */}
{productImage && (
{(productImagePreview || productImage) && (
<div className="mt-2">
<Input
placeholder="产品名称(如:沙发、椅子、花瓶)"
@ -905,4 +947,4 @@ export function SceneFusionView({ onBack, initialProductImage, initialProductNam
</div>
</div>
);
}
}