我做了一个离线法语背词网站:Le Vocabulaire
一个离线优先、无登录的法语学习网站,基于 Vue 3 + Vite + Pinia,支持单词卡、测验、统计与本地数据管理。
海缆系统重写手记:从 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 节点。 ...
海缆系统迭代记录:打磨细节,优化体验
距离 上次更新 又过了几天,这个海缆管理工具已经迭代到 v1.13.0。这一轮更新的主题是打磨细节——没有太多新功能,但在用户体验和代码质量上做了不少改进。 主要更新 💰 成本总览面板 (v1.11.0) Sales Order 表单里有各种成本卡片(Cable、Backhaul、Cross-Connect 等),之前填完只能靠脑算总成本。现在加了一个实时计算面板: ┌─────────────────────────────────────┐ │ 📊 Cost Totals Summary │ ├─────────────────────────────────────┤ │ Recurring (MRC): $2,500 /month │ │ One-time (NRC): $15,000 │ │ Amortized: $625 /month │ └─────────────────────────────────────┘ 设计细节: 面板跟随成本卡片的状态实时更新 支持 Toggle 选择器,可以快速开关成本类型 Amortized 值自动根据合同期限计算(NRC 分摊到每月) 为了这个功能,还重构了成本卡片的 UI 模式——原来的"Add Cost"按钮改成了Toggle 开关,更清晰地表达"这个成本项是否包含"的语义。 📱 浮动胶囊导航 (v1.12.0) 移动端的底部导航栏从全宽条形改成了浮动胶囊风格: Before: ┌─────────────────────────────────────┐ │ 🏠 📦 💰 👥 ⚙️ │ └─────────────────────────────────────┘ After: ╭───────────────────────╮ │ 🏠 📦 💰 👥 ⚙️ │ ╰───────────────────────╯ 这是参考了 iOS 17 和各种现代 App 的导航设计。关键实现细节: ...
海缆库存系统迭代:从功能完善到生产就绪
又过了一天,这个"随手造的轮子"已经迭代到了 v1.10.0。从 v1.2 的架构重构 到现在,系统经历了从"能用"到"好用"再到"可靠"的蜕变。 主要更新 🔄 销售订单续约系统 (v1.4.0 - v1.9.0) 这是最实用的新功能。之前合同到期需要手动创建新订单、重新填写所有信息,现在一键续约就能搞定。 核心设计思路: ID 连续性:续约后保持原始订单号,便于历史追溯 商务灵活性:支持续约时调整价格(MRC/NRC),记录新旧价差 智能日期计算:自动计算新合同期限,支持自定义合同长度 ┌─────────────────────────────────────────┐ │ 📋 Renewal Workspace │ ├─────────────────────────────────────────┤ │ Current MRC: $3,000 → New MRC: [$___]│ │ Current NRC: $500 → New NRC: [$___]│ │ │ │ ▼ Cost Renewals (Optional) │ │ ┌─ Cable Cost ────────────────┐ │ │ │ MRC: $___ Annual O&M: $___| │ │ └─────────────────────────────┘ │ └─────────────────────────────────────────┘ v1.9.0 集成成本续约:续约时可以同步更新 Cable、Backhaul、Cross-Connect 等供应商成本,确保 P&L 全程准确。 ...
海缆库存系统更新:从 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 子项需要显式设置高度等。 ...