jiangchengfeiyi-xiaochengxu/pages/my-order/myOrderList/myOrderList.vue

870 lines
23 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="flex-col justify-start items-center relative page" :style="{ backgroundImage: 'url(' + bkgUrl + ')' }">
<!-- <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] }">&ensp;全部&ensp;</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">&emsp;</text>
<text v-if="item.orderType === 'product'" class="timeSlot">&emsp;</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 } from '../../../common/globalImagesUrl';
import { publicPath } from '../../../common/globalImagesUrl';
import { onPullDownRefresh } from '@dcloudio/uni-app';
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 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 bkgUrl = ref(myOrderUrl + '/myOrderList/bkg.png')
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 = orderList.value.filter(item => item.orderStatus === orderStatusList[point.value])
}
}
const isSelectedState = async (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'
}
}
await getMyOrder()
if (point.value !== 0) {
orderList.value = orderList.value.filter(item => item.orderStatus === orderStatusList[point.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
}
})
console.log(res.data.data)
orderList.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) => { //微信支付按钮防抖
clearTimeout(wxPayTimer)
showLoading()
isShow.value = true //打开遮罩
wxPayTimer = setTimeout(async () => {
await wxPay(order.id, order.orderType)
}, 1000)
setTimeout(()=>{
hideLoading()
isShow.value = false //关闭遮罩
},2000)
}
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({
content: '支付成功',
showCancel: false
})
if (type === 'product') {
uni.redirectTo({
url: '/pages/my-order/myGeneralOrderDetail/myGeneralOrderDetail?id=' + oid
})
} else {
uni.redirectTo({
url: '/pages/my-order/myServiceOrderDetail/myServiceOrderDetail?id=' + oid
})
}
},
fail(e) {
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) {
console.error('支付请求失败');
uni.showModal({
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)
}
await getMyOrder()
}
}
})
}
const gotoDeleteOrder = (val) => {
uni.showModal({
title: '提示',
content: '您确定要删除订单吗?',
success: async (res) => {
if (res.confirm) {
await deleteOrder(val)
await getMyOrder()
}
}
})
}
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]
}
}
}
// 启动每个订单的倒计时(仅对待支付订单有效)
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() + 1); // 加上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 #00000040;
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: #000000;
}
.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>