Files
sub2api/frontend/src/views/user/paymentUx.ts
2026-04-21 00:05:09 +08:00

106 lines
3.4 KiB
TypeScript

import { normalizeVisibleMethod } from '@/components/payment/paymentFlow'
import { extractApiErrorCode } from '@/utils/apiError'
const DISPLAY_METHOD_ALIASES: Record<string, string> = {
wechat: 'wxpay',
wechat_pay: 'wxpay',
}
export interface PaymentScenarioContext {
paymentMethod: string
isMobile: boolean
isWechatBrowser: boolean
}
export interface PaymentScenarioErrorDescriptor {
messageKey: string
hintKey?: string
}
export function normalizePaymentMethodForDisplay(paymentType: string): string {
const trimmed = paymentType.trim().toLowerCase()
const visibleMethod = normalizeVisibleMethod(trimmed)
if (visibleMethod) return visibleMethod
return DISPLAY_METHOD_ALIASES[trimmed] ?? trimmed
}
export function paymentMethodI18nKey(paymentType: string): string {
return `payment.methods.${normalizePaymentMethodForDisplay(paymentType)}`
}
function defaultWechatHint(context: PaymentScenarioContext): string {
if (!context.isMobile) return 'payment.errors.wechatScanOnDesktopHint'
return 'payment.errors.wechatOpenInWeChatHint'
}
function defaultAlipayHint(context: PaymentScenarioContext): string {
if (context.isMobile) return 'payment.errors.alipayMobileOpenHint'
return 'payment.errors.alipayDesktopQrHint'
}
export function describePaymentScenarioError(
error: unknown,
context: PaymentScenarioContext,
): PaymentScenarioErrorDescriptor | null {
const method = normalizePaymentMethodForDisplay(context.paymentMethod)
const code = extractApiErrorCode(error)
const message = error instanceof Error
? error.message
: (typeof error === 'object' && error && 'message' in error && typeof error.message === 'string'
? error.message
: String(error || ''))
const normalizedMessage = message.toLowerCase()
if (method === 'wxpay') {
if (code === 'WECHAT_H5_NOT_AUTHORIZED') {
return {
messageKey: 'payment.errors.wechatH5NotAuthorized',
hintKey: defaultWechatHint(context),
}
}
if (code === 'WECHAT_PAYMENT_MP_NOT_CONFIGURED') {
return {
messageKey: 'payment.errors.wechatPaymentMpNotConfigured',
hintKey: context.isWechatBrowser
? 'payment.errors.wechatSwitchBrowserHint'
: defaultWechatHint(context),
}
}
if (code === 'NO_AVAILABLE_INSTANCE') {
return {
messageKey: 'payment.errors.wechatUnavailable',
hintKey: defaultWechatHint(context),
}
}
if (code === 'WECHAT_JSAPI_FAILED' || normalizedMessage.includes('get_brand_wcpay_request:fail')) {
return {
messageKey: 'payment.errors.wechatJsapiFailed',
hintKey: defaultWechatHint(context),
}
}
if (normalizedMessage.includes('weixinjsbridge is unavailable')) {
return {
messageKey: 'payment.errors.wechatJsapiUnavailable',
hintKey: 'payment.errors.wechatOpenInWeChatHint',
}
}
if (code === 'PAYMENT_GATEWAY_ERROR' || code === 'UNHANDLED_PAYMENT_SCENARIO') {
return {
messageKey: 'payment.errors.wechatUnavailable',
hintKey: defaultWechatHint(context),
}
}
}
if (method === 'alipay' && (code === 'PAYMENT_GATEWAY_ERROR' || code === 'UNHANDLED_PAYMENT_SCENARIO')) {
return {
messageKey: context.isMobile
? 'payment.errors.alipayMobileUnavailable'
: 'payment.errors.alipayDesktopUnavailable',
hintKey: defaultAlipayHint(context),
}
}
return null
}