feat(i18n): add error code mapping for payment API errors

This commit is contained in:
erio
2026-04-07 22:03:11 +08:00
parent f3276f1c17
commit f92397642a
4 changed files with 34 additions and 11 deletions
+1
View File
@@ -5144,6 +5144,7 @@ export default {
errors: {
tooManyPending: 'Too many pending orders (max {max}). Please complete or cancel existing orders first.',
cancelRateLimited: 'Too many cancellations. Please try again later.',
PENDING_ORDERS: 'This provider has pending orders. Please wait for them to complete before making changes.',
},
stripePay: 'Pay Now',
stripeSuccessProcessing: 'Payment successful, processing your order...',
+1
View File
@@ -5341,6 +5341,7 @@ export default {
errors: {
tooManyPending: '待支付订单过多(最多 {max} 个),请先完成或取消现有订单',
cancelRateLimited: '取消订单过于频繁,请稍后再试',
PENDING_ORDERS: '该服务商有未完成的订单,请等待订单完成后再操作',
},
stripePay: '立即支付',
stripeSuccessProcessing: '支付成功,正在处理订单...',
+24 -7
View File
@@ -10,6 +10,8 @@ interface ApiErrorLike {
code?: number | string
message?: string
error?: string
reason?: string
metadata?: Record<string, unknown>
response?: {
data?: {
detail?: string
@@ -19,21 +21,36 @@ interface ApiErrorLike {
}
}
/**
* Extract the error code from an API error object.
*/
export function extractApiErrorCode(err: unknown): string | undefined {
if (!err || typeof err !== 'object') return undefined
const e = err as ApiErrorLike
const code = e.code ?? e.reason ?? e.response?.data?.code
return code != null ? String(code) : undefined
}
/**
* Extract a displayable error message from an API error.
*
* Handles:
* - Plain objects from API client interceptor: { status, code, message }
* - Axios errors with response.data
* - Standard Error instances
* - Unknown types (stringified)
*
* @param err - The caught error (unknown type)
* @param fallback - Fallback message if none can be extracted (use t('common.error') or similar)
* @param i18nMap - Optional map of error codes to i18n translated strings
*/
export function extractApiErrorMessage(err: unknown, fallback = 'Unknown error'): string {
export function extractApiErrorMessage(
err: unknown,
fallback = 'Unknown error',
i18nMap?: Record<string, string>,
): string {
if (!err) return fallback
// Try i18n mapping by error code first
if (i18nMap) {
const code = extractApiErrorCode(err)
if (code && i18nMap[code]) return i18nMap[code]
}
// Plain object from API client interceptor (most common case)
if (typeof err === 'object' && err !== null) {
const e = err as ApiErrorLike
+8 -4
View File
@@ -2888,6 +2888,10 @@ const cancelRateLimitModeOptions = computed(() => [
{ value: 'fixed', label: t('admin.settings.payment.cancelRateLimitWindowModeFixed') },
])
const paymentErrorMap = computed(() => ({
PENDING_ORDERS: t('payment.errors.PENDING_ORDERS'),
}))
async function loadProviders() {
providersLoading.value = true
try { const res = await adminAPI.payment.getProviders(); providers.value = res.data || [] }
@@ -2920,7 +2924,7 @@ async function handleSaveProvider(payload: any) {
// Also save the overall settings so payment config changes are persisted together
await saveSettings()
} catch (err: unknown) {
appStore.showError(extractApiErrorMessage(err, t('common.error')))
appStore.showError(extractApiErrorMessage(err, t('common.error'), paymentErrorMap.value))
} finally {
providerSaving.value = false
}
@@ -2932,7 +2936,7 @@ async function handleToggleField(provider: ProviderInstance, field: 'enabled' |
await adminAPI.payment.updateProvider(provider.id, { [field]: newValue })
if (field === 'enabled') provider.enabled = newValue
else provider.refund_enabled = newValue
} catch (err: unknown) { appStore.showError(extractApiErrorMessage(err, t('common.error'))) }
} catch (err: unknown) { appStore.showError(extractApiErrorMessage(err, t('common.error'), paymentErrorMap.value)) }
}
async function handleToggleType(provider: ProviderInstance, type: string) {
@@ -2946,7 +2950,7 @@ async function handleToggleType(provider: ProviderInstance, type: string) {
try {
await adminAPI.payment.updateProvider(provider.id, { supported_types: updated } as any)
provider.supported_types = updated
} catch (err: unknown) { appStore.showError(extractApiErrorMessage(err, t('common.error'))) }
} catch (err: unknown) { appStore.showError(extractApiErrorMessage(err, t('common.error'), paymentErrorMap.value)) }
}
function confirmDeleteProvider(provider: ProviderInstance) {
@@ -2961,7 +2965,7 @@ async function handleDeleteProvider() {
appStore.showSuccess(t('common.deleted'))
showDeleteProviderDialog.value = false
loadProviders()
} catch (err: unknown) { appStore.showError(extractApiErrorMessage(err, t('common.error'))) }
} catch (err: unknown) { appStore.showError(extractApiErrorMessage(err, t('common.error'), paymentErrorMap.value)) }
}
onMounted(() => {