Files
device-voice-h5/openspec/changes/add-package-silence-extension/design.md
邹进 b2f802e6f8
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 25m59s
docs: 新增 C 端套餐沉默期展示与自助延期提案 add-package-silence-extension
2026-11-07 11:29:33 +09:00

88 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Context
- 后端 8-11 提供的沉默期 C 端能力(接口说明见 `junhong_cmp_fiber/docs/2026-10-27-实名即生效套餐沉默期-前端接口变更说明.md` 第 4、6、9 节):
- 套餐历史 `GET /api/c/v1/asset/package-history` 每笔套餐带 `silence` 对象,总开关关闭或不适用时不返回。
- `/api/c/v1/package-silence`:`GET /eligibility`、`GET /quote`、`POST /orders`、`GET /orders`、`GET /orders/:id`、`GET /records`。资产须属于当前客户。
- C 端现状(`iteration/8-11`):
- 套餐历史页 `pages/asset-package-history` 通过 `components/PackageHistoryNode.vue` 递归渲染主套餐与加油包,`api/modules/asset.js` 的 `normalizePackageHistoryNode` 用展开运算保留原字段,`silence` 会原样透传。
- 接口统一走 `utils/request.js`:`code !== 0` 时 reject 原始响应(含 `code`、`msg`、`data`),`showError: false` 可关闭默认提示。
- 支付:套餐购买走 `orderApi.create/pay`,微信用公众号 JSAPI(`wechatH5Pay`),支付宝走 `pages/alipay-payment`(`u-qrcode` 渲染二维码 + 复制链接),返回刷新用 `markPendingPaymentRefresh` / `consumePendingPaymentRefresh`。
- 支付方式标签与过滤在 `utils/payment-methods.js`,资产信息返回 `allowed_payment_methods`。
- 后端延期下单的支付:`POST /orders` 只返回 `qr_content`,按商户池路由:支付宝为 WAP 支付链接,微信为微信 H5 支付链接(`H5URL`),富友为扫码内容。没有返回 JSAPI 支付参数。
- 约束:基于 `iteration/8-11`,只部署测试环境;不改停复机逻辑;不改现有套餐购买流程。
## Goals / Non-Goals
**Goals:**
- 套餐历史可见沉默期状态与截止日,可延期的套餐有入口。
- 客户能自助完成付费延期并看到结果。
- 金额、可选天数、新截止日全部以后端为准。
**Non-Goals:**
- 特殊延期、线下登记、批量延期(后台功能)。
- 后端改动,包括为延期订单增加微信 JSAPI 支付。
- 生产发布。
## Decisions
### D1 沉默期展示放在 `PackageHistoryNode` 内
在套餐卡片"到期时间"下方加沉默期区域,`node.silence` 为空时整块不渲染;加油包节点复用同一组件,规则一致。不新开详情页,客户在原页面即可看到状态。状态名直接用后端 `silence_status_name`,前端只按 `silence_status` 选颜色(waiting 蓝、expired 红、ended 灰)。
备选:在套餐历史页顶部汇总沉默期。拒绝原因:一个资产可能有多笔套餐,按笔展示更清楚。
### D2 新增接口模块 `api/modules/packageSilence.js`
与现有模块风格一致,导出 `packageSilenceApi`:`getEligibility`、`quote`、`createOrder`、`getOrders`、`getOrder`、`getRecords`。下单和资格请求 `showError: false`,由页面按错误码映射提示(D6)。订单列表默认带当前资产 `asset_identifier`,只看当前资产的订单。
### D3 页面结构
新增三个页面并在 `pages.json` 注册:
| 页面 | 用途 |
|---|---|
| `pages/silence-extension/silence-extension` | 资格、选天数、试算、选支付方式、下单 |
| `pages/silence-orders/silence-orders` | 我的延期订单列表,点击进入详情(详情用同目录 `detail` 页) |
| `pages/silence-records/silence-records` | 某笔套餐的沉默期流水 |
延期页参数 `package_usage_id`,流水页参数 `package_usage_id`。入口:套餐卡片"延期""沉默期记录";"我的延期订单"放在套餐历史页右上角或延期页底部。
### D4 天数选择与试算
优先展示 `options` 档位(每档计费天数、金额、新截止日),默认选第一档;同时提供"自定义天数"输入,输入停止 500ms 后调 `quote`,以最后一次请求结果为准(丢弃过期响应)。前端只校验 `min_days ≤ days ≤ max_days` 和整数,金额一律显示后端值(分转元,两位小数)。
### D5 下单幂等与支付拉起
- `request_id` 在客户点击"确认支付"时生成(时间戳 + 随机串),存在页面状态中;同一次提交的网络重试复用,天数或支付方式变化后清空。
- 提交中按钮置为 loading,禁止重复提交。
- 支付宝:复用 `openAlipayPayment` 跳 `pages/alipay-payment`,二维码与复制链接都用 `qr_content`。
- 微信:后端返回的是微信 H5 支付链接或扫码内容,不是 JSAPI 参数。实现时先按"`qr_content` 是 http(s) 链接则 `window.location.href` 跳转,否则用 `u-qrcode` 渲染二维码并提示截图扫码"处理,见 Open Questions。
- 拉起前 `markPendingPaymentRefresh('silence-extension')`;延期页与订单详情 `onShow` 时 `consume` 到标记即查询订单详情。
### D6 错误码映射
在 `utils/silence-errors.js` 维护 1263~1274 的客户提示文案,1265、1266 用 `data` 中的范围拼接文案;资格接口的 `reason` 也映射为文案(not_expired、no_silence、extension_disabled、no_policy、exceeds_limit、refunded、order_pending、activated、adjust_pending)。未映射的错误码回退为后端 `msg`。
### D7 测试
沿用 `tests/october-h5.test.mjs` 的运行方式新增测试:套餐卡片沉默期显示与入口条件、天数校验、`request_id` 复用规则、错误码映射、支付返回刷新。
## Risks / Trade-offs
- [微信 H5 支付链接在微信内置浏览器中通常无法直接支付] → C 端主要在公众号内打开。上线测试前需要确认测试环境商户池给延期订单路由的微信渠道;若确实不能在微信内支付,短期只开放支付宝或二维码,长期需后端为延期订单提供 JSAPI 支付(另开后端变更)。
- [总开关默认关闭,测试环境看不到沉默期] → 验证前请超级管理员在后台打开总开关(打开前有 4 项检查)。
- [支付回跳不可靠] → 不依赖回跳,统一在 `onShow` 查订单详情;订单列表也可手动刷新。
- [延期下单不涉及停复机] → 延期只改套餐沉默期截止日;后端在延期生效后是否复机由后端规则决定,测试环境资产已全部在只读表中,不会真实复机。
## Migration Plan
1. 在 `iteration/8-11` 上实现并本地 `build:h5`(development 模式,接测试后端)。
2. 推送 `iteration/8-11` 部署测试环境(C 端 CI 目前推送未触发构建,需先查原因或手动部署)。
3. 测试环境打开沉默期总开关,用测试资产验证:展示、资格、试算、下单、支付、流水。
4. 回退:回滚 `iteration/8-11` 对应提交重新部署;后端关闭总开关时前端自动不显示沉默期。
## Open Questions
- 延期订单的微信支付方式:测试与生产商户池对延期订单走哪种微信渠道?是否需要后端提供 JSAPI 支付?决定前按 D5 的兜底方式实现。
- "我的延期订单"入口位置(套餐历史页右上角 / 首页功能卡 / 延期页底部),默认放套餐历史页右上角。