All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m7s
微信按当前 v2/v3 配置分别生成 MWEB/H5 链接,支付宝复用 C 端 WAP 链接,并让可用支付方式基于生效配置判断。 Constraint: 支付链接统一通过 qr_content 返回,由前端渲染二维码;按要求不运行测试 Rejected: 微信 Native 与支付宝当面付 | 会引入非当前商户配置所需的额外产品开通 Confidence: high Scope-risk: moderate Directive: 微信 H5/MWEB 二维码仅承诺系统相机或外部浏览器扫码链路 Tested: 相关 Go 包编译通过;gofmt 与 git diff --check 通过 Not-tested: 按用户要求未运行自动化测试及真实支付联调
13 KiB
13 KiB
代理钱包扫码充值实现与接口对接说明
面向:产品、前端和联调人员
范围:代理微信/支付宝桌面扫码自充、平台线下代充来源区分、支付状态轮询
接口细节:以docs/admin-openapi.yaml为准,本文说明前端调用顺序、字段口径和页面状态。
一、先看这几个关键结论
- 同一个创建接口有两条业务路径:代理账号使用
wechat|alipay在线自充;平台或超级管理员使用offline线下代充。 - 前端必须使用
recharge_source区分来源:platform_offline是平台线下代充,agent_online是代理在线自充;不要根据账号名称、备注或审批字段猜测。 - 代理不能选择充值店铺:在线充值的店铺和主钱包由登录上下文确定,请求不得发送
shop_id、支付凭证或备注。 - 二维码由前端渲染:后端在
qr_content返回支付 HTTPS URL,不返回二维码图片。 - 网络重试不能创建新请求 ID:同一次提交重试复用原
request_id;用户主动发起下一笔充值时生成新的request_id。 - 支付和钱包到账是两个阶段:
status=2表示第三方已收款、钱包入账处理中;只有status=3才表示钱包到账完成。 - 页面轮询只调用本地状态接口:前端不得直接调用微信、支付宝查单,也不要反复调用创建接口查询状态。
- 在线金额单位为分:最低
10000分(100 元),最高100000000分(100 万元);不要提交浮点元金额。
二、本次需求怎么实现
| 能力 | 后端实现 | 前端要做什么 |
|---|---|---|
| 可用支付方式 | 根据当前有效支付配置返回真正可用的 wechat、alipay |
打开充值弹窗时先查询;只展示返回数组中的方式 |
| 代理在线自充 | 从登录账号取得当前店铺和主钱包,创建充值单、支付单并按配置生成微信 v3 H5/v2 MWEB 或支付宝 WAP 支付 URL | 只提交金额、支付方式和请求 ID;用 qr_content 渲染二维码 |
| 平台线下代充 | 保留既有目标店铺、凭证和企业微信审批流程 | 平台页面继续提交 offline 请求并只读展示审批状态 |
| 充值来源 | 根据受控创建方式返回稳定来源枚举 | 列表、详情和支付状态统一展示 recharge_source_name |
| 支付确认 | 微信/支付宝回调确认第三方收款事实 | 前端无需调用回调接口 |
| 钱包入账 | Outbox/Worker 幂等增加代理主钱包余额 | status=2 展示“入账处理中”,status=3 展示“已到账” |
| 回调丢失恢复 | Worker 使用原支付单号主动查单并收敛状态 | 页面继续轮询本地状态,无需提供“重新查单”按钮 |
三、接口对接表
| 页面动作 | 接口 | 前端调用说明 |
|---|---|---|
| 打开代理在线充值弹窗 | GET /api/admin/agent-recharges/payment-methods |
仅代理账号调用;返回支付方式和金额上下限 |
| 创建在线扫码充值 | POST /api/admin/agent-recharges |
代理只传 amount + payment_method + request_id |
| 创建平台线下代充 | POST /api/admin/agent-recharges |
平台/超级管理员传 shop_id + amount + payment_method=offline + payment_voucher_key + remark |
| 查询充值列表 | GET /api/admin/agent-recharges |
支持 `recharge_source=platform_offline |
| 查询充值详情 | GET /api/admin/agent-recharges/:id |
使用返回的来源、充值状态和审批状态展示 |
| 轮询在线支付状态 | GET /api/admin/agent-recharges/:id/payment-status |
仅在线单使用;页面可见时每 3 秒调用,终态停止 |
| 支付回调 | 微信/支付宝既有回调地址 | 只由支付渠道调用,前端禁止调用 |
所有接口都使用 Bearer Token,成功响应统一为:
{
"code": 0,
"msg": "success",
"data": {},
"timestamp": "2026-07-27T16:00:00+08:00"
}
前端应同时检查 HTTP 状态和响应体 code,失败时优先展示后端返回的 msg。
四、代理在线扫码充值调用流程
4.1 查询可用支付方式
GET /api/admin/agent-recharges/payment-methods
Authorization: Bearer {token}
响应示例:
{
"code": 0,
"msg": "success",
"data": {
"methods": ["wechat", "alipay"],
"min_amount": 10000,
"max_amount": 100000000
},
"timestamp": "2026-07-27T16:00:00+08:00"
}
前端处理规则:
methods=[]:隐藏或禁用提交按钮,提示“当前暂无可用在线支付方式”。- 只显示返回的支付方式,不自行补充微信或支付宝。
- 金额校验直接使用返回的
min_amount、max_amount,提交值仍为整数分。 - 平台、超级管理员和企业账号不调用此接口。
4.2 创建在线充值单
POST /api/admin/agent-recharges
Authorization: Bearer {token}
Content-Type: application/json
微信请求示例:
{
"amount": 10000,
"payment_method": "wechat",
"request_id": "recharge-20260727-8f73d95d"
}
支付宝只需将 payment_method 改为 alipay。
在线请求禁止发送:
shop_idpayment_voucher_keyremark- 商户号、应用 ID、密钥、支付配置 ID
成功响应示例:
{
"code": 0,
"msg": "success",
"data": {
"recharge_id": 101,
"recharge_no": "ARCH20260727160000123456",
"payment_no": "PAY20260727160000987654",
"payment_method": "wechat",
"recharge_source": "agent_online",
"recharge_source_name": "代理在线自充",
"amount": 10000,
"qr_content": "https://pay.example.com/...",
"status": 1,
"status_name": "待支付"
},
"timestamp": "2026-07-27T16:00:00+08:00"
}
前端处理规则:
- 将
qr_content原样交给二维码组件,不解析、不改写、不拼接。 - 二维码页面保存
recharge_id,后续轮询使用该 ID,不使用payment_no查询。 - 同一次请求超时或网络断开时,重试必须复用原
request_id;后端会返回原充值单和原二维码内容。 - 用户关闭弹窗后重新点击“立即充值”,视为新一笔主动提交,必须生成新的
request_id。 - 相同
request_id改变金额或支付方式会返回冲突,前端不得自动覆盖原请求。
4.3 轮询支付和到账状态
GET /api/admin/agent-recharges/101/payment-status
Authorization: Bearer {token}
响应示例:
{
"code": 0,
"msg": "success",
"data": {
"recharge_id": 101,
"recharge_no": "ARCH20260727160000123456",
"recharge_source": "agent_online",
"recharge_source_name": "代理在线自充",
"status": 2,
"status_name": "已支付",
"payment_status": 1,
"payment_status_name": "已支付",
"paid_at": "2026-07-27 16:01:20",
"completed_at": null
},
"timestamp": "2026-07-27T16:01:21+08:00"
}
页面建议每 3 秒轮询一次,仅在二维码弹窗可见时执行。按以下状态展示:
status |
含义 | 页面展示 | 是否继续轮询 |
|---|---|---|---|
1 |
待支付 | 等待用户扫码付款 | 是 |
2 |
已支付 | 支付成功,钱包入账处理中 | 是 |
3 |
已完成 | 充值成功,钱包已到账 | 否 |
4 |
已关闭 | 订单已关闭,请重新发起充值 | 否 |
5 |
已退款 | 已退款 | 否 |
6 |
已驳回 | 已驳回 | 否 |
payment_status 的值为:0=待支付、1=已支付、2=已失败、3=已退款。页面主流程优先根据充值 status 判断;payment_status 用于补充支付阶段文案。
进入 status=3 后,前端刷新钱包余额和充值列表。不要在 status=2 时提前增加页面余额。
五、平台线下代充调用流程
平台或超级管理员继续调用同一个创建接口:
{
"shop_id": 20,
"amount": 50000,
"payment_method": "offline",
"payment_voucher_key": ["recharge-voucher/20260727/abc.png"],
"remark": "银行转账"
}
线下代充响应和后续列表/详情会返回:
{
"recharge_source": "platform_offline",
"recharge_source_name": "平台线下代充",
"approval_provider": "wecom",
"approval_status": 1,
"approval_status_name": "审批中"
}
前端处理规则:
- 代理账号不得展示线下代充表单。
- 平台线下单展示凭证、备注和企微审批状态,不展示扫码二维码。
- 存在
approval_instance_id或approval_provider=wecom时,只读展示审批进度,不显示旧的本地确认/驳回按钮。 - 在线充值的
approval_instance_id为null,不要显示企微审批区域。 /:id/payment-status是在线支付状态接口,线下代充详情使用GET /:id,不要轮询支付状态接口。
六、列表和详情对接
列表请求示例:
GET /api/admin/agent-recharges?page=1&page_size=20&recharge_source=agent_online&status=1
可用筛选参数:
| 参数 | 说明 |
|---|---|
page |
页码,默认 1 |
page_size |
每页条数,默认 20,最大 100 |
shop_id |
店铺 ID,按既有数据权限生效 |
status |
充值状态 1~6 |
recharge_source |
platform_offline 或 agent_online |
start_date |
开始日期,格式 YYYY-MM-DD |
end_date |
结束日期,格式 YYYY-MM-DD |
列表成功响应的分页数据位于:
{
"data": {
"items": [],
"total": 0,
"page": 1,
"size": 20
}
}
建议列表至少展示:充值单号、店铺、金额、recharge_source_name、支付方式、status_name、提交人和创建时间。
详情接口:
GET /api/admin/agent-recharges/{id}
页面分支必须以 recharge_source 为准:
agent_online:展示支付方式、第三方流水号、支付时间、完成时间;隐藏凭证和企微审批操作。platform_offline:展示支付凭证、备注、提交人和企微审批状态;隐藏二维码和在线轮询区域。
七、充值来源与状态字段
7.1 充值来源
| 字段值 | 中文名 | 创建人和路径 |
|---|---|---|
platform_offline |
平台线下代充 | 平台/超级管理员提交 payment_method=offline |
agent_online |
代理在线自充 | 代理提交 `payment_method=wechat |
前端展示中文时优先使用后端返回的 recharge_source_name,业务分支使用稳定枚举 recharge_source。
7.2 充值状态
| 状态 | 名称 | 说明 |
|---|---|---|
1 |
待支付 | 在线单等待扫码;线下单等待审批 |
2 |
已支付 | 第三方收款已确认,钱包可能仍在入账 |
3 |
已完成 | 钱包余额和唯一流水已提交 |
4 |
已关闭 | 在线支付关闭或预下单失败 |
5 |
已退款 | 充值已退款 |
6 |
已驳回 | 线下代充审批驳回 |
八、权限和错误处理
| 操作 | 平台/超级管理员 | 代理账号 | 企业账号 |
|---|---|---|---|
| 创建在线扫码充值 | 禁止 | 仅当前店铺主钱包 | 禁止 |
| 创建线下代充 | 允许 | 禁止 | 禁止 |
| 查询在线支付方式 | 禁止 | 允许 | 禁止 |
| 查询列表/详情 | 按既有数据范围 | 按店铺层级数据范围 | 禁止 |
| 查询在线支付状态 | 按既有数据范围 | 按店铺层级数据范围 | 禁止 |
前端不要根据错误文案判断资源是否存在。无权限或资源不可见时,后端可能统一返回“无权限操作该资源或资源不存在”。常见处理:
400:保留表单输入并展示参数错误,不自动重试。401:按现有登录失效流程处理。403:关闭无权限操作入口,不尝试换账号类型绕过。409或业务冲突码:检查是否错误复用了request_id。500/超时:在线创建可使用原request_id重试一次;不要生成新 ID,否则可能创建第二张充值单。
九、前端本期最容易漏掉的工作
- 在线充值表单不要复用线下表单对象后整体序列化,避免携带
shop_id、凭证或备注。 - 支付方式必须来自
/payment-methods,不要写死微信和支付宝都可用。 - 金额显示元、提交分;禁止使用浮点数直接乘除后提交。
- 二维码内容原样渲染,不记录到埋点、错误日志或浏览器持久化缓存。
- 同一次网络重试复用
request_id,新一笔主动充值换新 ID。 status=2只表示已收款、入账中,不能提前刷新成“钱包已到账”。- 列表、详情的页面分支使用
recharge_source,不要用payment_method或审批字段猜来源。 - 线下单不调用支付状态接口;在线单不展示企微审批按钮。
- 页面隐藏或浏览器切到后台时停止轮询,恢复可见后再继续。
- 进入终态后停止轮询并刷新钱包余额、充值列表。
十、联调和验收边界
- OpenAPI 已包含
/payment-methods、在线创建、列表来源筛选、详情来源字段和/payment-status。 - 后端已完成微信 v3 H5/v2 MWEB、支付宝 WAP 支付 URL、支付确认、异步钱包入账和回调丢失恢复的代码装配。
- 当前交付已通过
go build ./...、go vet ./...和 OpenSpec 严格校验。 - 按需求方要求,本次未启动 API/Worker,未连接 PostgreSQL/Redis,未调用真实支付渠道,未发送真实回调,也未运行自动化测试。
- 前端联调环境需具备完整支付配置;至少确认微信和支付宝创建响应分别返回非空
qr_content。 - 本需求不支持 JSAPI、H5、WAP、同设备拉起支付、主动取消、支付方式切换、二维码图片接口或在线退款。