<template> <view class=""> <view class="count_down" v-if="datas.paid==0&&countDown"> 还剩<text>{{countDown}}</text>订单自动取消 </view> <view class="m-card m-address" style="margin-top: 20rpx;"> <view class="address-info" @click="callPhone(shopInfo.phone)"> <view class="top" style="align-items: flex-start;"> <view style="color: #333;display: flex;align-items: center;"> <up-icon name="map"></up-icon> <text style="margin: 0 10rpx;">自提点</text> </view> <view v-if="shopInfo.id"> <view style="color: #333;"> {{shopInfo.name}} <!-- <text v-if="shopInfo.recommend" style="font-size: 20rpx;color: #fff;background-color: #20b128;padding: 2rpx 5rpx;padding: 1rpx 4rpx;">推荐</text> --> </view> <view style="font-size: 24rpx;color: #333;"> {{shopInfo.detailed_address}} </view> <view> <view v-if="shopInfo.phone"> <text style="margin-right: 10rpx;">{{shopInfo.name||shopInfo.mer_real_name}}</text> <text>{{shopInfo.phone}}</text> </view> <!-- <text v-if="shopInfo.distance" style="color: #20b128;font-size: 22rpx;border: 1px solid #20b128;border-radius: 4rpx;">{{shopInfo.distance}}</text> --> </view> </view> </view> </view> <!-- <view class="address-btn" v-if="datas.paid==0"> <view style="width: 80px;"><up-button @click="shopListShow=true" size="small" shape="circle" color="#f6f6f6" :customStyle="{color:'#666666'}">修改</up-button></view> </view> --> </view> <view class="m-card m-address" style="margin-top: 20rpx;" v-if="addressInfo && addressInfo.address_id"> <view class="address-info"> <view class="top"> <up-icon name="account"></up-icon> <view class="t-name">{{addressInfo.real_name}}</view> <view>{{addressInfo.phone}}</view> </view> <view class="bottom u-line-2"> {{addressInfo.detail}} </view> </view> <view class="address-btn" v-if="datas.paid==0"> <view style="width: 80px;"><up-button @click="showAddress = true" size="small" shape="circle" color="#f6f6f6" :customStyle="{color:'#666666'}">修改</up-button></view> </view> </view> <view class="m-card m-address" style="margin-top: 20rpx;" v-else> <view class="address-info"> <view class="top"> <up-icon name="account"></up-icon> <view class="t-name">未填写收货人信息</view> </view> </view> <view class="address-btn" v-if="datas.paid==0"> <view style="width: 80px;"><up-button @click="showAddress = true" size="small" shape="circle" color="#f6f6f6" :customStyle="{color:'#666666'}">修改</up-button></view> </view> </view> <view class="m-card m-good" v-for="(item,index) in datas.goods_list" :key="index"> <view class="image"> <up-image :src="item.image" width="120rpx" height="120rpx"></up-image> </view> <view class="body-content"> <view> <view class="title"> <view>{{item.store_name}}</view> <view>¥{{item.price}}</view> </view> <view class="tips"> <view>{{}}</view> <view>x{{item.nums}}{{item.unit_name}}</view> </view> </view> </view> </view> <view class="qr_code" v-if="datas.paid == 1 && datas.status == 1"> <up-image :src="datas.verify_img" width="404rpx" height="60rpx"></up-image> <view style="font-weight: bold;color: #333;font-size: 26;margin-top: 20rpx;"> 核销码 {{datas.verify_code}} </view> </view> <view class="m-card good-info" v-if="datas.paid==0"> <view v-if="datas.goods_list" class="row"> <view>商品总价 <text>共计{{datas.goods_list.length}}款商品</text></view> <view><text>¥</text>{{c_price(datas.total_price, 0)}}<text>.{{c_price(datas.total_price, 1)}}</text> </view> </view> <view class="row"> <view>运费</view> <view><text>¥</text>0<text>.00</text></view> </view> <view class="row-need"> <view style="margin-right: 10rpx;">需付款</view> <view v-if="datas.pay_price"> <text>¥</text>{{c_price(datas.pay_price, 0)}}<text>.{{c_price(datas.pay_price, 1)}}</text> </view> </view> </view> <view class="m-card good-info"> <view class="head-title">订单信息</view> <block v-if="datas.paid==0"> <view class="row"> <view>订单编号</view> <up-copy :content="datas.order_id"> <text>{{datas.order_id}} | 复制</text> </up-copy> </view> <view class="row"> <view>下单时间</view> <view>{{datas.create_time}}</view> </view> <view class="row" style="margin-bottom: 0;"> <view>支付状态</view> <view v-if="datas.paid">已支付</view> <view v-else class="red">待支付</view> </view> </block> <block v-else> <view v-if="datas.goods_list" class="row"> <view>实付款</view> <view><text>¥</text>{{c_price(datas.pay_price, 0)}}<text>.{{c_price(datas.pay_price, 1)}}</text> </view> </view> <view class="row"> <view>订单编号</view> <up-copy :content="datas.order_id"> <text>{{datas.order_id}} | 复制</text> </up-copy> </view> <view class="row"> <view>支付方式</view> <view>{{datas.pay_type==3?'余额支付':'微信支付'}}</view> </view> <view class="row"> <view>下单时间</view> <view>{{datas.create_time}}</view> </view> <view class="row" style="margin-bottom: 0;"> <view>支付状态</view> <view v-if="datas.paid == 1">已支付</view> <view v-else class="red">待支付</view> </view> </block> </view> <view style="width: 100%;height: 200rpx;"></view> <view class="fiexd-btn-box" v-if="datas.order_id"> <block v-if="!datas.paid"> <view style="color: #777777;" @click="showCancel=true">取消订单</view> <view style="width: 450rpx;"> <up-button color="#20B128" shape="circle" @click="rePay" :throttleTime="1000">立即支付 ¥{{datas.pay_price}}</up-button> </view> </block> <block v-else> <view></view> <view style="width: 450rpx;"> <!-- <up-button v-if="datas.status==0||datas.status==1" color="#20B128" shape="circle" @click="showTake=true">确认收货</up-button> --> <up-button color="#20B128" plain shape="circle" @click="purchaseAgain">再次购买</up-button> </view> </block> </view> <orderCanclePopup :show="showCancel" @close="showCancel=false" @change="submitCancel" /> <addressPopup ref="addressRef" :show="showAddress" :list="addressList" @close="showAddress=false" @change="changeAddress" /> <shopListPopupVue ref="shopRef" :show="shopListShow" :list="merchantList" @close="shopListShow=false" @change="changeShop" @search="searchShop" /> <modal :show="showTake" title="确认收货" content="请确认您已收到货" @close="showTake=false" @change="confirmReceipt"> </modal> </view> </template> <script setup> import { onLoad, onBackPress } from "@dcloudio/uni-app"; import { nextTick, ref, reactive } from "vue"; import addressPopup from "@/components/addressPopup.vue"; import orderCanclePopup from "@/components/orderCanclePopup.vue"; import shopListPopupVue from "@/components/shopListPopup.vue"; import modal from "@/components/modal.vue"; import { orderDetailApi, cancelOrderApi, rePaymentApi, confirmReceiptApi, purchaseAgainApi } from "@/api/order.js" import { addressListsApi, merchantListApi } from "@/api/user.js"; const showCancel = ref(false); const showTake = ref(false); const options = reactive({ width: 670, // 宽度 单位rpx height: 100, // 高度 单位rpx code: '', // 生成条形码的值 }, ) const submitCancel = (e) => { showCancel.value = false; cancelOrderApi({ order_id: datas.value.id, value: e.value }).then(res => { uni.showToast({ title: '取消成功', icon: 'none' }) uni.navigateBack({ success: () => { uni.$emit('reLoadOrderList') } }); }) } const datas = ref({}) const getDetails = () => { orderDetailApi({ order_id: datas.value.id }).then(res => { datas.value = res.data; options.code = datas.value.verify_code; // 生成条形码的值 shopInfo.value = res.data.store_info; if (addressList.value.length > 0 && res.data.paid) { addressInfo.value = addressList.value.find(item => item.address_id == res.data.address_id); } else { addressInfo.value = { address_id: res.data.address_id, real_name: res.data.real_name, phone: res.data.user_phone, detail: res.data.user_address } } nextTick(() => { shopRef.value.setCheck(shopInfo.value.mer_id); addressRef.value.setCheck(addressInfo.value.address_id); }) if (!res.data.paid) { targetDate = new Date(res.data.create_time).getTime() + 10 * 60 * 1000; // 每秒更新一次倒计时 timer = setInterval(updateCountdown, 1000); updateCountdown(); } }).catch(err => { uni.navigateBack(); }) } const c_price = (price, index = 0) => { price = price + ''; return price.split('.')[index] || (index ? '00' : '0'); } // 选择地址 const addressRef = ref(null); const showAddress = ref(false); const addressInfo = ref({ address_id: '' }); const changeAddress = (e) => { addressInfo.value = e; showAddress.value = false; } const openAddress = () => { if (addressList.length > 0) showAddress.value = true; else uni.navigateTo({ url: '/pagesOrder/addressEdit/addressEdit' }) } // 地址相关 const addressList = ref([]); const getAddressList = () => { addressListsApi().then(res => { addressList.value = res.data.lists; addressList.value.forEach(item => { if (item.is_default) { addressInfo.value = item; } }) if (addressList.value.length > 0) { addressInfo.value = addressList.value[0]; } if (addressInfo.value.address_id) nextTick(() => { addressRef.value.setCheck(addressInfo.value.address_id); }) }) } getAddressList(); const shopRef = ref(false); const shopListShow = ref(false); const merchantList = ref([]); const myAddressInfo = ref({ long: "", lat: "" }) const shopInfo = ref({ mer_id: '' }); const getMerchantList = (mer_name = null) => { merchantListApi({ ...myAddressInfo.value, mer_name: mer_name ? mer_name : '' }).then(res => { merchantList.value = res.data.lists; if (mer_name === null && myAddressInfo.value.long && merchantList.value.length > 0 && !shopInfo .value.mer_id) { shopInfo.value = merchantList.value[0]; nextTick(() => { shopRef.value.setCheck(shopInfo.value.mer_id); }) } }) } // getMerchantList(); // 定位 const LoadAddress = () => { uni.getLocation({ success: (res) => {}, fail: (err) => { uni.$u.toast('定位失败, 请手动选择提货点!') }, complete: (res) => { myAddressInfo.value.long = res.longitude || ""; myAddressInfo.value.lat = res.latitude || ""; getMerchantList(); } }) } const changeShop = (e) => { LoadAddress(); shopInfo.value = e; shopListShow.value = false; } const searchShop = (e) => { getMerchantList(e) } const rePay = () => { rePaymentApi({ order_id: datas.value.id, mer_id: shopInfo.value.mer_id, address_id: addressInfo.value.address_id, pay_type: 1 }).then(res => { if (!res.data?.nonceStr) return uni.$u.toast('支付失败!'); uni.requestPayment({ provider: 'wxpay', timeStamp: res.data.timeStamp, nonceStr: res.data.nonceStr, package: res.data.package, signType: res.data.signType, paySign: res.data.paySign, success: (e) => { if (e.errMsg == 'requestPayment:ok') { uni.showModal({ title: '订单支付成功', confirmText: '确认', success: (e) => { uni.navigateBack({ success: () => { uni.$emit('reLoadOrderList') } }); } }) } else uni.$u.toast('支付失败') }, fail: (e) => { uni.$u.toast('用户取消支付') } }) }).catch(err => { uni.$u.toast('网络错误') }) } // 再次购买 const purchaseAgain = () => { purchaseAgainApi({ order_id: datas.value.id }).then(res => { uni.$u.toast('已加入购物车'); uni.navigateTo({ url: '/pages/cart/cart' }) }) } // 设置目标日期 let targetDate = ""; let countDown = ref(""); let timer = null; // 更新倒计时函数 function updateCountdown() { const now = new Date().getTime(); const distance = targetDate - now; if (distance < 0) return clearInterval(timer); // 计算剩余时间 const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((distance % (1000 * 60)) / 1000); countDown.value = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; // 如果目标日期已过,显示提示信息 if (distance < 0) { console.log('倒计时结束'); countDown.value = "" } } // 确认收货 const confirmReceipt = () => { confirmReceiptApi({ order_id: datas.value.id }).then(res => { showTake.value = false; uni.$u.toast('确认收货成功'); uni.navigateBack({ success: () => { uni.$emit('reLoadOrderList'); } }) }) } // 拨打电话 const callPhone = (phone) => { uni.makePhoneCall({ phoneNumber: phone }) } onLoad((option) => { uni.setNavigationBarTitle({ title: option.type == 0 ? '等待付款' : '订单详情' }); if (option.id) { datas.value.id = option.id; getDetails() } }) onBackPress(() => { clearInterval(timer); console.log("清除"); }) </script> <style lang="scss"> .count_down { padding-top: 20rpx; text-align: center; color: #444444; text { color: #F55726; padding: 0 10rpx; } } .m-card { width: 710rpx; margin: 0 auto; background-color: #fff; border-radius: 14rpx; box-sizing: border-box; padding: 20rpx; color: #333333; } .qr_code { margin: 0 20rpx 20rpx; display: flex; flex-direction: column; justify-content: center; align-items: center; height: 300rpx; background: #fff; border-radius: 5px; } .m-address { margin-bottom: 20rpx; display: flex; justify-content: space-between; color: #999999; .address-info { width: 510rpx; .top { display: flex; font-size: 28rpx; .t-name { color: #444; margin: 0 10rpx; } } .bottom { font-size: 24rpx; } } } .m-good { display: flex; justify-content: space-between; margin-bottom: 20rpx; .image { width: 120rpx; height: 120rpx; margin-right: 20rpx; border-radius: 14rpx; overflow: hidden; } .body-content { width: 490rpx; display: flex; flex-direction: column; justify-content: space-between; color: #989898; .title { display: flex; justify-content: space-between; font-size: 28rpx; color: #444; } .tips { display: flex; justify-content: space-between; font-size: 24rpx; margin-top: 10rpx; } .time { background-color: #F6F6F6; padding: 5rpx 10rpx; font-size: 26rpx; color: #444; border-radius: 10rpx; } } } .good-info { margin-bottom: 20rpx; .head-title { margin-bottom: 18rpx; color: #000; font-weight: bold; } .row { display: flex; justify-content: space-between; margin-bottom: 18rpx; .red { color: #F55726; } } .row-need { display: flex; justify-content: flex-end; color: #F55726; } text { font-size: 22rpx; } } </style>