hookehuyr

feat: 添加重新支付功能开关并优化支付失败处理

- 新增 ENABLE_REPAY_FEATURE 配置项(默认关闭)
- 关闭重新支付时,订单列表不显示重新支付按钮和倒计时
- 支付失败/取消时友好提示并返回上一页
- 移除提交订单页的循环支付逻辑
- 优化等待页超时和失败处理,自动跳转首页

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
......@@ -36,7 +36,7 @@
>下单时间:<text>{{ reserve_info.order_time }}</text></view
>
</view>
<view v-if="is_pay_pending" class="booking-list-item-footer" @tap.stop>
<view v-if="enable_repay && is_pay_pending" class="booking-list-item-footer" @tap.stop>
<view v-if="countdown_seconds > 0" class="countdown">剩余支付时间:{{ countdown_text }}</view>
<view v-else class="countdown timeout">支付已超时</view>
<view v-if="countdown_seconds > 0" class="repay-btn" @tap.stop="onRepay">重新支付</view>
......@@ -50,9 +50,13 @@ import Taro from '@tarojs/taro'
import { IconFont } from '@nutui/icons-vue-taro'
import { useGo } from '@/hooks/useGo'
import { wechat_pay } from '@/utils/wechatPay'
import { ENABLE_REPAY_FEATURE } from '@/utils/config'
const go = useGo()
// 是否启用重新支付功能
const enable_repay = computed(() => ENABLE_REPAY_FEATURE)
const props = defineProps({
data: {
type: Object,
......@@ -224,7 +228,7 @@ const onRepay = async () => {
while (should_continue) {
const pay_id = reserve_info.value?.pay_id
const pay_res = await wechat_pay({ pay_id })
if (pay_res && pay_res.code == 1) {
if (pay_res && pay_res.code === 1) {
go('/success', { pay_id })
return
}
......
......@@ -75,7 +75,7 @@
import { ref, computed } from 'vue'
import Taro, { useDidShow, useRouter as useTaroRouter } from '@tarojs/taro'
import { IconFont } from '@nutui/icons-vue-taro'
import { useGo, useReplace } from '@/hooks/useGo'
import { useGo } from '@/hooks/useGo'
import icon_check1 from '@/assets/images/多选01@2x.png'
import icon_check2 from '@/assets/images/多选02@2x.png'
import { personListAPI, addReserveAPI } from '@/api/index'
......@@ -84,7 +84,6 @@ import { mask_id_number } from '@/utils/tools'
const router = useTaroRouter()
const go = useGo()
const replace = useReplace()
const visitorList = ref([])
const date = ref('')
......@@ -174,36 +173,10 @@ const refreshVisitorList = async options => {
}
}
let is_showing_pay_modal = false
/**
* @description 支付未完成弹窗(防并发)
* @param {string} content 弹窗内容
* @returns {Promise<boolean>} true=继续支付,false=离开
*/
const showPayErrorModal = async content => {
if (is_showing_pay_modal) {
return
}
is_showing_pay_modal = true
try {
const res = await Taro.showModal({
title: '提示',
content: content || '支付失败,请稍后再试',
showCancel: true,
cancelText: '离开',
confirmText: '继续支付'
})
return !!res?.confirm
} finally {
is_showing_pay_modal = false
}
}
/**
* @description 提交订单
* - 先创建预约单拿 pay_id(支持“待支付订单”复用)
* - need_pay=1 时循环拉起微信支付,直到成功或用户取消
* - 先创建预约单拿 pay_id(支持"待支付订单"复用)
* - need_pay=1 时拉起微信支付
* @returns {Promise<void>} 无返回值
*/
const submitBtn = async () => {
......@@ -236,7 +209,7 @@ const submitBtn = async () => {
Taro.hideLoading()
}
if (!reserve_res || reserve_res.code != 1) {
if (!reserve_res || reserve_res.code !== 1) {
return
}
pay_id = reserve_res.data.pay_id
......@@ -248,25 +221,16 @@ const submitBtn = async () => {
// 以接口返回的 need_pay 为准:1=需要支付,0=不需要支付
if (Number(need_pay) === 1 || need_pay === true) {
// 初始化循环
let should_continue = true
// 循环支付直到支付成功或用户取消支付
while (should_continue) {
const pay_res = await wechat_pay({ pay_id })
if (pay_res && pay_res.code == 1) {
if (pay_res && pay_res.code === 1) {
pending_pay_id.value = null
pending_need_pay.value = null
go('/success', { pay_id })
return
}
// 刷新参观者列表, 清除已预约标记
// 支付失败/取消后,刷新参观者列表
refreshVisitorList({ reset_checked: true }).catch(() => {})
should_continue = await showPayErrorModal(
pay_res?.msg || '支付未完成,可再次点击提交订单继续支付'
)
}
replace('/bookingList')
// wechat_pay 内部已经处理了弹窗和返回上一页,这里不需要额外处理
} else {
pending_pay_id.value = null
pending_need_pay.value = null
......
......@@ -26,7 +26,7 @@
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import Taro, { useRouter } from '@tarojs/taro'
import { useRouter } from '@tarojs/taro'
import { IconFont } from '@nutui/icons-vue-taro'
import { billPayStatusAPI } from '@/api/index'
import { useGo } from '@/hooks/useGo'
......@@ -59,6 +59,12 @@ const startCountdown = () => {
current.value.seconds = remaining.value
} else {
clearInterval(countdownTimer)
clearInterval(timer)
// 倒计时结束,跳转到首页
pay_msg.value = '支付确认超时,请稍后在订单列表中查看'
setTimeout(() => {
go('/pages/index/index', 'replace')
}, 2000)
}
}, 1000)
}
......@@ -68,7 +74,7 @@ const checkStatus = async () => {
return
}
try {
const { code, data } = await billPayStatusAPI({ pay_id })
const { data } = await billPayStatusAPI({ pay_id })
// TAG:轮询支付回调
if (data) {
switch (data.status) {
......@@ -85,6 +91,10 @@ const checkStatus = async () => {
break
case PAY_STATUS.FAIL:
pay_msg.value = '订单支付失败'
// 支付失败后跳转到首页
setTimeout(() => {
go('/pages/index/index', 'replace')
}, 2000)
break
}
}
......
......@@ -28,4 +28,11 @@ export const REQUEST_DEFAULT_PARAMS = {
client_name: '智慧西园寺'
}
/**
* @description 重新支付功能开关
* - false:关闭重新支付功能,支付失败/取消后直接返回上一页(默认)
* - true:开启重新支付功能,允许用户重新支付
*/
export const ENABLE_REPAY_FEATURE = false
export default BASE_URL
......
......@@ -7,6 +7,7 @@
*/
import Taro from '@tarojs/taro'
import { wxPayAPI } from '@/api/wx/pay'
import { ENABLE_REPAY_FEATURE } from '@/utils/config'
/**
* @description 微信支付
......@@ -53,11 +54,29 @@ export const wechat_pay = async ({ pay_id }) => {
// 优化错误提示文案
const errMsg = pay_result?.err?.errMsg || ''
let friendlyMsg = '支付未完成'
let showConfirmAndBack = false
if (errMsg.includes('cancel')) {
friendlyMsg = '您已取消支付'
showConfirmAndBack = true
} else if (errMsg.includes('fail')) {
friendlyMsg = '支付失败,请稍后重试'
friendlyMsg = '支付失败'
showConfirmAndBack = true
}
// 如果重新支付功能关闭,直接提示并返回上一页
if (!ENABLE_REPAY_FEATURE && showConfirmAndBack) {
await Taro.showModal({
title: friendlyMsg,
content: '订单未完成支付,如有需要请重新预约',
showCancel: false,
confirmText: '我知道了'
})
// 返回上一页
const pages = Taro.getCurrentPages()
if (pages.length > 1) {
Taro.navigateBack()
}
}
return { code: 0, data: pay_result?.err || null, msg: friendlyMsg }
......