移动端浏览器支付 ok
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
import { computed, onBeforeUnmount, ref, watch } from 'vue'
|
||||
import QRCode from 'qrcode'
|
||||
import { showDialog, showToast } from 'vant'
|
||||
|
||||
import { queryOrderPayment, type PaymentOrder } from '@/features/orders/api/orders'
|
||||
|
||||
type PaidHandler = () => Promise<void> | void
|
||||
|
||||
export function mobilePaymentPayURL(payment?: PaymentOrder | null) {
|
||||
return payment?.jspay_url || payment?.td_code || payment?.jspay_info || ''
|
||||
}
|
||||
|
||||
function isInAppPaymentBrowser() {
|
||||
if (typeof navigator === 'undefined') return false
|
||||
const ua = navigator.userAgent || ''
|
||||
return /MicroMessenger|AlipayClient/i.test(ua)
|
||||
}
|
||||
|
||||
function isHTTPURL(value: string) {
|
||||
return /^https?:\/\//i.test(value)
|
||||
}
|
||||
|
||||
export function useMobilePaymentCashier() {
|
||||
const paymentPopupVisible = ref(false)
|
||||
const activePayment = ref<PaymentOrder | null>(null)
|
||||
const paymentQRCodeURL = ref('')
|
||||
const qrGenerating = ref(false)
|
||||
const checkingPayment = ref(false)
|
||||
let paymentPollingTimer: number | undefined
|
||||
let paidHandler: PaidHandler | undefined
|
||||
|
||||
const payURL = computed(() => mobilePaymentPayURL(activePayment.value))
|
||||
|
||||
async function openMobilePaymentCashier(payment: PaymentOrder, onPaid?: PaidHandler) {
|
||||
activePayment.value = payment
|
||||
paidHandler = onPaid
|
||||
|
||||
if (payment.paid) {
|
||||
await handlePaid()
|
||||
return
|
||||
}
|
||||
|
||||
const currentPayURL = mobilePaymentPayURL(payment)
|
||||
if (currentPayURL && isHTTPURL(currentPayURL) && isInAppPaymentBrowser()) {
|
||||
window.location.href = currentPayURL
|
||||
return
|
||||
}
|
||||
|
||||
if (currentPayURL && isHTTPURL(currentPayURL)) {
|
||||
paymentPopupVisible.value = true
|
||||
await renderPaymentQRCode(payment)
|
||||
startPaymentPolling()
|
||||
return
|
||||
}
|
||||
|
||||
await showDialog({
|
||||
title: '订单支付',
|
||||
message: currentPayURL || '支付单已创建,请稍后刷新订单状态。',
|
||||
confirmButtonText: '知道了',
|
||||
})
|
||||
}
|
||||
|
||||
async function renderPaymentQRCode(payment = activePayment.value) {
|
||||
const currentPayURL = mobilePaymentPayURL(payment)
|
||||
paymentQRCodeURL.value = ''
|
||||
if (!currentPayURL || !isHTTPURL(currentPayURL)) return
|
||||
|
||||
qrGenerating.value = true
|
||||
try {
|
||||
paymentQRCodeURL.value = await QRCode.toDataURL(currentPayURL, {
|
||||
width: 220,
|
||||
margin: 1,
|
||||
errorCorrectionLevel: 'M',
|
||||
color: {
|
||||
dark: '#111827',
|
||||
light: '#ffffff',
|
||||
},
|
||||
})
|
||||
} catch {
|
||||
showToast({ message: '二维码生成失败', icon: 'cross' })
|
||||
} finally {
|
||||
qrGenerating.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function startPaymentPolling() {
|
||||
stopPaymentPolling()
|
||||
paymentPollingTimer = window.setInterval(() => {
|
||||
void refreshPaymentStatus(true)
|
||||
}, 2500)
|
||||
}
|
||||
|
||||
function stopPaymentPolling() {
|
||||
if (paymentPollingTimer === undefined) return
|
||||
window.clearInterval(paymentPollingTimer)
|
||||
paymentPollingTimer = undefined
|
||||
}
|
||||
|
||||
async function refreshPaymentStatus(silent = false) {
|
||||
if (!activePayment.value || checkingPayment.value) return
|
||||
|
||||
checkingPayment.value = true
|
||||
const previousPayURL = payURL.value
|
||||
try {
|
||||
const payment = await queryOrderPayment(activePayment.value.order_id)
|
||||
activePayment.value = payment
|
||||
if (payment.paid) {
|
||||
await handlePaid()
|
||||
return
|
||||
}
|
||||
if (mobilePaymentPayURL(payment) !== previousPayURL) {
|
||||
await renderPaymentQRCode(payment)
|
||||
}
|
||||
if (!silent) {
|
||||
showToast({ message: '支付暂未完成', icon: 'info-o' })
|
||||
}
|
||||
} catch {
|
||||
if (!silent) {
|
||||
showToast({ message: '查询支付状态失败', icon: 'cross' })
|
||||
}
|
||||
} finally {
|
||||
checkingPayment.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handlePaid() {
|
||||
stopPaymentPolling()
|
||||
paymentPopupVisible.value = false
|
||||
showToast({ message: '支付成功,等待号主交接', icon: 'passed' })
|
||||
await paidHandler?.()
|
||||
}
|
||||
|
||||
watch(paymentPopupVisible, visible => {
|
||||
if (!visible) stopPaymentPolling()
|
||||
})
|
||||
|
||||
onBeforeUnmount(stopPaymentPolling)
|
||||
|
||||
return {
|
||||
paymentPopupVisible,
|
||||
activePayment,
|
||||
payURL,
|
||||
paymentQRCodeURL,
|
||||
qrGenerating,
|
||||
checkingPayment,
|
||||
openMobilePaymentCashier,
|
||||
refreshPaymentStatus,
|
||||
stopPaymentPolling,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user