| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 | <template>	<view class="o-header-list">		<view :class="[selected == index ? 'sel-item-list' : 'item-list']" v-for="(item, index) in orderTypeList"			:key="index" @click="selectedItem(index)">{{ item }}</view>	</view>	<view style="height: 80rpx;"></view>	<view class="content">		<view class="o-orderlist-card" v-for="item in orderList" :key="item.orderId"			@click="RouterUtils.to_page(`/pages/index/toBeUsed/index?orderId=${item.orderId}&orderType=${item.orderType}&isPayOrder=1`)">			<view class="o-order-name">				<view class="order-name" v-if="item?.orderProInfoList && item.orderProInfoList.length > 0">{{					item.orderType == 5 ? '上课地点' : '场地' }}:{{ item?.orderProInfoList[0].address || '--'					}}</view>				<!-- 待付款 -->				<view class="order-status" v-if="item.orderStatus == 0">待支付(剩余{{ item.downTime }})</view>				<view class="item-order-status" style="color:#FB5B5B;" v-if="item.orderStatus == 1">待使用</view>				<view class="item-order-status" v-if="item.orderStatus == 2">已使用</view>				<view class="item-order-status" v-if="item.orderStatus == 3">已到期</view>				<view class="item-order-status" v-if="item.orderStatus == 4">已取消</view>				<view class="item-order-status" v-if="item.orderStatus == 5">待退款</view>				<view class="item-order-status" v-if="item.orderStatus == 6">已退款</view>			</view>			<view class="line"></view>			<view class="o-order-info">				<view class="item-info">					<!-- 有保险 -->					<scroll-view class="scroll-view_H scroll-order" scroll-x="true"						v-if="item?.orderInsureList?.length > 0 && item?.orderProInfoList && item.orderProInfoList.length > 0">						<view class="scroll-view-item_H scroll-order-item">							<view class="item-order">								<view class="order-img">									<image :src="item.orderProInfoList[0].productImage" mode="">									</image>								</view>								<view class="order-name textHidden">{{ item?.orderProInfoList[0].productName }}</view>							</view>						</view>						<view class="scroll-view-item_H scroll-order-item">							<view class="item-order">								<view class="order-img">									<image :src="item?.orderInsureList[0].productImage.split(',')[0]" mode="">									</image>								</view>								<view class="order-name textHidden">{{ item?.orderInsureList[0].productName }}</view>							</view>						</view>					</scroll-view>					<!-- 没保险 -->					<view class="item-order-single" v-else>						<view class="single-img">							<image								:src="item?.orderProInfoList && item.orderProInfoList.length > 0 ? item?.orderProInfoList[0]?.productImage.split(',')[0] : ''"								mode=""></image>						</view>						<view class="single-name">							<view class="item-single-name textHidden"								v-if="item.orderType != 1 && item?.orderProInfoList && item.orderProInfoList.length > 0">								{{									item?.orderProInfoList[0].productName }}</view>							<view class="item-single-name" v-else-if="item.orderType == 1 && item?.orderProInfoList">								<!-- {{ item.orderProInfoList[0].productName }} -->								<view class="textHidden" v-for="name in item.orderProInfoList" :key="name.id">{{									name.productName }}</view>							</view>						</view>					</view>				</view>				<view class="order-data">					<view class="order-price"><text class="mini-text">¥</text>{{ item.price.toFixed(2) }}</view>					<view class="order-num">共{{ item?.orderProInfoList?.length || 0 }}件</view>				</view>			</view>			<view class="line"></view>			<!-- 待付款 -->			<view class="o-order-btn">				<view class="cancel-btn" v-if="item?.orderStatus == 0" @click.stop="cancelOrder(item)">取消订单</view>				<view class="pay-btn" v-if="item?.orderStatus == 0" @click.stop="submitPay(item)">付款</view>				<!-- 售后/退款 -->				<view class="pay-btn"					v-if="item?.orderStatus == 2 && item.orEvaluate == 0 && item.orderType != 3 && item.orderType != 4 && item?.orderProInfoList && item.orderProInfoList.length > 0"					@click.stop="RouterUtils.to_page(`/pages/index/writeComments/index?siteId=${item.addressSiteId}&orderId=${item.orderId}&siteName=${item.orderProInfoList[0].address}`)">					评价</view>				<!-- 已使用 -->				<view class="cancel-btn" v-if="selected == 4">申请退款</view>				<view class="pay-btn" v-if="selected == 4">凭证</view>			</view>			<!-- 待使用 -->			<view class="o-order-tips"				v-if="item.orderStatus == 1 && item.orderType != 3 && item.orderType != 4 && item?.orderProInfoList && item.orderProInfoList.length > 0">				<text					v-if="item.orderProInfoList[0].frameTimeStr && item.orderProInfoList[0].frameTimeStr != '00:00-00:00'">限{{						item.orderProInfoList[0].frameTimeStr }}使用,过期作废</text>				<text v-if="item.earlyRefundTime">请按时到场,退款需提前{{ item.earlyRefundTime }}分钟</text>			</view>		</view>		<zs-empty v-if="orderList.length == 0"></zs-empty>	</view></template><script lang="ts" setup>import { ref, onMounted, onUnmounted } from 'vue'import { http } from '@/utils/http'import { onLoad, onReachBottom, onShow } from '@dcloudio/uni-app';import zsEmpty from '@/components/zs-empty/index.vue';import { RouterUtils, TipsUtils } from '@/utils/util';import { useCacheStore } from '@/stores/cache'const cache = useCacheStore()const selected = ref(0)const orderTypeList = ref(['全部', '待付款', '待使用', '已使用', '退款/售后'])onLoad((option) => {})onShow(() => {	// selected.value = cache.get('ORDER_SEL_INDEX') || 0	const statusMap:any = {		0: { orderStatus: null, orAfterSale: 0 },		1: { orderStatus: 0, orAfterSale: 0 },		2: { orderStatus: 1, orAfterSale: 0 },		3: { orderStatus: 2, orAfterSale: 0 },		4: { orderStatus: null, orAfterSale: 1 }	}	const selectedIndex = cache.get('ORDER_SEL_INDEX')	selected.value = selectedIndex||0	if (statusMap[selectedIndex]) {		Object.assign(orderFormData.value, statusMap[selectedIndex])	}	// 使用完成后移除缓存	cache.remove('ORDER_SEL_INDEX')	getOrderList()})onReachBottom(() => {	orderFormData.value.pageNo++;	getOrderList()})onMounted(() => {	// getOrderList()})const selectedItem = (i) => {	orderFormData.value.pageNo = 1	selected.value = i	if (selected.value == 0) {		orderFormData.value.orderStatus = null		orderFormData.value.orAfterSale = 0	} else if (selected.value == 1) {		orderFormData.value.orderStatus = 0		orderFormData.value.orAfterSale = 0	} else if (selected.value == 2) {		orderFormData.value.orAfterSale = 0		orderFormData.value.orderStatus = 1	} else if (selected.value == 3) {		orderFormData.value.orAfterSale = 0		orderFormData.value.orderStatus = 2	} else if (selected.value == 4) {		orderFormData.value.orderStatus = null		orderFormData.value.orAfterSale = 1	}	getOrderList()}// 提交支付startconst orderCode = ref()const orderId = ref()const submitPay = (e: any) => {	http.put(`/order/payOrder?appOrderId=${e.orderId}`, {}, { loading: true }).then((res) => {		orderCode.value = res.result.orderCode		orderId.value = res.result.orderId		paymentOrder(res.result.params)	})}const paymentOrder = (payInfo: object) => {	// getOrderQuery(orderCode.value, orderId.value)	console.log(payInfo, '支付参数');	uni.requestPayment({		provider: 'wxpay',		...payInfo,		success: function (res) {			console.log('支付成功', res);			setTimeout(() => {				getOrderQuery(orderCode.value, orderId.value)			}, 500)		},		fail: function (err) {			console.log('支付失败', err);			// TipsUtils.tips_toast('支付失败,请稍后重试');		}	});}const getOrderQuery = (orderCode: string, orderId: string, retryCount = 0) => {	http.get('/order/orderQuery', { data: { orderCode: orderCode }, loading: true }).then((res) => {		if (res.result == '100001') {			TipsUtils.tips_toast('支付成功');			getOrderList()		} else if (retryCount <= 3) {			setTimeout(() => {				getOrderQuery(orderCode, orderId, retryCount + 1)			}, 1000)		} else {			if (res.result == '100003') {				console.log('查询中,但已达到最大查询次数')			} else if (res.result == '100002') {				console.log('查询失败')			} else if (res.result == '100004') {				console.log('支付失败')				TipsUtils.tips_toast('支付失败')			}		}	}).catch((error) => {		console.error('查询订单失败:', error)		if (retryCount < 2) {			setTimeout(() => {				getOrderQuery(orderCode, orderId, retryCount + 1)			}, 1000)		}	})}// 提交支付end// 获取订单数据const orderFormData = ref({	pageNo: 1,	pageSize: 10,	orderStatus: null,	orAfterSale: 0})const orderList = ref([])// 订单状态 0-待付款 1-待使用 2-已使用 3-已到期 4-已取消 5-待退款 6已退款const getOrderList = () => {	http.post('/order/pageOrders', orderFormData.value, { loading: true }).then((res) => {		if (orderFormData.value.pageNo == 1) {			orderList.value = res.result.records		} else {			orderList.value = [...orderList.value, ...res.result.records]		}		orderList.value.forEach((item) => {			// const [datePart, timePart] = item.createTime.split(' ');			// const [year, month, day] = datePart.split('-').map(Number);			// const [hours, minutes, seconds] = timePart.split(':').map(Number);			// item.createTime = new Date(year, month - 1, day, hours, minutes, seconds);			console.log(item.createTime);			if (item.orderStatus == 0) {				item.downTime = "";				item.timer = null;				startCountdown(item);			}		})		console.log(orderList.value, '订单列表');	})}// 倒计时let callCount = 0;const startCountdown = (item) => {	if (item.timer) {		clearInterval(item.timer);	}	const endTime = new Date(item.epxTime);	const remainingTime = endTime - new Date();	if (remainingTime > 0) {		const minutes = Math.floor(remainingTime / (1000 * 60));		const seconds = Math.floor((remainingTime % (1000 * 60)) / 1000);		item.downTime = `${minutes.toString().padStart(2, '0')}分${seconds.toString().padStart(2, '0')}秒`;		item.timer = setInterval(() => {			const now = new Date();			const newRemainingTime = endTime - now;			if (newRemainingTime <= 0) {				clearInterval(item.timer);				item.downTime = "00:00";				if (callCount < 3) {					callCount++;					setTimeout(()=>{					getOrderList();					},500)				}				return;			}			const newMinutes = Math.floor(newRemainingTime / (1000 * 60));			const newSeconds = Math.floor((newRemainingTime % (1000 * 60)) / 1000);			item.downTime = `${newMinutes.toString().padStart(2, '0')}分${newSeconds.toString().padStart(2, '0')}秒`;		}, 1000);	} else {		item.downTime = "00:00";		if (callCount < 3) {			callCount++;			getOrderList();		}	}}const cancelOrder = async (e: any) => {	let res: any = await TipsUtils.tips_alert('确定取消订单吗?', true)	if (res.confirm) {		http.put(`/order/cancelOrder?orderId=${e.orderId}`, {}, { loading: true }).then((res: any) => {			TipsUtils.tips_toast('订单已取消')			getOrderList()		})	}}onUnmounted(() => {	orderList.value.forEach(item => {		if (item.timer) {			clearInterval(item.timer);		}	});});</script><style lang="less" scoped>.o-header-list {	position: fixed;	top: 0;	width: 100%;	display: flex;	align-items: center;	justify-content: space-around;	height: 80rpx;	background: #fff;	z-index: 1000;	.sel-item-list {		font-weight: bold;		font-size: 28rpx;		color: #222222;		transition: all .3s;	}	.item-list {		font-size: 28rpx;		color: #AAAAAA;		transition: all .3s;	}}.o-orderlist-card {	background: #FFFFFF;	border-radius: 32rpx;	padding: 20rpx;	margin-top: 20rpx;	.o-order-name {		display: flex;		align-items: center;		justify-content: space-between;		margin-bottom: 26rpx;		.order-name {			font-size: 24rpx;			color: #222222;		}		.order-status {			font-weight: bold;			font-size: 28rpx;			color: #FB5B5B;		}		.item-order-status {			font-weight: bold;			font-size: 28rpx;			color: #AAAAAA;		}	}	.o-order-info {		display: flex;		align-items: center;		justify-content: space-between;		margin-top: 24rpx;		margin-bottom: 24rpx;		.item-info {			// 多个商品			.scroll-order {				width: 500rpx;				.scroll-order-item {					margin-right: 20rpx;					.item-order {						.order-img {							&>image {								width: 160rpx;								height: 160rpx;								border-radius: 16rpx;							}						}						.order-name {							width: 160rpx;							font-size: 28rpx;							color: #222222;						}					}				}			}			// 单个商品			.item-order-single {				display: flex;				align-items: center;				gap: 20rpx;				.single-img {					&>image {						width: 160rpx;						height: 160rpx;						border-radius: 16rpx;					}				}				.single-name {					width: 360rpx;					font-size: 28rpx;					color: #222222;					.item-single-name {						width: 360rpx;						margin-bottom: 10rpx;					}				}			}		}		.order-data {			width: 400rpx;			border-left: 1rpx solid #efefef;			text-align: center;			.order-price {				font-weight: 600;				font-size: 28rpx;				color: #FB5B5B;			}			.order-num {				margin-top: 10rpx;				font-size: 24rpx;				color: #AAAAAA;			}		}	}	.o-order-btn {		display: flex;		align-items: center;		justify-content: flex-end;		gap: 20rpx;		margin-top: 24rpx;		.cancel-btn {			width: 200rpx;			height: 68rpx;			background: #FFFFFF;			border-radius: 60rpx;			border: 2rpx solid #AAAAAA;			font-weight: bold;			font-size: 28rpx;			color: #AAAAAA;			line-height: 68rpx;			text-align: center;		}		.pay-btn {			width: 200rpx;			height: 68rpx;			background: #C8FF0C;			border-radius: 60rpx;			font-weight: bold;			font-size: 28rpx;			color: #222222;			text-align: center;			line-height: 68rpx;		}	}	.o-order-tips {		margin-top: 24rpx;		background: #F6F6F6;		border-radius: 16rpx;		padding: 20rpx;		font-size: 28rpx;		color: #222222;	}}</style>
 |