Files
one-pipe-system/openspec/changes/update-agent-self-recharge-and-offline-approval/design.md
2026-09-12 11:27:50 +08:00

6.9 KiB
Raw Blame History

Context

AUG26-017 给代理预存款带来两类变化:在线自充的收款方式从「由支付配置自动决定」改为「超管配置允许范围」;线下预存款审批从「金额 + 支付凭证」补齐为「收款方式 + 交易流水号 + 其他凭证」。后端接口边界已经确认:

用途 接口
在线可用方式 GET /api/admin/agent-self-recharge-payment-methods,代理/平台可用,超管 403旧接口 GET /api/admin/agent-recharges/payment-methods 保留但前端不再调用
允许范围读取 GET /api/admin/system-configsmodulepagepage_size,返回 list / page / page_size / total
允许范围写入 PUT /api/admin/system-configs/{key},请求体 { key, value }value 为字符串化配置值
交易流水号识别 POST /api/admin/agent-recharges/payment-voucher-ocr,请求 { payment_voucher_key },响应 { external_transaction_no }
线下创建 POST /api/admin/agent-rechargespayment_method=offline 时新增 offline_payment_method_idexternal_transaction_noother_voucher_key
列表与详情 GET /api/admin/agent-rechargesGET /api/admin/agent-recharges/{id} 新增 5 个响应字段

Goals / Non-Goals

Goals

  • 在线充值只展示后端返回的实际可用方式,并优雅处理空列表。
  • 超管可在既有系统配置页面维护允许范围,无需新增接口或页面。
  • 线下预存款申请可提交收款方式、交易流水号与其他凭证,并支持 OCR 预填流水号。
  • 列表与详情正确展示两类交易号与收款方式快照。

Non-Goals

  • 不新增「代理自充设置」独立页面与专用配置接口。
  • 不实现允许范围的审计查询接口(后端记录操作者、前后值与时间,前端不查询)。
  • 不实现后端接口、商户池交集计算、企微审批回调。
  • 不实现 H5/C 端在线充值,不为企业账号做分支。

Decisions

允许范围沿用受控系统配置

允许范围配置项的读取与写入统一走系统配置:读取 GET /api/admin/system-configs,写入 PUT /api/admin/system-configs/{key}。系统配置页已是元数据驱动的通用渲染器(value_type 决定控件、enum_values 决定枚举选项、readonlysensitive 决定保护策略),因此后端的允许范围配置项注册后即可在页面中展示与编辑。

前端 MUST NOT 硬编码该配置项的 config_key,也 MUST NOT 新增专用设置写接口。该配置项归属 c2b.payment 模块,属于现有 SystemConfigModule 取值,无需扩展模块枚举。

允许范围的枚举取值为 wechat_only(仅微信支付)、alipay_only(仅支付宝支付)、both(同时支持微信与支付宝);系统配置页展示与选择时使用中文标签,未命中映射时回退展示原值。

超管入口使用一个「代理自充设置」菜单项,跳转到系统配置页面并带 module=c2b.payment 过滤条件;系统配置页面除了既有的 config_key query还需支持从 route.query.module 初始化模块筛选,保证跳转后列表已按模块收敛。

在线可用方式

取值
接口 GET /api/admin/agent-self-recharge-payment-methods
响应 { methods: (wechat | alipay)[], min_amount, max_amount }
空列表 只提示「当前暂无可用的在线支付方式」,禁用提交,不解释被限制还是无可用商户
超管 该接口对超管返回 403前端在超管视角不请求它仅通过系统配置查看允许范围
存量单 配置变更不影响已创建的待支付单,前端不在配置变更后刷新待支付单

金额上下限优先使用接口返回的 min_amount / max_amount(单位分),接口未返回时回退既有常量。

线下预存款创建字段

字段 必填 说明
offline_payment_method_id 取自 GET /api/admin/employee-collection-payment-methods 的启用项(enabled=truepage_size=100
external_transaction_no 交易流水号OCR 预填后人工确认,可编辑;前端不做重复校验
other_voucher_key 其他凭证对象键数组,最多 5 个
payment_voucher_key 支付凭证,至少 1 个,与其他凭证分开提交

历史线下单的收款方式只用 offline_payment_method_code / offline_payment_method_name 快照展示,不用 offline_payment_method_id 反查字典当前值。

列表筛选保持后端已有参数集合(pagepage_sizeshop_idstatusrecharge_sourcestart_dateend_date),不新增交易流水号筛选,交易流水号只做展示。

OCR 预填交互

  • 入口:线下代充弹窗支付凭证区的「识别凭证」按钮,取已上传的第一个 payment_voucher_key;未上传凭证时禁用。
  • 请求:POST /api/admin/agent-recharges/payment-voucher-ocr;通过 BaseService.post 的第三个参数传 { timeout: 30000 },请求期间按钮与交易流水号字段展示 loading 并防重复点击。
  • 成功:把 external_transaction_no 写入交易流水号输入框,字段保持可编辑并提示对照凭证核对。
  • 失败(凭证不是图片、对象不存在、识别服务异常):只提示,不清空已填内容、不阻断手工填写与提交。
  • 只预填交易流水号,金额、付款人、付款时间、备注一律不预填。

凭证上传类型

取上传地址时必须显式声明 content_typeimage/jpeg,否则 OCR 会以「不是图片」直接拒绝。VoucherUpload 新增可选 contentType prop代理充值的支付凭证与其他凭证固定传 image/jpeg,并把它透传给 StorageService.getUploadUrlStorageService.uploadFile

交易流水号展示

payment_transaction_id 是在线渠道返回的权威交易号,只有在线单有值;external_transaction_no 是线下人工申报的交易流水号。两者独立展示、互不覆盖:在线单只展示前者,线下单只展示后者。

详情页保持只读

代理充值详情页只做信息展示,顶部仅保留返回导航;本次新增的交易流水号、收款方式与其他凭证都只读呈现,不引入任何业务操作按钮。创建、确认线下充值、驳回等操作入口仍留在列表页操作列。

Risks / Trade-offs

  • 配置 Key 由后端注册决定:前端不硬编码,配置项按 c2b.payment 模块渲染;若后端最终调整模块归属,只需同步调整菜单跳转的 module 参数。
  • OCR 端到端约 15 至 16 秒:必须配置不低于 30 秒的超时并展示 loading否则用户容易重复点击。
  • 强制声明 image/jpeg:按需求文档要求统一声明为 image/jpeg,上传非 JPEG 图片时以声明类型为准。
  • 收款方式字典项被引用后会冻结:展示历史单依赖快照字段,避免字典改名或停用导致历史数据展示漂移。