You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

472 lines
12 KiB

1 day ago
<template>
<view class="page">
<view class="fixed-head">
<view class="nav" :style="{'height': navHeight + 'px'}">
<view class="back-btn" :style="{'top': backTop + 'px'}" @tap="back">
<uni-icons type="left" size="26"></uni-icons>
</view>
<view class="nav-title">自配送订单</view>
</view>
<view class="tabs">
<view class="tab" :class="{active: tab === 'pickup'}" @tap="switchTab('pickup')">待取货</view>
<view class="tab" :class="{active: tab === 'complete'}" @tap="switchTab('complete')">待送达</view>
</view>
</view>
<scroll-view class="list" :style="{'top': listTop + 'px'}" scroll-y @scrolltolower="loadMore">
<view class="card" v-for="(item,index) in list" :key="item.id">
<view class="card-head">
<view class="tag">商家自配送</view>
<view class="time">{{item.mustFinishTime | formatTime}}前送达</view>
</view>
<view class="order-code" v-if="item.numberCode">#{{item.numberCode}}</view>
<view class="address">
<view class="dot get"></view>
<view>
<view class="name">{{item.shopName}}</view>
<view class="desc">{{item.shopAddress}}</view>
<view class="phone-row" v-if="item.shopPhone" @tap.stop="makeCall(item.shopPhone)">
商家电话{{item.shopPhone}}
</view>
</view>
</view>
<view class="address">
<view class="dot send"></view>
<view>
<view class="name">{{item.receiverName}} {{item.receiverPhone}}</view>
<view class="desc">{{item.receiverAddress}}</view>
<view class="phone-row" v-if="item.receiverPhone" @tap.stop="makeCall(item.receiverPhone)">
用户电话{{item.receiverPhone}}
</view>
</view>
</view>
<view class="goods-row" v-if="item.goodsList && item.goodsList.length > 0" @tap="productDetail(item)">
<view class="goods-title">商品详情</view>
<view class="goods-desc">{{goodsCount(item)}}点击查看规格和数量</view>
<uni-icons type="right" size="14" color="#7a8582"></uni-icons>
</view>
<view class="remark" v-if="item.remark">备注{{item.remark}}</view>
<view class="fee">配送费 {{item.deliveryFee || 0}}</view>
<view class="btn" @tap="handleOrder(index,item)">
{{buttonText(item)}}
</view>
</view>
<view class="empty" v-if="list.length === 0 && loadStatus === 'nomore'">暂无订单</view>
</scroll-view>
<uni-popup ref="productPopup" background-color="transparent">
<view class="product-popup-content">
<view class="product-popup-header">
<view class="product-popup-title">商品详情</view>
<view class="product-popup-subtitle">请核对商品规格和数量</view>
</view>
<view class="product-popup-list" v-if="productData && productData.length > 0">
<view class="product-popup-card" v-for="(item1,index1) in productData" :key="index1">
<view class="product-popup-img">
<img :src="item1.productPicture" alt="">
</view>
<view class="product-popup-info">
<view class="product-popup-name">{{item1.productName}}</view>
<view class="product-popup-spec">
<text class="product-popup-label">规格</text>
<text class="product-popup-spec-text">{{formatSpecs(item1.specs)}}</text>
</view>
</view>
<view class="product-popup-quantity">
<view class="product-popup-quantity-num">x{{item1.quantity}}</view>
<view class="product-popup-quantity-label">数量</view>
</view>
</view>
</view>
<view class="product-popup-empty" v-else>暂无商品详情</view>
</view>
</uni-popup>
</view>
</template>
<script>
export default {
data() {
return {
tab: 'pickup',
list: [],
loadStatus: 'more',
totalPages: 1,
searchForm: {
pageNum: 1,
pageSize: 10,
status: 1,
deliveryType: 1,
shopDelivery: 1,
shopId: '',
workerId: '',
regionId: ''
},
menuButtonInfo: {},
navHeight: 120,
backTop: 88,
listTop: 210,
productData: []
}
},
filters: {
formatTime(value) {
if (!value) return '';
const date = new Date(value);
return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
}
},
onShow() {
this.initNavMetrics();
this.initWorkerFromShop();
this.resetList();
},
methods: {
initNavMetrics() {
const rect = uni.getMenuButtonBoundingClientRect();
this.menuButtonInfo = rect || {};
const top = rect && rect.top ? rect.top : 32;
const height = rect && rect.height ? rect.height : 32;
this.backTop = top + 6;
this.navHeight = top + height + 52;
this.listTop = this.navHeight + 76;
},
back() {
uni.navigateBack();
},
initWorkerFromShop() {
const shop = this.getCurrentShop();
this.searchForm.shopId = uni.getStorageSync('shopId');
this.searchForm.regionId = JSON.parse(uni.getStorageSync('area')).id;
this.searchForm.workerId = shop.workerId || '';
this.worker = {
workerId: shop.workerId || '',
workerName: shop.workerName || '',
workerPhone: shop.workerPhone || ''
};
},
getCurrentShop() {
const shopList = uni.getStorageSync('schoolShop') || [];
const shopId = uni.getStorageSync('shopId');
if (Array.isArray(shopList)) {
return shopList.find(item => item.id == shopId) || {};
}
return {};
},
switchTab(tab) {
this.tab = tab;
this.resetList();
},
resetList() {
this.list = [];
this.searchForm.pageNum = 1;
this.totalPages = 1;
this.loadStatus = 'more';
this.searchForm.status = this.tab === 'pickup' ? 1 : 2;
this.getList();
},
loadMore() {
if (this.searchForm.pageNum >= this.totalPages) return;
this.searchForm.pageNum++;
this.getList();
},
getList() {
if (!this.searchForm.workerId) {
this.loadStatus = 'nomore';
this.tui.toast('店铺未绑定自配送配送员');
return;
}
this.tui.request('/mall/delivery/pageShopDelivery', 'POST', this.searchForm, false, false).then((res) => {
if (res.code == 200) {
const records = res.result.records || [];
this.list = this.searchForm.pageNum == 1 ? records : this.list.concat(records);
this.totalPages = res.result.pages || 1;
this.loadStatus = this.searchForm.pageNum >= this.totalPages ? 'nomore' : 'more';
} else {
this.tui.toast(res.message);
}
});
},
handleOrder(index, item) {
if (this.tab === 'pickup' && !item.arriveTime) {
this.changeStatus(index, item, 1);
return;
}
this.changeStatus(index, item, this.tab === 'pickup' ? 2 : 3);
},
buttonText(item) {
if (this.tab === 'pickup') {
return item.arriveTime ? '确认取货' : '已到店';
}
return '确认送达';
},
changeStatus(index, item, status) {
const url = status === 1 ? '/mall/delivery/arriveShop' : (status === 2 ? '/mall/delivery/pickup' : '/mall/delivery/complete');
this.tui.request(url, 'POST', {
regionId: this.searchForm.regionId,
deliveryId: item.id,
workerId: this.worker.workerId
}, false, true).then((res) => {
if (res.code == 200) {
if (status === 1) {
this.$set(this.list[index], 'arriveTime', new Date());
} else {
this.list.splice(index, 1);
}
this.tui.toast(res.message || '操作成功');
} else {
this.tui.toast(res.message);
}
});
},
productDetail(item) {
this.productData = item.goodsList || [];
this.$refs.productPopup.open();
},
goodsCount(item) {
return (item.goodsList || []).reduce((sum, goods) => sum + Number(goods.quantity || 0), 0);
},
formatSpecs(data) {
let str;
if (typeof data === 'object' && data !== null) {
str = JSON.stringify(data);
} else if (typeof data === 'string') {
str = data;
} else {
str = String(data || '');
}
return str.replace(/[{}"]/g, '');
},
makeCall(phone) {
if (!phone) return;
uni.makePhoneCall({
phoneNumber: phone
});
}
}
}
</script>
<style>
.page{
height: 100vh;
background: #F5F8F5;
padding: 0 24rpx;
box-sizing: border-box;
position: relative;
overflow: hidden;
}
.fixed-head{
position: absolute;
top: -40rpx;
left: 24rpx;
right: 24rpx;
z-index: 10;
background: #F5F8F5;
}
.nav{
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.back-btn{
position: absolute;
left: 0;
width: 68rpx;
height: 68rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: rgba(255, 255, 255, 0.9);
box-shadow: 0 8rpx 20rpx rgba(0, 35, 28, 0.08);
}
.nav-title{
position: absolute;
bottom: 18rpx;
font-size: 32rpx;
font-weight: 800;
}
.tabs{
display: flex;
background: #fff;
border-radius: 24rpx;
padding: 10rpx;
margin-bottom: 0;
}
.tab{
flex: 1;
text-align: center;
height: 70rpx;
line-height: 70rpx;
border-radius: 20rpx;
font-weight: 700;
}
.tab.active{
background: linear-gradient(90deg, #e3ff96, #a6ffea);
}
.list{
position: absolute;
left: 24rpx;
right: 24rpx;
bottom: 0;
box-sizing: border-box;
padding-top: 20rpx;
padding-bottom: 36rpx;
}
.card{
background: #fff;
border-radius: 24rpx;
padding: 24rpx;
margin-bottom: 20rpx;
box-shadow: 0 12rpx 30rpx rgba(0, 35, 28, 0.08);
}
.card-head{
display: flex;
align-items: center;
justify-content: space-between;
}
.tag{
background: rgba(255, 111, 44, 0.1);
color: #ff6f2c;
padding: 8rpx 16rpx;
border-radius: 18rpx;
font-weight: 700;
}
.time{
color: #666;
}
.order-code{
margin-top: 18rpx;
font-size: 32rpx;
font-weight: 800;
}
.address{
display: flex;
margin-top: 18rpx;
}
.dot{
width: 44rpx;
height: 44rpx;
line-height: 44rpx;
text-align: center;
border-radius: 50%;
color: #fff;
margin-right: 16rpx;
}
.get{
background: #0b9b73;
}
.send{
background: #ff6f2c;
}
.name{
font-weight: 700;
}
.desc,.remark,.fee{
margin-top: 8rpx;
color: #666;
line-height: 38rpx;
}
.phone-row{
display: inline-block;
margin-top: 8rpx;
color: #0b9b73;
font-weight: 700;
line-height: 34rpx;
}
.goods-row{
display: flex;
align-items: center;
margin-top: 20rpx;
padding: 18rpx 20rpx;
border-radius: 18rpx;
background: rgba(247, 248, 248, 0.8);
}
.goods-title{
font-weight: 800;
margin-right: 16rpx;
}
.goods-desc{
flex: 1;
color: #666;
font-size: 24rpx;
}
.btn{
margin-top: 24rpx;
height: 76rpx;
line-height: 76rpx;
text-align: center;
border-radius: 38rpx;
background: linear-gradient(90deg, #e3ff96, #a6ffea);
font-weight: 800;
}
.empty{
text-align: center;
color: #888;
padding: 80rpx 0;
}
.product-popup-content{
width: 650rpx;
max-height: 850rpx;
padding: 30rpx;
border-radius: 28rpx;
background: #fff;
box-sizing: border-box;
}
.product-popup-title{
font-size: 32rpx;
font-weight: 800;
}
.product-popup-subtitle{
margin-top: 8rpx;
color: #888;
font-size: 24rpx;
}
.product-popup-list{
margin-top: 24rpx;
max-height: 680rpx;
overflow-y: auto;
}
.product-popup-card{
display: flex;
align-items: center;
padding: 18rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.product-popup-img img{
width: 90rpx;
height: 90rpx;
border-radius: 16rpx;
margin-right: 18rpx;
}
.product-popup-info{
flex: 1;
min-width: 0;
}
.product-popup-name{
font-weight: 800;
line-height: 38rpx;
}
.product-popup-spec{
margin-top: 8rpx;
color: #777;
font-size: 24rpx;
}
.product-popup-label{
margin-right: 10rpx;
color: #999;
}
.product-popup-quantity{
width: 80rpx;
text-align: right;
}
.product-popup-quantity-num{
font-weight: 800;
}
.product-popup-quantity-label,
.product-popup-empty{
color: #888;
font-size: 22rpx;
}
</style>