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.
592 lines
12 KiB
592 lines
12 KiB
<template>
|
|
<view class="logistics-container">
|
|
<!-- 物流状态头部 -->
|
|
<view class="status-header">
|
|
<view class="status-info">
|
|
<view class="status-icon">
|
|
<image :src="getStatusIcon(logisticsInfo.status)" mode="aspectFit" />
|
|
</view>
|
|
<view class="status-content">
|
|
<view class="status-title">{{ getStatusText(logisticsInfo.status) }}</view>
|
|
<view class="status-desc" v-if="logisticsInfo.lastUpdate">
|
|
最新状态:{{ logisticsInfo.lastUpdate }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 快递信息 -->
|
|
<view class="express-section">
|
|
<view class="section-title">快递信息</view>
|
|
<view class="express-card">
|
|
<view class="express-item">
|
|
<text class="express-label">快递公司</text>
|
|
<text class="express-value">{{ logisticsInfo.expressCompany || '--' }}</text>
|
|
</view>
|
|
<view class="express-item">
|
|
<text class="express-label">快递单号</text>
|
|
<text class="express-value" @longpress="copyExpressNo">{{ logisticsInfo.expressNo || '--' }}</text>
|
|
</view>
|
|
<view class="express-item">
|
|
<text class="express-label">发货时间</text>
|
|
<text class="express-value">{{ logisticsInfo.shippingTime || '--' }}</text>
|
|
</view>
|
|
<view class="express-item">
|
|
<text class="express-label">预计送达</text>
|
|
<text class="express-value">{{ logisticsInfo.estimatedTime || '--' }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 收货地址 -->
|
|
<view class="address-section">
|
|
<view class="section-title">收货地址</view>
|
|
<view class="address-card">
|
|
<view class="address-info">
|
|
<view class="recipient-info">
|
|
<text class="recipient-name">{{ addressInfo.linkName }}</text>
|
|
<text class="recipient-phone">{{ addressInfo.phone }}</text>
|
|
</view>
|
|
<view class="address-detail">
|
|
{{ addressInfo.province }}{{ addressInfo.city }}{{ addressInfo.area }}{{ addressInfo.address }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 物流轨迹 -->
|
|
<view class="trace-section">
|
|
<view class="section-title">物流轨迹</view>
|
|
<view class="trace-list">
|
|
<view
|
|
class="trace-item"
|
|
v-for="(trace, index) in logisticsTrace"
|
|
:key="index"
|
|
:class="{ 'is-current': index === 0 }"
|
|
>
|
|
<view class="trace-time">{{ trace.time }}</view>
|
|
<view class="trace-content">
|
|
<view class="trace-status">{{ trace.status }}</view>
|
|
<view class="trace-location" v-if="trace.location">{{ trace.location }}</view>
|
|
<view class="trace-remark" v-if="trace.remark">{{ trace.remark }}</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 空状态 -->
|
|
<view class="empty-trace" v-if="!logisticsTrace || logisticsTrace.length === 0">
|
|
<image class="empty-image" src="/static/images/empty-logistics.png" mode="aspectFit" />
|
|
<text class="empty-text">暂无物流轨迹信息</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 联系供应商 -->
|
|
<view class="contact-section">
|
|
<view class="section-title">联系供应商</view>
|
|
<view class="contact-card">
|
|
<view class="supplier-info">
|
|
<view class="supplier-name">{{ supplierInfo.name || '默认供应商' }}</view>
|
|
<view class="supplier-phone">联系电话:{{ supplierInfo.phone || '暂无' }}</view>
|
|
</view>
|
|
<button class="contact-btn" @click="contactSupplier">
|
|
<text>联系供应商</text>
|
|
</button>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 订单操作 -->
|
|
<view class="order-actions">
|
|
<button
|
|
class="action-btn confirm-btn"
|
|
@click="confirmReceipt"
|
|
v-if="logisticsInfo.status === 3"
|
|
>
|
|
确认收货
|
|
</button>
|
|
<button
|
|
class="action-btn secondary-btn"
|
|
@click="applyAfterSale"
|
|
v-if="[2, 3, 4].includes(logisticsInfo.status)"
|
|
>
|
|
申请售后
|
|
</button>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
orderId: '',
|
|
logisticsInfo: {
|
|
status: 0,
|
|
expressCompany: '',
|
|
expressNo: '',
|
|
shippingTime: '',
|
|
estimatedTime: '',
|
|
lastUpdate: ''
|
|
},
|
|
addressInfo: {
|
|
linkName: '',
|
|
phone: '',
|
|
province: '',
|
|
city: '',
|
|
area: '',
|
|
address: ''
|
|
},
|
|
supplierInfo: {
|
|
name: '',
|
|
phone: ''
|
|
},
|
|
logisticsTrace: []
|
|
};
|
|
},
|
|
onLoad(options) {
|
|
if (options.orderId) {
|
|
this.orderId = options.orderId;
|
|
this.loadLogisticsInfo();
|
|
}
|
|
},
|
|
methods: {
|
|
// 加载物流信息
|
|
async loadLogisticsInfo() {
|
|
try {
|
|
uni.showLoading({
|
|
title: '加载中...'
|
|
});
|
|
|
|
this.Post(
|
|
{ orderId: this.orderId },
|
|
'/framework/haveFeeling/order/logistics',
|
|
'DES'
|
|
).then((res) => {
|
|
if (res.code == 200) {
|
|
this.logisticsInfo = res.data.logistics || {};
|
|
this.addressInfo = res.data.address || {};
|
|
this.supplierInfo = res.data.supplier || {};
|
|
this.logisticsTrace = res.data.trace || [];
|
|
} else {
|
|
uni.showToast({
|
|
title: res.msg,
|
|
icon: 'none'
|
|
});
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('加载物流信息失败:', error);
|
|
uni.showToast({
|
|
title: '加载失败',
|
|
icon: 'none'
|
|
});
|
|
} finally {
|
|
uni.hideLoading();
|
|
}
|
|
},
|
|
|
|
// 获取状态文本
|
|
getStatusText(status) {
|
|
const statusMap = {
|
|
0: '待发货',
|
|
1: '已发货',
|
|
2: '运输中',
|
|
3: '派送中',
|
|
4: '已签收',
|
|
5: '异常'
|
|
};
|
|
return statusMap[status] || '待发货';
|
|
},
|
|
|
|
// 获取状态图标
|
|
getStatusIcon(status) {
|
|
const iconMap = {
|
|
0: '/static/images/logistics-waiting.png',
|
|
1: '/static/images/logistics-shipped.png',
|
|
2: '/static/images/logistics-transit.png',
|
|
3: '/static/images/logistics-delivering.png',
|
|
4: '/static/images/logistics-completed.png',
|
|
5: '/static/images/logistics-exception.png'
|
|
};
|
|
return iconMap[status] || '/static/images/logistics-waiting.png';
|
|
},
|
|
|
|
// 复制快递单号
|
|
copyExpressNo() {
|
|
if (this.logisticsInfo.expressNo) {
|
|
uni.setClipboardData({
|
|
data: this.logisticsInfo.expressNo,
|
|
success: () => {
|
|
uni.showToast({
|
|
title: '快递单号已复制',
|
|
icon: 'success'
|
|
});
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
// 联系供应商
|
|
contactSupplier() {
|
|
if (this.supplierInfo.phone) {
|
|
uni.makePhoneCall({
|
|
phoneNumber: this.supplierInfo.phone
|
|
});
|
|
} else {
|
|
uni.showToast({
|
|
title: '暂无供应商联系方式',
|
|
icon: 'none'
|
|
});
|
|
}
|
|
},
|
|
|
|
// 确认收货
|
|
confirmReceipt() {
|
|
uni.showModal({
|
|
title: '确认收货',
|
|
content: '确认已收到所有商品吗?',
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
this.confirmReceiptApi();
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
// 确认收货API
|
|
confirmReceiptApi() {
|
|
uni.showLoading({
|
|
title: '确认中...'
|
|
});
|
|
|
|
this.Post(
|
|
{ orderId: this.orderId },
|
|
'/framework/haveFeeling/order/confirm',
|
|
'DES'
|
|
).then((res) => {
|
|
uni.hideLoading();
|
|
if (res.code == 200) {
|
|
uni.showToast({
|
|
title: '确认收货成功',
|
|
icon: 'success'
|
|
});
|
|
setTimeout(() => {
|
|
uni.navigateBack();
|
|
}, 800);
|
|
} else {
|
|
uni.showToast({
|
|
title: res.msg || '确认收货失败',
|
|
icon: 'none'
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
// 申请售后
|
|
applyAfterSale() {
|
|
uni.navigateTo({
|
|
url: `/subPackages/haveFeeling/aftersale?orderId=${this.orderId}`
|
|
});
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.logistics-container {
|
|
min-height: 100vh;
|
|
background-color: #f5f5f5;
|
|
padding-bottom: 100rpx;
|
|
}
|
|
|
|
// 状态头部
|
|
.status-header {
|
|
background-color: #fff;
|
|
padding: 40rpx 30rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.status-info {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.status-icon {
|
|
width: 80rpx;
|
|
height: 80rpx;
|
|
margin-right: 24rpx;
|
|
|
|
image {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
}
|
|
|
|
.status-content {
|
|
flex: 1;
|
|
}
|
|
|
|
.status-title {
|
|
font-size: 32rpx;
|
|
color: #333;
|
|
font-weight: 600;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.status-desc {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
}
|
|
|
|
// 通用样式
|
|
.section-title {
|
|
font-size: 28rpx;
|
|
font-weight: 600;
|
|
color: #333;
|
|
margin-bottom: 24rpx;
|
|
}
|
|
|
|
// 快递信息
|
|
.express-section {
|
|
background-color: #fff;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.express-card {
|
|
background-color: #f8f9fa;
|
|
border-radius: 12rpx;
|
|
padding: 24rpx;
|
|
}
|
|
|
|
.express-item {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20rpx;
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
}
|
|
|
|
.express-label {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.express-value {
|
|
font-size: 26rpx;
|
|
color: #333;
|
|
font-weight: 500;
|
|
}
|
|
|
|
// 收货地址
|
|
.address-section {
|
|
background-color: #fff;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.address-card {
|
|
background-color: #f8f9fa;
|
|
border-radius: 12rpx;
|
|
padding: 24rpx;
|
|
}
|
|
|
|
.recipient-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 20rpx;
|
|
margin-bottom: 16rpx;
|
|
}
|
|
|
|
.recipient-name {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.recipient-phone {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.address-detail {
|
|
font-size: 26rpx;
|
|
color: #333;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
// 物流轨迹
|
|
.trace-section {
|
|
background-color: #fff;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.trace-list {
|
|
.trace-item {
|
|
display: flex;
|
|
padding: 24rpx 0;
|
|
border-left: 2rpx solid #e2e8f0;
|
|
padding-left: 40rpx;
|
|
position: relative;
|
|
margin-bottom: 16rpx;
|
|
|
|
&:before {
|
|
content: '';
|
|
position: absolute;
|
|
left: -8rpx;
|
|
top: 30rpx;
|
|
width: 14rpx;
|
|
height: 14rpx;
|
|
border-radius: 50%;
|
|
background-color: #e2e8f0;
|
|
}
|
|
|
|
&.is-current {
|
|
border-left-color: #007aff;
|
|
|
|
&:before {
|
|
background-color: #007aff;
|
|
box-shadow: 0 0 0 4rpx rgba(0, 122, 255, 0.2);
|
|
}
|
|
|
|
.trace-time,
|
|
.trace-status {
|
|
color: #007aff;
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
|
|
&:last-child {
|
|
border-left-color: transparent;
|
|
}
|
|
}
|
|
}
|
|
|
|
.trace-time {
|
|
font-size: 22rpx;
|
|
color: #999;
|
|
margin-bottom: 8rpx;
|
|
min-width: 120rpx;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.trace-content {
|
|
flex: 1;
|
|
margin-left: 20rpx;
|
|
}
|
|
|
|
.trace-status {
|
|
font-size: 26rpx;
|
|
color: #333;
|
|
margin-bottom: 6rpx;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.trace-location {
|
|
font-size: 22rpx;
|
|
color: #666;
|
|
margin-bottom: 4rpx;
|
|
}
|
|
|
|
.trace-remark {
|
|
font-size: 22rpx;
|
|
color: #999;
|
|
}
|
|
|
|
// 空状态
|
|
.empty-trace {
|
|
text-align: center;
|
|
padding: 80rpx 40rpx;
|
|
}
|
|
|
|
.empty-image {
|
|
width: 200rpx;
|
|
height: 200rpx;
|
|
margin-bottom: 30rpx;
|
|
opacity: 0.6;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 28rpx;
|
|
color: #999;
|
|
}
|
|
|
|
// 联系供应商
|
|
.contact-section {
|
|
background-color: #fff;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.contact-card {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
background-color: #f8f9fa;
|
|
border-radius: 12rpx;
|
|
padding: 24rpx;
|
|
}
|
|
|
|
.supplier-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.supplier-name {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
font-weight: 600;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.supplier-phone {
|
|
font-size: 24rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.contact-btn {
|
|
padding: 12rpx 24rpx;
|
|
border-radius: 20rpx;
|
|
font-size: 24rpx;
|
|
background-color: #007aff;
|
|
color: #fff;
|
|
border: none;
|
|
}
|
|
|
|
// 订单操作
|
|
.order-actions {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
background-color: #fff;
|
|
padding: 20rpx 30rpx;
|
|
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
|
border-top: 1rpx solid #eee;
|
|
display: flex;
|
|
gap: 16rpx;
|
|
}
|
|
|
|
.action-btn {
|
|
flex: 1;
|
|
padding: 20rpx 0;
|
|
border-radius: 10rpx;
|
|
font-size: 28rpx;
|
|
font-weight: 600;
|
|
border: none;
|
|
text-align: center;
|
|
|
|
&.confirm-btn {
|
|
background-color: #48bb78;
|
|
color: #fff;
|
|
}
|
|
|
|
&.secondary-btn {
|
|
background-color: #f5f5f5;
|
|
color: #666;
|
|
border: 1rpx solid #ddd;
|
|
}
|
|
}
|
|
</style>
|