mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-28 16:09:34 +00:00
Merge branch 'main' into fix/image-tier-validation
This commit is contained in:
@@ -34,7 +34,7 @@
|
||||
<ToggleSwitch :label="t('common.enabled')" :checked="form.enabled" @toggle="form.enabled = !form.enabled" />
|
||||
<ToggleSwitch :label="t('admin.settings.payment.refundEnabled')" :checked="form.refund_enabled" @toggle="form.refund_enabled = !form.refund_enabled; if (!form.refund_enabled) form.allow_user_refund = false" />
|
||||
<ToggleSwitch v-if="form.refund_enabled" :label="t('admin.settings.payment.allowUserRefund')" :checked="form.allow_user_refund" @toggle="form.allow_user_refund = !form.allow_user_refund" />
|
||||
<div v-if="form.provider_key === 'easypay'" class="flex items-center gap-2">
|
||||
<div v-if="supportsPaymentMode" class="flex items-center gap-2">
|
||||
<span class="text-xs font-medium text-gray-500 dark:text-gray-400">{{ t('admin.settings.payment.paymentMode') }}</span>
|
||||
<div class="flex gap-1.5">
|
||||
<button
|
||||
@@ -278,11 +278,37 @@ import {
|
||||
WEBHOOK_PATHS,
|
||||
PAYMENT_MODE_QRCODE,
|
||||
PAYMENT_MODE_POPUP,
|
||||
PAYMENT_MODE_REDIRECT,
|
||||
STRIPE_SDK_API_VERSION,
|
||||
getAvailableTypes,
|
||||
extractBaseUrl,
|
||||
} from './providerConfig'
|
||||
|
||||
/** Default payment_mode per provider key — "" means "no preference, use
|
||||
* provider's built-in default behavior". */
|
||||
function defaultPaymentMode(providerKey: string): string {
|
||||
if (providerKey === 'easypay') return PAYMENT_MODE_QRCODE
|
||||
return ''
|
||||
}
|
||||
|
||||
/** Provider keys whose admin UI exposes a payment_mode selector.
|
||||
* Other providers always send payment_mode = ''. */
|
||||
function providerSupportsPaymentMode(providerKey: string): boolean {
|
||||
return providerKey === 'easypay' || providerKey === 'alipay'
|
||||
}
|
||||
|
||||
/** Allowed payment_mode values per provider. Used to coerce DB values
|
||||
* from a different provider (or stale data) back to the default. */
|
||||
function isValidPaymentMode(providerKey: string, mode: string): boolean {
|
||||
if (providerKey === 'easypay') {
|
||||
return mode === PAYMENT_MODE_QRCODE || mode === PAYMENT_MODE_POPUP
|
||||
}
|
||||
if (providerKey === 'alipay') {
|
||||
return mode === '' || mode === PAYMENT_MODE_REDIRECT
|
||||
}
|
||||
return mode === ''
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
show: boolean
|
||||
saving: boolean
|
||||
@@ -359,7 +385,17 @@ const providerWebhookHint = computed(() =>
|
||||
|
||||
const callbackPaths = computed(() => PROVIDER_CALLBACK_PATHS[form.provider_key] || null)
|
||||
|
||||
const supportsPaymentMode = computed(() => providerSupportsPaymentMode(form.provider_key))
|
||||
|
||||
const paymentModeOptions = computed(() => {
|
||||
if (form.provider_key === 'alipay') {
|
||||
// For Alipay official: "" = default (precreate → page.pay fallback);
|
||||
// "redirect" = always open the Alipay checkout page in a new tab.
|
||||
return [
|
||||
{ value: '', label: t('admin.settings.payment.modeQRCode') },
|
||||
{ value: PAYMENT_MODE_REDIRECT, label: t('admin.settings.payment.modeRedirect') },
|
||||
]
|
||||
}
|
||||
return [
|
||||
{ value: PAYMENT_MODE_QRCODE, label: t('admin.settings.payment.modeQRCode') },
|
||||
{ value: PAYMENT_MODE_POPUP, label: t('admin.settings.payment.modePopup') },
|
||||
@@ -476,6 +512,7 @@ function toggleType(type: string) {
|
||||
|
||||
function onKeyChange() {
|
||||
form.supported_types = [...(PROVIDER_SUPPORTED_TYPES[form.provider_key] || [])]
|
||||
form.payment_mode = defaultPaymentMode(form.provider_key)
|
||||
clearConfig()
|
||||
applyDefaults()
|
||||
}
|
||||
@@ -591,7 +628,7 @@ function handleSave() {
|
||||
name: form.name,
|
||||
supported_types: form.supported_types,
|
||||
enabled: form.enabled,
|
||||
payment_mode: form.provider_key === 'easypay' ? form.payment_mode : '',
|
||||
payment_mode: supportsPaymentMode.value ? form.payment_mode : '',
|
||||
refund_enabled: form.refund_enabled,
|
||||
allow_user_refund: form.refund_enabled ? form.allow_user_refund : false,
|
||||
config: filteredConfig,
|
||||
@@ -611,7 +648,7 @@ function reset(defaultKey: string) {
|
||||
form.provider_key = defaultKey
|
||||
form.supported_types = [...(PROVIDER_SUPPORTED_TYPES[defaultKey] || [])]
|
||||
form.enabled = true
|
||||
form.payment_mode = defaultKey === 'easypay' ? PAYMENT_MODE_QRCODE : ''
|
||||
form.payment_mode = defaultPaymentMode(defaultKey)
|
||||
form.refund_enabled = false
|
||||
form.allow_user_refund = false
|
||||
clearConfig()
|
||||
@@ -623,7 +660,12 @@ function loadProvider(provider: ProviderInstance) {
|
||||
form.provider_key = provider.provider_key
|
||||
form.supported_types = provider.supported_types
|
||||
form.enabled = provider.enabled
|
||||
form.payment_mode = provider.payment_mode || (provider.provider_key === 'easypay' ? PAYMENT_MODE_QRCODE : '')
|
||||
// Coerce to a valid value for this provider. Guards against stale data
|
||||
// (e.g. "popup" written by an older client) showing up as an unselected
|
||||
// button in the dialog.
|
||||
form.payment_mode = isValidPaymentMode(provider.provider_key, provider.payment_mode || '')
|
||||
? (provider.payment_mode || '')
|
||||
: defaultPaymentMode(provider.provider_key)
|
||||
form.refund_enabled = provider.refund_enabled
|
||||
form.allow_user_refund = provider.allow_user_refund
|
||||
clearConfig()
|
||||
|
||||
@@ -69,7 +69,7 @@ import Icon from '@/components/icons/Icon.vue'
|
||||
import ToggleSwitch from './ToggleSwitch.vue'
|
||||
import type { ProviderInstance } from '@/types/payment'
|
||||
import type { TypeOption } from './providerConfig'
|
||||
import { PAYMENT_MODE_QRCODE, PAYMENT_MODE_POPUP } from './providerConfig'
|
||||
import { PAYMENT_MODE_QRCODE, PAYMENT_MODE_POPUP, PAYMENT_MODE_REDIRECT } from './providerConfig'
|
||||
|
||||
const PROVIDER_KEY_LABELS: Record<string, string> = {
|
||||
easypay: 'admin.settings.payment.providerEasypay',
|
||||
@@ -99,6 +99,7 @@ const keyLabel = computed(() => t(PROVIDER_KEY_LABELS[props.provider.provider_ke
|
||||
const modeLabel = computed(() => {
|
||||
if (props.provider.payment_mode === PAYMENT_MODE_QRCODE) return t('admin.settings.payment.modeQRCode')
|
||||
if (props.provider.payment_mode === PAYMENT_MODE_POPUP) return t('admin.settings.payment.modePopup')
|
||||
if (props.provider.payment_mode === PAYMENT_MODE_REDIRECT) return t('admin.settings.payment.modeRedirect')
|
||||
return ''
|
||||
})
|
||||
|
||||
|
||||
@@ -47,6 +47,11 @@ export const METHOD_ORDER = ['alipay', 'alipay_direct', 'wxpay', 'wxpay_direct',
|
||||
/** Payment mode constants */
|
||||
export const PAYMENT_MODE_QRCODE = 'qrcode'
|
||||
export const PAYMENT_MODE_POPUP = 'popup'
|
||||
/** Alipay-only: skip FACE_TO_FACE_PAYMENT precreate and open the Alipay
|
||||
* checkout page in a new tab instead. Backend `alipay.go` matches on this
|
||||
* literal (case-insensitive); other values fall back to the default
|
||||
* precreate→pagepay flow. */
|
||||
export const PAYMENT_MODE_REDIRECT = 'redirect'
|
||||
|
||||
export const PAYMENT_CURRENCY_OPTIONS: TypeOption[] = [
|
||||
{ value: 'CNY', label: 'CNY' },
|
||||
|
||||
Reference in New Issue
Block a user