feat(payment): add recharge fee rate setting and fix provider card UI
- Add recharge_fee_rate system setting (percentage fee on top of recharge amount) - Full backend chain: config constant, PaymentConfig struct, update validation, read/write persistence, DTO, handler GET/PUT responses - Frontend: settings input with preview, i18n (zh/en), API types - Fix provider card toggle layout: labels above switches to save width - Fix Chinese translation: "EasyPay" → "易支付" in provider description
This commit is contained in:
@@ -189,6 +189,7 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
|
|||||||
PaymentEnabledTypes: paymentCfg.EnabledTypes,
|
PaymentEnabledTypes: paymentCfg.EnabledTypes,
|
||||||
PaymentBalanceDisabled: paymentCfg.BalanceDisabled,
|
PaymentBalanceDisabled: paymentCfg.BalanceDisabled,
|
||||||
PaymentBalanceRechargeMultiplier: paymentCfg.BalanceRechargeMultiplier,
|
PaymentBalanceRechargeMultiplier: paymentCfg.BalanceRechargeMultiplier,
|
||||||
|
PaymentRechargeFeeRate: paymentCfg.RechargeFeeRate,
|
||||||
PaymentLoadBalanceStrat: paymentCfg.LoadBalanceStrategy,
|
PaymentLoadBalanceStrat: paymentCfg.LoadBalanceStrategy,
|
||||||
PaymentProductNamePrefix: paymentCfg.ProductNamePrefix,
|
PaymentProductNamePrefix: paymentCfg.ProductNamePrefix,
|
||||||
PaymentProductNameSuffix: paymentCfg.ProductNameSuffix,
|
PaymentProductNameSuffix: paymentCfg.ProductNameSuffix,
|
||||||
@@ -327,6 +328,7 @@ type UpdateSettingsRequest struct {
|
|||||||
PaymentEnabledTypes []string `json:"payment_enabled_types"`
|
PaymentEnabledTypes []string `json:"payment_enabled_types"`
|
||||||
PaymentBalanceDisabled *bool `json:"payment_balance_disabled"`
|
PaymentBalanceDisabled *bool `json:"payment_balance_disabled"`
|
||||||
PaymentBalanceRechargeMultiplier *float64 `json:"payment_balance_recharge_multiplier"`
|
PaymentBalanceRechargeMultiplier *float64 `json:"payment_balance_recharge_multiplier"`
|
||||||
|
PaymentRechargeFeeRate *float64 `json:"payment_recharge_fee_rate"`
|
||||||
PaymentLoadBalanceStrat *string `json:"payment_load_balance_strategy"`
|
PaymentLoadBalanceStrat *string `json:"payment_load_balance_strategy"`
|
||||||
PaymentProductNamePrefix *string `json:"payment_product_name_prefix"`
|
PaymentProductNamePrefix *string `json:"payment_product_name_prefix"`
|
||||||
PaymentProductNameSuffix *string `json:"payment_product_name_suffix"`
|
PaymentProductNameSuffix *string `json:"payment_product_name_suffix"`
|
||||||
@@ -945,6 +947,7 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
|||||||
EnabledTypes: req.PaymentEnabledTypes,
|
EnabledTypes: req.PaymentEnabledTypes,
|
||||||
BalanceDisabled: req.PaymentBalanceDisabled,
|
BalanceDisabled: req.PaymentBalanceDisabled,
|
||||||
BalanceRechargeMultiplier: req.PaymentBalanceRechargeMultiplier,
|
BalanceRechargeMultiplier: req.PaymentBalanceRechargeMultiplier,
|
||||||
|
RechargeFeeRate: req.PaymentRechargeFeeRate,
|
||||||
LoadBalanceStrategy: req.PaymentLoadBalanceStrat,
|
LoadBalanceStrategy: req.PaymentLoadBalanceStrat,
|
||||||
ProductNamePrefix: req.PaymentProductNamePrefix,
|
ProductNamePrefix: req.PaymentProductNamePrefix,
|
||||||
ProductNameSuffix: req.PaymentProductNameSuffix,
|
ProductNameSuffix: req.PaymentProductNameSuffix,
|
||||||
@@ -1086,6 +1089,7 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
|||||||
PaymentEnabledTypes: updatedPaymentCfg.EnabledTypes,
|
PaymentEnabledTypes: updatedPaymentCfg.EnabledTypes,
|
||||||
PaymentBalanceDisabled: updatedPaymentCfg.BalanceDisabled,
|
PaymentBalanceDisabled: updatedPaymentCfg.BalanceDisabled,
|
||||||
PaymentBalanceRechargeMultiplier: updatedPaymentCfg.BalanceRechargeMultiplier,
|
PaymentBalanceRechargeMultiplier: updatedPaymentCfg.BalanceRechargeMultiplier,
|
||||||
|
PaymentRechargeFeeRate: updatedPaymentCfg.RechargeFeeRate,
|
||||||
PaymentLoadBalanceStrat: updatedPaymentCfg.LoadBalanceStrategy,
|
PaymentLoadBalanceStrat: updatedPaymentCfg.LoadBalanceStrategy,
|
||||||
PaymentProductNamePrefix: updatedPaymentCfg.ProductNamePrefix,
|
PaymentProductNamePrefix: updatedPaymentCfg.ProductNamePrefix,
|
||||||
PaymentProductNameSuffix: updatedPaymentCfg.ProductNameSuffix,
|
PaymentProductNameSuffix: updatedPaymentCfg.ProductNameSuffix,
|
||||||
@@ -1105,7 +1109,7 @@ func hasPaymentFields(req UpdateSettingsRequest) bool {
|
|||||||
req.PaymentMaxAmount != nil || req.PaymentDailyLimit != nil ||
|
req.PaymentMaxAmount != nil || req.PaymentDailyLimit != nil ||
|
||||||
req.PaymentOrderTimeoutMin != nil || req.PaymentMaxPendingOrders != nil ||
|
req.PaymentOrderTimeoutMin != nil || req.PaymentMaxPendingOrders != nil ||
|
||||||
req.PaymentEnabledTypes != nil || req.PaymentBalanceDisabled != nil ||
|
req.PaymentEnabledTypes != nil || req.PaymentBalanceDisabled != nil ||
|
||||||
req.PaymentBalanceRechargeMultiplier != nil ||
|
req.PaymentBalanceRechargeMultiplier != nil || req.PaymentRechargeFeeRate != nil ||
|
||||||
req.PaymentLoadBalanceStrat != nil || req.PaymentProductNamePrefix != nil ||
|
req.PaymentLoadBalanceStrat != nil || req.PaymentProductNamePrefix != nil ||
|
||||||
req.PaymentProductNameSuffix != nil || req.PaymentHelpImageURL != nil ||
|
req.PaymentProductNameSuffix != nil || req.PaymentHelpImageURL != nil ||
|
||||||
req.PaymentHelpText != nil || req.PaymentCancelRateLimitEnabled != nil ||
|
req.PaymentHelpText != nil || req.PaymentCancelRateLimitEnabled != nil ||
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ type SystemSettings struct {
|
|||||||
PaymentEnabledTypes []string `json:"payment_enabled_types"`
|
PaymentEnabledTypes []string `json:"payment_enabled_types"`
|
||||||
PaymentBalanceDisabled bool `json:"payment_balance_disabled"`
|
PaymentBalanceDisabled bool `json:"payment_balance_disabled"`
|
||||||
PaymentBalanceRechargeMultiplier float64 `json:"payment_balance_recharge_multiplier"`
|
PaymentBalanceRechargeMultiplier float64 `json:"payment_balance_recharge_multiplier"`
|
||||||
|
PaymentRechargeFeeRate float64 `json:"payment_recharge_fee_rate"`
|
||||||
PaymentLoadBalanceStrat string `json:"payment_load_balance_strategy"`
|
PaymentLoadBalanceStrat string `json:"payment_load_balance_strategy"`
|
||||||
PaymentProductNamePrefix string `json:"payment_product_name_prefix"`
|
PaymentProductNamePrefix string `json:"payment_product_name_prefix"`
|
||||||
PaymentProductNameSuffix string `json:"payment_product_name_suffix"`
|
PaymentProductNameSuffix string `json:"payment_product_name_suffix"`
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ func (h *PaymentHandler) GetCheckoutInfo(c *gin.Context) {
|
|||||||
Plans: planList,
|
Plans: planList,
|
||||||
BalanceDisabled: cfg.BalanceDisabled,
|
BalanceDisabled: cfg.BalanceDisabled,
|
||||||
BalanceRechargeMultiplier: cfg.BalanceRechargeMultiplier,
|
BalanceRechargeMultiplier: cfg.BalanceRechargeMultiplier,
|
||||||
|
RechargeFeeRate: cfg.RechargeFeeRate,
|
||||||
HelpText: cfg.HelpText,
|
HelpText: cfg.HelpText,
|
||||||
HelpImageURL: cfg.HelpImageURL,
|
HelpImageURL: cfg.HelpImageURL,
|
||||||
StripePublishableKey: cfg.StripePublishableKey,
|
StripePublishableKey: cfg.StripePublishableKey,
|
||||||
@@ -145,6 +146,7 @@ type checkoutInfoResponse struct {
|
|||||||
Plans []checkoutPlan `json:"plans"`
|
Plans []checkoutPlan `json:"plans"`
|
||||||
BalanceDisabled bool `json:"balance_disabled"`
|
BalanceDisabled bool `json:"balance_disabled"`
|
||||||
BalanceRechargeMultiplier float64 `json:"balance_recharge_multiplier"`
|
BalanceRechargeMultiplier float64 `json:"balance_recharge_multiplier"`
|
||||||
|
RechargeFeeRate float64 `json:"recharge_fee_rate"`
|
||||||
HelpText string `json:"help_text"`
|
HelpText string `json:"help_text"`
|
||||||
HelpImageURL string `json:"help_image_url"`
|
HelpImageURL string `json:"help_image_url"`
|
||||||
StripePublishableKey string `json:"stripe_publishable_key"`
|
StripePublishableKey string `json:"stripe_publishable_key"`
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ const (
|
|||||||
SettingLoadBalanceStrategy = "LOAD_BALANCE_STRATEGY"
|
SettingLoadBalanceStrategy = "LOAD_BALANCE_STRATEGY"
|
||||||
SettingBalancePayDisabled = "BALANCE_PAYMENT_DISABLED"
|
SettingBalancePayDisabled = "BALANCE_PAYMENT_DISABLED"
|
||||||
SettingBalanceRechargeMult = "BALANCE_RECHARGE_MULTIPLIER"
|
SettingBalanceRechargeMult = "BALANCE_RECHARGE_MULTIPLIER"
|
||||||
|
SettingRechargeFeeRate = "RECHARGE_FEE_RATE"
|
||||||
SettingProductNamePrefix = "PRODUCT_NAME_PREFIX"
|
SettingProductNamePrefix = "PRODUCT_NAME_PREFIX"
|
||||||
SettingProductNameSuffix = "PRODUCT_NAME_SUFFIX"
|
SettingProductNameSuffix = "PRODUCT_NAME_SUFFIX"
|
||||||
SettingHelpImageURL = "PAYMENT_HELP_IMAGE_URL"
|
SettingHelpImageURL = "PAYMENT_HELP_IMAGE_URL"
|
||||||
@@ -52,6 +53,7 @@ type PaymentConfig struct {
|
|||||||
EnabledTypes []string `json:"enabled_payment_types"`
|
EnabledTypes []string `json:"enabled_payment_types"`
|
||||||
BalanceDisabled bool `json:"balance_disabled"`
|
BalanceDisabled bool `json:"balance_disabled"`
|
||||||
BalanceRechargeMultiplier float64 `json:"balance_recharge_multiplier"`
|
BalanceRechargeMultiplier float64 `json:"balance_recharge_multiplier"`
|
||||||
|
RechargeFeeRate float64 `json:"recharge_fee_rate"`
|
||||||
LoadBalanceStrategy string `json:"load_balance_strategy"`
|
LoadBalanceStrategy string `json:"load_balance_strategy"`
|
||||||
ProductNamePrefix string `json:"product_name_prefix"`
|
ProductNamePrefix string `json:"product_name_prefix"`
|
||||||
ProductNameSuffix string `json:"product_name_suffix"`
|
ProductNameSuffix string `json:"product_name_suffix"`
|
||||||
@@ -78,6 +80,7 @@ type UpdatePaymentConfigRequest struct {
|
|||||||
EnabledTypes []string `json:"enabled_payment_types"`
|
EnabledTypes []string `json:"enabled_payment_types"`
|
||||||
BalanceDisabled *bool `json:"balance_disabled"`
|
BalanceDisabled *bool `json:"balance_disabled"`
|
||||||
BalanceRechargeMultiplier *float64 `json:"balance_recharge_multiplier"`
|
BalanceRechargeMultiplier *float64 `json:"balance_recharge_multiplier"`
|
||||||
|
RechargeFeeRate *float64 `json:"recharge_fee_rate"`
|
||||||
LoadBalanceStrategy *string `json:"load_balance_strategy"`
|
LoadBalanceStrategy *string `json:"load_balance_strategy"`
|
||||||
ProductNamePrefix *string `json:"product_name_prefix"`
|
ProductNamePrefix *string `json:"product_name_prefix"`
|
||||||
ProductNameSuffix *string `json:"product_name_suffix"`
|
ProductNameSuffix *string `json:"product_name_suffix"`
|
||||||
@@ -188,7 +191,7 @@ func (s *PaymentConfigService) GetPaymentConfig(ctx context.Context) (*PaymentCo
|
|||||||
keys := []string{
|
keys := []string{
|
||||||
SettingPaymentEnabled, SettingMinRechargeAmount, SettingMaxRechargeAmount,
|
SettingPaymentEnabled, SettingMinRechargeAmount, SettingMaxRechargeAmount,
|
||||||
SettingDailyRechargeLimit, SettingOrderTimeoutMinutes, SettingMaxPendingOrders,
|
SettingDailyRechargeLimit, SettingOrderTimeoutMinutes, SettingMaxPendingOrders,
|
||||||
SettingEnabledPaymentTypes, SettingBalancePayDisabled, SettingBalanceRechargeMult, SettingLoadBalanceStrategy,
|
SettingEnabledPaymentTypes, SettingBalancePayDisabled, SettingBalanceRechargeMult, SettingRechargeFeeRate, SettingLoadBalanceStrategy,
|
||||||
SettingProductNamePrefix, SettingProductNameSuffix,
|
SettingProductNamePrefix, SettingProductNameSuffix,
|
||||||
SettingHelpImageURL, SettingHelpText,
|
SettingHelpImageURL, SettingHelpText,
|
||||||
SettingCancelRateLimitOn, SettingCancelRateLimitMax,
|
SettingCancelRateLimitOn, SettingCancelRateLimitMax,
|
||||||
@@ -214,6 +217,7 @@ func (s *PaymentConfigService) parsePaymentConfig(vals map[string]string) *Payme
|
|||||||
MaxPendingOrders: pcParseInt(vals[SettingMaxPendingOrders], defaultMaxPendingOrders),
|
MaxPendingOrders: pcParseInt(vals[SettingMaxPendingOrders], defaultMaxPendingOrders),
|
||||||
BalanceDisabled: vals[SettingBalancePayDisabled] == "true",
|
BalanceDisabled: vals[SettingBalancePayDisabled] == "true",
|
||||||
BalanceRechargeMultiplier: normalizeBalanceRechargeMultiplier(pcParseFloat(vals[SettingBalanceRechargeMult], defaultBalanceRechargeMultiplier)),
|
BalanceRechargeMultiplier: normalizeBalanceRechargeMultiplier(pcParseFloat(vals[SettingBalanceRechargeMult], defaultBalanceRechargeMultiplier)),
|
||||||
|
RechargeFeeRate: pcParseFloat(vals[SettingRechargeFeeRate], 0),
|
||||||
LoadBalanceStrategy: vals[SettingLoadBalanceStrategy],
|
LoadBalanceStrategy: vals[SettingLoadBalanceStrategy],
|
||||||
ProductNamePrefix: vals[SettingProductNamePrefix],
|
ProductNamePrefix: vals[SettingProductNamePrefix],
|
||||||
ProductNameSuffix: vals[SettingProductNameSuffix],
|
ProductNameSuffix: vals[SettingProductNameSuffix],
|
||||||
@@ -267,6 +271,11 @@ func (s *PaymentConfigService) UpdatePaymentConfig(ctx context.Context, req Upda
|
|||||||
return infraerrors.BadRequest("INVALID_BALANCE_RECHARGE_MULTIPLIER", "balance recharge multiplier must be greater than 0")
|
return infraerrors.BadRequest("INVALID_BALANCE_RECHARGE_MULTIPLIER", "balance recharge multiplier must be greater than 0")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if req.RechargeFeeRate != nil {
|
||||||
|
if math.IsNaN(*req.RechargeFeeRate) || math.IsInf(*req.RechargeFeeRate, 0) || *req.RechargeFeeRate < 0 {
|
||||||
|
return infraerrors.BadRequest("INVALID_RECHARGE_FEE_RATE", "recharge fee rate must be >= 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
m := map[string]string{
|
m := map[string]string{
|
||||||
SettingPaymentEnabled: formatBoolOrEmpty(req.Enabled),
|
SettingPaymentEnabled: formatBoolOrEmpty(req.Enabled),
|
||||||
SettingMinRechargeAmount: formatPositiveFloat(req.MinAmount),
|
SettingMinRechargeAmount: formatPositiveFloat(req.MinAmount),
|
||||||
@@ -276,6 +285,7 @@ func (s *PaymentConfigService) UpdatePaymentConfig(ctx context.Context, req Upda
|
|||||||
SettingMaxPendingOrders: formatPositiveInt(req.MaxPendingOrders),
|
SettingMaxPendingOrders: formatPositiveInt(req.MaxPendingOrders),
|
||||||
SettingBalancePayDisabled: formatBoolOrEmpty(req.BalanceDisabled),
|
SettingBalancePayDisabled: formatBoolOrEmpty(req.BalanceDisabled),
|
||||||
SettingBalanceRechargeMult: formatPositiveFloat(req.BalanceRechargeMultiplier),
|
SettingBalanceRechargeMult: formatPositiveFloat(req.BalanceRechargeMultiplier),
|
||||||
|
SettingRechargeFeeRate: formatNonNegativeFloat(req.RechargeFeeRate),
|
||||||
SettingLoadBalanceStrategy: derefStr(req.LoadBalanceStrategy),
|
SettingLoadBalanceStrategy: derefStr(req.LoadBalanceStrategy),
|
||||||
SettingProductNamePrefix: derefStr(req.ProductNamePrefix),
|
SettingProductNamePrefix: derefStr(req.ProductNamePrefix),
|
||||||
SettingProductNameSuffix: derefStr(req.ProductNameSuffix),
|
SettingProductNameSuffix: derefStr(req.ProductNameSuffix),
|
||||||
@@ -309,6 +319,13 @@ func formatPositiveFloat(v *float64) string {
|
|||||||
return strconv.FormatFloat(*v, 'f', 2, 64)
|
return strconv.FormatFloat(*v, 'f', 2, 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func formatNonNegativeFloat(v *float64) string {
|
||||||
|
if v == nil || *v < 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strconv.FormatFloat(*v, 'f', 2, 64)
|
||||||
|
}
|
||||||
|
|
||||||
func formatPositiveInt(v *int) string {
|
func formatPositiveInt(v *int) string {
|
||||||
if v == nil || *v <= 0 {
|
if v == nil || *v <= 0 {
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ export interface SystemSettings {
|
|||||||
payment_enabled_types: string[]
|
payment_enabled_types: string[]
|
||||||
payment_balance_disabled: boolean
|
payment_balance_disabled: boolean
|
||||||
payment_balance_recharge_multiplier: number
|
payment_balance_recharge_multiplier: number
|
||||||
|
payment_recharge_fee_rate: number
|
||||||
payment_load_balance_strategy: string
|
payment_load_balance_strategy: string
|
||||||
payment_product_name_prefix: string
|
payment_product_name_prefix: string
|
||||||
payment_product_name_suffix: string
|
payment_product_name_suffix: string
|
||||||
@@ -233,6 +234,7 @@ export interface UpdateSettingsRequest {
|
|||||||
payment_enabled_types?: string[]
|
payment_enabled_types?: string[]
|
||||||
payment_balance_disabled?: boolean
|
payment_balance_disabled?: boolean
|
||||||
payment_balance_recharge_multiplier?: number
|
payment_balance_recharge_multiplier?: number
|
||||||
|
payment_recharge_fee_rate?: number
|
||||||
payment_load_balance_strategy?: string
|
payment_load_balance_strategy?: string
|
||||||
payment_product_name_prefix?: string
|
payment_product_name_prefix?: string
|
||||||
payment_product_name_suffix?: string
|
payment_product_name_suffix?: string
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<label class="flex items-center gap-1.5 cursor-pointer">
|
<label class="flex flex-col items-center gap-0.5 cursor-pointer">
|
||||||
<span class="text-xs text-gray-500 dark:text-gray-400">{{ label }}</span>
|
<span class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ label }}</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
role="switch"
|
role="switch"
|
||||||
|
|||||||
@@ -4569,6 +4569,9 @@ export default {
|
|||||||
balanceRechargeMultiplier: 'Balance Recharge Multiplier',
|
balanceRechargeMultiplier: 'Balance Recharge Multiplier',
|
||||||
balanceRechargeMultiplierHint: 'How many USD balance the user receives for each 1 CNY paid',
|
balanceRechargeMultiplierHint: 'How many USD balance the user receives for each 1 CNY paid',
|
||||||
balanceRechargePreview: 'Preview: 1 CNY = {usd} USD',
|
balanceRechargePreview: 'Preview: 1 CNY = {usd} USD',
|
||||||
|
rechargeFeeRate: 'Recharge Fee Rate',
|
||||||
|
rechargeFeeRateHint: 'Percentage of service fee charged on top of recharge amount, 0 means no fee',
|
||||||
|
rechargeFeePreview: 'Preview: Recharge 100, fee {fee}',
|
||||||
orderTimeout: 'Order Timeout',
|
orderTimeout: 'Order Timeout',
|
||||||
orderTimeoutHint: 'In minutes, minimum 1',
|
orderTimeoutHint: 'In minutes, minimum 1',
|
||||||
maxPendingOrders: 'Max Pending Orders',
|
maxPendingOrders: 'Max Pending Orders',
|
||||||
|
|||||||
@@ -4726,13 +4726,16 @@ export default {
|
|||||||
enabledHint: '启用或禁用支付系统',
|
enabledHint: '启用或禁用支付系统',
|
||||||
enabledPaymentTypes: '启用的服务商',
|
enabledPaymentTypes: '启用的服务商',
|
||||||
enabledPaymentTypesHint: '禁用服务商将同时禁用对应的实例。',
|
enabledPaymentTypesHint: '禁用服务商将同时禁用对应的实例。',
|
||||||
findProvider: '正在寻找合适的 EasyPay 服务商?',
|
findProvider: '正在寻找合适的易支付服务商?',
|
||||||
minAmount: '最低金额',
|
minAmount: '最低金额',
|
||||||
maxAmount: '最高金额',
|
maxAmount: '最高金额',
|
||||||
dailyLimit: '每日限额',
|
dailyLimit: '每日限额',
|
||||||
balanceRechargeMultiplier: '余额充值倍率',
|
balanceRechargeMultiplier: '余额充值倍率',
|
||||||
balanceRechargeMultiplierHint: '用户每支付 1 CNY 可获得多少 USD 余额',
|
balanceRechargeMultiplierHint: '用户每支付 1 CNY 可获得多少 USD 余额',
|
||||||
balanceRechargePreview: '预览:1 CNY = {usd} USD',
|
balanceRechargePreview: '预览:1 CNY = {usd} USD',
|
||||||
|
rechargeFeeRate: '充值手续费率',
|
||||||
|
rechargeFeeRateHint: '用户充值时额外收取的手续费百分比,0 表示不收取手续费',
|
||||||
|
rechargeFeePreview: '预览:充值 100 元,手续费 {fee} 元',
|
||||||
orderTimeout: '订单超时时间',
|
orderTimeout: '订单超时时间',
|
||||||
orderTimeoutHint: '单位:分钟,至少 1 分钟',
|
orderTimeoutHint: '单位:分钟,至少 1 分钟',
|
||||||
maxPendingOrders: '最大待支付订单数',
|
maxPendingOrders: '最大待支付订单数',
|
||||||
|
|||||||
@@ -2381,6 +2381,12 @@
|
|||||||
<p class="mt-0.5 text-xs text-gray-400">{{ t('admin.settings.payment.balanceRechargeMultiplierHint') }}</p>
|
<p class="mt-0.5 text-xs text-gray-400">{{ t('admin.settings.payment.balanceRechargeMultiplierHint') }}</p>
|
||||||
<p class="mt-1 text-xs font-medium text-primary-600 dark:text-primary-400">{{ t('admin.settings.payment.balanceRechargePreview', { usd: (Number(form.payment_balance_recharge_multiplier) || 1).toFixed(2) }) }}</p>
|
<p class="mt-1 text-xs font-medium text-primary-600 dark:text-primary-400">{{ t('admin.settings.payment.balanceRechargePreview', { usd: (Number(form.payment_balance_recharge_multiplier) || 1).toFixed(2) }) }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="input-label">{{ t('admin.settings.payment.rechargeFeeRate') }}</label>
|
||||||
|
<input :value="form.payment_recharge_fee_rate || ''" @input="form.payment_recharge_fee_rate = parseFloat(($event.target as HTMLInputElement).value) || 0" type="number" step="0.01" min="0" class="input" />
|
||||||
|
<p class="mt-0.5 text-xs text-gray-400">{{ t('admin.settings.payment.rechargeFeeRateHint') }}</p>
|
||||||
|
<p v-if="(Number(form.payment_recharge_fee_rate) || 0) > 0" class="mt-1 text-xs font-medium text-primary-600 dark:text-primary-400">{{ t('admin.settings.payment.rechargeFeePreview', { fee: (Number(form.payment_recharge_fee_rate) || 0).toFixed(2) }) }}</p>
|
||||||
|
</div>
|
||||||
<div><label class="input-label">{{ t('admin.settings.payment.orderTimeout') }} <span class="text-red-500">*</span></label><input v-model.number="form.payment_order_timeout_minutes" type="number" min="1" class="input" required /><p class="mt-0.5 text-xs text-gray-400">{{ t('admin.settings.payment.orderTimeoutHint') }}</p></div>
|
<div><label class="input-label">{{ t('admin.settings.payment.orderTimeout') }} <span class="text-red-500">*</span></label><input v-model.number="form.payment_order_timeout_minutes" type="number" min="1" class="input" required /><p class="mt-0.5 text-xs text-gray-400">{{ t('admin.settings.payment.orderTimeoutHint') }}</p></div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Row 3: Pending orders + load balance + cancel rate limit (all in one row) -->
|
<!-- Row 3: Pending orders + load balance + cancel rate limit (all in one row) -->
|
||||||
@@ -2974,7 +2980,7 @@ const form = reactive<SettingsForm>({
|
|||||||
home_content: '',
|
home_content: '',
|
||||||
backend_mode_enabled: false,
|
backend_mode_enabled: false,
|
||||||
hide_ccs_import_button: false,
|
hide_ccs_import_button: false,
|
||||||
payment_enabled: false, payment_min_amount: 1, payment_max_amount: 10000, payment_daily_limit: 50000, payment_max_pending_orders: 3, payment_order_timeout_minutes: 30, payment_balance_disabled: false, payment_balance_recharge_multiplier: 1, payment_enabled_types: [], payment_help_image_url: '', payment_help_text: '', payment_product_name_prefix: '', payment_product_name_suffix: '', payment_load_balance_strategy: 'round-robin', payment_cancel_rate_limit_enabled: false, payment_cancel_rate_limit_max: 10, payment_cancel_rate_limit_window: 1, payment_cancel_rate_limit_unit: 'day', payment_cancel_rate_limit_window_mode: 'rolling',
|
payment_enabled: false, payment_min_amount: 1, payment_max_amount: 10000, payment_daily_limit: 50000, payment_max_pending_orders: 3, payment_order_timeout_minutes: 30, payment_balance_disabled: false, payment_balance_recharge_multiplier: 1, payment_recharge_fee_rate: 0, payment_enabled_types: [], payment_help_image_url: '', payment_help_text: '', payment_product_name_prefix: '', payment_product_name_suffix: '', payment_load_balance_strategy: 'round-robin', payment_cancel_rate_limit_enabled: false, payment_cancel_rate_limit_max: 10, payment_cancel_rate_limit_window: 1, payment_cancel_rate_limit_unit: 'day', payment_cancel_rate_limit_window_mode: 'rolling',
|
||||||
table_default_page_size: tablePageSizeDefault,
|
table_default_page_size: tablePageSizeDefault,
|
||||||
table_page_size_options: [10, 20, 50, 100],
|
table_page_size_options: [10, 20, 50, 100],
|
||||||
custom_menu_items: [] as Array<{id: string; label: string; icon_svg: string; url: string; visibility: 'user' | 'admin'; sort_order: number}>,
|
custom_menu_items: [] as Array<{id: string; label: string; icon_svg: string; url: string; visibility: 'user' | 'admin'; sort_order: number}>,
|
||||||
@@ -3634,6 +3640,7 @@ async function saveSettings() {
|
|||||||
payment_order_timeout_minutes: Number(form.payment_order_timeout_minutes) || 0,
|
payment_order_timeout_minutes: Number(form.payment_order_timeout_minutes) || 0,
|
||||||
payment_balance_disabled: form.payment_balance_disabled,
|
payment_balance_disabled: form.payment_balance_disabled,
|
||||||
payment_balance_recharge_multiplier: Number(form.payment_balance_recharge_multiplier) || 1,
|
payment_balance_recharge_multiplier: Number(form.payment_balance_recharge_multiplier) || 1,
|
||||||
|
payment_recharge_fee_rate: Number(form.payment_recharge_fee_rate) || 0,
|
||||||
payment_enabled_types: form.payment_enabled_types,
|
payment_enabled_types: form.payment_enabled_types,
|
||||||
payment_load_balance_strategy: form.payment_load_balance_strategy,
|
payment_load_balance_strategy: form.payment_load_balance_strategy,
|
||||||
payment_product_name_prefix: form.payment_product_name_prefix,
|
payment_product_name_prefix: form.payment_product_name_prefix,
|
||||||
|
|||||||
Reference in New Issue
Block a user