Files
2026-09-12 11:27:50 +08:00

4.5 KiB
Raw Permalink Blame History

商户池详情与商户凭证契约设计

Context

支付商户与商户池管理页已经上线,运营在使用时遇到三个问题:商户池详情入口和支付商户不一致且信息不完整、新增商户池直接报错、商户凭证缺少字段枚举与类型校验。本次优化只新增详情页、收敛成员顺序数据源,并在既有凭证写入表单上叠加契约校验,不改变接口路径与请求结构。

Goals

  • 让商户池详情的入口和展示完整度与支付商户详情对齐。
  • 让新增/编辑商户池恢复可用,并且拖拽排序结果仍按顺序提交。
  • 让前端提交的商户凭证满足后端的字段枚举、必填键、值类型与商户标识约束。

Non-Goals

  • 不改变“更换凭证”表单的交互方式与凭证值不回显约束。
  • 不新增后端接口。

Decisions

商户池详情复用支付商户详情的入口模式

支付商户详情已采用“列表点击名称 → 独立详情页”的模式,因此商户池改为同样方式:列表名称列渲染为可点击文本,点击后跳转 /settings/payment-merchant-pools/pool-detail/:id,并移除行操作里的“详情”抽屉。

详情页复用 src/components/common/DetailPage.vue,按“基本信息”“轮询配置”“运行状态”三组展示字段。创建时间、更新时间只在接口返回时渲染,避免出现空白字段行。

替代方案是保留抽屉并补齐字段;但两个详情入口不一致会让运营难以形成稳定预期,因此不采用。

成员商户名称由前端解析

详情接口只返回 member_ids。详情页在加载详情后按该商户池的 payment_method 拉取支付商户列表,把成员 ID 映射为商户名称展示,同时保留成员数量。解析不到名称时展示“未知商户”,不展示 member_ids 原始 ID避免把内部标识暴露给运营。

成员顺序使用单一数据源

原实现同时监听 form.member_idsorderedMemberIds,并在两个回调中互相赋新数组,形成“赋值 → 触发 → 再赋值”的无限循环,从而在新增商户池时触发 Maximum recursive updates exceeded

修复方式是把成员顺序收敛为单一数据源:orderedMemberIds 改为基于 form.member_idscomputedget 返回成员数组set 写回成员数组)。VueDraggable 通过 v-model 触发 setter 写回 form.member_ids,不再存在互相触发的 watch。

凭证字段枚举固化在类型模块并在提交前校验

凭证必填键由后端契约按 payment_methodprovider_type 组合给出,前端与该契约保持一致,因此把枚举定义在 src/types/api/paymentMerchantPools.tsPAYMENT_CREDENTIAL_FIELD_SPECS 描述每个 provider_type 的必填键与可选键,PAYMENT_CREDENTIAL_BOOLEAN_KEYSPAYMENT_CREDENTIAL_INTEGER_KEYS 描述 ali_productionali_pay_expire_minutes 的值类型,PAYMENT_MERCHANT_IDENTITY_KEYS 描述商户标识必须一致的凭证字段。枚举之外的字段名一律拦截,避免提交必然被后端拒绝的请求。

buildPaymentCredentials 负责提交前校验并转换:拒绝不属于当前服务商的字段名、补齐必填键检查、把布尔字段与整数字段从输入框字符串转换为布尔值/数字、校验 merchant_identity 与对应凭证字段一致。表单继续使用“字段名 + 字段值”的通用编辑方式,只在分隔线下方展示当前服务商的必填/可选字段提示。

替代方案是把凭证表单改成按服务商渲染固定中文标签字段;该方案会改变既有交互与凭证只写约定,本次不采用。

凭证仅平台账号可读写

凭证读取与写入入口复用既有平台账号限制:/settings/payment-merchant-pools 及其详情路由都带 allowedUserTypes: [1, 2],页面内 canManage 再按 isPlatformAccount 过滤操作。凭证值只在当前编辑会话内存中存在,提交、取消或关闭后清空,不进入 Pinia 持久化、浏览器存储、日志或错误上报。

Risks and Trade-offs

  • 详情页与支付商户详情一样受 allowedUserTypes: [1, 2] 限制,代理与企业账号无法访问。
  • 商户池成员名称依赖支付商户列表接口,成员数量超过单页上限时可能解析不到名称,此时展示“未知商户”而不是原始 ID。
  • 凭证字段枚举与后端校验规则必须保持一致;后端新增字段时前端需要同步更新枚举,否则提交会被前端拦截。