海缆系统重写手记:从 Vanilla JS 到 React + TypeScript

距离上次更新已经过了一个多月。这段时间发生了一件大事——整个系统推倒重写了。 上篇文章结尾我说过:“项目规模已经到了 Vanilla JS 的舒适边界”。当时觉得还能再撑一阵,结果只过了两周,代码就彻底失控了。 重写的导火索 v1.13 之后又迭代了几个版本(v1.14 到 v1.16),每次都在原有架构上加功能: 合同终止与续约:销售订单和库存资源都需要支持提前终止、到期续约、逐项操作 批次容量管理:Base + Batch 模式的成本分摊 CSV/Excel 导入:三步向导式批量数据导入 移动端卡片视图:客户、供应商列表的响应式适配 每加一个功能,都要在多个 IIFE 模块间穿针引线。salesForm.js 拆了又拆、拆出了十几个子模块,inventory.js 也开始走上同样的路。代码量突破了 21000 行,但真正让我下决心的不是行数,而是两个具体的痛点: 1. 状态管理的噩梦 续约弹窗需要同时操作多个成本项,每个成本项有独立的日期、金额、选中状态。用 DOM 操作来维护这些状态,代码写出来是这样的: // 每次点击复选框,手动同步所有关联 DOM const checkbox = card.querySelector('.renew-checkbox'); const dateInput = card.querySelector('.renew-start-date'); const termInput = card.querySelector('.renew-term'); if (checkbox.checked) { dateInput.disabled = false; termInput.disabled = false; recalcEndDate(card); updateSubmitButton(); } else { dateInput.disabled = true; // ... 还要清理 N 个联动状态 } 同样的逻辑用 React 写: const [items, setItems] = useState(initialItems); // 选中状态变了,UI 自动更新 <Checkbox checked={item.selected} onCheckedChange={(v) => updateItem(i, { selected: v })} /> 2. 测试的死角 v1.x 加了测试框架,但能测的只有纯函数(日期计算、状态判断)。涉及 DOM 的业务逻辑根本没法测,因为每个模块都依赖全局的 App 对象和一堆 DOM 节点。 ...

February 25, 2026 · Legion

海缆库存系统更新:从 Excel 工具到商业级应用

距离上一篇文章发布刚好三天,这个"随手造的轮子"又经历了一轮密集迭代。原本以为 v1.0 已经够用了,结果实际使用中发现:能跑和好用之间差距还挺大的。 这一轮更新了什么? 🏢 CRM/SRM 集成 最大的变化是引入了客户和供应商管理。 之前销售订单里的客户名称是自由文本——想填什么填什么。问题很快就暴露了: 同一个客户,不同订单里名字不一样(“Telia” vs “Telia Carrier” vs “Telia Company”) 统计时根本没法聚合 供应商信息更是散落在各个成本卡片里 现在改成了关系型设计: 新增 Customers 和 Suppliers 表 销售订单、库存成本卡片里的客户/供应商字段,变成可搜索的下拉框 后台存储的是 UUID 外键,前端显示简称 这个改动涉及到 SQL migration、Store 层 CRUD、表单验证、UI 组件……工作量比想象的大不少。 📐 销售订单表单重新设计 原来的表单是简单的两栏布局,随着字段越来越多,变得又长又乱。这次做了一次嵌套式主从布局: ┌─────────────────────────────────────────────────────────────┐ │ Profitability │ Sales Info │ Cost Structure │ │ Analysis │ │ │ │ (Sticky) │──────────────┴──────────────────────────│ │ │ Order Notes (Full Width) │ └──────────────────┴─────────────────────────────────────────┘ 左侧边栏:利润分析卡片,设置为 position: sticky,滚动时始终可见 右侧主区域:销售信息 + 成本结构用 2 栏 grid,备注独占一行 移动端:自动堆叠成单列 sticky 元素在嵌套容器里的表现踩了不少坑,比如父容器 overflow 属性会影响 sticky 生效、flex 子项需要显式设置高度等。 ...

January 14, 2026 · Legion