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

@@ -57,6 +57,7 @@ import { computed, ref, onMounted, onUnmounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute } from 'vue-router'
import { extractApiErrorMessage } from '@/utils/apiError'
import { isMobileDevice } from '@/utils/device'
interface StripeWithWechatPay {
confirmWechatPayPayment(clientSecret: string, options: Record<string, unknown>): Promise<{ error?: { message?: string }; paymentIntent?: { status: string } }>
@@ -129,7 +130,7 @@ async function initStripe(clientSecret: string, publishableKey: string) {
// WeChat: Stripe shows its built-in QR dialog, user scans, promise resolves
hint.value = t('payment.stripePopup.loadingQr')
const result = await (stripe as unknown as StripeWithWechatPay).confirmWechatPayPayment(clientSecret, {
payment_method_options: { wechat_pay: { client: 'web' } },
payment_method_options: { wechat_pay: { client: isMobileDevice() ? 'mobile_web' : 'web' } },
})
if (result.error) {
error.value = result.error.message || t('payment.result.failed')