mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-24 16:05:44 +08:00
fix(payment): inject paymentMode into provider config for correct redirect
The EasyPay provider reads paymentMode from e.config["paymentMode"] to decide between redirect (submit.php) and API (mapi.php) paths. However, paymentMode is stored as a separate DB column, not inside the encrypted config JSON. SelectInstance() returned it in the InstanceSelection struct but never injected it into the Config map, so the provider always fell through to the API/QR path. Also includes: - Subscription success flow: show "订阅成功" and refresh on return - Active subscription card: platform colors, rate/quota display - Subscription plan card: compact layout to save height - Provider list: drag-and-drop reorder via sort_order
This commit is contained in:
@@ -86,6 +86,11 @@ func (lb *DefaultLoadBalancer) SelectInstance(ctx context.Context, providerKey s
|
||||
return nil, fmt.Errorf("decrypt instance %d config: %w", selected.ID, err)
|
||||
}
|
||||
|
||||
// Inject payment_mode into config so providers can read it uniformly
|
||||
if selected.PaymentMode != "" {
|
||||
config["paymentMode"] = selected.PaymentMode
|
||||
}
|
||||
|
||||
return &InstanceSelection{
|
||||
InstanceID: fmt.Sprintf("%d", selected.ID),
|
||||
Config: config,
|
||||
|
||||
@@ -40,23 +40,37 @@
|
||||
<div class="h-5 w-5 animate-spin rounded-full border-2 border-primary-500 border-t-transparent" />
|
||||
</div>
|
||||
|
||||
<!-- Provider cards -->
|
||||
<div v-else-if="providers.length" class="space-y-3">
|
||||
<ProviderCard
|
||||
v-for="p in providers"
|
||||
:key="p.id"
|
||||
:provider="p"
|
||||
:enabled="isEnabled(p.provider_key)"
|
||||
:available-types="getTypes(p.provider_key)"
|
||||
@toggle-field="(field) => emit('toggleField', p, field)"
|
||||
@toggle-type="(type) => emit('toggleType', p, type)"
|
||||
@edit="emit('edit', p)"
|
||||
@delete="emit('delete', p)"
|
||||
/>
|
||||
</div>
|
||||
<!-- Provider cards (draggable) -->
|
||||
<VueDraggable
|
||||
v-if="providers.length"
|
||||
v-model="localProviders"
|
||||
:animation="200"
|
||||
handle=".drag-handle"
|
||||
class="space-y-3"
|
||||
@end="onDragEnd"
|
||||
>
|
||||
<div v-for="p in localProviders" :key="p.id" class="flex items-start gap-2">
|
||||
<div class="drag-handle mt-3 flex cursor-grab items-center text-gray-300 hover:text-gray-500 active:cursor-grabbing dark:text-dark-600 dark:hover:text-dark-400">
|
||||
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M7 2a2 2 0 1 0 0 4 2 2 0 0 0 0-4zM13 2a2 2 0 1 0 0 4 2 2 0 0 0 0-4zM7 8a2 2 0 1 0 0 4 2 2 0 0 0 0-4zM13 8a2 2 0 1 0 0 4 2 2 0 0 0 0-4zM7 14a2 2 0 1 0 0 4 2 2 0 0 0 0-4zM13 14a2 2 0 1 0 0 4 2 2 0 0 0 0-4z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<ProviderCard
|
||||
:provider="p"
|
||||
:enabled="isEnabled(p.provider_key)"
|
||||
:available-types="getTypes(p.provider_key)"
|
||||
@toggle-field="(field) => emit('toggleField', p, field)"
|
||||
@toggle-type="(type) => emit('toggleType', p, type)"
|
||||
@edit="emit('edit', p)"
|
||||
@delete="emit('delete', p)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</VueDraggable>
|
||||
|
||||
<!-- Empty -->
|
||||
<div v-else class="py-6 text-center">
|
||||
<div v-else-if="!loading" class="py-6 text-center">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ canCreate
|
||||
? t('admin.settings.payment.noProviders')
|
||||
@@ -75,7 +89,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { VueDraggable } from 'vue-draggable-plus'
|
||||
import Icon from '@/components/icons/Icon.vue'
|
||||
import ProviderCard from './ProviderCard.vue'
|
||||
import type { ProviderInstance } from '@/types/payment'
|
||||
@@ -98,10 +114,25 @@ const emit = defineEmits<{
|
||||
delete: [provider: ProviderInstance]
|
||||
toggleField: [provider: ProviderInstance, field: 'enabled' | 'refund_enabled']
|
||||
toggleType: [provider: ProviderInstance, type: string]
|
||||
reorder: [providers: { id: number; sort_order: number }[]]
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const localProviders = ref<ProviderInstance[]>([])
|
||||
|
||||
watch(() => props.providers, (val) => {
|
||||
localProviders.value = [...val]
|
||||
}, { immediate: true })
|
||||
|
||||
function onDragEnd() {
|
||||
const updates = localProviders.value.map((p, idx) => ({
|
||||
id: p.id,
|
||||
sort_order: idx,
|
||||
}))
|
||||
emit('reorder', updates)
|
||||
}
|
||||
|
||||
function isEnabled(providerKey: string): boolean {
|
||||
const enabled = props.enabledPaymentTypes
|
||||
if (providerKey === 'easypay') {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class="flex h-16 w-16 items-center justify-center rounded-full bg-green-100 dark:bg-green-900/30">
|
||||
<Icon name="check" size="lg" class="text-green-500" />
|
||||
</div>
|
||||
<p class="text-lg font-bold text-gray-900 dark:text-white">{{ t('payment.result.success') }}</p>
|
||||
<p class="text-lg font-bold text-gray-900 dark:text-white">{{ props.orderType === 'subscription' ? t('payment.result.subscriptionSuccess') : t('payment.result.success') }}</p>
|
||||
<div v-if="paidOrder" class="w-full rounded-xl bg-gray-50 p-4 dark:bg-dark-800">
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between">
|
||||
@@ -98,6 +98,7 @@ const props = defineProps<{
|
||||
expiresAt: string
|
||||
paymentType: string
|
||||
payUrl?: string
|
||||
orderType?: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{ done: []; success: [] }>()
|
||||
|
||||
@@ -10,63 +10,56 @@
|
||||
<!-- Colored top accent bar -->
|
||||
<div :class="['h-1.5', accentClass]" />
|
||||
|
||||
<div class="flex flex-1 flex-col p-5">
|
||||
<!-- Header: name + platform badge -->
|
||||
<div class="mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="text-base font-bold text-gray-900 dark:text-white">{{ plan.name }}</h3>
|
||||
<span :class="['rounded-full px-2 py-0.5 text-[11px] font-medium', badgeLightClass]">
|
||||
{{ pLabel }}
|
||||
</span>
|
||||
<div class="flex flex-1 flex-col p-4">
|
||||
<!-- Header: name + badge + price -->
|
||||
<div class="mb-3 flex items-start justify-between gap-2">
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="truncate text-base font-bold text-gray-900 dark:text-white">{{ plan.name }}</h3>
|
||||
<span :class="['shrink-0 rounded-full px-2 py-0.5 text-[11px] font-medium', badgeLightClass]">
|
||||
{{ pLabel }}
|
||||
</span>
|
||||
</div>
|
||||
<p v-if="plan.description" class="mt-0.5 text-xs leading-relaxed text-gray-500 dark:text-dark-400 line-clamp-2">
|
||||
{{ plan.description }}
|
||||
</p>
|
||||
</div>
|
||||
<p v-if="plan.group_name" class="mt-1 text-xs text-gray-400 dark:text-dark-500">
|
||||
{{ plan.group_name }}
|
||||
</p>
|
||||
<p v-if="plan.description" class="mt-1.5 text-sm leading-relaxed text-gray-500 dark:text-dark-400">
|
||||
{{ plan.description }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Price section -->
|
||||
<div class="mb-4">
|
||||
<div class="flex items-baseline gap-1.5">
|
||||
<span class="text-sm text-gray-400 dark:text-dark-500">¥</span>
|
||||
<span :class="['text-4xl font-extrabold tracking-tight', textClass]">{{ plan.price }}</span>
|
||||
<span class="text-sm text-gray-400 dark:text-dark-500">/ {{ validitySuffix }}</span>
|
||||
</div>
|
||||
<div v-if="plan.original_price" class="mt-1 flex items-center gap-2">
|
||||
<span class="text-sm text-gray-400 line-through dark:text-dark-500">
|
||||
¥{{ plan.original_price }}
|
||||
</span>
|
||||
<span :class="['rounded px-1.5 py-0.5 text-[11px] font-semibold', discountClass]">
|
||||
{{ discountText }}
|
||||
</span>
|
||||
<div class="shrink-0 text-right">
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-xs text-gray-400 dark:text-dark-500">¥</span>
|
||||
<span :class="['text-2xl font-extrabold tracking-tight', textClass]">{{ plan.price }}</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-400 dark:text-dark-500">/ {{ validitySuffix }}</span>
|
||||
<div v-if="plan.original_price" class="mt-0.5 flex items-center justify-end gap-1.5">
|
||||
<span class="text-xs text-gray-400 line-through dark:text-dark-500">¥{{ plan.original_price }}</span>
|
||||
<span :class="['rounded px-1 py-0.5 text-[10px] font-semibold', discountClass]">{{ discountText }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Group quota info -->
|
||||
<div class="mb-4 space-y-1.5 rounded-lg bg-gray-50 px-3 py-2.5 dark:bg-dark-700/50">
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<!-- Group quota info (compact) -->
|
||||
<div class="mb-3 grid grid-cols-2 gap-x-3 gap-y-1 rounded-lg bg-gray-50 px-3 py-2 text-xs dark:bg-dark-700/50">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-gray-400 dark:text-dark-500">{{ t('payment.planCard.rate') }}</span>
|
||||
<span class="font-medium text-gray-700 dark:text-gray-300">{{ rateDisplay }}</span>
|
||||
</div>
|
||||
<div v-if="plan.daily_limit_usd != null" class="flex items-center justify-between text-xs">
|
||||
<div v-if="plan.daily_limit_usd != null" class="flex items-center justify-between">
|
||||
<span class="text-gray-400 dark:text-dark-500">{{ t('payment.planCard.dailyLimit') }}</span>
|
||||
<span class="font-medium text-gray-700 dark:text-gray-300">${{ plan.daily_limit_usd }}</span>
|
||||
</div>
|
||||
<div v-if="plan.weekly_limit_usd != null" class="flex items-center justify-between text-xs">
|
||||
<div v-if="plan.weekly_limit_usd != null" class="flex items-center justify-between">
|
||||
<span class="text-gray-400 dark:text-dark-500">{{ t('payment.planCard.weeklyLimit') }}</span>
|
||||
<span class="font-medium text-gray-700 dark:text-gray-300">${{ plan.weekly_limit_usd }}</span>
|
||||
</div>
|
||||
<div v-if="plan.monthly_limit_usd != null" class="flex items-center justify-between text-xs">
|
||||
<div v-if="plan.monthly_limit_usd != null" class="flex items-center justify-between">
|
||||
<span class="text-gray-400 dark:text-dark-500">{{ t('payment.planCard.monthlyLimit') }}</span>
|
||||
<span class="font-medium text-gray-700 dark:text-gray-300">${{ plan.monthly_limit_usd }}</span>
|
||||
</div>
|
||||
<div v-if="plan.daily_limit_usd == null && plan.weekly_limit_usd == null && plan.monthly_limit_usd == null" class="flex items-center justify-between text-xs">
|
||||
<div v-if="plan.daily_limit_usd == null && plan.weekly_limit_usd == null && plan.monthly_limit_usd == null" class="flex items-center justify-between">
|
||||
<span class="text-gray-400 dark:text-dark-500">{{ t('payment.planCard.quota') }}</span>
|
||||
<span class="font-medium text-gray-700 dark:text-gray-300">{{ t('payment.planCard.unlimited') }}</span>
|
||||
</div>
|
||||
<div v-if="modelScopeLabels.length > 0" class="flex items-center justify-between text-xs">
|
||||
<div v-if="modelScopeLabels.length > 0" class="col-span-2 flex items-center justify-between">
|
||||
<span class="text-gray-400 dark:text-dark-500">{{ t('payment.planCard.models') }}</span>
|
||||
<div class="flex flex-wrap justify-end gap-1">
|
||||
<span v-for="scope in modelScopeLabels" :key="scope"
|
||||
@@ -77,25 +70,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Features list with checkmarks -->
|
||||
<div v-if="plan.features.length > 0" class="mb-4 space-y-2">
|
||||
<div v-for="feature in plan.features" :key="feature" class="flex items-start gap-2">
|
||||
<svg :class="['mt-0.5 h-4 w-4 flex-shrink-0', iconClass]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<!-- Features list (compact) -->
|
||||
<div v-if="plan.features.length > 0" class="mb-3 space-y-1">
|
||||
<div v-for="feature in plan.features" :key="feature" class="flex items-start gap-1.5">
|
||||
<svg :class="['mt-0.5 h-3.5 w-3.5 flex-shrink-0', iconClass]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" />
|
||||
</svg>
|
||||
<span class="text-sm text-gray-600 dark:text-gray-300">{{ feature }}</span>
|
||||
<span class="text-xs text-gray-600 dark:text-gray-300">{{ feature }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1" />
|
||||
|
||||
<!-- Validity badge -->
|
||||
<div class="mb-3 text-center">
|
||||
<span :class="['rounded-full px-3 py-1 text-xs font-medium', badgeLightClass]">
|
||||
{{ validityLabel }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Subscribe Button -->
|
||||
<button
|
||||
type="button"
|
||||
@@ -162,14 +148,6 @@ const modelScopeLabels = computed(() => {
|
||||
return scopes.map(s => MODEL_SCOPE_LABELS[s] || s)
|
||||
})
|
||||
|
||||
const validityLabel = computed(() => {
|
||||
const d = props.plan.validity_days
|
||||
const u = props.plan.validity_unit || 'day'
|
||||
if (u === 'month') return d === 1 ? t('payment.oneMonth') : `${d} ${t('payment.months')}`
|
||||
if (u === 'year') return d === 1 ? t('payment.oneYear') : `${d} ${t('payment.years')}`
|
||||
return `${d} ${t('payment.days')}`
|
||||
})
|
||||
|
||||
const validitySuffix = computed(() => {
|
||||
const u = props.plan.validity_unit || 'day'
|
||||
if (u === 'month') return t('payment.perMonth')
|
||||
|
||||
@@ -5131,6 +5131,7 @@ export default {
|
||||
},
|
||||
result: {
|
||||
success: 'Payment Successful',
|
||||
subscriptionSuccess: 'Subscription Successful',
|
||||
failed: 'Payment Failed',
|
||||
backToRecharge: 'Back to Recharge',
|
||||
viewOrders: 'View Orders',
|
||||
|
||||
@@ -5328,6 +5328,7 @@ export default {
|
||||
},
|
||||
result: {
|
||||
success: '支付成功',
|
||||
subscriptionSuccess: '订阅成功',
|
||||
failed: '支付失败',
|
||||
backToRecharge: '返回充值',
|
||||
viewOrders: '查看订单',
|
||||
|
||||
@@ -135,6 +135,7 @@ export interface ProviderInstance {
|
||||
payment_mode: string
|
||||
refund_enabled: boolean
|
||||
limits: string
|
||||
sort_order: number
|
||||
}
|
||||
|
||||
// ==================== Request / Response ====================
|
||||
|
||||
@@ -1746,6 +1746,7 @@
|
||||
@delete="confirmDeleteProvider"
|
||||
@toggle-field="handleToggleField"
|
||||
@toggle-type="handleToggleType"
|
||||
@reorder="handleReorderProviders"
|
||||
/>
|
||||
|
||||
</div>
|
||||
@@ -2957,6 +2958,22 @@ function confirmDeleteProvider(provider: ProviderInstance) {
|
||||
showDeleteProviderDialog.value = true
|
||||
}
|
||||
|
||||
async function handleReorderProviders(updates: { id: number; sort_order: number }[]) {
|
||||
try {
|
||||
await Promise.all(
|
||||
updates.map(u => adminAPI.payment.updateProvider(u.id, { sort_order: u.sort_order } as Partial<ProviderInstance>))
|
||||
)
|
||||
// Update local state to match new order
|
||||
for (const u of updates) {
|
||||
const p = providers.value.find(p => p.id === u.id)
|
||||
if (p) p.sort_order = u.sort_order
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
appStore.showError(extractApiErrorMessage(err, t('common.error')))
|
||||
loadProviders()
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDeleteProvider() {
|
||||
if (!deletingProviderId.value) return
|
||||
try {
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
:expires-at="paymentState.expiresAt"
|
||||
:payment-type="paymentState.paymentType"
|
||||
:pay-url="paymentState.payUrl"
|
||||
@done="resetPayment"
|
||||
:order-type="paymentState.orderType"
|
||||
@done="onPaymentDone"
|
||||
@success="onPaymentSuccess"
|
||||
/>
|
||||
</template>
|
||||
@@ -96,17 +97,35 @@
|
||||
<!-- Subscribe Tab -->
|
||||
<template v-else-if="activeTab === 'subscription'">
|
||||
<!-- Active Subscription Card -->
|
||||
<div v-if="activeSubscriptions.length > 0" class="card p-5">
|
||||
<div v-if="activeSubscriptions.length > 0" class="space-y-3">
|
||||
<p class="text-xs font-medium text-gray-400 dark:text-gray-500">{{ t('payment.activeSubscription') }}</p>
|
||||
<div v-for="sub in activeSubscriptions" :key="sub.id" class="mt-2 flex items-center justify-between">
|
||||
<div>
|
||||
<p class="text-sm font-semibold text-gray-900 dark:text-white">{{ sub.group?.name || `Group #${sub.group_id}` }}</p>
|
||||
<p v-if="sub.expires_at" class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('userSubscriptions.daysRemaining', { days: getDaysRemaining(sub.expires_at) }) }}
|
||||
</p>
|
||||
<p v-else class="text-xs text-gray-500 dark:text-gray-400">{{ t('userSubscriptions.noExpiration') }}</p>
|
||||
<div v-for="sub in activeSubscriptions" :key="sub.id"
|
||||
class="card overflow-hidden">
|
||||
<div :class="['h-1', platformAccentBarClass(sub.group?.platform || '')]" />
|
||||
<div class="p-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<h4 class="text-sm font-semibold text-gray-900 dark:text-white">
|
||||
{{ sub.group?.name || `Group #${sub.group_id}` }}
|
||||
</h4>
|
||||
<span :class="['rounded-full px-2 py-0.5 text-[10px] font-medium', platformBadgeLightClass(sub.group?.platform || '')]">
|
||||
{{ platformLabel(sub.group?.platform || '') }}
|
||||
</span>
|
||||
</div>
|
||||
<span class="badge badge-success text-xs">{{ t('userSubscriptions.status.active') }}</span>
|
||||
</div>
|
||||
<div class="mt-2 flex flex-wrap gap-x-4 gap-y-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
<span>{{ t('payment.planCard.rate') }}: ×{{ sub.group?.rate_multiplier ?? 1 }}</span>
|
||||
<span v-if="sub.group?.daily_limit_usd != null">{{ t('payment.planCard.dailyLimit') }}: ${{ sub.group.daily_limit_usd }}</span>
|
||||
<span v-if="sub.group?.weekly_limit_usd != null">{{ t('payment.planCard.weeklyLimit') }}: ${{ sub.group.weekly_limit_usd }}</span>
|
||||
<span v-if="sub.group?.monthly_limit_usd != null">{{ t('payment.planCard.monthlyLimit') }}: ${{ sub.group.monthly_limit_usd }}</span>
|
||||
<span v-if="!sub.group?.daily_limit_usd && !sub.group?.weekly_limit_usd && !sub.group?.monthly_limit_usd">{{ t('payment.planCard.quota') }}: {{ t('payment.planCard.unlimited') }}</span>
|
||||
</div>
|
||||
<div class="mt-2 text-xs text-gray-500 dark:text-gray-400">
|
||||
<span v-if="sub.expires_at">{{ t('userSubscriptions.daysRemaining', { days: getDaysRemaining(sub.expires_at) }) }}</span>
|
||||
<span v-else>{{ t('userSubscriptions.noExpiration') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="badge badge-success text-xs">{{ t('userSubscriptions.status.active') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="card p-5">
|
||||
@@ -207,6 +226,7 @@ import AppLayout from '@/components/layout/AppLayout.vue'
|
||||
import AmountInput from '@/components/payment/AmountInput.vue'
|
||||
import PaymentMethodSelector from '@/components/payment/PaymentMethodSelector.vue'
|
||||
import { METHOD_ORDER, POPUP_WINDOW_FEATURES } from '@/components/payment/providerConfig'
|
||||
import { platformAccentBarClass, platformBadgeLightClass, platformLabel } from '@/utils/platformColors'
|
||||
import SubscriptionPlanCard from '@/components/payment/SubscriptionPlanCard.vue'
|
||||
import PaymentStatusPanel from '@/components/payment/PaymentStatusPanel.vue'
|
||||
import StripePaymentInline from '@/components/payment/StripePaymentInline.vue'
|
||||
@@ -238,21 +258,34 @@ const previewImage = ref('')
|
||||
|
||||
// Payment phase: 'select' → 'paying' (QR/redirect) or 'stripe' (inline Stripe)
|
||||
const paymentPhase = ref<'select' | 'paying' | 'stripe'>('select')
|
||||
const paymentState = ref({ orderId: 0, qrCode: '', expiresAt: '', paymentType: '', payUrl: '', clientSecret: '', payAmount: 0 })
|
||||
const paymentState = ref({ orderId: 0, qrCode: '', expiresAt: '', paymentType: '', payUrl: '', clientSecret: '', payAmount: 0, orderType: '' })
|
||||
|
||||
function resetPayment() {
|
||||
paymentPhase.value = 'select'
|
||||
paymentState.value = { orderId: 0, qrCode: '', expiresAt: '', paymentType: '', payUrl: '', clientSecret: '', payAmount: 0 }
|
||||
paymentState.value = { orderId: 0, qrCode: '', expiresAt: '', paymentType: '', payUrl: '', clientSecret: '', payAmount: 0, orderType: '' }
|
||||
}
|
||||
|
||||
function onPaymentDone() {
|
||||
const wasSubscription = paymentState.value.orderType === 'subscription'
|
||||
resetPayment()
|
||||
selectedPlan.value = null
|
||||
if (wasSubscription) {
|
||||
subscriptionStore.fetchActiveSubscriptions(true).catch(() => {})
|
||||
}
|
||||
}
|
||||
|
||||
function onPaymentSuccess() {
|
||||
authStore.refreshUser()
|
||||
resetPayment()
|
||||
selectedPlan.value = null
|
||||
if (paymentState.value.orderType === 'subscription') {
|
||||
subscriptionStore.fetchActiveSubscriptions(true).catch(() => {})
|
||||
}
|
||||
}
|
||||
|
||||
function onStripeSuccess() {
|
||||
authStore.refreshUser()
|
||||
if (paymentState.value.orderType === 'subscription') {
|
||||
subscriptionStore.fetchActiveSubscriptions(true).catch(() => {})
|
||||
}
|
||||
resetPayment()
|
||||
selectedPlan.value = null
|
||||
}
|
||||
@@ -424,6 +457,7 @@ async function createOrder(orderAmount: number, orderType: string, planId?: numb
|
||||
orderId: result.order_id, qrCode: '', expiresAt: '',
|
||||
paymentType: selectedMethod.value, payUrl: '',
|
||||
clientSecret: result.client_secret, payAmount: result.pay_amount,
|
||||
orderType,
|
||||
}
|
||||
paymentPhase.value = 'stripe'
|
||||
} else if (result.qr_code) {
|
||||
@@ -432,6 +466,7 @@ async function createOrder(orderAmount: number, orderType: string, planId?: numb
|
||||
orderId: result.order_id, qrCode: result.qr_code,
|
||||
expiresAt: result.expires_at || '', paymentType: selectedMethod.value, payUrl: '',
|
||||
clientSecret: '', payAmount: 0,
|
||||
orderType,
|
||||
}
|
||||
paymentPhase.value = 'paying'
|
||||
} else if (result.pay_url) {
|
||||
@@ -441,6 +476,7 @@ async function createOrder(orderAmount: number, orderType: string, planId?: numb
|
||||
orderId: result.order_id, qrCode: '', expiresAt: result.expires_at || '',
|
||||
paymentType: selectedMethod.value, payUrl: result.pay_url,
|
||||
clientSecret: '', payAmount: 0,
|
||||
orderType,
|
||||
}
|
||||
paymentPhase.value = 'paying'
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user