2026-05-25-money-input-thousand-separator.md 6.2 KB

金额/单价千分位输入与展示 — Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 在 web-admin 统一金额/单价的「聚焦纯数字、失焦千分位、提交数值」交互,并统一只读列表/详情的千分位展示。

Architecture: 抽取 money-format.ts 纯函数 + AmountInput 封装 el-input;业务页替换金额类 el-input-number 与局部重复逻辑;只读处使用 formatMoneyDisplay。

Tech Stack: Vue 3、Element Plus、TypeScript、现有 Prettier/ESLint 规范。

Design spec: docs/superpowers/specs/2026-05-25-money-input-thousand-separator-design.md


File map

操作 路径
Create web-admin/src/utils/money-format.ts
Create web-admin/src/components/common/amount-input/index.vue
Modify web-admin/src/views/pilot-service/channel-service-order/index.vue
Modify web-admin/src/views/pilot-service/channel-service-order-finance/index.vue
Modify openspec/changes/zkxw-engineering-standards/specs/ui-conventions/spec.md
Later P1+ channel/index.vue, cell-product-price/index.vue, project-price-system/index.vue, ProtocolFormDialog.vue, payment-info/index.vue, …

Task 1: 金额格式化工具

Files:

  • Create: web-admin/src/utils/money-format.ts

  • [ ] Step 1: 实现三个导出函数

export function addThousandSeparators(intStr: string): string { /* 字符串分段,无前瞻正则 */ }

export function sanitizeMoneyInput(value: string, precision = 2): string { /* 去逗号、单小数点、截断小数 */ }

export function formatMoneyDisplay(value: string | number | null | undefined, precision = 2): string

export function parseMoneyToNumber(value: string, precision = 2): number | null
  • Step 2: 本地快速验证

在 Node 或浏览器控制台执行:

formatMoneyDisplay(1234567.89) // '1,234,567.89'
parseMoneyToNumber('1,234.56') // 1234.56

Task 2: AmountInput 组件

Files:

  • Create: web-admin/src/components/common/amount-input/index.vue

  • [ ] Step 1: 实现组件

  • defineModel<number | null>() 或 modelValue + emit('update:modelValue')

  • 内部 displayText,watch(modelValue) 在非聚焦时同步为 formatMoneyDisplay

  • @focus → sanitize 展示

  • @input → sanitizeMoneyInput 写回 displayText

  • @blur → parseMoneyToNumber → emit;displayText = formatMoneyDisplay

  • Props: min, max, precision, placeholder, disabled, clearable

  • [ ] Step 2: 在渠道服务订单页面临时引用验证

仅 import 一个弹窗字段 smoke test(Task 3 会全量替换)。


Task 3: 渠道服务订单页(P0)

Files:

  • Modify: web-admin/src/views/pilot-service/channel-service-order/index.vue

  • [ ] Step 1: 删除页面内重复函数

移除 addThousandSeparators、formatRechargeAmountDisplay、sanitizeRechargeAmountInput、parseRechargeAmountInput、parseAmountInputToNumber(若仅用于充值)、rechargeAmountInput 及相关 handler。

  • Step 2: 替换可编辑金额
位置 替换为
发起充值 <AmountInput v-model="rechargeForm.amount" :min="0.01" />
申请退款 <AmountInput v-model="refundTxnForm.amount" :min="0.01" :max="currentBalance" />
新增/编辑 产品明细单价 <AmountInput v-model="row.unitPrice" :min="0" @change="calcItemAmount(row)" />
  • Step 3: 只读展示

将列表/查看/合计中的 formatAmount(金额类)改为 formatMoneyDisplay,或:

const formatAmount = (v: any) => formatMoneyDisplay(v, 2)

仅当该文件内 formatAmount 全部用于金额时方可整文件替换。

  • Step 4: 手工验收

按 spec 第 6 节 5 条检查;提交充值/退款 payload 为 number。


Task 4: 财务确认页只读列(P1 片段)

Files:

  • Modify: web-admin/src/views/pilot-service/channel-service-order-finance/index.vue

  • [ ] Step 1: formatAmount → formatMoneyDisplay

列表金额、详情单价/金额、确认弹窗中的金额文案。


Task 5: UI 规范 OpenSpec

Files:

  • Modify: openspec/changes/zkxw-engineering-standards/specs/ui-conventions/spec.md

  • [ ] Step 1: 新增 Requirement「金额与单价千分位」

SHALL 行为表 + AmountInput + formatMoneyDisplay 路径说明。


Task 6: P1 中试服务其余页(可并行子任务)

Files:

  • Modify: web-admin/src/views/pilot-service/channel/index.vue(协议价行内)
  • Modify: web-admin/src/views/pilot-service/cell-product-price/index.vue
  • Modify: web-admin/src/views/pilot-service/project-price-system/index.vue
  • Modify: web-admin/src/views/pilot-service/checkup-institution/index.vue、CheckupPackagePanel.vue

每文件重复 Task 3 的替换模式:金额类 el-input-number → AmountInput;只读 → formatMoneyDisplay。


Task 7: P2 细胞存储(后续迭代)

Files:

  • Modify: web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue
  • Modify: web-admin/src/views/cell-storage/payment-info/index.vue
  • 只读:ProtocolViewDialog.vue、payment/refund confirm 列表

Task 8: 图谱更新(Agent 规则)

  • Step 1: ./scripts/update-graph.sh frontend(完成 P0 后)

Self-review(plan ↔ spec)

Spec 要求 Task
聚焦/失焦/提交行为 Task 1–2
只读千分位 Task 3–4, 6–7
禁止页面内复制正则 Task 3 删除重复
数量字段排除 各 Task 仅改单价/金额
OpenSpec Task 5
分期 P0–P3 Task 3–7

执行选项

Plan 已保存至 docs/superpowers/plans/2026-05-25-money-input-thousand-separator.md。

  1. Subagent-Driven — 按 Task 派发子代理,逐 Task 评审
  2. Inline Execution — 当前会话按 Task 1→3 连续实现(建议先 P0)

请告知:是否批准设计 spec,以及希望先执行 P0(工具 + 组件 + 渠道服务订单) 还是全量分期推进。