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

6.9 KiB
Raw Blame History

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 的兜底方式实现。
  • "我的延期订单"入口位置(套餐历史页右上角 / 首页功能卡 / 延期页底部),默认放套餐历史页右上角。