<template> <view class="flex-col justify-start relative page" :style="{ backgroundImage: 'url(' + bkgPubilcPath + ')' }"> <view class="shrink-0 section" :style="{ backgroundImage: 'url(' + bkgPubilcPath + ')'}"></view> <view class="flex-col section_2 pos"> <view class="flex-row justify-between group"> <view class="flex-col justify-start items-center text-wrapper" @click="changeState(0)"> <text class="font text">全部</text> <view class="flex-col justify-start items-center" v-if="isShow[0]" style="border: 1.88rpx solid #E79EA1; width: 90rpx; margin-top: 5rpx;"></view> </view> <view class="flex-col justify-start" @click="changeState(1)"> <text class="font text_2">待拍摄</text> <view class="flex-col justify-start items-center" v-if="isShow[1]" style="border: 1.88rpx solid #E79EA1; width: 90rpx; margin-top: 5rpx;"></view> </view> <view class="flex-col justify-start" @click="changeState(2)"> <text class="font text_3">已完成</text> <view class="flex-col justify-start items-center" v-if="isShow[2]" style="border: 1.88rpx solid #E79EA1; width: 90rpx; margin-top: 5rpx;"></view> </view> </view> <!-- <view class="flex-col justify-start items-center group_2"><view class="section_3"></view></view> --> </view> <view class="flex-col pos_2"> <view class="flex-col mt-20 list-item" v-for="(item, index) in advanceOrderList" :key="index" @click="gotoDetailPage(item.id)"> <view class="flex-col"> <view class="flex-row items-center group_3" style="display: flex; justify-content: space-between; align-items: center;"> <view style="display: flex; align-items: center; height: 30rpx;"> <view class="group_4"> <text class="font_2">订单号</text> <text class="font_3 text_4">:</text> </view> <view><text class="font_4 text_5">{{ item.orderNumber }}</text></view> </view> <view> <text v-if="item.orderStatus === '待支付'" class="font_5 text_6">{{ item.countdown }}</text> <text class="font_6 text_7">{{ item.orderStatus }}</text> </view> </view> <view class="flex-row group_5"> <image class="image" mode="aspectFill" :src="publicPath + item.photoProductsSnapshot.introImg" /> <view class="flex-col items-start flex-1 group_6 ml-19"> <text class="font_7 text_8">{{ item.photoProductsSnapshot.name}}</text> <text class="font_8 mt-43">¥{{ item.totalAmount.toFixed(2) }}</text> </view> </view> </view> <view class="flex-col mt-17"> <view class="flex-col section_4"> <text class="self-start font_7 text_9">预约信息</text> <view class="mt-8 flex-col self-stretch"> <text class="self-start font_7 text_10">预约门店:哈尔滨师范大学</text> <view class="flex-row justify-between items-center self-stretch group_7"> <text class="font_7 text_11">到店时间:{{ item.specificDate }} {{ item.timePoint }}</text> <image class="image_2" :src="bookUrl + '/photoProductsOrderDetail/nav.png'" @click.stop="nav" /> </view> <view class="flex-row justify-between items-baseline self-stretch"> <text class="font_9">妆造服务:{{ item.isMakeup === 1 ? '本店上妆' : '无需妆造' }}</text> <text class="font_10 text_12" @click.stop="nav">导航</text> </view> </view> <text class="mt-8 self-start font_7 text_13">拍摄场地:{{ item.isIndoors == 1 ? '室内' : '室外' }}</text> </view> <view class="flex-row justify-end items-center group_8"> <text class="font_2 text_14">实付款:</text> <text class="font_88">¥{{ item.totalAmount.toFixed(2) }}</text> </view> <view class="flex-row justify-center group_9"> <view style="opacity: 0; border: none" v-if="item.orderStatus !== '待支付'" class="ml-10 flex-col justify-start items-center text-wrapper_2"> </view> <view style="opacity: 0; border: none" v-if="item.orderStatus !== '待支付'" class="ml-10 flex-col justify-start items-center text-wrapper_3"> </view> <view @click.stop> <button v-if="item.orderStatus !== '交易关闭'" open-type="contact" bindcontact="handleContact" session-from="sessionFrom" class="flex-col justify-start items-center text-wrapper_2"> <text class="font_6 text_15">联系客服</text> </button> </view> <view v-if="item.orderStatus === '交易关闭'" class="ml-10 flex-col justify-start items-center text-wrapper_2" @click.stop="openDeleteBookingOrderPopup(item.id)"> <text class="font_6">删除订单</text> </view> <view v-if="item.orderStatus === '待支付'" class="ml-10 flex-col justify-start items-center text-wrapper_2" @click.stop="openCancelBookingOrderPopup(item.id)"> <text class="font_6">取消订单</text> </view> <view v-if="item.orderStatus === '待支付'" @click.stop="wxPayFd(item.id)" class="ml-10 flex-col justify-start items-center text-wrapper_3"> <text class="font_11 text_16">去付款</text> </view> </view> </view> </view> </view> </view> <uni-popup ref="cancelBookingOrder" :maskClick="false" :animation="false"> <view class="cancel-booking-order"> <cancelOrderVue></cancelOrderVue> </view> </uni-popup> <uni-popup ref="deleteBookingOrder" :maskClick="false" :animation="false"> <view class="cancel-booking-order"> <deleteOrderVue></deleteOrderVue> </view> </uni-popup> <!-- 遮罩层 --> <view v-if="isShowMask" class="overlay"></view> </template> <script setup lang="ts"> import {nextTick, onBeforeUnmount, onMounted, onUnmounted, ref} from 'vue' import { bookUrl } from '../../../common/globalImagesUrl'; import emitter from '../../../utils/emitter'; import cancelOrderVue from '../component/cancelOrder.vue'; import deleteOrderVue from '../component/deleteOrder.vue'; import { onLoad, onPullDownRefresh } from "@dcloudio/uni-app"; import { baseUrl } from '../../../api/request'; import { getFonts } from '../../../common/globalFont'; import { publicPath,bkgPubilcPath } from '../../../common/globalImagesUrl'; const cookie = wx.getStorageSync("cookie") //请求头 const isShow = ref([true, false, false]) const cancelBookingOrder = ref(null) const deleteBookingOrder = ref(null) const advanceOrderList = ref([]) const tempAdvanceOrderList = ref([]) const isShowMask = ref(false) let wxPayTimer = null; let loading = false; let point = 0 let isLoading = ref(false) const bkgUrl = ref(bookUrl + '/photoProductsOrderDetail/bkg.png') onLoad(() => { getFonts() }) const gotoDetailPage = (val) => { uni.navigateTo({ url: '/pages/book/myPhotoProductsOrderDetail/myPhotoProductsOrderDetail?id=' + val }) } const flushAdvanceOrderListHandler = () => { getAdvanceOrder() }; const closeCancelOrderPopupHandler = () => { nextTick(() => { if (cancelBookingOrder.value) { cancelBookingOrder.value.close() } }) } const closeDeleteOrderPopupHandler = () => { nextTick(() => { if (deleteBookingOrder.value) { deleteBookingOrder.value.close() } }) } onPullDownRefresh( async ()=>{ //下拉刷新 await getAdvanceOrder() setTimeout(()=>{ uni.stopPullDownRefresh() //停止下拉刷新 },1000) }) onMounted( async () => { getFonts() await getAdvanceOrder() emitter.on('closeCancelOrderPopup', closeCancelOrderPopupHandler) emitter.on('closeDeleteOrderPopup', closeDeleteOrderPopupHandler) emitter.on('flushAdvanceOrderList', flushAdvanceOrderListHandler) }) onUnmounted(() => { console.log('组件已卸载') emitter.off('closeCancelOrderPopup', closeCancelOrderPopupHandler) emitter.off('closeDeleteOrderPopup', closeDeleteOrderPopupHandler) emitter.off('flushAdvanceOrderList', flushAdvanceOrderListHandler) }) const openCancelBookingOrderPopup = (orderId:any) => { emitter.emit('sendBookingOrderId', orderId) cancelBookingOrder.value.open('center') } const openDeleteBookingOrderPopup = (orderId:any) => { emitter.emit('sendDeleteOrderId', orderId) deleteBookingOrder.value.open('center') } const changeState = (index:any) => { if (point === index) return point = index if (!isShow.value[index]) { for (var i = 0; i < 3; i ++ ) { if (i == index) { isShow.value[i] = true } else { isShow.value[i] = false } } } if (index === 0) { advanceOrderList.value = tempAdvanceOrderList.value } if (index === 1) { advanceOrderList.value = tempAdvanceOrderList.value.filter(item => item.orderStatus === '待发货') } if (index === 2) { advanceOrderList.value = tempAdvanceOrderList.value.filter(item => item.orderStatus === '交易成功') } } const nav = () => { wx.openLocation({ latitude: 45.867741, longitude: 126.560037, name: '哈尔滨师范大学(松北校区)', address: '黑龙江省哈尔滨市呼兰区利民经济开发区师大路1号', success: (res) => { console.log(res) } }) } const wxPayFd = (oid) => { //微信支付按钮防抖 showLoading() isShowMask.value = true //打开遮罩 wxPay(oid) } const wxPay = async ( oid )=> { //传入订单id try { const res = await uni.request({ url: baseUrl + '/wechat/payment/photo/create', method: 'POST', header: { 'cookie': wx.getStorageSync("cookie") }, data: { id: oid } }) const paymentData = res.data.data wx.requestPayment({ appid: paymentData.appId, nonceStr: paymentData.nonceStr, package: paymentData.packageVal, paySign: paymentData.paySign, timeStamp: paymentData.timeStamp, signType: paymentData.signType, success(res) { uni.showModal({ title: '提示', content: '支付成功', showCancel: false }) }, fail(e) { }, complete() { uni.redirectTo({ url: '/pages/book/myPhotoProductsOrderDetail/myPhotoProductsOrderDetail?id=' + oid }) } }) }catch(error) { uni.showModal({ title: '提示', content: '支付失败,请刷新后重试', showCancel: false }) } } function showLoading() { if (!loading) { wx.showLoading({ title: '加载中...', }); loading = true; } } function hideLoading() { if (loading) { wx.hideLoading(); loading = false; } } const getAdvanceOrder = async () => { advanceOrderList.value.forEach(order => { if (order.countdownInterval) { clearInterval(order.countdownInterval); // 清除定时器 } }) const res = await uni.request({ url: baseUrl + '/advanceOrder/list/my', method: 'POST', header: { cookie } }) advanceOrderList.value = res.data.data tempAdvanceOrderList.value = res.data.data console.log('订单列表打印==================>') advanceOrderList.value.forEach(order => { if (order.orderStatus === '待支付') { startCountdown(order) } }); } // 启动每个订单的倒计时(仅对待支付订单有效) const startCountdown = (order) => { if (order.orderStatus === '待支付') { order.endTime = add30Minutes(order.createTime); // 设置最终取消时间 order.countdownInterval = setInterval(() => { const now = Math.floor(Date.now() / 1000); // 获取当前时间的时间戳(秒) const remainingTime = order.endTime - now; if (remainingTime <= 0) { order.countdown = '00:00'; clearInterval(order.countdownInterval); // 清除定时器 order.orderStatus = '交易关闭' uni.showModal({ title: '提示', content: '订单超时未支付,已取消', showCancel: false }) } else { const minutes = Math.floor(remainingTime / 60); // 计算剩余分钟 const seconds = remainingTime % 60; // 计算剩余秒数 order.countdown = `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; } }, 1000); } }; // 时间格式化函数,处理后端返回的时间 const parseDate = (dateString) => { const [date, time] = dateString.split(' '); const [year, month, day] = date.split('-').map(Number); const [hour, minute, second] = time.split(':').map(Number); return new Date(year, month - 1, day, hour, minute, second); // JavaScript Date的月份是从0开始的 }; // 给订单创建时间加上30分钟 const add30Minutes = (createdTime) => { const date = parseDate(createdTime); date.setMinutes(date.getMinutes() + 15); // 加上30分钟 return Math.floor(date.getTime() / 1000); // 返回时间戳(秒) }; // 在组件卸载时清除所有定时器,避免内存泄漏 onBeforeUnmount(() => { advanceOrderList.value.forEach(order => { if (order.countdownInterval) { clearInterval(order.countdownInterval); // 清除定时器 } }) }); const routerJump = (val:any) => { let pages = getCurrentPages(); var num = pages.length if (num == 1) return ; console.log(pages) //当前页面栈总数 var backnum = num for( var i = 0; i < num; i ++ ) { //循环找到指定页面路由所在的页数 if(pages[i].route == val){ //'pages/mypage/mypage'替换成A页面的路由地址 backnum = num - i - 1 //计算返回的层数,总数-指定页面页数-1 } } uni.navigateBack({ delta:backnum //返回的页面数,如果 delta 大于现有页面数,则返回到首页。 }) } onUnmounted(() => { // routerJump('/pages/book/myPhotoProductDetail/myPhotoProductDetail') }) </script> <style scoped lang="scss"> button { padding: 0; margin: 0; background-color: #fff; } button::after{ border: none; } .overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.4); /* 半透明黑色背景 */ z-index: 999; } .cancel-booking-order { // height: 800rpx; margin-top: -150rpx; } .ml-19 { margin-left: 35.63rpx; } .mt-43 { margin-top: 80.63rpx; } .mt-17 { margin-top: 31.88rpx; } .page { background-color: #ffffff; overflow: hidden; background-size: 100% 100%; background-repeat: no-repeat; width: 100%; overflow-y: auto; overflow-x: hidden; height: 100%; } .section { background-size: 100% 100%; background-repeat: no-repeat; width: 750rpx; height: 100vh; } .section_2 { padding-left: 80.63rpx; padding-right: 71.25rpx; background-color: #EBE7E4; } .pos { position: fixed; left: 0; right: 0; top: 0; z-index: 99; } .group { padding: 13.75rpx 0 0rpx; } .text-wrapper { width: 91.88rpx; } .font { font-size: 30rpx; font-family: FangZhengFonts; color: #323232; } .text { line-height: 48.48rpx; } .text_2 { line-height: 48.24rpx; } .text_3 { line-height: 47.43rpx; } .group_2 { // border-left: solid 99.38rpx #e79ea1; // border-right: solid 99.38rpx #e79ea1; } .section_3 { background-color: #e79ea1; width: 99.38rpx; height: 5.63rpx; } .pos_2 { position: absolute; left: 15rpx; right: 15rpx; top: 100.5rpx; } .list-item { padding: 22.5rpx; box-sizing: content-box; background-color: #fff; border-radius: 18.75rpx; } .list-item:first-child { margin-top: 0; } .list-item:last-child { margin-bottom: 50rpx; } .group_3 { padding: 0 15rpx 18.75rpx; border-bottom: solid 1.88rpx #dbdbdb; } .group_4 { line-height: 25.84rpx; height: 25.84rpx; } .font_2 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 25.84rpx; color: #323232; } .font_3 { font-size: 26.25rpx; font-family: Open Sans; line-height: 17.53rpx; color: #323232; } .text_4 { line-height: 16.8rpx; } .font_4 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 17.53rpx; color: #323232; } .text_5 { font-size: 28.13rpx; line-height: 25.84rpx; } .font_5 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 17.53rpx; color: #e79ea1; } .text_6 { // margin-left: 45rpx; } .font_6 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 25.84rpx; color: #e79ea1; } .text_7 { margin-left: 3.75rpx; line-height: 24.71rpx; } .group_5 { padding: 15rpx 15rpx 0; } .image { width: 120rpx; height: 133.13rpx; } .group_6 { margin-bottom: 3.75rpx; } .font_8 { font-size: 33.75rpx; font-family: FangZhengFonts; line-height: 22.54rpx; color: #000; } .font_88 { font-size: 33.75rpx; font-family: FangZhengFonts; line-height: 22.54rpx; color: #c35c5d;; } .section_4 { margin: 0 12.5rpx; padding: 22.5rpx 18.75rpx; background-color: #f4f4f4; border-radius: 9.38rpx; } .font_7 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 25.84rpx; color: #323232; } .text_9 { font-size: 28.13rpx; line-height: 26.25rpx; } .text_8 { font-size: 28.13rpx; line-height: 27.36rpx; } .text_10 { line-height: 25.33rpx; } .group_7 { margin-top: 3.75rpx; } .text_11 { line-height: 24.51rpx; } .image_2 { // margin-right: 7.5rpx; width: 45rpx; height: 45rpx; } .font_9 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 23.79rpx; color: #323232; } .font_10 { font-size: 22.5rpx; font-family: FangZhengFonts; line-height: 21.09rpx; color: #323232; } .text_12 { margin-right: 3.75rpx; } .text_13 { line-height: 24.21rpx; } .group_8 { padding: 30rpx 22.5rpx 22.5rpx; border-bottom: solid 1.88rpx #dbdbdb; } .text_14 { font-size: 28.13rpx; line-height: 26.7rpx; } .group_9 { padding: 20.63rpx 0 0 180rpx; } .text_15 { line-height: 25.54rpx; } .text-wrapper_2 { padding: 15rpx 0; background-color: #ffffff; border-radius: 75rpx; width: 153.75rpx; height: 56.25rpx; border: solid 1.88rpx #e79ea1; } .text-wrapper_3 { padding: 15rpx 0; background-color: #e79ea1; border-radius: 75rpx; width: 153.75rpx; height: 56.25rpx; } .font_11 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 25.84rpx; color: #ffffff; } .text_16 { line-height: 24rpx; } /* 去掉滚动条样式 */ ::-webkit-scrollbar { display: none; } @import url(../../../common/css/global.css); </style>