f
This commit is contained in:
@@ -429,6 +429,7 @@
|
|||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
:close-on-press-escape="false"
|
:close-on-press-escape="false"
|
||||||
class="qr-code-dialog"
|
class="qr-code-dialog"
|
||||||
|
@close="handleQrCodeDialogClose"
|
||||||
>
|
>
|
||||||
<div class="qr-code-container">
|
<div class="qr-code-container">
|
||||||
<div class="qr-code-wrapper">
|
<div class="qr-code-wrapper">
|
||||||
@@ -437,6 +438,7 @@
|
|||||||
<p class="qr-code-tip">请使用微信扫描上方二维码完成支付</p>
|
<p class="qr-code-tip">请使用微信扫描上方二维码完成支付</p>
|
||||||
<p class="qr-code-amount">支付金额:¥{{ formatPrice(wechatForm.amount) }}</p>
|
<p class="qr-code-amount">支付金额:¥{{ formatPrice(wechatForm.amount) }}</p>
|
||||||
<p v-if="isCheckingPayment" class="qr-code-checking">正在确认支付状态,请稍候...</p>
|
<p v-if="isCheckingPayment" class="qr-code-checking">正在确认支付状态,请稍候...</p>
|
||||||
|
<p class="qr-code-tip">关闭窗口后将继续确认支付结果,请勿重复支付</p>
|
||||||
<el-button type="primary" @click="closeQrCodeDialog" class="close-qr-btn">关闭</el-button>
|
<el-button type="primary" @click="closeQrCodeDialog" class="close-qr-btn">关闭</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@@ -476,6 +478,11 @@ const showQrCodeDialog = ref(false)
|
|||||||
const qrCodeCanvas = ref(null)
|
const qrCodeCanvas = ref(null)
|
||||||
const currentWechatOrderNo = ref(null)
|
const currentWechatOrderNo = ref(null)
|
||||||
const isCheckingPayment = ref(false)
|
const isCheckingPayment = ref(false)
|
||||||
|
const wechatPaymentResolved = ref(false)
|
||||||
|
const skipQrCloseRedirect = ref(false)
|
||||||
|
const wechatDialogPollCount = ref(0)
|
||||||
|
const WECHAT_POLL_INTERVAL_MS = 5000
|
||||||
|
const WECHAT_DIALOG_MAX_POLL_COUNT = 12 // 弹窗内最多轮询12次(约1分钟),之后跳转处理页
|
||||||
let wechatOrderPollTimer = null
|
let wechatOrderPollTimer = null
|
||||||
|
|
||||||
// 钱包信息
|
// 钱包信息
|
||||||
@@ -993,26 +1000,78 @@ const showQrCode = async (codeUrl) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭二维码弹窗
|
// 关闭二维码弹窗(用户主动关闭,跳转处理页继续轮询)
|
||||||
const closeQrCodeDialog = () => {
|
const closeQrCodeDialog = () => {
|
||||||
stopWechatOrderPolling()
|
|
||||||
showQrCodeDialog.value = false
|
showQrCodeDialog.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleQrCodeDialogClose = () => {
|
||||||
|
if (wechatPaymentResolved.value) {
|
||||||
|
wechatPaymentResolved.value = false
|
||||||
|
stopWechatOrderPolling()
|
||||||
currentWechatOrderNo.value = null
|
currentWechatOrderNo.value = null
|
||||||
isCheckingPayment.value = false
|
isCheckingPayment.value = false
|
||||||
|
wechatDialogPollCount.value = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipQrCloseRedirect.value) {
|
||||||
|
skipQrCloseRedirect.value = false
|
||||||
|
isCheckingPayment.value = false
|
||||||
|
wechatDialogPollCount.value = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderNo = currentWechatOrderNo.value
|
||||||
|
const orderAmount = wechatForm.amount
|
||||||
|
stopWechatOrderPolling()
|
||||||
|
currentWechatOrderNo.value = null
|
||||||
|
isCheckingPayment.value = false
|
||||||
|
wechatDialogPollCount.value = 0
|
||||||
|
|
||||||
|
if (orderNo) {
|
||||||
|
router.push({
|
||||||
|
path: '/finance/wallet/processing',
|
||||||
|
query: {
|
||||||
|
out_trade_no: orderNo,
|
||||||
|
amount: orderAmount,
|
||||||
|
payment_type: 'wechat',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const redirectToWechatProcessingPage = () => {
|
||||||
|
const orderNo = currentWechatOrderNo.value
|
||||||
|
const orderAmount = wechatForm.amount
|
||||||
|
if (!orderNo) return
|
||||||
|
|
||||||
|
stopWechatOrderPolling()
|
||||||
|
skipQrCloseRedirect.value = true
|
||||||
|
currentWechatOrderNo.value = null
|
||||||
|
wechatDialogPollCount.value = 0
|
||||||
|
showQrCodeDialog.value = false
|
||||||
|
isCheckingPayment.value = false
|
||||||
|
router.push({
|
||||||
|
path: '/finance/wallet/processing',
|
||||||
|
query: {
|
||||||
|
out_trade_no: orderNo,
|
||||||
|
amount: orderAmount,
|
||||||
|
payment_type: 'wechat',
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始轮询微信订单状态
|
// 开始轮询微信订单状态
|
||||||
const startWechatOrderPolling = () => {
|
const startWechatOrderPolling = () => {
|
||||||
// 清除之前的定时器
|
|
||||||
stopWechatOrderPolling()
|
stopWechatOrderPolling()
|
||||||
|
wechatDialogPollCount.value = 0
|
||||||
// 立即检查一次
|
|
||||||
checkWechatOrderStatus()
|
checkWechatOrderStatus()
|
||||||
|
|
||||||
// 每3秒轮询一次
|
|
||||||
wechatOrderPollTimer = setInterval(() => {
|
wechatOrderPollTimer = setInterval(() => {
|
||||||
|
wechatDialogPollCount.value++
|
||||||
checkWechatOrderStatus()
|
checkWechatOrderStatus()
|
||||||
}, 3000)
|
}, WECHAT_POLL_INTERVAL_MS)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 停止轮询
|
// 停止轮询
|
||||||
@@ -1029,47 +1088,49 @@ const checkWechatOrderStatus = async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wechatDialogPollCount.value >= WECHAT_DIALOG_MAX_POLL_COUNT) {
|
||||||
|
redirectToWechatProcessingPage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
isCheckingPayment.value = true
|
isCheckingPayment.value = true
|
||||||
const response = await callProtectedAPI(financeApi.getWechatOrderStatus, {
|
const response = await financeApi.getWechatOrderStatus({
|
||||||
out_trade_no: currentWechatOrderNo.value
|
out_trade_no: currentWechatOrderNo.value
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!response || !response.data) {
|
if (!response?.data) {
|
||||||
isCheckingPayment.value = false
|
isCheckingPayment.value = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderStatus = response.data.status
|
const orderStatus = response.data.status
|
||||||
|
|
||||||
// 订单状态:pending, success, failed, closed
|
|
||||||
if (orderStatus === 'success') {
|
if (orderStatus === 'success') {
|
||||||
// 支付成功
|
wechatPaymentResolved.value = true
|
||||||
stopWechatOrderPolling()
|
stopWechatOrderPolling()
|
||||||
isCheckingPayment.value = false
|
isCheckingPayment.value = false
|
||||||
closeQrCodeDialog()
|
showQrCodeDialog.value = false
|
||||||
ElMessage.success('充值成功!')
|
ElMessage.success('充值成功!')
|
||||||
|
|
||||||
// 刷新钱包余额
|
|
||||||
await loadWalletInfo()
|
await loadWalletInfo()
|
||||||
|
|
||||||
// 重置表单
|
|
||||||
wechatForm.amount = ''
|
wechatForm.amount = ''
|
||||||
selectedPresetAmount.value = null
|
selectedPresetAmount.value = null
|
||||||
|
currentWechatOrderNo.value = null
|
||||||
|
wechatDialogPollCount.value = 0
|
||||||
} else if (orderStatus === 'failed' || orderStatus === 'closed') {
|
} else if (orderStatus === 'failed' || orderStatus === 'closed') {
|
||||||
// 支付失败或关闭
|
wechatPaymentResolved.value = true
|
||||||
stopWechatOrderPolling()
|
stopWechatOrderPolling()
|
||||||
isCheckingPayment.value = false
|
isCheckingPayment.value = false
|
||||||
|
showQrCodeDialog.value = false
|
||||||
ElMessage.error('支付失败,请重新支付')
|
ElMessage.error('支付失败,请重新支付')
|
||||||
closeQrCodeDialog()
|
currentWechatOrderNo.value = null
|
||||||
|
wechatDialogPollCount.value = 0
|
||||||
} else {
|
} else {
|
||||||
// pending 状态继续轮询
|
|
||||||
isCheckingPayment.value = false
|
isCheckingPayment.value = false
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('查询微信订单状态失败:', error)
|
console.error('查询微信订单状态失败:', error)
|
||||||
isCheckingPayment.value = false
|
isCheckingPayment.value = false
|
||||||
// 不显示错误,继续轮询
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -119,7 +119,7 @@
|
|||||||
<span class="font-medium">{{ orderInfo.out_trade_no }}</span>
|
<span class="font-medium">{{ orderInfo.out_trade_no }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<span class="text-gray-500">支付宝交易号:</span>
|
<span class="text-gray-500">{{ tradeNoLabel }}:</span>
|
||||||
<span class="font-medium">{{ orderInfo.trade_no || '暂无' }}</span>
|
<span class="font-medium">{{ orderInfo.trade_no || '暂无' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
@@ -245,6 +245,57 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 轮询超时(支付可能仍在处理中) -->
|
||||||
|
<div v-else-if="orderStatus === 'timeout'" class="text-center">
|
||||||
|
<div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-yellow-100">
|
||||||
|
<svg
|
||||||
|
class="h-6 w-6 text-yellow-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h2 class="mt-6 text-3xl font-extrabold text-gray-900">仍在确认支付结果</h2>
|
||||||
|
<p class="mt-2 text-sm text-gray-600">
|
||||||
|
若您已完成支付,余额通常会在几分钟内到账,请稍后刷新钱包查看。
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="mt-8 bg-white shadow rounded-lg p-6">
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-gray-500">订单号:</span>
|
||||||
|
<span class="font-medium">{{ orderInfo.out_trade_no }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-gray-500">金额:</span>
|
||||||
|
<span class="font-medium text-green-600">¥{{ orderInfo.amount }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-8 space-y-3">
|
||||||
|
<button
|
||||||
|
@click="goToWallet"
|
||||||
|
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||||
|
>
|
||||||
|
返回钱包查看余额
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="contactService"
|
||||||
|
class="w-full flex justify-center py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||||
|
>
|
||||||
|
联系客服
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 其他状态 -->
|
<!-- 其他状态 -->
|
||||||
<div v-else class="text-center">
|
<div v-else class="text-center">
|
||||||
<div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-yellow-100">
|
<div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-yellow-100">
|
||||||
@@ -291,12 +342,16 @@ export default {
|
|||||||
const orderStatus = ref('processing')
|
const orderStatus = ref('processing')
|
||||||
const isProcessing = ref(true)
|
const isProcessing = ref(true)
|
||||||
const pollCount = ref(0)
|
const pollCount = ref(0)
|
||||||
const maxPollCount = ref(30) // 最多轮询30次
|
const maxPollCount = ref(36) // 最多轮询36次(约3分钟)
|
||||||
|
const pollIntervalMs = 5000 // 每5秒查询一次,避免过于频繁
|
||||||
const pollInterval = ref(null)
|
const pollInterval = ref(null)
|
||||||
|
|
||||||
// 获取URL参数
|
// 获取URL参数
|
||||||
const outTradeNo = route.query.out_trade_no
|
const outTradeNo = route.query.out_trade_no
|
||||||
const amount = route.query.amount
|
const amount = route.query.amount
|
||||||
|
const paymentType = route.query.payment_type === 'wechat' ? 'wechat' : 'alipay'
|
||||||
|
const isWechatPay = computed(() => paymentType === 'wechat')
|
||||||
|
const tradeNoLabel = computed(() => (isWechatPay.value ? '微信交易号' : '支付宝交易号'))
|
||||||
|
|
||||||
// 初始化订单信息
|
// 初始化订单信息
|
||||||
orderInfo.value = {
|
orderInfo.value = {
|
||||||
@@ -304,6 +359,15 @@ export default {
|
|||||||
amount: amount,
|
amount: amount,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizeOrderData = (data) => {
|
||||||
|
if (!data) return data
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
amount: data.amount ?? amount,
|
||||||
|
trade_no: data.trade_no || data.transaction_id || null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 格式化时间
|
// 格式化时间
|
||||||
const formatTime = (timeStr) => {
|
const formatTime = (timeStr) => {
|
||||||
if (!timeStr) return '暂无'
|
if (!timeStr) return '暂无'
|
||||||
@@ -313,41 +377,45 @@ export default {
|
|||||||
// 查询订单状态
|
// 查询订单状态
|
||||||
const queryOrderStatus = async () => {
|
const queryOrderStatus = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await financeApi.getAlipayOrderStatus({ out_trade_no: outTradeNo })
|
const response = isWechatPay.value
|
||||||
orderInfo.value = response.data
|
? await financeApi.getWechatOrderStatus({ out_trade_no: outTradeNo })
|
||||||
// 根据状态更新页面
|
: await financeApi.getAlipayOrderStatus({ out_trade_no: outTradeNo })
|
||||||
|
|
||||||
|
if (!response?.data) return
|
||||||
|
|
||||||
|
orderInfo.value = normalizeOrderData(response.data)
|
||||||
|
|
||||||
if (response.data.status === 'success') {
|
if (response.data.status === 'success') {
|
||||||
orderStatus.value = 'success'
|
orderStatus.value = 'success'
|
||||||
isProcessing.value = false
|
isProcessing.value = false
|
||||||
stopPolling()
|
stopPolling()
|
||||||
} else if (response.data.status === 'failed') {
|
} else if (response.data.status === 'failed' || response.data.status === 'closed') {
|
||||||
orderStatus.value = 'failed'
|
orderStatus.value = 'failed'
|
||||||
isProcessing.value = false
|
isProcessing.value = false
|
||||||
stopPolling()
|
stopPolling()
|
||||||
} else if (response.data.status === 'pending') {
|
} else if (pollCount.value >= maxPollCount.value) {
|
||||||
// 继续轮询,轮询次数在setInterval中已经增加
|
orderStatus.value = 'timeout'
|
||||||
if (pollCount.value >= maxPollCount.value) {
|
isProcessing.value = false
|
||||||
// 超过最大轮询次数,停止轮询
|
|
||||||
stopPolling()
|
stopPolling()
|
||||||
// 可以显示超时提示
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('查询订单状态失败:', error)
|
console.error('查询订单状态失败:', error)
|
||||||
// 查询失败时继续轮询,不要停止
|
if (pollCount.value >= maxPollCount.value) {
|
||||||
|
orderStatus.value = 'timeout'
|
||||||
|
isProcessing.value = false
|
||||||
|
stopPolling()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始轮询
|
// 开始轮询
|
||||||
const startPolling = () => {
|
const startPolling = () => {
|
||||||
// 立即查询一次
|
|
||||||
queryOrderStatus()
|
queryOrderStatus()
|
||||||
|
|
||||||
// 每3秒查询一次
|
|
||||||
pollInterval.value = setInterval(() => {
|
pollInterval.value = setInterval(() => {
|
||||||
pollCount.value++ // 增加轮询次数
|
pollCount.value++
|
||||||
queryOrderStatus()
|
queryOrderStatus()
|
||||||
}, 3000)
|
}, pollIntervalMs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 停止轮询
|
// 停止轮询
|
||||||
@@ -368,10 +436,13 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const retryPayment = () => {
|
const retryPayment = () => {
|
||||||
// 重新创建支付订单
|
|
||||||
router.push({
|
router.push({
|
||||||
path: '/finance/wallet',
|
path: '/finance/wallet',
|
||||||
query: { retry: 'true', amount: amount },
|
query: {
|
||||||
|
retry: 'true',
|
||||||
|
amount: amount,
|
||||||
|
method: isWechatPay.value ? 'wechat' : 'alipay',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,6 +475,7 @@ export default {
|
|||||||
isProcessing,
|
isProcessing,
|
||||||
pollCount,
|
pollCount,
|
||||||
maxPollCount,
|
maxPollCount,
|
||||||
|
tradeNoLabel,
|
||||||
formatTime,
|
formatTime,
|
||||||
goToWallet,
|
goToWallet,
|
||||||
goToRechargeRecords,
|
goToRechargeRecords,
|
||||||
|
|||||||
Reference in New Issue
Block a user