hookehuyr

feat(订单): 添加支付倒计时功能并优化订单状态管理

- 在订单卡片和订单列表中添加支付倒计时显示
- 实现倒计时自动更新和超时自动取消订单功能
- 优化订单状态更新逻辑,确保响应式更新
- 添加倒计时定时器清理机制,防止内存泄漏
<!--
* @Date: 2023-12-20 14:11:11
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-07-15 15:56:28
* @LastEditTime: 2025-07-16 18:20:38
* @FilePath: /jgdl/src/components/payCard.vue
* @Description: 文件描述
-->
......@@ -11,7 +11,7 @@
<view style="padding: 2rem 1rem; text-align: center;">
<view style="font-size: 32rpx;">实付金额</view>
<view style="color: red; margin: 10rpx 0;"><text style="font-size: 50rpx;">¥</text><text style="font-size: 80rpx;">{{ price }}</text></view>
<!-- <view style="font-size: 28rpx; margin-bottom: 20rpx;">支付剩余时间 <text style="color: red;">{{ formatTime(remain_time) }}</text></view> -->
<view style="font-size: 28rpx; margin-bottom: 20rpx;">支付剩余时间 <text style="color: red;">{{ formatTime(remain_time) }}</text></view>
<nut-button block color="#fb923c" @tap="goToPay">立即支付</nut-button>
</view>
</nut-action-sheet>
......
......@@ -709,3 +709,15 @@
color: #374151;
line-height: 1.5;
}
.payment-countdown {
display: flex;
justify-content: flex-end;
margin: 16rpx 0;
}
.countdown-text {
color: #ff4757;
font-size: 24rpx;
font-weight: 500;
}
......
<!--
* @Date: 2022-09-19 14:11:06
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-07-14 18:18:12
* @LastEditTime: 2025-07-16 18:22:16
* @FilePath: /jgdl/src/pages/myOrders/index.vue
* @Description: 订单管理页面
-->
......@@ -77,8 +77,13 @@
</nut-col>
</nut-row>
<!-- 支付剩余时间 -->
<view v-if="viewMode === 'buy' && order.status === 3" class="payment-countdown">
<text class="countdown-text">剩余支付时间:{{ formatCountdown(order.remain_time) }}</text>
</view>
<!-- 操作按钮 -->
<view class="order-actions">
<view v-if="!order.is_sold" class="order-actions">
<!-- 买车模式:待支付状态 -->
<template v-if="viewMode === 'buy' && order.status === 3">
<nut-button type="default" size="small" @click="handleCancelOrder(order.id)"
......@@ -309,7 +314,7 @@
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
import Taro from '@tarojs/taro'
import './index.less'
import { $ } from '@tarojs/extend'
......@@ -361,6 +366,9 @@ const soldOrders = ref([])
const currentPage = ref(0)
const pageLimit = ref(10)
// 倒计时相关状态
const countdownIntervals = ref(new Map()) // 存储每个订单的倒计时定时器
/**
* 根据当前视图模式和筛选条件获取过滤后的订单列表
*/
......@@ -425,10 +433,17 @@ const loadOrderData = async (isLoadMore = false) => {
// 处理多个订单数据
const newOrders = response.data.list.map(orderData => {
// 处理details数组,取第一个元素作为details对象
return {
const processedOrder = {
...orderData,
details: orderData.details && orderData.details.length > 0 ? orderData.details[0] : null
}
// 为待支付订单添加mock的倒计时时间(1800秒用于测试)
if (processedOrder.status === 3) {
processedOrder.remain_time = processedOrder.pay_time || 1800
}
return processedOrder
})
const targetOrders = viewMode.value === 'buy' ? boughtOrders : soldOrders
......@@ -441,6 +456,13 @@ const loadOrderData = async (isLoadMore = false) => {
currentPage.value = 0
}
// 为待支付订单启动倒计时
newOrders.forEach(order => {
if (order.status === 3 && order.remain_time) {
startCountdown(order)
}
})
// 判断是否还有更多数据
hasMore.value = newOrders.length === pageLimit.value
} else {
......@@ -535,12 +557,124 @@ const getStatusClass = (status) => {
}
/**
* 格式化倒计时显示
* @param {number} seconds - 剩余秒数
* @returns {string} 格式化的时间字符串 HH:MM:SS
*/
const formatCountdown = (seconds) => {
if (!seconds || seconds <= 0) {
return '00:00:00'
}
const hours = Math.floor(seconds / 3600)
const minutes = Math.floor((seconds % 3600) / 60)
const secs = seconds % 60
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
}
/**
* 启动订单倒计时
* @param {Object} order - 订单对象
*/
const startCountdown = (order) => {
if (!order || order.status !== 3 || !order.remain_time) {
return
}
// 清除已存在的定时器
if (countdownIntervals.value.has(order.id)) {
clearInterval(countdownIntervals.value.get(order.id))
}
const timer = setInterval(async () => {
const orders = viewMode.value === 'buy' ? boughtOrders : soldOrders
const targetOrderIndex = orders.value.findIndex(o => o.id === order.id)
if (targetOrderIndex !== -1) {
const targetOrder = orders.value[targetOrderIndex]
if (targetOrder.remain_time > 0) {
// 创建新的订单对象来触发响应式更新
const updatedOrder = {
...targetOrder,
remain_time: targetOrder.remain_time - 1
}
// 替换数组中的订单对象
orders.value.splice(targetOrderIndex, 1, updatedOrder)
// 使用nextTick确保DOM更新
await nextTick()
} else {
// 时间到,取消订单
clearInterval(timer)
countdownIntervals.value.delete(order.id)
handleTimeoutCancel(targetOrder)
}
} else {
// 订单不存在,清除定时器
clearInterval(timer)
countdownIntervals.value.delete(order.id)
}
}, 1000)
countdownIntervals.value.set(order.id, timer)
}
/**
* 处理超时取消订单
* @param {Object} order - 订单对象
*/
const handleTimeoutCancel = async (order) => {
// 清除该订单的倒计时定时器
if (countdownIntervals.value.has(order.id)) {
clearInterval(countdownIntervals.value.get(order.id))
countdownIntervals.value.delete(order.id)
}
// 更新订单状态为已取消
const orders = viewMode.value === 'buy' ? boughtOrders : soldOrders
const targetOrderIndex = orders.value.findIndex(o => o.id === order.id)
if (targetOrderIndex !== -1) {
// 创建新的订单对象来触发响应式更新
const updatedOrder = {
...orders.value[targetOrderIndex],
status: 7
}
// 替换数组中的订单对象
orders.value.splice(targetOrderIndex, 1, updatedOrder)
// 使用nextTick确保DOM更新
await nextTick()
}
Taro.showToast({
title: '订单已超时取消',
icon: 'none',
duration: 2000
})
}
/**
* 清除所有倒计时定时器
*/
const clearAllCountdowns = () => {
countdownIntervals.value.forEach((timer) => {
clearInterval(timer)
})
countdownIntervals.value.clear()
}
/**
* 处理支付
*/
const handlePayment = ({ id, total_amount }) => {
const handlePayment = ({ id, total_amount, remain_time }) => {
onPay({
id,
remain_time: 1800, // 30分钟
remain_time, // 30分钟
price: total_amount
})
}
......@@ -775,8 +909,26 @@ const performCancelOrder = async (orderId) => {
const order = orders.value.find(o => o.id === orderId)
if (order) {
// 清除该订单的倒计时定时器
if (countdownIntervals.value.has(orderId)) {
clearInterval(countdownIntervals.value.get(orderId))
countdownIntervals.value.delete(orderId)
}
// 更新订单状态为已取消
order.status = 7
const orders = viewMode.value === 'buy' ? boughtOrders : soldOrders
const targetOrderIndex = orders.value.findIndex(o => o.id === orderId)
if (targetOrderIndex !== -1) {
// 创建新的订单对象来触发响应式更新
const updatedOrder = {
...orders.value[targetOrderIndex],
status: 7
}
// 替换数组中的订单对象
orders.value.splice(targetOrderIndex, 1, updatedOrder)
}
Taro.showToast({
title: '订单已取消',
......@@ -882,6 +1034,11 @@ onMounted(async () => {
}
}, 500);
})
// 页面卸载时清理定时器
onUnmounted(() => {
clearAllCountdowns()
})
</script>
<script>
......