From f564599b578f88434f1c94d758db8e316a887888 Mon Sep 17 00:00:00 2001 From: mike Date: Mon, 27 Jul 2026 16:30:15 +0800 Subject: [PATCH] Update App.jsx via upload script - 2026-07-27 16:29:52 --- App.jsx | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/App.jsx b/App.jsx index e0ed4f4..432835c 100644 --- a/App.jsx +++ b/App.jsx @@ -440,6 +440,37 @@ function productExportRows(p, categories) { } // 收集导出这份产品规格书需要翻译的全部词条(字段名 + 品类/机型这些中文数值 + 备注自由文本) +// 按型号名称去重合并:"同一个型号只能存在1个"——如果传入的产品和列表里某个已有产品 +// 型号名称相同(但不是同一条记录本身),说明是重复建了同型号,这时用新参数覆盖旧记录 +// (复用旧记录的id),但保留旧记录里手动维护的图片/对客卖点/正本价格/内部备注,不会被 +// 这次导入/新建的技术参数覆盖清空(因为AI批量导入/新建产品表单都不会填这几项)。 +// 如果传入的产品本身就是列表里已有的那一条(正常编辑保存),走普通按id更新。 +function upsertProductByName(list, product) { + const dupIdx = list.findIndex(p => p.id !== product.id && p.name.trim() === product.name.trim()); + const selfIdx = list.findIndex(p => p.id === product.id); + if (dupIdx !== -1) { + const existing = list[dupIdx]; + const merged = { + ...product, + id: existing.id, + productImageFileName: existing.productImageFileName, + productImageOriginalName: existing.productImageOriginalName, + sellingPoints: existing.sellingPoints, + costPrice: existing.costPrice, + notes: existing.notes, + }; + let copy = list.map((p, i) => (i === dupIdx ? merged : p)); + if (selfIdx !== -1 && selfIdx !== dupIdx) copy = copy.filter((_, i) => i !== selfIdx); + return { list: copy, collision: true, isNew: false, resultId: existing.id }; + } + if (selfIdx !== -1) { + const copy = [...list]; + copy[selfIdx] = product; + return { list: copy, collision: false, isNew: false, resultId: product.id }; + } + return { list: [...list, product], collision: false, isNew: true, resultId: product.id }; +} + function gatherExportTerms(p, categories) { const cat = (categories || []).find(c => c.id === p.category); const terms = new Set(['产品规格书', '* 产品规格如有变动,恕不另行通知', '型号', '品牌', '产品大类']); @@ -1858,14 +1889,27 @@ function MainApp({ username, onLogout }) { id: 'p_' + Date.now() + '_' + i + '_' + Math.random().toString(36).slice(2, 7), name: n, })); - setProducts(prev => { - const exists = prev.some(p => p.id === primary.id); - const withPrimary = exists ? prev.map(p => (p.id === primary.id ? primary : p)) : [...prev, primary]; - return [...withPrimary, ...extras]; + let working = products; + let newCount = 0; + let collisionCount = 0; + let primarySelectId = primary.id; + [primary, ...extras].forEach((prod, i) => { + const res = upsertProductByName(working, prod); + working = res.list; + if (res.collision) collisionCount++; + else if (res.isNew) newCount++; + if (i === 0) primarySelectId = res.resultId; }); - setSelectedProductId(primary.id); + setProducts(working); + setSelectedProductId(primarySelectId); setProductDraft(null); - notify(extras.length > 0 ? `已保存,共新建 ${1 + extras.length} 个产品` : '已保存'); + if (extras.length > 0) { + notify(`已保存:新建 ${newCount} 个${collisionCount > 0 ? `,型号已存在覆盖更新 ${collisionCount} 个` : ''}`); + } else if (collisionCount > 0) { + notify('型号已存在,已用最新参数覆盖更新(图片/卖点/成本价/备注保留原样)'); + } else { + notify('已保存'); + } } function deleteProduct(id) { if (!window.confirm('确定删除该产品档案?此操作不可恢复。')) return; @@ -2000,10 +2044,22 @@ function MainApp({ username, onLogout }) { const included = (aiImportDrafts || []).filter(d => d.include && d.name.trim()); if (!included.length) { notify('没有勾选任何要导入的产品'); return; } const { categories: newCats, resolved } = resolveCategoriesForImport(productCategories, included); - const newProducts = resolved.map(buildProductFromAiDraft); + let working = products; + let newCount = 0; + let collisionCount = 0; + resolved.forEach((d, idx) => { + const productData = buildProductFromAiDraft(d, idx); + const res = upsertProductByName(working, productData); + working = res.list; + if (res.collision) collisionCount++; + else if (res.isNew) newCount++; + }); + setProducts(working); setProductCategories(newCats); - setProducts(prev => [...prev, ...newProducts]); - notify(`已导入 ${newProducts.length} 个产品`); + const parts = []; + if (newCount) parts.push(`新建 ${newCount} 个`); + if (collisionCount) parts.push(`型号已存在,覆盖更新为最新参数 ${collisionCount} 个`); + notify(`导入完成:${parts.join(',')}`); closeAiImport(); }