252 lines
7.5 KiB
Vue
252 lines
7.5 KiB
Vue
|
|
<template>
|
|||
|
|
<full-page v-if="data">
|
|||
|
|
<view :style="elderVarStyle">
|
|||
|
|
<view class="px-15 py-12 bg-white shadow-lg leading-normal">
|
|||
|
|
<view class="pb-5">
|
|||
|
|
<text class="text-base text-gray">收货人:</text>
|
|||
|
|
<text class="text-base text-dark">{{ data.receiveName }} {{ data.receivePhone }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view>
|
|||
|
|
<text class="text-base text-gray">收货地址:</text>
|
|||
|
|
<text v-if="data.receiveRegion && data.receiveRegion.length > 0" class="text-base text-dark">
|
|||
|
|
{{ data.receiveRegion.join('') }}
|
|||
|
|
</text>
|
|||
|
|
<text v-if="data.receiveAddress" class="text-base text-dark">
|
|||
|
|
{{ data.receiveAddress }}
|
|||
|
|
</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<view class="mt-15 bg-white shadow-lg">
|
|||
|
|
<view class="flex items-center px-15 py-12 border-b">
|
|||
|
|
<view v-if="data.shippingType === 'fengniao'" class="flex-shrink-0 flex items-center">
|
|||
|
|
<image class="flex-shrink-0 shipping-icon mr-5" src="/static/icons/fengniao.svg"></image>
|
|||
|
|
<view class="flex-shrink-0 mr-10 text-base text-drak">蜂鸟配送</view>
|
|||
|
|
</view>
|
|||
|
|
<view v-else-if="data.shippingType === 'ems'" class="flex-shrink-0 flex items-center">
|
|||
|
|
<image class="flex-shrink-0 shipping-icon mr-5" src="/static/icons/ems.svg"></image>
|
|||
|
|
<view class="flex-shrink-0 mr-10 text-base text-drak">快递邮寄</view>
|
|||
|
|
</view>
|
|||
|
|
<view class="flex-grow w-0 flex items-center justify-end">
|
|||
|
|
<view class="flex-grow w-0 truncate text-sm text-dark text-right mr-5">
|
|||
|
|
{{ data.shippingNo }}
|
|||
|
|
</view>
|
|||
|
|
<view class="flex-shrink-0 text-base text-primary" @click="copy">复制</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<view class="px-15 pb-50">
|
|||
|
|
<view v-for="(i, idx) in eventList" class="route-item pt-5 relative"
|
|||
|
|
:class="{ active: idx === 0, last: idx === eventList.length - 1 }">
|
|||
|
|
<view class="route-header flex items-center flex-wrap">
|
|||
|
|
<view class="mr-5 text-base font-semibold" :class="idx === 0 ? 'text-warning' : 'text-dark'">
|
|||
|
|
{{ i.status }}
|
|||
|
|
</view>
|
|||
|
|
<view class="text-sm" :class="idx === 0 ? 'text-warning' : 'text-gray'">{{ i.time }}</view>
|
|||
|
|
</view>
|
|||
|
|
<template v-if="data.shippingType === 'fengniao'">
|
|||
|
|
<view v-if="i.knightName || i.knightPhone" class="flex flex-wrap pb-10 leading-normal">
|
|||
|
|
<view v-if="i.knightName" class="flex-shrink-0">
|
|||
|
|
<text class="text-sm text-gray">骑手:</text>
|
|||
|
|
<text class="mr-10 text-sm text-primary">{{ i.knightName }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view v-if="i.knightPhone" class="flex-shrink-0">
|
|||
|
|
<text class="text-sm text-gray">骑手电话:</text>
|
|||
|
|
<text class="text-sm text-primary" @click="contact(i.knightPhone)">{{ i.knightPhone }}</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
<template v-else-if="data.shippingType === 'ems'">
|
|||
|
|
<view class="text-base text-dark leading-normal">{{ i.place }}</view>
|
|||
|
|
<view class="leading-normal">
|
|||
|
|
<text v-for="item in i.descTextList" :key="item.key" class="mr-10 text-sm"
|
|||
|
|
:class="item.type === 'phone' ? 'text-primary' : 'text-dark'"
|
|||
|
|
@click="contact(item.type === 'phone' ? item.text : '')">
|
|||
|
|
{{ item.text }}
|
|||
|
|
</text>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
</view>
|
|||
|
|
<empty-data v-if="eventList.length === 0" height="50vh" />
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</full-page>
|
|||
|
|
</template>
|
|||
|
|
<script setup>
|
|||
|
|
import { computed, ref } from 'vue';
|
|||
|
|
import { onLoad, onShow } from '@dcloudio/uni-app';
|
|||
|
|
import useElder from '@/hooks/useElder';
|
|||
|
|
import useUser from '@/hooks/useUser';
|
|||
|
|
import { getShippingDetail } from '@/utils/api';
|
|||
|
|
import { toast, loading as showLoading, hideLoading } from '@/utils/widget';
|
|||
|
|
import fullPage from '@/components/full-page.vue';
|
|||
|
|
import emptyData from "@/components/empty.vue";
|
|||
|
|
|
|||
|
|
const { elderVarStyle } = useElder();
|
|||
|
|
const id = ref('');
|
|||
|
|
const data = ref(null)
|
|||
|
|
const { userInfo } = useUser();
|
|||
|
|
|
|||
|
|
const eventList = computed(() => {
|
|||
|
|
if (data.value && data.value.shippingType === 'fengniao') {
|
|||
|
|
const shippingDetail = data.value.shippingDetail || {};
|
|||
|
|
const eventLogDetails = Array.isArray(shippingDetail.eventLogDetails) ? shippingDetail.eventLogDetails : [];
|
|||
|
|
return eventLogDetails.map(item => ({
|
|||
|
|
knightName: item.knightName,
|
|||
|
|
knightPhone: item.knightPhone,
|
|||
|
|
time: item.time,
|
|||
|
|
status: item.status
|
|||
|
|
})).sort((a, b) => new Date(b.time) - new Date(a.time));
|
|||
|
|
} else if (data.value && data.value.shippingType === 'ems') {
|
|||
|
|
const eventLogDetails = Array.isArray(data.value.shippingDetail) ? data.value.shippingDetail : [];
|
|||
|
|
return eventLogDetails.map((i, idx) => ({
|
|||
|
|
status: i.opName,
|
|||
|
|
time: i.opTime,
|
|||
|
|
place: `${i.opOrgProvName}-${i.opOrgCity}-${i.opOrgName}`,
|
|||
|
|
descTextList: getDescTextList(i.opDesc, idx),
|
|||
|
|
}))
|
|||
|
|
}
|
|||
|
|
return [];
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
function copy() {
|
|||
|
|
uni.setClipboardData({
|
|||
|
|
data: data.value.shippingNo,
|
|||
|
|
success: () => toast('复制成功')
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function contact(phoneNumber) {
|
|||
|
|
if (!phoneNumber) return;
|
|||
|
|
uni.makePhoneCall({
|
|||
|
|
phoneNumber,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function getDescTextList(desc, index) {
|
|||
|
|
if (typeof desc !== 'string') return [];
|
|||
|
|
|
|||
|
|
// 匹配11位手机号(以1开头的数字)
|
|||
|
|
const phoneRegex = /1[3-9]\d{9}/g;
|
|||
|
|
const result = [];
|
|||
|
|
let lastIndex = 0;
|
|||
|
|
let match;
|
|||
|
|
|
|||
|
|
// 查找所有手机号
|
|||
|
|
while ((match = phoneRegex.exec(desc)) !== null) {
|
|||
|
|
// 添加手机号之前的普通文本
|
|||
|
|
if (match.index > lastIndex) {
|
|||
|
|
const textBefore = desc.substring(lastIndex, match.index);
|
|||
|
|
if (textBefore) {
|
|||
|
|
result.push({
|
|||
|
|
text: textBefore,
|
|||
|
|
type: 'text'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加手机号
|
|||
|
|
result.push({
|
|||
|
|
text: match[0],
|
|||
|
|
type: 'phone'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
lastIndex = match.index + match[0].length;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加最后一个手机号之后的普通文本
|
|||
|
|
if (lastIndex < desc.length) {
|
|||
|
|
const textAfter = desc.substring(lastIndex);
|
|||
|
|
if (textAfter) {
|
|||
|
|
result.push({
|
|||
|
|
text: textAfter,
|
|||
|
|
type: 'text'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果没有找到手机号,返回整个文本作为普通文本
|
|||
|
|
if (result.length === 0) {
|
|||
|
|
result.push({
|
|||
|
|
text: desc,
|
|||
|
|
type: 'text'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
return result.map((i, idx) => ({
|
|||
|
|
key: `${index}-${Date.now()}-${idx}`,
|
|||
|
|
text: i.text,
|
|||
|
|
type: i.type
|
|||
|
|
}));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async function getDetail() {
|
|||
|
|
showLoading();
|
|||
|
|
const res = await getShippingDetail({ accountId: userInfo.value.userId, id: id.value });
|
|||
|
|
hideLoading();
|
|||
|
|
if (res && res.success) {
|
|||
|
|
data.value = res.data;
|
|||
|
|
} else {
|
|||
|
|
await toast(res.message || '获取配送信息失败');
|
|||
|
|
uni.navigateBack();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
onLoad(options => {
|
|||
|
|
id.value = options.id || '';
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
onShow(() => {
|
|||
|
|
getDetail()
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
</script>
|
|||
|
|
<style scoped>
|
|||
|
|
page {
|
|||
|
|
background: #f5f5f5;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.shipping-icon {
|
|||
|
|
width: 48rpx;
|
|||
|
|
height: 48rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.route-item {
|
|||
|
|
padding-left: 60rpx
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.route-item::before {
|
|||
|
|
content: "";
|
|||
|
|
position: absolute;
|
|||
|
|
top: 33rpx;
|
|||
|
|
left: 22rpx;
|
|||
|
|
width: 16rpx;
|
|||
|
|
height: 16rpx;
|
|||
|
|
background: #999;
|
|||
|
|
border-radius: 50%;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.route-item.active::before {
|
|||
|
|
background: #f56c6c;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.route-item::after {
|
|||
|
|
content: "";
|
|||
|
|
position: absolute;
|
|||
|
|
top: 53rpx;
|
|||
|
|
bottom: -24rpx;
|
|||
|
|
left: 28rpx;
|
|||
|
|
border-left: 4rpx dashed #999;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.route-item.last::after {
|
|||
|
|
display: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.route-header {
|
|||
|
|
min-height: 72rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.pb-50 {
|
|||
|
|
padding-bottom: 100rpx;
|
|||
|
|
}
|
|||
|
|
</style>
|