Polish EasyPay custom method UI

This commit is contained in:
Albert Coady
2026-07-06 15:00:29 +08:00
parent 0dc6e56aae
commit a5a2fea045
5 changed files with 65 additions and 52 deletions
@@ -44,6 +44,7 @@ import alipayIcon from '@/assets/icons/alipay.svg'
import wxpayIcon from '@/assets/icons/wxpay.svg'
import stripeIcon from '@/assets/icons/stripe.svg'
import airwallexIcon from '@/assets/icons/airwallex.svg'
import paymentIcon from '@/assets/icons/payment.svg'
export interface PaymentMethodOption {
type: string
@@ -68,6 +69,7 @@ const METHOD_ICONS: Record<string, string> = {
wxpay: wxpayIcon,
stripe: stripeIcon,
airwallex: airwallexIcon,
credit_card: paymentIcon,
}
const sortedMethods = computed(() => {
@@ -83,7 +85,7 @@ function methodIcon(type: string): string {
if (type.includes('alipay')) return METHOD_ICONS.alipay
if (type.includes('wxpay')) return METHOD_ICONS.wxpay
if (type === 'airwallex') return METHOD_ICONS.airwallex
return METHOD_ICONS[type] || stripeIcon
return METHOD_ICONS[type] || paymentIcon
}
function methodLabel(method: PaymentMethodOption): string {
@@ -70,6 +70,49 @@
</div>
</div>
<div v-if="form.provider_key === 'easypay'" class="space-y-3 rounded-lg border border-gray-100 p-3 dark:border-dark-700">
<div class="flex items-center justify-between gap-3">
<div>
<h5 class="text-sm font-medium text-gray-900 dark:text-white">
{{ t('admin.settings.payment.easypayCustomMethods') }}
</h5>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
{{ t('admin.settings.payment.easypayCustomMethodsHint') }}
</p>
</div>
<button type="button" class="btn btn-secondary btn-sm" @click="addEasyPayCustomMethod">
{{ t('admin.settings.payment.addCustomMethod') }}
</button>
</div>
<div v-if="easyPayCustomMethods.length" class="space-y-2">
<div
v-for="(method, index) in easyPayCustomMethods"
:key="index"
class="grid grid-cols-[1fr_1fr_1fr_auto] items-end gap-2"
>
<div>
<label class="text-xs text-gray-500 dark:text-gray-400">{{ t('admin.settings.payment.customMethodType') }}</label>
<input v-model="method.type" type="text" class="input mt-0.5" placeholder="credit_card" />
</div>
<div>
<label class="text-xs text-gray-500 dark:text-gray-400">{{ t('admin.settings.payment.customMethodUpstreamType') }}</label>
<input v-model="method.upstreamType" type="text" class="input mt-0.5" placeholder="credit_card" />
</div>
<div>
<label class="text-xs text-gray-500 dark:text-gray-400">{{ t('admin.settings.payment.customMethodDisplayName') }}</label>
<input v-model="method.displayName" type="text" class="input mt-0.5" placeholder="信用卡" />
</div>
<button
type="button"
class="rounded-lg border border-red-200 px-2.5 py-2 text-xs font-medium text-red-600 transition-colors hover:bg-red-50 dark:border-red-800/60 dark:text-red-300 dark:hover:bg-red-900/20"
@click="removeEasyPayCustomMethod(index)"
>
{{ t('common.delete') }}
</button>
</div>
</div>
</div>
<!-- Config fields -->
<div class="border-t border-gray-200 pt-4 dark:border-dark-700">
@@ -168,49 +211,6 @@
</div>
</div>
<div v-if="form.provider_key === 'easypay'" class="mt-4 space-y-3 rounded-lg border border-gray-100 p-3 dark:border-dark-700">
<div class="flex items-center justify-between gap-3">
<div>
<h5 class="text-sm font-medium text-gray-900 dark:text-white">
{{ t('admin.settings.payment.easypayCustomMethods') }}
</h5>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
{{ t('admin.settings.payment.easypayCustomMethodsHint') }}
</p>
</div>
<button type="button" class="btn btn-secondary btn-sm" @click="addEasyPayCustomMethod">
{{ t('admin.settings.payment.addCustomMethod') }}
</button>
</div>
<div v-if="easyPayCustomMethods.length" class="space-y-2">
<div
v-for="(method, index) in easyPayCustomMethods"
:key="index"
class="grid grid-cols-[1fr_1fr_1fr_auto] items-end gap-2"
>
<div>
<label class="text-xs text-gray-500 dark:text-gray-400">{{ t('admin.settings.payment.customMethodType') }}</label>
<input v-model="method.type" type="text" class="input mt-0.5" placeholder="ldc" />
</div>
<div>
<label class="text-xs text-gray-500 dark:text-gray-400">{{ t('admin.settings.payment.customMethodUpstreamType') }}</label>
<input v-model="method.upstreamType" type="text" class="input mt-0.5" placeholder="epay" />
</div>
<div>
<label class="text-xs text-gray-500 dark:text-gray-400">{{ t('admin.settings.payment.customMethodDisplayName') }}</label>
<input v-model="method.displayName" type="text" class="input mt-0.5" placeholder="LDC" />
</div>
<button
type="button"
class="rounded-lg border border-red-200 px-2.5 py-2 text-xs font-medium text-red-600 transition-colors hover:bg-red-50 dark:border-red-800/60 dark:text-red-300 dark:hover:bg-red-900/20"
@click="removeEasyPayCustomMethod(index)"
>
{{ t('common.delete') }}
</button>
</div>
</div>
</div>
<!-- Callback URLs (each = editable URL + fixed path) -->
<div v-if="callbackPaths" class="mt-4 space-y-3">
<div v-if="callbackPaths.notifyUrl">
@@ -187,9 +187,10 @@ describe('PaymentProviderDialog payment guide', () => {
await nextTick()
const inputs = wrapper.findAll('input[type="text"]')
const ldcTypeInput = inputs.find(input => (input.element as HTMLInputElement).placeholder === 'ldc')
const upstreamTypeInput = inputs.find(input => (input.element as HTMLInputElement).placeholder === 'epay')
const displayNameInput = inputs.find(input => (input.element as HTMLInputElement).placeholder === 'LDC')
const customTypeInputs = inputs.filter(input => (input.element as HTMLInputElement).placeholder === 'credit_card')
const ldcTypeInput = customTypeInputs[0]
const upstreamTypeInput = customTypeInputs[1]
const displayNameInput = inputs.find(input => (input.element as HTMLInputElement).placeholder === '信用卡')
if (!ldcTypeInput || !upstreamTypeInput || !displayNameInput) {
throw new Error('custom method inputs not found')
}
@@ -229,9 +230,10 @@ describe('PaymentProviderDialog payment guide', () => {
await nextTick()
const inputs = wrapper.findAll('input[type="text"]')
const typeInput = inputs.find(input => (input.element as HTMLInputElement).placeholder === 'ldc')
const upstreamTypeInput = inputs.find(input => (input.element as HTMLInputElement).placeholder === 'epay')
const displayNameInput = inputs.find(input => (input.element as HTMLInputElement).placeholder === 'LDC')
const customTypeInputs = inputs.filter(input => (input.element as HTMLInputElement).placeholder === 'credit_card')
const typeInput = customTypeInputs[0]
const upstreamTypeInput = customTypeInputs[1]
const displayNameInput = inputs.find(input => (input.element as HTMLInputElement).placeholder === '信用卡')
if (!typeInput || !upstreamTypeInput || !displayNameInput) {
throw new Error('custom method inputs not found')
}