zhwl-miniapp/pages/shop/orderDetail.vue
2025-06-26 12:38:35 +08:00

384 lines
18 KiB
Vue

<template>
<view class="waper">
<u-navbar :autoBack="true" :placeholder="true" bgColor="#FBFBFB">
<view slot='center' class="navbar_title">订单详情</view>
</u-navbar>
<view class="waper_content" v-if="detail" :style="detail.status == 0 ? ('padding-bottom: ' + waperBottom + 'px;') : ''">
<view class="status">
<view>{{detail.statusText}}</view>
<view v-if="detail.status == 0">
<text>剩余支付时间</text>
<text>{{secondsToTime(timeNum)}}</text>
</view>
<view v-if="detail.status > 0">
<text>买家已付款,请等待商家发货</text>
</view>
</view>
<view class="address">
<view class="icon">
<image class="img" src="https://common/address.png" mode=""></image>
</view>
<view class="text">
<view>{{detail.provinceName + detail.cityName + detail.areaName + ' ' + detail.address}}</view>
<view>
<text>{{detail.consignee}}</text>
<text>{{detail.phone}}</text>
</view>
</view>
</view>
<view class="goods">
<view class="title">{{detail.orderItemList[0].storeName}}</view>
<view class="list_waper">
<view class="list" v-for="(i, index) in detail.orderItemList" :key="index">
<view class="img">
<image :src="$utils.setImgUrl(i.goodsImage)" mode=""></image>
</view>
<view class="text">
<view class="name">{{i.goodsTitle}}
<!-- <text v-if="detail.status > 0">{{i.refundStatus == 2 ? i.refundStatusText : i.dispatchStatusText}}</text> -->
</view>
<view class="tag">
<view>
<text v-if="i.goodsSkuText">{{i.goodsSkuName}}</text>
</view>
<view>X{{i.goodsNum}}</view>
</view>
<view class="money">
<text>总价:¥{{i.goodsPrice.toFixed(2)}}</text>
<view class="btns">
<text v-if="(detail.status == 1 || detail.status == 2) && i.refundStatus < 1" @click="showRefund(i)">退款</text>
<text v-if="detail.status == 1 && i.dispatchStatus == 1 && i.refundStatus == 0" @click="itemDispatch(i)">确认收货</text>
<text v-if="(detail.status == 1 || detail.status == 2) && i.refundStatus >= 1" @click="toRefundDetail(i.aftersale.id)">退款详情</text>
<text v-if="(detail.status == 1 || detail.status == 2) && i.refundStatus == -1" @click="toRefundDetail(i.aftersale.id)">拒绝退款</text>
</view>
</view>
<view class="money" v-if="i.expressName">
<text>快递公司:{{i.expressName}}</text>
</view>
<view class="money" v-if="i.expressNo">
<text>快递单号:{{i.expressNo}}</text>
</view>
</view>
</view>
</view>
</view>
<view class="order">
<view class="title">订单信息</view>
<view class="content">
<view class="list">
<view>商品总价</view>
<view>¥{{detail.goodsAmount.toFixed(2)}}</view>
</view>
<view class="list">
<view>运费</view>
<view>{{detail.dispatchAmount ? (detail.dispatchAmount).toFixed(2) : '包邮'}}</view>
</view>
<view class="list">
<view>配送方式</view>
<view>邮寄</view>
</view>
<view class="list">
<view>订单编号</view>
<view>
<text>{{detail.orderSn}}</text>
<text @click="copyCode(detail.orderSn)">复制</text>
</view>
</view>
<view class="list">
<view>创建时间</view>
<view>{{detail.createTime}}</view>
</view>
<view class="list" v-if="detail.paytime">
<view>付款时间</view>
<view>{{detail.paytime}}</view>
</view>
<view class="list">
<view>备注</view>
<view>{{detail.remark || '无'}}</view>
</view>
</view>
</view>
</view>
<view class="bottom" :style="'padding-bottom: ' + safeAreaBottom + 'px'" v-if="detail.status == 0">
<view class="bottom_waper">
<view @click="cancel">取消订单</view>
<view class="active" @click="payOrder">立即支付</view>
</view>
</view>
<u-popup :show="refund" mode="bottom" bgColor="transparent">
<view class="refund_waper">
<view class="title">请选择类型
<view class="icon" @click="closeRefund">
<u-icon name="close" size="32rpx" color="#333"></u-icon>
</view>
</view>
<view class="cont">
<view :class="{active: refundIndex === 0}" @click="refundIndex = 0;">仅退款</view>
<view :class="{active: refundIndex === 1}" @click="refundIndex = 1;">退货退款</view>
</view>
<view class="btn" @click="confirmRefund">下一步</view>
</view>
</u-popup>
</view>
</template>
<script>
export default {
data () {
return {
safeAreaBottom: 0,
waperBottom: 0,
detail: null,
refund: false,
refundIndex: null,
refundData: null,
timeNum: 0,
timer: null
}
},
onLoad (options) {
this.safeAreaBottom = this.$safeAreaBottom;
this.waperBottom = this.safeAreaBottom + uni.upx2px(152);
this.orderdetail(options.id);
},
onShow () {
if (this.detail) this.orderdetail(this.detail.id)
},
onUnload () {
clearInterval(this.timer);
this.timer = null;
},
methods: {
async itemDispatch (item) {
let info = await this.$shop.confirmReceipt({ orderId: item.orderId, orderItemIds: [item.id] });
uni.showToast({ mask: true, title: '操作成功', icon: 'success' });
this.orderdetail(this.detail.id)
},
async orderdetail(id) {
let info = await this.$shop.orderdetail(id)
info.data.dispatchStatus = false;
info.data.orderItemList.forEach((item, index) => {
if (item.goodsSkuText) info.data.orderItemList[index].goodsSkuName = info.data.orderItemList[index].goodsSkuText.split(',').join('-');
if (item.dispatchStatus > 0) info.data.dispatchStatus = true;
})
if (info.data.status == 0) {
let configData = uni.getStorageSync('configData');
let creaetdTime = parseInt(new Date(info.data.createTime).getTime() / 1000);
let nowtime = parseInt(new Date().getTime() / 1000);
if ((creaetdTime + configData.expirationTime * 60) >= nowtime) {
this.timeNum = (creaetdTime + configData.expirationTime * 60) - nowtime;
this.setIntervalFn()
}
}
this.detail = info.data;
},
secondsToTime(seconds) {
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = seconds % 60;
return (minutes >= 10 ? minutes : '0' + minutes) + ":" + (remainingSeconds >= 10 ? remainingSeconds : '0' + remainingSeconds);
},
setIntervalFn () {
clearInterval(this.timer);
this.timer = setInterval(() => {
if (this.timeNum <= 0) {
clearInterval(this.timer)
uni.navigateBack()
}
this.timeNum --;
}, 1000)
},
copyCode (str) {
uni.setClipboardData({
data: str,
success: () => {
uni.showToast({ mask: true, title: '内容已复制到剪切板', icon: 'none' })
}
})
},
async payOrder () {
uni.showLoading({ mask: true })
let info = await this.$shop.getWcscOrderSession({ orderId: this.detail.id });
if (info.code == 200) {
let patInfo = JSON.parse(info.msg);
uni.requestPayment({
provider: 'wxpay',
timeStamp: patInfo.timeStamp,
nonceStr: patInfo.nonceStr,
package: patInfo.packageValue,
signType: patInfo.signType,
paySign: patInfo.paySign,
success: (res) => {
uni.hideLoading();
this.showSuccess = true;
this.orderdetail(this.detail.id);
},
fail: function (err) {
uni.hideLoading();
uni.showToast({ mask: true, title: '支付取消', icon: 'none' })
}
});
} else {
uni.hideLoading();
uni.showToast({ mask: true, title: info.msg, icon: 'none' });
}
},
async cancel() {
let info = await this.$shop.cancleOrder({ orderId: this.detail.id, storeId: this.detail.orderItemList[0].storeId })
uni.showToast({ mask: true, title: '操作成功', icon: 'success' })
this.orderdetail(this.detail.id);
},
showRefund (info) {
this.refundData = info;
this.refundIndex = null;
this.refund = true;
},
closeRefund () {
this.refund = false;
this.refundIndex = null;
},
confirmRefund () {
if (this.refundIndex === null) {
uni.showToast({ mask: true, title: '请选择类型', icon: 'null' })
return false;
}
this.refundData.type = this.refundIndex;
uni.navigateTo({ url: '/pages/shop/refund?info=' + encodeURIComponent(JSON.stringify(this.refundData)) })
this.refundIndex = null;
this.refund = false;
},
toRefundDetail (id) {
uni.navigateTo({
url: '/pages/shop/refundReason?id=' + id
})
}
}
}
</script>
<style lang="scss">
.waper_content{
width: 100%; box-sizing: border-box; padding: 24rpx;
.status{
width: 100%;
view{
&:nth-child(1){ font-weight: 500; font-size: 48rpx; color: rgba(0,0,0,0.85); line-height: 56rpx; }
&:nth-child(2){
margin-top: 5rpx; display: flex; align-items: center; height: 46rpx;
text{
&:nth-child(1){ color: rgba(0,0,0,0.45); font-size: 28rpx; }
&:nth-child(2){ margin-left: 16rpx; font-weight: bold; font-size: 28rpx; color: #FF5833; }
}
}
}
}
.address{
width: 100%; margin-top: 32rpx; height: 140rpx; background: #fff; border-radius: 10rpx; box-sizing: border-box; padding: 0 24rpx 0 100rpx; position: relative;
.icon{ width: 36rpx; height: 50rpx; position: absolute; left: 34rpx; top: 50%; transform: translateY(-50%); }
.text{
width: 100%; display: flex; flex-direction: column; justify-content: center; height: 100%;
view{
&:nth-child(1){ height: 43rpx; width: 100%; font-size: 28rpx; color: rgba(0,0,0,0.85); font-weight: 500; line-height: 33rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
&:nth-child(2){
margin-top: 14rpx; height: 36rpx; display: flex; align-items: center; font-size: 24rpx; color: rgba(0,0,0,0.65); line-height: 28rpx;
text{
margin-right: 36rpx;
&:last-child{ margin-right: 0; }
}
}
}
}
}
.goods{
width: 100%; margin-top: 20rpx; background: #fff; border-radius: 10rpx; box-sizing: border-box; padding: 32rpx 24rpx 0;
.title{ line-height: 38rpx; color: #000; font-size: 32rpx; font-weight: 500; }
.list_waper{
width: 100%;
.list{
width: 100%; box-sizing: border-box; padding: 28rpx 0 28rpx 190rpx; position: relative; margin-top: 20rpx; min-height: 170rpx; border-bottom: 1rpx solid rgba(0,0,0,0.1);
&:last-child{ border-bottom: none; }
.img{
width: 170rpx; height: 170rpx; position: absolute; left: 0; top: 20rpx;
image{ border-radius: 10rpx; }
}
.text{
width: 100%;
.name{
color: rgba(0,0,0,0.85); line-height: 33rpx; font-size: 28rpx; font-weight: 500; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; position: relative; box-sizing: border-box;
// text{ position: absolute; right: 0; top: 0; line-height: 40rpx; color: #FF5833; }
}
.tag{
width: 100%; margin-top: 20rpx; display: flex; justify-content: space-between; align-items: center; height: 48rpx;
view{
&:nth-child(1){
display: flex; align-items: center;
text{ height: 48rpx; line-height: 48rpx; padding: 0 24rpx; box-sizing: border-box; background: #F4F4F4; border-radius: 2rpx; color: rgba(0,0,0,0.65); font-size: 24rpx; }
}
&:nth-child(2){ color: rgba(0,0,0,0.65); font-size: 24rpx; }
}
}
.money{
width: 100%; display: flex; align-items: center; justify-content: flex-end; margin-top: 30rpx;
text{ font-size: 28rpx; color: rgba(0,0,0,0.85); line-height: 33rpx; }
}
.btns{
display: flex; align-items: center; justify-content: flex-end; margin-left: 20rpx;
text{
width: 128rpx; height: 50rpx; border-radius: 50rpx; box-sizing: border-box; border: 2rpx solid #A2A2A4; text-align: center; line-height: 46rpx; color: #A2A2A4; font-size: 24rpx; font-weight: 500; margin-right: 20rpx;
&:last-child{ margin-right: 0; }
}
}
}
}
}
}
.order{
width: 100%; margin-top: 20rpx; background: #fff; border-radius: 10rpx; box-sizing: border-box; padding: 32rpx 24rpx 24rpx;
.title{ line-height: 38rpx; color: rgba(0,0,0,0.85); font-size: 32rpx; font-weight: 500; }
.content{
width: 100%; margin-top: 24rpx;
.list{
width: 100%; box-sizing: border-box; padding-left: 130rpx; position: relative; min-height: 40rpx; margin-bottom: 18rpx;
&:last-child{ margin-bottom: 0; }
view{
&:nth-child(1){ color: rgba(0,0,0,0.65); font-size: 28rpx; position: absolute; left: 0; top: 0; line-height: 33rpx; }
&:nth-child(2){
color: rgba(0,0,0,0.85); font-size: 28rpx; line-height: 33rpx; display: flex; width: 100%; justify-content: flex-end; align-items: center;
text:last-child{
margin-left: 48rpx; color: #3F79FF; position: relative;
&::after{ content: ""; width: 2rpx; height: 24rpx; background: #A2A2A4; position: absolute; left: -23rpx; top: 50%; transform: translateY(-50%); }
}
}
}
}
}
}
}
.bottom{
width: 100%; box-shadow: 0rpx -1rpx 6rpx 0rpx rgba(0,0,0,0.05); position: fixed; bottom: 0; left: 0; background: #fff;
.bottom_waper{
width: 100%; height: 120rpx; box-sizing: border-box; padding: 0 32rpx; display: flex; justify-content: flex-end; align-items: center;
view{
width: 228rpx; height: 80rpx; margin-right: 20rpx; box-sizing: border-box; border: 1rpx solid #999999; border-radius: 66rpx; text-align: center; line-height: 80rpx; font-size: 30rpx; color: rgba(0,0,0,0.45);
&:last-child{ margin-right: 0; }
&.active{ background: #03AE80; border-color: #03AE80; color: #fff; font-weight: 500; }
}
}
}
.refund_waper{
width: 100%; background: #fff; box-sizing: border-box; padding: 32rpx 32rpx 20rpx; border-radius: 30rpx 30rpx 0 0;
.title{
line-height: 42rpx; color: rgba(0,0,0,0.65); font-size: 36rpx; font-weight: 500; text-align: center; position: relative;
.icon{ position: absolute; right: 0; top: 0; }
}
.cont{
width: 100%; margin-top: 49rpx; display: flex; justify-content: center; align-items: center;
view{
width: 302rpx; height: 80rpx; box-sizing: border-box; border: 1rpx solid #999999; border-radius: 10rpx; text-align: center; line-height: 78rpx; color: rgba(0,0,0,0.45); font-size: 30rpx;
&.active{ background: #03AE80; border-color: #03AE80; color: #fff; }
&:first-child { margin-right: 20rpx; }
}
}
.btn{ width: 100%; height: 80rpx; background: #03AE80; border-radius: 66rpx; text-align: center; line-height: 80rpx; color: #fff; font-size: 32rpx; font-weight: 500; margin-top: 76rpx; }
}
</style>