feat(payment): add H5/mobile payment support

Backend:
- Parse EasyPay `payurl2` field, prefer H5 link on mobile
- Add `device=mobile` to EasyPay submit.php (popup) mode
- Expand isMobile detection keywords (add ipad/ipod)

Frontend:
- Add `isMobileDevice()` utility (userAgentData + UA regex)
- Mobile + pay_url: direct redirect instead of QR/popup
- Popup blocked fallback: auto-redirect when window.open fails
- Stripe WeChat Pay: dynamic client param (mobile_web vs web)
This commit is contained in:
erio
2026-04-11 00:44:54 +08:00
parent e3a000e0d4
commit 7515590324
6 changed files with 46 additions and 5 deletions

View File

@@ -263,6 +263,7 @@ import { useSubscriptionStore } from '@/stores/subscriptions'
import { useAppStore } from '@/stores'
import { paymentAPI } from '@/api/payment'
import { extractApiErrorMessage } from '@/utils/apiError'
import { isMobileDevice } from '@/utils/device'
import type { SubscriptionPlan, CheckoutInfoResponse } from '@/types/payment'
import AppLayout from '@/components/layout/AppLayout.vue'
import AmountInput from '@/components/payment/AmountInput.vue'
@@ -528,7 +529,10 @@ async function createOrder(orderAmount: number, orderType: string, planId?: numb
plan_id: planId,
})
const openWindow = (url: string) => {
window.open(url, 'paymentPopup', POPUP_WINDOW_FEATURES)
const win = window.open(url, 'paymentPopup', POPUP_WINDOW_FEATURES)
if (!win || win.closed) {
window.location.href = url
}
}
if (result.client_secret) {
// Stripe: show Payment Element inline (user picks method → confirms → redirect if needed)
@@ -539,6 +543,17 @@ async function createOrder(orderAmount: number, orderType: string, planId?: numb
orderType,
}
paymentPhase.value = 'stripe'
} else if (isMobileDevice() && result.pay_url) {
// Mobile + pay_url: redirect directly instead of QR/popup (mobile browsers block popups)
paymentState.value = {
orderId: result.order_id, qrCode: '', expiresAt: result.expires_at || '',
paymentType: selectedMethod.value, payUrl: result.pay_url,
clientSecret: '', payAmount: 0,
orderType,
}
paymentPhase.value = 'paying'
window.location.href = result.pay_url
return
} else if (result.qr_code) {
// QR mode: show QR code inline
paymentState.value = {