fix(product-create): 新建商品上传健壮性 — loading/失败提示/等齐再关抽屉
- 原 close() 在图片上传之前执行 + 上传无 catch → 失败静默,商品建了却无图 - 改:create 后用 Promise.all 等全部图传完,saving 态贯穿整个上传(抽屉不提前关, 「创建中…」可见) - 上传失败 → flash「图片上传失败 · 已保留可重试」,不关抽屉 - createdRef 暂存已建商品:重试只补传图,不重复建商品 - onCreate 失败也给提示(不再静默) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
2e880714b1
commit
b8fc1a0749
@@ -48,6 +48,8 @@ export function ProductCreateDrawer({ open, close, onCreate, onUploadImage, onCr
|
||||
const [toast, setToast] = useState<{ title: string; sub: string } | null>(null);
|
||||
const imgInputRef = useRef<HTMLInputElement | null>(null);
|
||||
const toastTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
// 已建商品句柄:onCreate 成功但图片上传失败时暂存,重试只补传图不重复建商品
|
||||
const createdRef = useRef<Product | null>(null);
|
||||
|
||||
function flash(title: string, sub: string) {
|
||||
if (toastTimer.current) clearTimeout(toastTimer.current);
|
||||
@@ -68,6 +70,7 @@ export function ProductCreateDrawer({ open, close, onCreate, onUploadImage, onCr
|
||||
setImages((list) => { list.forEach((item) => URL.revokeObjectURL(item.url)); return []; });
|
||||
setDragOver(false);
|
||||
setTitleError(false);
|
||||
createdRef.current = null;
|
||||
}
|
||||
// 每次打开抽屉时复位表单(含商品库「继续创建商品」二次打开)
|
||||
useEffect(() => { if (open) resetForm(); }, [open]);
|
||||
@@ -132,23 +135,35 @@ export function ProductCreateDrawer({ open, close, onCreate, onUploadImage, onCr
|
||||
setSaving(true);
|
||||
try {
|
||||
const files = images.map((item) => item.file);
|
||||
const created = await onCreate({
|
||||
title: name,
|
||||
category: category || catOptions[0],
|
||||
target_audience: target.trim() || undefined,
|
||||
selling_points: finalBullets.map((item, index) => ({ title: item, detail: item, sort_order: index }))
|
||||
});
|
||||
close();
|
||||
if (!created) return;
|
||||
// 把抽屉里选的主图逐张随商品一起上传持久化(否则卡片/详情看不到图)
|
||||
// 若上次已建好商品(仅图片上传失败),本次重试只补传图,不重复建商品
|
||||
let created = createdRef.current;
|
||||
if (!created) {
|
||||
created = (await onCreate({
|
||||
title: name,
|
||||
category: category || catOptions[0],
|
||||
target_audience: target.trim() || undefined,
|
||||
selling_points: finalBullets.map((item, index) => ({ title: item, detail: item, sort_order: index }))
|
||||
})) || null;
|
||||
if (!created) { flash("商品创建失败", "请稍后重试"); return; } // 不静默:建库失败也给提示
|
||||
createdRef.current = created;
|
||||
}
|
||||
// 主图随商品上传持久化:等全部传完再关抽屉(原先 close 在上传前 + 无 catch → 图悄悄传失败,商品却已建)
|
||||
if (files.length && onUploadImage) {
|
||||
for (let i = 0; i < files.length; i += 1) {
|
||||
const fd = new FormData();
|
||||
fd.append("file", files[i]);
|
||||
fd.append("name", `${name}-主图${files.length > 1 ? `-${i + 1}` : ""}`);
|
||||
await onUploadImage(created.id, fd);
|
||||
try {
|
||||
await Promise.all(files.map((file, i) => {
|
||||
const fd = new FormData();
|
||||
fd.append("file", file);
|
||||
fd.append("name", `${name}-主图${files.length > 1 ? `-${i + 1}` : ""}`);
|
||||
return onUploadImage(created!.id, fd);
|
||||
}));
|
||||
} catch {
|
||||
// 不关抽屉、不重复建商品:留着让用户点「创建商品」重试上传(网络恢复后即成)
|
||||
flash("图片上传失败", "已保留 · 点「创建商品」可重试上传");
|
||||
return;
|
||||
}
|
||||
}
|
||||
createdRef.current = null;
|
||||
close();
|
||||
onCreated?.(created);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
|
||||
Reference in New Issue
Block a user