前端表单到 PDF 报价表:用对象化管理产品提升可维护性
8/4/2025, 6:01:02 PM
在生成报价表的过程中,旧代码用多个数组存储价格和数量,并通过魔法数字合并重复的配件数量,导致代码难以阅读和维护。本文介绍了如何将产品及配件视作对象,通过统一的 SKU 静态数组和组合映射,实现表单数据的智能合并与 PDF 渲染。优化后代码语义清晰,新增或修改产品无需调整核心逻辑,大幅提升可维护性和扩展性。
页面需求
用户填写他所需的各个产品数量,前端生成报价表 pdf 供用户下载。
原始数据结构及其缺陷
前端展示的效果是四个区块,每个区块由 1 个主产品 + 几个配件组成,其中有些配件在区块之间是重复出现的。导致用户填写所需数量的时候其实有 22 个框供其填写,但最终我们要合成 10 个 sku。
原始实现选择把价格和数量存为两个数组:
// 价格数组(已改写价格,但保持相同项相同)
const ASeriesPrices = [300, 50, 80, 30, 20, 10];
const BSeriesPrices = [500, 50, 120, 30, 20, 10];
const CSeriesPrices = [400, 50, 80, 30, 10];
const D75SeriesPrices = [600, 50, 120, 30, 10];
const productUnitPrices = [
...s1SeriesPrices,
...s175SeriesPrices,
...s1ProSeriesPrices,
...s1Pro75SeriesPrices,
];
// 渲染 pdf 的函数
export const generatePDF = (currency) => {
...
// 把同一 sku 加起来
productNumArrayPre[1] +=
productNumArrayPre[7] + productNumArrayPre[13] + productNumArrayPre[18];
productNumArrayPre[2] += productNumArrayPre[14];
productNumArrayPre[3] +=
productNumArrayPre[9] + productNumArrayPre[15] + productNumArrayPre[20];
productNumArrayPre[4] += productNumArrayPre[10];
productNumArrayPre[5] +=
productNumArrayPre[11] + productNumArrayPre[16] + productNumArrayPre[21];
productNumArrayPre[8] += productNumArrayPre[19];
// 剔除掉不要的数据,剩下的数据用于渲染
const productNumArray = productNumArrayPre.map((_, index) => {
if ([7, 9, 10, 11, 13, 14, 15, 16, 18, 19, 20, 21].includes(index)) {
return 0;
} else {
return _;
}
});
...
};
这样的代码有两个问题:
- 可读性差。全是魔法数字,没办法一眼看出哪个数据对应哪个产品;
- 难以维护。不管是改现有产品还是添加新产品,价格数组和合成 sku 的部分都要调整多处。
用对象描述产品
其实前面的问题就是把产品的属性拆开来看了。当需要数据的时候不仅要在几个数组之间找,还对顺序有硬性要求。优化思路就是把产品视作对象,需要数据的时候直接去找那个对象,然后获取它身上你需要的属性即可。
// 静态对象数组,接下来的数据都从这里取来加工
const SKUS = [
{ id: 'productA', name: '产品A', price: 300, type: 'product' },
...
{ id: 'accessoriesB', name: '配件B', price: 10, type: 'accessories' }
];
// 用于渲染表单的数组
const PRODUCT_COMBINATIONS = [
['productA', ..., 'accessoriesB'],
...
['productD', ..., 'accessoriesB'],
];
// 表单状态(实际由 rc-field-form 管理)
const [quantities, setQuantities] = useState({
// key: `${组合索引}-${skuId}`
'0-productA': 0,
...
'3-accessoriesB': 0,
});
// 把同一 sku 加起来
const totalSkuCounts = {};
for (let key in quantities) {
const [, skuId] = key.split('-');
totalSkuCounts[skuId] = (totalSkuCounts[skuId] || 0) + quantities[key];
}
此时语义就很明显了,代码所做的事就是从表单状态中逐个取出 skuId,并把 skuId 相同的数量加起来。要修改或添加产品只需要修改静态对象数组,余下的逻辑代码都不用动!