Update App.jsx via upload script - 2026-08-21 10:01:57
This commit is contained in:
parent
5489ea44b8
commit
d493486b76
61
App.jsx
61
App.jsx
|
|
@ -766,6 +766,8 @@ function upsertProductByName(list, product) {
|
||||||
id: existing.id,
|
id: existing.id,
|
||||||
productImageFileName: existing.productImageFileName,
|
productImageFileName: existing.productImageFileName,
|
||||||
productImageOriginalName: existing.productImageOriginalName,
|
productImageOriginalName: existing.productImageOriginalName,
|
||||||
|
brochureFileName: existing.brochureFileName,
|
||||||
|
brochureOriginalName: existing.brochureOriginalName,
|
||||||
sellingPoints: existing.sellingPoints,
|
sellingPoints: existing.sellingPoints,
|
||||||
costPrice: existing.costPrice,
|
costPrice: existing.costPrice,
|
||||||
notes: existing.notes,
|
notes: existing.notes,
|
||||||
|
|
@ -931,6 +933,7 @@ const blankProduct = () => ({
|
||||||
extraSpecs: [], // 动态兜底参数:AI识别到但不在上面任何具名字段里的参数,原样保留 {label, value},如 [{label:'浮充电压', value:'13.7VDC/节'}]
|
extraSpecs: [], // 动态兜底参数:AI识别到但不在上面任何具名字段里的参数,原样保留 {label, value},如 [{label:'浮充电压', value:'13.7VDC/节'}]
|
||||||
backPanelTemplateId: '', // 引用的后板图模板id(可跨产品共用同一个模板),迷你UPS不适用
|
backPanelTemplateId: '', // 引用的后板图模板id(可跨产品共用同一个模板),迷你UPS不适用
|
||||||
productImageFileName: '', productImageOriginalName: '', // 产品主图,导出多语言PDF时展示
|
productImageFileName: '', productImageOriginalName: '', // 产品主图,导出多语言PDF时展示
|
||||||
|
brochureFileName: '', brochureOriginalName: '', // 原版彩页(厂家原始彩页PDF/图片),只做保存和下载,不参与PDF导出排版
|
||||||
sellingPoints: '', // 对客卖点/主要特点,每行一条,专门给客户看的(和下面的costPrice/notes内部信息彻底分开,不会一起导出)
|
sellingPoints: '', // 对客卖点/主要特点,每行一条,专门给客户看的(和下面的costPrice/notes内部信息彻底分开,不会一起导出)
|
||||||
costPrice: '', notes: '',
|
costPrice: '', notes: '',
|
||||||
});
|
});
|
||||||
|
|
@ -1748,6 +1751,7 @@ const Styles = () => (
|
||||||
color: var(--ink-soft); font-size: 13px; cursor: pointer; transition: border-color 0.15s, color 0.15s;
|
color: var(--ink-soft); font-size: 13px; cursor: pointer; transition: border-color 0.15s, color 0.15s;
|
||||||
}
|
}
|
||||||
.tax-add-category:hover { border-color: var(--blue); color: var(--blue); }
|
.tax-add-category:hover { border-color: var(--blue); color: var(--blue); }
|
||||||
|
.brochure-file-chip { width: 40px; height: 40px; border-radius: 8px; background: var(--copper-soft); color: var(--copper); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||||
.catalog-view-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; flex-wrap: wrap; gap: 10px; }
|
.catalog-view-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; flex-wrap: wrap; gap: 10px; }
|
||||||
.cert-view-head { display: flex; align-items: center; justify-content: flex-end; margin-bottom: 14px; }
|
.cert-view-head { display: flex; align-items: center; justify-content: flex-end; margin-bottom: 14px; }
|
||||||
.cert-add-btn {
|
.cert-add-btn {
|
||||||
|
|
@ -4924,6 +4928,25 @@ function ProductForm({ draft, setDraft, onSave, onCancel, categories, onManage,
|
||||||
try { await deleteFile(draft.id, draft.productImageFileName); } catch (e) {}
|
try { await deleteFile(draft.id, draft.productImageFileName); } catch (e) {}
|
||||||
set({ productImageFileName: '', productImageOriginalName: '' });
|
set({ productImageFileName: '', productImageOriginalName: '' });
|
||||||
}
|
}
|
||||||
|
const [brochureUploading, setBrochureUploading] = useState(false);
|
||||||
|
async function handleBrochurePick(file) {
|
||||||
|
if (!file) return;
|
||||||
|
setBrochureUploading(true);
|
||||||
|
try {
|
||||||
|
const res = await uploadFile(draft.id, file);
|
||||||
|
set({ brochureFileName: res.fileName, brochureOriginalName: res.originalName });
|
||||||
|
} catch (e) {
|
||||||
|
if (onNotify) onNotify('彩页上传失败,请重试');
|
||||||
|
} finally {
|
||||||
|
setBrochureUploading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function handleBrochureRemove() {
|
||||||
|
if (!draft.brochureFileName) return;
|
||||||
|
if (!window.confirm('确定删除已上传的原版彩页?')) return;
|
||||||
|
try { await deleteFile(draft.id, draft.brochureFileName); } catch (e) {}
|
||||||
|
set({ brochureFileName: '', brochureOriginalName: '' });
|
||||||
|
}
|
||||||
function addExtraName() { set({ extraNames: [...extraNames, ''] }); }
|
function addExtraName() { set({ extraNames: [...extraNames, ''] }); }
|
||||||
function updateExtraName(idx, val) { const arr = [...extraNames]; arr[idx] = val; set({ extraNames: arr }); }
|
function updateExtraName(idx, val) { const arr = [...extraNames]; arr[idx] = val; set({ extraNames: arr }); }
|
||||||
function removeExtraName(idx) { set({ extraNames: extraNames.filter((_, i) => i !== idx) }); }
|
function removeExtraName(idx) { set({ extraNames: extraNames.filter((_, i) => i !== idx) }); }
|
||||||
|
|
@ -5380,6 +5403,33 @@ function ProductForm({ draft, setDraft, onSave, onCancel, categories, onManage,
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="field">
|
||||||
|
<div className="field-label-row">
|
||||||
|
<span className="field-label">原版彩页(可选,保存厂家原始彩页文件,支持PDF/图片,仅用于保存和下载)</span>
|
||||||
|
</div>
|
||||||
|
{draft.brochureFileName ? (
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||||
|
<div className="brochure-file-chip">
|
||||||
|
<FileText size={16} />
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
href={`/uploads/${draft.id}/${draft.brochureFileName}`} target="_blank" rel="noreferrer" download={draft.brochureOriginalName}
|
||||||
|
style={{ fontSize: 12.5, color: 'var(--blue)', flex: 1, wordBreak: 'break-word' }}
|
||||||
|
>{draft.brochureOriginalName}</a>
|
||||||
|
<label className="btn btn-sm" style={{ cursor: brochureUploading ? 'default' : 'pointer' }}>
|
||||||
|
{brochureUploading ? '上传中…' : '替换'}
|
||||||
|
<input type="file" style={{ display: 'none' }} disabled={brochureUploading} onChange={e => handleBrochurePick(e.target.files && e.target.files[0])} />
|
||||||
|
</label>
|
||||||
|
<button className="btn btn-sm btn-ghost btn-danger" onClick={handleBrochureRemove}><Trash2 size={12} /></button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<label className="tax-add-category" style={{ display: 'block', cursor: brochureUploading ? 'default' : 'pointer' }}>
|
||||||
|
<input type="file" style={{ display: 'none' }} disabled={brochureUploading} onChange={e => handleBrochurePick(e.target.files && e.target.files[0])} />
|
||||||
|
<FileText size={16} style={{ verticalAlign: -3, marginRight: 4 }} />{brochureUploading ? '上传中…' : '点击上传原版彩页'}
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="field">
|
<div className="field">
|
||||||
<span className="field-label">其他参数(AI识别到、但暂未收录成正式字段的参数,原样保留,也会显示在详情页和多语言PDF导出里)</span>
|
<span className="field-label">其他参数(AI识别到、但暂未收录成正式字段的参数,原样保留,也会显示在详情页和多语言PDF导出里)</span>
|
||||||
{(draft.extraSpecs || []).map((item, idx) => (
|
{(draft.extraSpecs || []).map((item, idx) => (
|
||||||
|
|
@ -5478,6 +5528,17 @@ function ProductDetail({ product: p, onEdit, onDelete, categories, exportLang, o
|
||||||
<BackPanelReadOnly template={backPanelTemplate} />
|
<BackPanelReadOnly template={backPanelTemplate} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{p.brochureFileName && (
|
||||||
|
<div className="field">
|
||||||
|
<span className="field-label">原版彩页</span>
|
||||||
|
<a
|
||||||
|
href={`/uploads/${p.id}/${p.brochureFileName}`} target="_blank" rel="noreferrer" download={p.brochureOriginalName}
|
||||||
|
className="btn btn-sm" style={{ display: 'inline-flex' }}
|
||||||
|
>
|
||||||
|
<FileText size={12} />{p.brochureOriginalName || '下载原版彩页'}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{p.notes && <div className="field"><span className="field-label">备注</span><div style={{ fontSize: 12.5, whiteSpace: 'pre-wrap' }}>{p.notes}</div></div>}
|
{p.notes && <div className="field"><span className="field-label">备注</span><div style={{ fontSize: 12.5, whiteSpace: 'pre-wrap' }}>{p.notes}</div></div>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue