diff --git a/frontend/src/components/payment/PaymentProviderDialog.vue b/frontend/src/components/payment/PaymentProviderDialog.vue
index bbd006b447..bea4b5b9c2 100644
--- a/frontend/src/components/payment/PaymentProviderDialog.vue
+++ b/frontend/src/components/payment/PaymentProviderDialog.vue
@@ -158,7 +158,7 @@
type="number"
:value="getLimitVal(lt.value, 'singleMin')"
@input="setLimitVal(lt.value, 'singleMin', ($event.target as HTMLInputElement).value)"
- class="input mt-0.5" min="1" step="0.01" :placeholder="t('admin.settings.payment.limitsHint')"
+ class="input mt-0.5" min="1" step="0.01" :placeholder="limitPlaceholder(lt.value)"
/>
@@ -167,7 +167,7 @@
type="number"
:value="getLimitVal(lt.value, 'singleMax')"
@input="setLimitVal(lt.value, 'singleMax', ($event.target as HTMLInputElement).value)"
- class="input mt-0.5" min="1" step="0.01" :placeholder="t('admin.settings.payment.limitsHint')"
+ class="input mt-0.5" min="1" step="0.01" :placeholder="limitPlaceholder(lt.value)"
/>
@@ -176,7 +176,7 @@
type="number"
:value="getLimitVal(lt.value, 'dailyLimit')"
@input="setLimitVal(lt.value, 'dailyLimit', ($event.target as HTMLInputElement).value)"
- class="input mt-0.5" min="1" step="0.01" :placeholder="t('admin.settings.payment.limitsHint')"
+ class="input mt-0.5" min="1" step="0.01" :placeholder="limitPlaceholder(lt.value)"
/>
@@ -327,6 +327,20 @@ function getLimitVal(paymentType: string, field: string): string {
return val && val > 0 ? String(val) : ''
}
+/** Returns true if any limit field for this payment type has a value */
+function hasAnyLimit(paymentType: string): boolean {
+ const l = limits[paymentType]
+ if (!l) return false
+ return (l.singleMin > 0) || (l.singleMax > 0) || (l.dailyLimit > 0)
+}
+
+/** Dynamic placeholder: "不限制" if sibling has value, "使用全局配置" if all empty */
+function limitPlaceholder(paymentType: string): string {
+ return hasAnyLimit(paymentType)
+ ? t('admin.settings.payment.limitsNoLimit')
+ : t('admin.settings.payment.limitsUseGlobal')
+}
+
function setLimitVal(paymentType: string, field: string, val: string) {
if (!limits[paymentType]) limits[paymentType] = {}
const num = Number(val)
diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts
index 9abb1df557..b4f5e6d07a 100644
--- a/frontend/src/i18n/locales/en.ts
+++ b/frontend/src/i18n/locales/en.ts
@@ -4398,7 +4398,9 @@ export default {
limitSingleMin: 'Min per order',
limitSingleMax: 'Max per order',
limitDaily: 'Daily limit',
- limitsHint: 'Leave empty to use global settings',
+ limitsHint: 'All empty = use global config; partially filled = empty means no limit',
+ limitsUseGlobal: 'Use global',
+ limitsNoLimit: '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 30569be74b..43bee04a83 100644
--- a/frontend/src/i18n/locales/zh.ts
+++ b/frontend/src/i18n/locales/zh.ts
@@ -4571,7 +4571,9 @@ export default {
limitSingleMin: '单笔最低',
limitSingleMax: '单笔最高',
limitDaily: '每日限额',
- limitsHint: '留空表示使用全局配置',
+ limitsHint: '全部留空使用全局配置,部分填写时留空项表示不限制',
+ limitsUseGlobal: '使用全局配置',
+ limitsNoLimit: '不限制',
productNamePrefix: '商品名前缀',
productNameSuffix: '商品名后缀',
preview: '预览',
diff --git a/frontend/src/views/user/PaymentView.vue b/frontend/src/views/user/PaymentView.vue
index b4f79997cf..fd59f216c8 100644
--- a/frontend/src/views/user/PaymentView.vue
+++ b/frontend/src/views/user/PaymentView.vue
@@ -231,7 +231,9 @@ async function createOrder(orderAmount: number, orderType: string, planId?: numb
plan_id: planId,
})
if (result.client_secret) {
- router.push({ path: '/payment/stripe', query: { order_id: String(result.order_id), client_secret: result.client_secret } })
+ const stripeUrl = router.resolve({ path: '/payment/stripe', query: { order_id: String(result.order_id), client_secret: result.client_secret } }).href
+ window.open(stripeUrl, '_blank')
+ router.push({ path: '/payment/qrcode', query: { order_id: String(result.order_id), expires_at: result.expires_at || '', payment_type: 'stripe' } })
} else if (result.qr_code) {
router.push({ path: '/payment/qrcode', query: { order_id: String(result.order_id), qr: result.qr_code || '', pay_url: result.pay_url || '', expires_at: result.expires_at || '', payment_type: selectedMethod.value } })
} else if (result.pay_url) {