Files
sub2api/backend/internal/payment
erio f2c6687cbf feat(payment): structured error codes + frontend i18n mapping
后端返回结构化错误码(reason + metadata 关键词),前端按 reason 查 i18n 文案并用 metadata 填充占位符,用户看到本地化提示而不是英文原始错误。

Backend:
- wxpay.go: 校验错误从 fmt.Errorf 改为 infraerrors.BadRequest 结构化,新增 reason 码:
  - WXPAY_CONFIG_MISSING_KEY (metadata: key)
  - WXPAY_CONFIG_INVALID_KEY_LENGTH (metadata: key, expected, actual)
  - WXPAY_CONFIG_PAIR_VIOLATION (metadata: keys)
- payment_order.go: invokeProvider 用 errors.As 识别 ApplicationError 透传(保留 wxpay 的 reason/metadata),只有非结构化 err 才 fallback 到 PAYMENT_PROVIDER_MISCONFIGURED;其他几个用户可见错误(TOO_MANY_PENDING / DAILY_LIMIT_EXCEEDED / PAYMENT_GATEWAY_ERROR / NO_AVAILABLE_INSTANCE)message 简化为关键词,参数放 metadata
- wxpay_test.go: 更新断言匹配新的 reason code

Frontend:
- apiError.ts: extractApiErrorCode 优先返回 reason(字符串错误码)而非 HTTP 数字;新增 extractI18nErrorMessage 按 namespace.reason 查 i18n 并以 metadata 作模板变量
- 12 个支付相关 Vue 文件(用户/管理/组件)统一改用 extractI18nErrorMessage('payment.errors', ...)
- i18n zh/en locales 下的 payment.errors 添加完整错误码文案(PAYMENT_DISABLED / INVALID_AMOUNT / TOO_MANY_PENDING / DAILY_LIMIT_EXCEEDED / WXPAY_CONFIG_* 等共 20+ 条,支持 {max}/{remaining}/{key} 等占位符)
- 移除 SettingsView 中已失效的 paymentErrorMap computed
2026-04-20 18:45:30 +08:00
..