<template> <view class="flex-col justify-start items-center relative page" :style="{ backgroundImage: 'url(' + bkgPubilcPath + ')' }"> <!-- <image class="image_3" src="https://ide.code.fun/api/image?token=67cf80c84ae84d001228feb1&name=666fe70fbe2b3eb6bec964adf12deccc.png" /> --> <view class="flex-col section pos"> <view class="flex-col relative section_2"> <view class="flex-row justify-center section_3" style="display: flex; align-items: center;" @click="gotoResearch"> <image class="image" :src="myOrderUrl + '/myOrderList/ss.png'" /> <text class="font text ml-17" v-if="isHiddenInput">搜索订单</text> <input class="font text ml-7" v-if="!isHiddenInput" placeholder="搜索订单" :disabled="true" v-model="orderNumber" style="width: 85%; color: #323232;"/> </view> <view class="flex-row justify-between group"> <view @click="isSelectedState(0)"> <text class="font_2 text_2" :style="{ color: color[0] }"> 全部 </text> <view class="flex-col justify-start items-center" v-if="isShowUnderLine[0]" style="border: 1.88rpx solid #e79ea1; width: 90rpx; margin-top: 10rpx;"></view> </view> <view @click="isSelectedState(1)"> <text class="font_2 text_3" :style="{ color: color[1] }">待支付</text> <view class="flex-col justify-start items-center" v-if="isShowUnderLine[1]" style="border: 1.88rpx solid #e79ea1; width: 90rpx; margin-top: 10rpx;"></view> </view> <view @click="isSelectedState(2)"> <text class="font_2 text_4" :style="{ color: color[2] }">待发货</text> <view class="flex-col justify-start items-center" v-if="isShowUnderLine[2]" style="border: 1.88rpx solid #e79ea1; width: 90rpx; margin-top: 10rpx;"></view> </view> <view @click="isSelectedState(3)"> <text class="font_2 text_5" :style="{ color: color[3] }">待收货</text> <view class="flex-col justify-start items-center" v-if="isShowUnderLine[3]" style="border: 1.88rpx solid #e79ea1; width: 90rpx; margin-top: 10rpx;"></view> </view> <view @click="isSelectedState(4)"> <text class="font_2 text_6" :style="{ color: color[4] }">已退款</text> <view class="flex-col justify-start items-center" v-if="isShowUnderLine[4]" style="border: 1.88rpx solid #e79ea1; width: 90rpx; margin-top: 10rpx;"></view> </view> </view> </view> <view class="flex-col list mt-14"> <view class="flex-col list-item mt-20" v-for="(item, index) in orderList" :key="index" @click="gotoOrderDetail(item.id, item.orderType)"> <view class="flex-row justify-between group_3"> <text class="font_2 text_7">泠珑水月阁</text> <view class="flex-row items-center group_1"> <text class="font_3 text_8" v-if="item.orderStatus === '待支付'">{{ item.countdown }}</text> <text class="font text_9 ml-4">{{ item.orderStatus }}</text> </view> </view> <view class="flex-row items-center group_16"> <text class="font_4">订单编号:</text> <text class="font_5 text_10">{{ item.orderNumber }}</text> </view> <view class="flex-col group_4"> <view class="flex-row justify-between list-item_2 group_6" v-for="(subItem, index) in item.orderItemList" :key="index"> <view class="flex-row"> <image class="image_2" mode="aspectFill" :src="publicPath + subItem.goodSnapshot.goodImg.split(';')[0]" /> <view class="flex-col items-start group_19 ml-11"> <text class="font_2">{{ subItem.goodSnapshot.name }}</text> <text v-if="item.orderType === 'service'" class="appointmentDate">已选时间:{{ subItem.reservationDate }} {{ getWeekday(subItem.reservationDate) }}</text> <text v-if="item.orderType === 'service'" class="timeSlot">{{ subItem.timeSlot }}</text> <text v-if="item.orderType === 'product'" class="appointmentDate"> </text> <text v-if="item.orderType === 'product'" class="timeSlot"> </text> <text class="font_6 text_28 mt-18">¥{{ subItem.goodSnapshot.price.toFixed(2) }}</text> </view> </view> <text class="self-start font_7 text_29">×{{ subItem.quantity }}</text> </view> </view> <view class="flex-col group_12"> <view class="flex-row justify-end items-baseline group_13"> <text class="font_8 text_14">已优惠:</text> <text class="font_6 text_15 ml-9">¥{{ item.couponSnapshot === null ? (0).toFixed(2) : item.couponSnapshot.conditionAmount.toFixed(2) }}</text> </view> <view class="flex-row justify-end items-baseline mt-12 group_13_2"> <text class="font_8 text_16">应付款:</text> <text class="font_9 text_17 ml-9">¥{{ item.totalAmount.toFixed(2) }}</text> </view> </view> <view class="flex-row justify-end group_14"> <view class="nav" @click.stop="nav" v-if="item.orderType === 'service'"> <navVue></navVue> </view> <view class="flex-col justify-start items-center text-wrapper" v-if="item.operationList[0]" @click.stop="gotoCancelOrder(item.id, item.orderType)"> <text class="font_10">取消订单</text> </view> <view @click.stop> <button class="flex-col justify-start items-center text-wrapper" v-if="item.operationList[1]" open-type="contact" bindcontact="handleContact" session-from="sessionFrom"> <text class="font_10">联系客服</text> </button> </view> <view class="flex-col justify-start items-center text-wrapper" v-if="item.operationList[2]" @click.stop="gotoDeleteOrder(item.id)"> <text class="font_10">删除订单</text> </view> <view class="flex-col justify-start items-center text-wrapper_2 ml-11" v-if="item.operationList[3]" @click.stop="wxPayFd(item)"> <text class="font_11 text_18">去付款</text> </view> <view class="flex-col justify-start items-center text-wrapper_2 ml-11" v-if="item.operationList[4] && item.orderType === 'product'" @click.stop="fd(item.id)"> <text class="font_11 text_18">查看物流</text> </view> <view class="flex-col justify-start items-center text-wrapper_2 ml-11" style="background-color: #fff;" v-if="item.operationList[5]"> <text class="font_11 text_18"></text> </view> </view> </view> </view> </view> </view> <!-- 遮罩层 --> <view v-if="isShow" class="overlay"></view> </template> <script setup> import {onBeforeUnmount, onMounted, onUnmounted, ref} from 'vue' import { baseUrl } from '../../../api/request'; import { onLoad, onShow } from "@dcloudio/uni-app"; import { JudgeIsNullity } from '../../../common/globalFunction'; import navVue from '../component/nav.vue'; import emitter from '../../../utils/emitter'; import { getFonts } from '../../../common/globalFont'; import { myOrderUrl,bkgPubilcPath } from '../../../common/globalImagesUrl'; import { publicPath } from '../../../common/globalImagesUrl'; import { onPullDownRefresh } from '@dcloudio/uni-app'; import { showTips } from '../../../common/globalFunction'; const color = ref(new Array(5).fill('#323232')) const point = ref(0) const isShowUnderLine = ref([true, false, false, false, false]) let orderStatusList = ['全部', '待支付', '待发货', '待收货', '已退款'] const cookie = wx.getStorageSync('cookie') const orderList = ref([]) const tempOrderList = ref([]) const orderNumber = ref('') const isHiddenInput = ref(true) const status = ref(0) let debounceTimer = null; let wxPayTimer = null; let loading = false; let isLoading = ref(false) let isShow = ref(false) const flushOrderListHandler = () => { getMyOrder() } onLoad((options) => { getFonts() orderNumber.value = options.orderNumber if (!JudgeIsNullity(orderNumber.value)) { isHiddenInput.value = false } status.value = options.status }) onMounted(() => { color.value[0] = '#e79ea1' if (!JudgeIsNullity(status.value)) { getMyStatusOrder(Number(status.value)) } else { getMyOrder() } emitter.on('flushOrderList', flushOrderListHandler) }) onPullDownRefresh( async ()=>{ //下拉刷新 color.value[0] = '#e79ea1' if (!JudgeIsNullity(status.value)) { getMyStatusOrder(Number(status.value)) } else { getMyOrder() } emitter.on('flushOrderList', flushOrderListHandler) setTimeout(()=>{ uni.stopPullDownRefresh() //停止下拉刷新 },1000) }) onUnmounted(() => { emitter.off('flushOrderList', flushOrderListHandler) }) const getMyStatusOrder = async (val) => { point.value = val for (var i = 0; i < 5; i ++ ) { if (i === val) { isShowUnderLine.value[i] = true color.value[i] = '#e79ea1' } else { isShowUnderLine.value[i] = false color.value[i] = '#323232' } } await getMyOrder() if (point.value !== 0) { orderList.value = tempOrderList.value.filter(item => item.orderStatus === orderStatusList[point.value]) } else { orderList.value = tempOrderList.value } } const isSelectedState = (val) => { if (point.value === val) return point.value = val for (var i = 0; i < 5; i ++ ) { if (i === val) { isShowUnderLine.value[i] = true color.value[i] = '#e79ea1' } else { isShowUnderLine.value[i] = false color.value[i] = '#323232' } } if (point.value !== 0) { orderList.value = tempOrderList.value.filter(item => item.orderStatus === orderStatusList[point.value]) } else { orderList.value = tempOrderList.value } } const getMyOrder = async () => { orderList.value.forEach(order => { if (order.countdownInterval) { clearInterval(order.countdownInterval); // 清除定时器 } }) const res = await uni.request({ url: baseUrl + '/order/list', method: 'POST', header: { cookie } }) orderList.value = res.data.data tempOrderList.value = res.data.data dealTimeout() orderList.value.forEach(order => { if (order.orderStatus === '待支付') { startCountdown(order) } }); if (!JudgeIsNullity(orderNumber.value)) { orderList.value = orderList.value.filter(item => item.orderNumber === orderNumber.value) } } const gotoResearch = () => { uni.navigateTo({ url: '../researchOrder/researchOrder' }) } const gotoOrderDetail = (val, type) => { if (type === 'product') { uni.navigateTo({ url: '../myGeneralOrderDetail/myGeneralOrderDetail?id=' + val }) } else { uni.navigateTo({ url: '../myServiceOrderDetail/myServiceOrderDetail?id=' + val }) } } const wxPayFd = (order) => { //微信支付按钮防抖 showLoading() isShow.value = true //打开遮罩 wxPay(order.id, order.orderType) } function showLoading() { //加载弹窗 if (!loading) { wx.showLoading({ title: '加载中...', }); loading = true; isLoading.value = true } } function hideLoading() { //关闭弹窗 if (loading) { wx.hideLoading(); loading = false; isLoading.value = false } } const wxPay = async( oid , type)=> { //传入订单id try { const res = await uni.request({ url: baseUrl + '/wechat/payment/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 () { if (type === 'product') { uni.redirectTo({ url: '/pages/my-order/myGeneralOrderDetail/myGeneralOrderDetail?id=' + oid }) } else { uni.redirectTo({ url: '/pages/my-order/myServiceOrderDetail/myServiceOrderDetail?id=' + oid }) } } }) }catch(error) { uni.showModal({ title: '提示', content: '支付失败,请刷新后重试', showCancel: false }) } } const fd = (val) => { //防抖 clearTimeout(debounceTimer) showLoading() debounceTimer = setTimeout(async () => { await gotoDelieverPage(val) hideLoading() }, 1000) } let waybillToken = '' var plugin = requirePlugin('logisticsPlugin') const gotoDelieverPage = (val) => { uni.request({ url: baseUrl + '/logistics/get/info', method: 'POST', data: { id: val }, header: { cookie }, success: (res) => { console.log(res.data.data) waybillToken = res.data.data.waybill_token plugin.openWaybillTracking({ waybillToken: waybillToken }) } }) } const gotoCancelOrder = (val, type) => { uni.showModal({ title: '提示', content: '您确定要取消订单吗?', success: async (res) => { if (res.confirm) { if (type === 'product'){ await cancelGeneralOrder(val) } else { await cancelServiceOrder(val) } showTips('取消成功') await getMyOrder() } } }) } const gotoDeleteOrder = (val) => { uni.showModal({ title: '提示', content: '您确定要删除订单吗?', success: async (res) => { if (res.confirm) { await deleteOrder(val) await getMyOrder() showTips('删除成功') } } }) } const cancelGeneralOrder = async (val) => { const res = await uni.request({ url: baseUrl + '/order/cancel/id', method: 'POST', header: { cookie }, data: { id: val } }) console.log(res.data.data) } const cancelServiceOrder = async (val) => { const res = await uni.request({ url: baseUrl + '/order/cancel/service/id', method: 'POST', header: { cookie }, data: { id: val } }) console.log(res.data.data) } const deleteOrder = async (val) => { const res = await uni.request({ url: baseUrl + '/order/delete/id', method: 'POST', header: { cookie }, data: { id: val } }) console.log('=================================>', res.data.data) } const dealTimeout = () => { for (var i = 0; i < orderList.value.length; i ++ ) { let order = orderList.value[i] if (order.orderStatus === '待支付') { orderList.value[i].operationList = [true, false, false, true, false, false] } else if (order.orderStatus === '待发货') { orderList.value[i].operationList = [false, true, false, false, false, false] } else if (order.orderStatus === '待收货') { orderList.value[i].operationList = [false, true, false, false, true, false] } else if (order.orderStatus === '已退款') { orderList.value[i].operationList = [false, true, false, false, false, false] } else if (order.orderStatus === '交易关闭') { orderList.value[i].operationList = [false, false, true, false, false, false] } else if (order.orderStatus === '交易成功') { orderList.value[i].operationList = [false, false, false, false, false, true] }else { orderList.value[i].operationList = [false, false, false, false, false, true] } } } // 启动每个订单的倒计时(仅对待支付订单有效) 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 = '交易关闭' dealTimeout() 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(() => { orderList.value.forEach(order => { if (order.countdownInterval) { clearInterval(order.countdownInterval); // 清除定时器 } }) }); const nav = () => { wx.openLocation({ latitude: 45.867741, longitude: 126.560037, name: '哈尔滨师范大学(松北校区)', address: '黑龙江省哈尔滨市呼兰区利民经济开发区师大路1号', success: (res) => { console.log(res) } }) } function getWeekday(dateStr) { const date = new Date(dateStr); const weekdays = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]; return weekdays[date.getDay()]; } </script> <style scoped lang="scss"> .nav { position: absolute; left: 15rpx; top: 25rpx; } .overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.4); /* 半透明黑色背景 */ z-index: 999; } button{padding: 0;margin: 0;} button::after{ border: none; } .page { background-color: #ffffff; background-size: 100% 100%; background-repeat: no-repeat; width: 100%; overflow-y: auto; overflow-x: hidden; height: 100vh; } .appointmentDate { margin-top: 20.63rpx; font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 24.51rpx; color: #818181; margin-left: 3.75rpx; } .timeSlot { margin-top: 20.63rpx; font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 17.53rpx; color: #818181; margin-left: 3.75rpx; } .ml-7 { margin-left: 13.13rpx; } .ml-9 { margin-left: 16.88rpx; } .ml-11 { margin-left: 20.63rpx; } .pos { position: absolute; left: 0; right: 0; top: 0; } .section_2 { padding: 31.88rpx 35.63rpx 0; background-color: #ffffff; box-shadow: 0rpx 3.75rpx 3.75rpx #32323240; position: fixed; top: 0; left: 0; right: 0; z-index: 99; } .section_3 { padding: 13.13rpx 0 15rpx; height: 60rpx; background-color: #f3f3f3; border-radius: 75rpx; } .image { width: 28.13rpx; height: 28.13rpx; margin-right: 10rpx; } .font { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 25.84rpx; color: #ffaaa5; } .text { color: #bdbdbd; margin-left: 10rpx; } .group { padding: 24.26rpx 0 0; } .font_2 { font-size: 30rpx; font-family: FangZhengFonts; line-height: 29.18rpx; color: #323232; } .text_2 { line-height: 28.24rpx; } .text_3 { line-height: 28.24rpx; } .text_4 { line-height: 28.24rpx; } .text_5 { line-height: 28.24rpx; } .text_6 { line-height: 28.24rpx; } .list { padding: 170rpx 15rpx 50rpx; } .list-item { padding: 28.01rpx 22.5rpx 0 24.38rpx; background-color: #ffffff; border-radius: 18.75rpx; } .list-item:first-child { margin-top: 0; } .group_3 { padding-left: 9.96rpx; padding-right: 4.5rpx; } .text_7 { line-height: 28.01rpx; } .group_1 { margin-top: 2.34rpx; } .font_3 { font-size: 30rpx; font-family: FangZhengFonts; line-height: 18.73rpx; color: #ffaaa5; } .text_8 { font-size: 28.13rpx; line-height: 18.79rpx; } .text_9 { line-height: 25.74rpx; } .group_16 { margin-top: 19.26rpx; padding: 0 8.94rpx; } .font_4 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 25.84rpx; color: #818181; } .font_5 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 18.73rpx; color: #818181; } .text_10 { line-height: 17.53rpx; } .group_4 { margin-top: 30.06rpx; } .list-item_2:first-child { margin-top: 0; } .image_2 { border-radius: 9.38rpx; width: 146.25rpx; height: 165rpx; } .group_19 { margin-bottom: 3.32rpx; } .font_6 { font-size: 30rpx; font-family: FangZhengFonts; line-height: 22.18rpx; color: #323232; } .text_28 { margin-left: 3.36rpx; } .font_7 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 18.73rpx; color: #323232; } .text_29 { margin-right: 5.83rpx; margin-top: 136.88rpx; } .group_12 { margin-top: 66.28rpx; padding-left: 3.06rpx; padding-right: 3.04rpx; } .group_13 { padding: 0 10.11rpx; display: flex; justify-content: space-between; } .group_13_2 { padding: 0 10.11rpx; display: flex; justify-content: space-between; } .font_8 { font-size: 30rpx; font-family: FangZhengFonts; line-height: 25.84rpx; color: #323232; } .text_14 { font-size: 28.13rpx; line-height: 26.59rpx; } .text_15 { font-size: 28.13rpx; line-height: 20.79rpx; } .text_16 { font-size: 28.13rpx; line-height: 26.04rpx; } .font_9 { font-size: 30rpx; font-family: FangZhengFonts; line-height: 22.18rpx; font-weight: 600; color: #ffaaa5; } .text_17 { font-size: 28.13rpx; line-height: 21.13rpx; } .group_14 { position: relative; margin-top: 26.92rpx; padding: 33.75rpx 0 35.63rpx; border-top: solid 1.88rpx #dfdfdf; } .text-wrapper { padding: 13.35rpx 0 13.31rpx; background-color: #ffffff; border-radius: 75rpx; width: 153.75rpx; height: 56.25rpx; border: solid 1.88rpx #e79ea1; } .font_10 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 25.84rpx; color: #e79ea1; } .text-wrapper_2 { padding: 16.07rpx 0 16.18rpx; 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_18 { line-height: 24rpx; } .group_6 { margin-top: 28.75rpx; } @import url(../../../common/css/global.css); </style>