diff --git a/App.jsx b/App.jsx index 34a005d..910942f 100644 --- a/App.jsx +++ b/App.jsx @@ -411,7 +411,10 @@ function gatherExportTerms(p, categories) { else terms.add(r.labelKey); }); if (hasPortRow) terms.add('输出'); - if (p.notes && p.notes.trim()) { terms.add('备注'); terms.add(p.notes.trim()); } + // 对客卖点/主要特点:每行一条,都是要给客户看的文字,需要翻译 + (p.sellingPoints || '').split('\n').map(l => l.trim()).filter(Boolean).forEach(line => terms.add(line)); + // 注意:备注(notes)字段故意不收集、不导出——这里经常被用来记内部信息(成本价、 + // 采购渠道、库存数量这类),一旦跟着PDF发给客户后果很麻烦,所以规格书导出永远不碰这个字段。 return Array.from(terms); } @@ -430,6 +433,8 @@ const blankProduct = () => ({ batterySpec: '', // 迷你UPS专属:电池数量和容量,如 "5000mAh*4" dimensions: '', // 迷你UPS专属:尺寸(mm),如 "210*130*40" netWeight: '', // 迷你UPS专属:净重(kg) + productImageFileName: '', productImageOriginalName: '', // 产品主图,导出多语言PDF时展示 + sellingPoints: '', // 对客卖点/主要特点,每行一条,专门给客户看的(和下面的costPrice/notes内部信息彻底分开,不会一起导出) costPrice: '', notes: '', }); @@ -1112,6 +1117,14 @@ const Styles = () => ( .spec-sheet-table { margin-top: 0; border: 1px solid var(--copper-soft); border-top: none; } .spec-sheet-table td.spec-label { background: #F7F1E8; font-weight: 600; width: 38%; color: #6b5a3e; } .spec-sheet-table tr:nth-child(even) td { background: #FBF8F3; } + .spec-sheet-two-col { display: flex; gap: 32px; align-items: flex-start; } + .spec-sheet-left { flex: 0 0 240px; } + .spec-sheet-right { flex: 1; min-width: 0; } + .spec-sheet-image { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 6px; border: 1px solid var(--copper-soft); } + .spec-sheet-points { margin: 14px 0 0; padding-left: 18px; font-size: 12.5px; color: #444; line-height: 1.7; } + .spec-sheet-points li { margin-bottom: 4px; } + [dir="rtl"] .spec-sheet-two-col { flex-direction: row-reverse; } + [dir="rtl"] .spec-sheet-points { padding-left: 0; padding-right: 18px; } @media print { @@ -2506,7 +2519,7 @@ function MainApp({ username, onLogout }) {
{productDraft ? ( - setTaxManageMode(mode)} /> + setTaxManageMode(mode)} onNotify={notify} /> ) : selectedProduct ? ( startEditProduct(selectedProduct)} onDelete={() => deleteProduct(selectedProduct.id)} @@ -3442,7 +3455,7 @@ function CustomerDetail({ /* ----------------------------- product form / detail ----------------------------- */ -function ProductForm({ draft, setDraft, onSave, onCancel, categories, onManage }) { +function ProductForm({ draft, setDraft, onSave, onCancel, categories, onManage, onNotify }) { const set = (patch) => setDraft(d => ({ ...d, ...patch })); const cat = (categories || []).find(c => c.id === draft.category); const brandOptions = cat ? cat.brands : []; @@ -3451,6 +3464,24 @@ function ProductForm({ draft, setDraft, onSave, onCancel, categories, onManage } const isMiniUps = isUps && draft.type === '迷你UPS'; const maxKW = computeMaxPowerKW(draft.ratedPower, draft.ratedPowerUnit, draft.powerFactor); const extraNames = draft.extraNames || []; + const [imageUploading, setImageUploading] = useState(false); + async function handleImagePick(file) { + if (!file) return; + setImageUploading(true); + try { + const res = await uploadFile(draft.id, file); + set({ productImageFileName: res.fileName, productImageOriginalName: res.originalName }); + } catch (e) { + if (onNotify) onNotify('图片上传失败,请重试'); + } finally { + setImageUploading(false); + } + } + async function handleImageRemove() { + if (!draft.productImageFileName) return; + try { await deleteFile(draft.id, draft.productImageFileName); } catch (e) {} + set({ productImageFileName: '', productImageOriginalName: '' }); + } function addExtraName() { set({ extraNames: [...extraNames, ''] }); } function updateExtraName(idx, val) { const arr = [...extraNames]; arr[idx] = val; set({ extraNames: arr }); } function removeExtraName(idx) { set({ extraNames: extraNames.filter((_, i) => i !== idx) }); } @@ -3646,8 +3677,45 @@ function ProductForm({ draft, setDraft, onSave, onCancel, categories, onManage }
)} +
+
+ 产品主图(可选,用于多语言PDF导出) +
+ {draft.productImageFileName ? ( +
+ {draft.name} +
{draft.productImageOriginalName}
+ + +
+ ) : ( + + )} +
+ +
+ 对客卖点 / 主要特点(可选,每行一条,会显示在多语言PDF导出的资料里) +