# 账户中心套餐卡片与支付二维码弹窗设计 日期:2026-09-01 范围:只改 `laic-frontend` 的 `AccountView`(及必要样式),不改后台、不改代理。 ## 背景 账户中心流量购买与 SIM 充值已接上「选套餐 → 创建业务订单 → POST payments」主链路,但 UI 仍有两处缺口: 1. 套餐选择仍是默认横排 `t-radio` 文本行,视觉上像未完成;卡片网格此前只定了方向,代码未落地。 2. `POST /v1/account/payments` 已返回 `providerPayload`(实测为 AgPay 二维码 PNG),前端只 toast「请按返回凭证完成支付」,用户看不到码。 ## 目标 1. 流量页与 SIM 充值弹窗的套餐选择改为**卡片网格**(名称 / 容量 / 价格 / 有效期分区;选中高亮)。 2. 购买并支付 / 去支付成功后弹出**独立支付弹窗**:金额、业务类型、订单号、二维码、关闭;提供「我已支付,刷新状态」。 3. 流量与 SIM 共用同一支付弹窗逻辑。 4. 验收:本地看卡片样式;走通流量下单 → 弹窗出码;刷新状态可读支付/订单结果。 ## 非目标 - 不引入微信支付 JS SDK / 原生扫码 SDK。 - 不做自动轮询支付结果(仅手动刷新)。 - 不改后端订单/支付协议、不修 `payment_idempotency_key` 空串唯一索引问题。 - 不 seed SIM 卡/套餐;SIM 无数据时弹窗与卡片样式仍可用,但充值主路径可缺卡。 - 不改发票、账号安全、概览其它区块。 ## 现状 - 文件:`src/views/AccountView/AccountView.vue` - 流量套餐:`t-radio-group` + `t-radio`,文案单行 `名称 · GB · ¥x / 天` - SIM 套餐:充值弹窗内同样横排 radio - 支付:`createPayment` → `describePayment` toast;`urls.PAYMENT(id)` 已存在但未用于 UI 刷新 - 原型参考:`jcWeb 3` 通信卡充值有 `carrier-package-grid` 按钮卡;流量页旧稿是按 GB 快捷量,不是套餐卡 ## 设计 ### 1. 套餐卡片网格 保留 `t-radio-group` / `t-radio` 的无障碍选择与 `v-model`,只改结构与样式: ```vue {{ pkg.name }} {{ amountLabel }} {{ money(pkg.price) }} 有效期 {{ pkg.validityDays }} 天 ``` 样式要点: - 网格:`repeat(auto-fill, minmax(140px, 1fr))`,间距 8–10px - 卡片:白底、细边框、圆角;选中态蓝边 + 浅蓝底(对齐现有 `--blue` / `#f3f8fc`) - 隐藏原生 radio 圆点,整卡可点 - SIM 充值弹窗复用同一 class;字段映射:`amountGb`、`moneyFromFen(saleFeeFen)`、`validityMonths` 右侧「订单概要」不变;选中卡片后摘要可显示当前套餐金额(可选增强:有则显示,无则保持现文案)。 ### 2. 支付二维码弹窗 新增状态: ```js payDialogOpen payDialogLoading payDialogRefreshing payDialogError payDialogMeta = { businessType, // traffic_order | sim_recharge_order businessOrderId, transactionId, amountText, status, qrSrc, // data:image/png;base64,... 或可直接用于 title } ``` 触发: - `createTrafficOrderAndPay` / `payTrafficOrder` - SIM:`createSimRechargeAndPay` / `payPendingSimOrder` 成功拿到 payment 后: 1. 解析 `providerPayload` → `qrSrc` 2. 打开 `t-dialog`(`header=微信支付` / `扫码支付`) 3. toast 可保留一句短提示,或以弹窗为主、toast 降级为失败提示 弹窗内容: - 金额(大字) - 业务说明(云媒体流量 / 通信卡充值)+ 订单号 - 二维码 ``;无图时展示错误文案与「重新拉起支付」 - 底部:`关闭`、`我已支付,刷新状态` 刷新: - `GET urls.PAYMENT(transactionId)` - 若 `status === 'paid' | 'success'`:toast 成功,关弹窗,刷新订单/余额/SIM - 若仍 `processing/unpaid`:更新文案「尚未到账,可稍后重试」 - 同步刷新对应业务列表(`loadOrders` / `loadSim` / balance) ### 3. providerPayload 解析 实测 payload 为 PNG 二进制经 JSON 字符串化后的内容。前端兼容: 1. 已是 `data:image/...` → 直接用 2. 已是 `http(s)://` 或 `/...` URL → 直接用 3. 看起来像 base64(无空白或标准 base64)→ `data:image/png;base64,` + 原文 4. 其它:标记无图,弹窗提示「支付已创建,但二维码无法展示」 不引入第三方 QR 库。 ## 验收 1. 账户 → 云媒体流量:套餐为卡片网格,选中高亮,不再是单行默认 radio。 2. 点击「购买并支付」:创建订单 + 支付成功后弹出二维码弹窗,图可见。 3. 「去支付」同样弹窗。 4. 「我已支付,刷新状态」会请求支付详情并刷新订单列表。 5. SIM 充值弹窗套餐同为卡片;有支付结果时共用支付弹窗(无卡时不阻塞流量验收)。 ## 风险 - 若后端偶发返回非 PNG/非 base64 的 payload,弹窗需有降级文案,不能白屏。 - 取消订单后若仍写入空 `payment_idempotency_key`,可能再次误报「存在未付款订单」——属后端问题,本设计不修;测试前可清空串或取消后置 NULL。 - 真机微信扫码入账依赖外部支付回调,本轮以「出码 + 刷新接口」为前端验收标准。