From 97a9949085875ecfa2239a3d2b606e401374f931 Mon Sep 17 00:00:00 2001 From: erio Date: Mon, 6 Apr 2026 16:03:58 +0800 Subject: [PATCH] fix(frontend): 7 payment UI issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Remove duplicate page titles (AppLayout bar already shows them) 2. Fix daily_limit empty value causing Go unmarshal error (NaN -> 0) 3. Enabled payment types: text input -> toggle badges 4. Provider dialog: supported types -> toggle badges per provider key 5. Auto-derive supported types when changing provider key 6. Fix ¥ symbol showing as literal \u00A5 in Vue templates 7. Show payment method selector when >= 1 method (was > 1) --- frontend/src/i18n/locales/en.ts | 1 + frontend/src/i18n/locales/zh.ts | 1 + frontend/src/views/admin/SettingsView.vue | 113 ++++++++++++++++-- .../views/admin/orders/AdminOrdersView.vue | 7 -- .../orders/AdminPaymentDashboardView.vue | 6 +- .../admin/orders/AdminPaymentPlansView.vue | 20 ++-- frontend/src/views/user/PaymentView.vue | 12 +- frontend/src/views/user/UserOrdersView.vue | 17 +-- 8 files changed, 122 insertions(+), 55 deletions(-) diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index 11d2c5066a..be9221f7d3 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -4345,6 +4345,7 @@ export default { helpImageUrl: 'Help Image URL', manageProviders: 'Manage Providers', balancePaymentDisabled: 'Disable Balance Recharge', + noLimit: 'Empty = no limit', productNamePrefix: 'Product Name Prefix', productNameSuffix: 'Product Name Suffix', preview: 'Preview', diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index 9c1142ddc9..8575a5a2c7 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -4518,6 +4518,7 @@ export default { helpImageUrl: '帮助图片链接', manageProviders: '管理服务商', balancePaymentDisabled: '禁用余额充值', + noLimit: '留空表示不限制', productNamePrefix: '商品名前缀', productNameSuffix: '商品名后缀', preview: '预览', diff --git a/frontend/src/views/admin/SettingsView.vue b/frontend/src/views/admin/SettingsView.vue index 6c2e511b0a..fbb657698a 100644 --- a/frontend/src/views/admin/SettingsView.vue +++ b/frontend/src/views/admin/SettingsView.vue @@ -1671,16 +1671,32 @@
-
-
+
+
-
+
- -

{{ t('admin.settings.payment.enabledPaymentTypesHint') }}

+ +
+ +
+ +
+
@@ -1756,9 +1772,26 @@
-
+
+ +
+ +
+ +
-

{{ t('admin.settings.payment.supportedTypesHint') }}

@@ -2574,11 +2607,11 @@ async function saveSettings() { : [] const paymentPayload = { enabled: form.payment_enabled, - min_amount: form.payment_min_amount, - max_amount: form.payment_max_amount, - daily_limit: form.payment_daily_limit, - max_pending_orders: form.payment_max_pending_orders, - order_timeout_minutes: form.payment_order_timeout_minutes, + min_amount: Number(form.payment_min_amount) || 0, + max_amount: Number(form.payment_max_amount) || 0, + daily_limit: Number(form.payment_daily_limit) || 0, + max_pending_orders: Number(form.payment_max_pending_orders) || 0, + order_timeout_minutes: Number(form.payment_order_timeout_minutes) || 0, balance_disabled: form.payment_balance_disabled, enabled_payment_types: enabledTypes, product_name_prefix: form.payment_product_name_prefix, @@ -2887,6 +2920,32 @@ async function saveBetaPolicySettings() { // ==================== Provider Management ==================== +const PROVIDER_SUPPORTED_TYPES: Record = { + easypay: ['alipay', 'wxpay'], + alipay: ['alipay'], + wxpay: ['wxpay'], + stripe: ['stripe'], +} + +const allPaymentTypes = computed(() => [ + { value: 'alipay', label: t('payment.methods.alipay') }, + { value: 'wxpay', label: t('payment.methods.wxpay') }, + { value: 'stripe', label: t('payment.methods.stripe') }, +]) + +function isPaymentTypeEnabled(type: string): boolean { + return form.payment_enabled_types.split(',').map(s => s.trim()).filter(Boolean).includes(type) +} + +function togglePaymentType(type: string) { + const current = form.payment_enabled_types.split(',').map(s => s.trim()).filter(Boolean) + if (current.includes(type)) { + form.payment_enabled_types = current.filter(t => t !== type).join(',') + } else { + form.payment_enabled_types = [...current, type].join(',') + } +} + const providersLoading = ref(false) const providerSaving = ref(false) const providers = ref([]) @@ -2915,6 +2974,33 @@ const loadBalanceOptions = computed(() => [ { value: 'round-robin', label: t('admin.settings.payment.strategyRoundRobin') }, { value: 'least-amount', label: t('admin.settings.payment.strategyLeastAmount') }, ]) + +const providerAvailableTypes = computed(() => { + const types = PROVIDER_SUPPORTED_TYPES[providerForm.provider_key] || [] + return types.map(t => { + const found = allPaymentTypes.value.find(pt => pt.value === t) + return found || { value: t, label: t } + }) +}) + +function isProviderTypeSelected(type: string): boolean { + return providerForm.supported_types.split(',').map(s => s.trim()).filter(Boolean).includes(type) +} + +function toggleProviderSupportedType(type: string) { + const current = providerForm.supported_types.split(',').map(s => s.trim()).filter(Boolean) + if (current.includes(type)) { + providerForm.supported_types = current.filter(t => t !== type).join(',') + } else { + providerForm.supported_types = [...current, type].join(',') + } +} + +function onProviderKeyChange() { + // Auto-select all supported types for the new provider key + providerForm.supported_types = (PROVIDER_SUPPORTED_TYPES[providerForm.provider_key] || []).join(',') +} + function providerKeyLabel(key: string): string { return providerKeyOptions.find(o => o.value === key)?.label || key } @@ -2925,7 +3011,8 @@ async function loadProviders() { finally { providersLoading.value = false } } function resetProviderForm() { - providerForm.name = ''; providerForm.provider_key = 'easypay'; providerForm.supported_types = '' + providerForm.name = ''; providerForm.provider_key = 'easypay' + providerForm.supported_types = (PROVIDER_SUPPORTED_TYPES['easypay'] || []).join(',') providerForm.enabled = true; providerForm.refund_enabled = false Object.keys(providerConfig).forEach(k => { (providerConfig as any)[k] = '' }) } diff --git a/frontend/src/views/admin/orders/AdminOrdersView.vue b/frontend/src/views/admin/orders/AdminOrdersView.vue index 0e94a5b8f5..9f48c2303e 100644 --- a/frontend/src/views/admin/orders/AdminOrdersView.vue +++ b/frontend/src/views/admin/orders/AdminOrdersView.vue @@ -1,13 +1,6 @@