Case Study
POS 机支付云系统
面向多品牌收单场景的支付云管理台:设备、交易、结算数据的统一视图与离线可用能力。
-60%
类型错误率
3 端
统一组件与主题
离线可用
IndexedDB 本地缓存
背景
支付云管理台要同时承载三类使用者:运营看交易大盘,风控查异常流水,运维管设备状态。旧系统由多个时期的技术栈拼接而成,同一个「交易详情」在不同模块有三套实现,字段口径也不一致。项目的第一优先级不是加功能,而是建立统一的类型与组件边界。
我的角色
- 负责管理台核心模块的前端架构与开发:交易查询、设备管理、结算对账、权限体系对接。
- 主导 JavaScript → TypeScript 的渐进式迁移与 Vue2 → Vue3 的架构升级。
- 搭建图表与大数据量表格的通用方案,抽象出可复用的业务组件。
关键设计
1. 用类型定义统一「口径」
迁移不是给变量补 : string,而是先把领域模型抽出来:
export type TransactionStatus = 'pending' | 'success' | 'failed' | 'reversed';
export interface Transaction {
id: string;
merchantId: string;
amount: number; // 单位:分,避免浮点误差
currency: 'CNY';
status: TransactionStatus;
paidAt: string | null; // ISO 8601
deviceSn: string;
}
金额统一用「分」存储与计算,展示层再做格式化;时间统一 ISO 字符串,避免 Date 在序列化时丢失时区。仅这两条约定,就消掉了对账页面长期存在的「差一分钱」争议。
2. 编译期就拦住跨模块误用
配合 vue-tsc 与 GitLab CI,类型检查成为合并前的硬性门禁;同时开启 strict、noUncheckedIndexedAccess,把「可能为空」显式化。最终类型相关缺陷下降约 60%,评审时也不再需要靠人工核对字段。
3. 大数据量表格与图表的性能取舍
- 交易列表采用虚拟滚动 + 分页缓存,单页 5000 行仍保持滚动流畅。
- 图表只渲染视口内的系列,切换筛选时复用实例而不是重建。
- 高频查询结果写入 IndexedDB,弱网或后端抖动时优先展示本地快照,并标注数据时间。
支付类系统的体验底线是「不误导」。宁可显示「数据截至 10:32」的旧快照,也不要因为请求失败展示一片空白。
结果
- TypeScript 覆盖率从不足 20% 提升到核心模块 100%,类型错误率下降约 60%。
- 交易、设备、结算三个模块共用一套表格与图表能力,新页面开发时间显著缩短。
- 弱网环境下管理台仍可查看最近一次交易快照,客服排障不再依赖「刷新试试」。
复盘
前端重构最容易陷入「为了新而新」。这次迁移真正产生价值的,是借 TypeScript 强制团队对金额单位、时间格式、状态枚举达成一致的约定。技术升级只是手段,口径统一才是收益。