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>
|