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
| 操作 | 路径 |
|---|---|
| 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, … |
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
在 Node 或浏览器控制台执行:
formatMoneyDisplay(1234567.89) // '1,234,567.89'
parseMoneyToNumber('1,234.56') // 1234.56
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 会全量替换)。
Files:
Modify: web-admin/src/views/pilot-service/channel-service-order/index.vue
[ ] Step 1: 删除页面内重复函数
移除 addThousandSeparators、formatRechargeAmountDisplay、sanitizeRechargeAmountInput、parseRechargeAmountInput、parseAmountInputToNumber(若仅用于充值)、rechargeAmountInput 及相关 handler。
| 位置 | 替换为 |
|---|---|
| 发起充值 | <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)" /> |
将列表/查看/合计中的 formatAmount(金额类)改为 formatMoneyDisplay,或:
const formatAmount = (v: any) => formatMoneyDisplay(v, 2)
仅当该文件内 formatAmount 全部用于金额时方可整文件替换。
按 spec 第 6 节 5 条检查;提交充值/退款 payload 为 number。
Files:
Modify: web-admin/src/views/pilot-service/channel-service-order-finance/index.vue
[ ] Step 1: formatAmount → formatMoneyDisplay
列表金额、详情单价/金额、确认弹窗中的金额文案。
Files:
Modify: openspec/changes/zkxw-engineering-standards/specs/ui-conventions/spec.md
[ ] Step 1: 新增 Requirement「金额与单价千分位」
SHALL 行为表 + AmountInput + formatMoneyDisplay 路径说明。
Files:
web-admin/src/views/pilot-service/channel/index.vue(协议价行内)web-admin/src/views/pilot-service/cell-product-price/index.vueweb-admin/src/views/pilot-service/project-price-system/index.vueweb-admin/src/views/pilot-service/checkup-institution/index.vue、CheckupPackagePanel.vue每文件重复 Task 3 的替换模式:金额类 el-input-number → AmountInput;只读 → formatMoneyDisplay。
Files:
web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vueweb-admin/src/views/cell-storage/payment-info/index.vueProtocolViewDialog.vue、payment/refund confirm 列表./scripts/update-graph.sh frontend(完成 P0 后)| 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。
请告知:是否批准设计 spec,以及希望先执行 P0(工具 + 组件 + 渠道服务订单) 还是全量分期推进。