feat: 新增确认送达弹框组件、添加安卓打包测试证书、骑手配送流程接口对接
This commit is contained in:
@@ -1,16 +1,14 @@
|
||||
<template>
|
||||
<s-layout title="订单详情" class="set-userinfo-wrap">
|
||||
<view class="order-detail-page">
|
||||
<!-- 地图占位(可替换为原生 map 组件或第三方地图组件) -->
|
||||
<!-- 地图区域 -->
|
||||
<view class="map-area">
|
||||
<!-- 真实项目建议使用 <map> 并渲染 polyline/markers -->
|
||||
<image class="map-image" src="/static/img/map-placeholder.png" mode="widthFix" v-if="!mapAvailable" />
|
||||
<map v-else class="map-native" :latitude="order?.pickupLat" :longitude="order?.pickupLng" show-location
|
||||
<map class="map-native" :latitude="order?.pickupLat" :longitude="order?.pickupLng" show-location
|
||||
enable-3D enable-zoom :scale="16"></map>
|
||||
<view class="map-overlay">
|
||||
<view class="eta">距离商家{{ distanceText }},预计{{ etaText }}到达</view>
|
||||
<view class="nav-btn" @click="navigateToShop">导航到商家</view>
|
||||
</view>
|
||||
<cover-view class="map-overlay">
|
||||
<cover-view class="eta">距离商家{{ distanceText }},预计{{ etaText }}到达</cover-view>
|
||||
<cover-view class="nav-btn" @click="navigateToShop">导航到商家</cover-view>
|
||||
</cover-view>
|
||||
</view>
|
||||
|
||||
<!-- 地址块 -->
|
||||
@@ -67,7 +65,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 占位底部高度,避免内容被底部按钮遮挡 -->
|
||||
<view style="height:140rpx;"></view>
|
||||
<view style="height:200rpx;"></view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部操作 -->
|
||||
@@ -76,10 +74,13 @@
|
||||
<view class="icon-phone" @click="callPhone(order?.receiverPhone)"></view>
|
||||
</view>
|
||||
<view class="right-actions">
|
||||
<view class="btn remind">催单</view>
|
||||
<view class="btn remind"
|
||||
@click="sheep.$helper.toast('功能开发中ing')">催单</view>
|
||||
<view class="btn remind" @click="openRemindPopup">电话联系</view>
|
||||
<!-- <view class="btn confirm">转单</view> -->
|
||||
<view class="btn confirm" @click="confirmArrive">确认到店</view>
|
||||
<view class="btn confirm" v-if="order?.deliveryStatus == 2" @click="confirmArrive">确认到店</view>
|
||||
<view class="btn confirm" v-if="order?.deliveryStatus == 3" @click="confirmPickup">确认取餐</view>
|
||||
<view class="btn handover" v-if="order?.deliveryStatus == 4" @click="deliveryHandover">送达交接点</view>
|
||||
<view class="btn handover" v-if="order?.deliveryStatus == 5" @click="openDeliveryPopup">确认送达顾客</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 催单弹框 -->
|
||||
@@ -98,6 +99,15 @@
|
||||
<view class="remind-cancel" @click="showRemind = false">取消</view>
|
||||
</template>
|
||||
</up-popup>
|
||||
|
||||
<!-- 确认送达顾客弹框 -->
|
||||
<DeliveryPopup
|
||||
:show="showDeliveryPopup"
|
||||
:receiverPhone="order?.receiverPhone || ''"
|
||||
@update:show="showDeliveryPopup = $event"
|
||||
@submit="handleDeliveryConfirm"
|
||||
@close="showDeliveryPopup = false"
|
||||
/>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
@@ -111,11 +121,13 @@
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app';
|
||||
import sheep from '@/sheep';
|
||||
import DeliveryOrderApi from '@/sheep/api/member/deliveryOrder';
|
||||
import DeliveryPopup from '@/pages/index/components/delivery-popup.vue';
|
||||
|
||||
const orderId = ref(null);
|
||||
const order = ref(null);
|
||||
const loading = ref(false);
|
||||
const mapAvailable = ref(false); // 如果需要使用 map 组件,置为 true
|
||||
const mapAvailable = ref(true); // 如果需要使用 map 组件,置为 true
|
||||
|
||||
// 入口:从页面参数取 orderId,然后加载数据
|
||||
onLoad((options = {}) => {
|
||||
@@ -126,51 +138,36 @@
|
||||
async function fetchOrder() {
|
||||
loading.value = true;
|
||||
try {
|
||||
// 优先尝试平台统一 request(项目内可能封装在 sheep.request 或 sheep.api)
|
||||
if (sheep && typeof sheep.request === 'function') {
|
||||
const res = await sheep.request({
|
||||
url: '/order/detail',
|
||||
method: 'GET',
|
||||
data: {
|
||||
id: orderId.value
|
||||
}
|
||||
});
|
||||
// 根据封装不同,这里兼容 res.data 或 res
|
||||
order.value = (res && res.data) ? res.data : res;
|
||||
} else if (sheep && sheep.$api && sheep.$api.trade && typeof sheep.$api.trade.detail === 'function') {
|
||||
const res = await sheep.$api.trade.detail({
|
||||
id: orderId.value
|
||||
});
|
||||
order.value = res?.data || res;
|
||||
} else {
|
||||
// 回退 mock 数据,避免界面空白,开发时替换为真实接口
|
||||
// 使用 DeliveryOrderApi 获取配送单详情
|
||||
const res = await DeliveryOrderApi.getDetail(orderId.value);
|
||||
// 根据封装不同,这里兼容 res.data 或 res
|
||||
const resData = (res && res.data) ? res.data : res;
|
||||
console.log("res数据:", res);
|
||||
|
||||
if (resData) {
|
||||
// 字段映射:将接口返回字段映射到页面使用字段
|
||||
order.value = {
|
||||
id: orderId.value || 1001,
|
||||
shopName: '店铺名(示例)',
|
||||
pickupAddress: '广东省广州市天河区学院站荷光路118-121号',
|
||||
pickupLat: 23.1005,
|
||||
pickupLng: 113.3301,
|
||||
deliveryAddress: '广东省广州市天河区华景新城软件园区B栋西梯501',
|
||||
deliveryLat: 23.105,
|
||||
deliveryLng: 113.335,
|
||||
receiverName: '张先生',
|
||||
receiverPhone: '13900001234',
|
||||
note: '依据餐量提供餐具',
|
||||
items: [{
|
||||
name: '商品名称A',
|
||||
spec: '规格1',
|
||||
quantity: 2,
|
||||
price: 23.89
|
||||
},
|
||||
{
|
||||
name: '商品名称B',
|
||||
spec: '规格2',
|
||||
quantity: 1,
|
||||
price: 45.00
|
||||
}
|
||||
]
|
||||
...resData,
|
||||
// 店铺坐标 (取货点)
|
||||
pickupLat: resData.shopLatitude,
|
||||
pickupLng: resData.shopLongitude,
|
||||
pickupAddress: resData.shopAddress,
|
||||
// 收货地址
|
||||
deliveryLat: resData.receiverLatitude,
|
||||
deliveryLng: resData.receiverLongitude,
|
||||
deliveryAddress: resData.receiverAddress,
|
||||
// 商品列表
|
||||
items: resData.orderItemDataList?.map(item => ({
|
||||
name: item.productName,
|
||||
quantity: item.quantity,
|
||||
price: parseFloat(item.unitPrice) || 0
|
||||
})) || [],
|
||||
// 备注
|
||||
note: resData.orderRemark,
|
||||
deliveryStatus: resData.deliveryStatus
|
||||
};
|
||||
}
|
||||
console.log("order.value数据:", order.value);
|
||||
} catch (e) {
|
||||
console.error('fetchOrder error', e);
|
||||
// 友好提示
|
||||
@@ -240,6 +237,42 @@
|
||||
showRemind.value = false;
|
||||
}
|
||||
|
||||
// 确认送达顾客弹框控制
|
||||
const showDeliveryPopup = ref(false);
|
||||
|
||||
function openDeliveryPopup() {
|
||||
showDeliveryPopup.value = true;
|
||||
}
|
||||
|
||||
// 确认送达顾客
|
||||
async function handleDeliveryConfirm(imageUrl) {
|
||||
console.log('送达照片URL:', imageUrl);
|
||||
|
||||
if (!orderId.value) {
|
||||
sheep.$helper.toast('订单信息异常');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await DeliveryOrderApi.riderConfirmDelivery({
|
||||
deliveryOrderId: orderId.value,
|
||||
imageUrl: imageUrl
|
||||
});
|
||||
|
||||
if (res.code === 0 && res.data === true) {
|
||||
sheep.$helper.toast('已提交送达照片');
|
||||
showDeliveryPopup.value = false;
|
||||
// 刷新订单状态
|
||||
fetchOrder();
|
||||
} else {
|
||||
sheep.$helper.toast(res.msg || '提交失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('确认送达异常:', error);
|
||||
sheep.$helper.toast('提交失败,请重试');
|
||||
}
|
||||
}
|
||||
|
||||
function callShopPhone() {
|
||||
// 商家电话优先使用 order.shopPhone,否则尝试 fallback
|
||||
const phone = order.value?.shopPhone || order.value?.shopPhoneNumber || order.value?.receiverPhone || '';
|
||||
@@ -261,29 +294,68 @@
|
||||
closeRemindPopup();
|
||||
}
|
||||
|
||||
function confirmArrive() {
|
||||
// 确认到店:调用接口或本地改变状态
|
||||
if (!order.value) return;
|
||||
// 示例:调用后端接口(兼容性判断)
|
||||
(async () => {
|
||||
try {
|
||||
if (sheep && typeof sheep.request === 'function') {
|
||||
await sheep.request({
|
||||
url: '/order/confirmArrive',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id: order.value.id
|
||||
}
|
||||
});
|
||||
}
|
||||
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast('已确认到店');
|
||||
// 可在此刷新订单状态
|
||||
// 确认到店
|
||||
async function confirmArrive() {
|
||||
if (!order.value || !orderId.value) return;
|
||||
|
||||
try {
|
||||
uni.showLoading({ title: '提交中...' });
|
||||
const res = await DeliveryOrderApi.riderConfirmArrival(orderId.value);
|
||||
uni.hideLoading();
|
||||
|
||||
if (res.code === 0 && res.data === true) {
|
||||
sheep.$helper.toast('已确认到店');
|
||||
// 刷新订单状态
|
||||
fetchOrder();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast('确认失败,请重试');
|
||||
} else {
|
||||
sheep.$helper.toast(res.msg || '确认到店失败');
|
||||
}
|
||||
})();
|
||||
} catch (e) {
|
||||
uni.hideLoading();
|
||||
console.error('confirmArrive error', e);
|
||||
sheep.$helper.toast('确认失败,请重试');
|
||||
}
|
||||
}
|
||||
|
||||
// 确认取餐
|
||||
async function confirmPickup() {
|
||||
if (!order.value || !orderId.value) return;
|
||||
|
||||
try {
|
||||
uni.showLoading({ title: '提交中...' });
|
||||
const res = await DeliveryOrderApi.riderConfirmPickup(orderId.value);
|
||||
uni.hideLoading();
|
||||
|
||||
if (res.code === 0 && res.data === true) {
|
||||
sheep.$helper.toast('已确认取餐');
|
||||
// 刷新订单状态
|
||||
fetchOrder();
|
||||
} else {
|
||||
sheep.$helper.toast(res.msg || '确认取餐失败');
|
||||
}
|
||||
} catch (e) {
|
||||
uni.hideLoading();
|
||||
console.error('confirmPickup error', e);
|
||||
sheep.$helper.toast('确认失败,请重试');
|
||||
}
|
||||
}
|
||||
|
||||
// 送达交接点
|
||||
async function deliveryHandover() {
|
||||
if (!order.value || !orderId.value) return;
|
||||
|
||||
try {
|
||||
uni.showLoading({ title: '提交中...' });
|
||||
await DeliveryOrderApi.riderDeliveryHandover(orderId.value);
|
||||
uni.hideLoading();
|
||||
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast('已送达交接点');
|
||||
// 刷新订单状态
|
||||
fetchOrder();
|
||||
} catch (e) {
|
||||
console.error('deliveryHandover error', e);
|
||||
uni.hideLoading();
|
||||
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast('提交失败,请重试');
|
||||
}
|
||||
}
|
||||
|
||||
//跳转交接记录
|
||||
@@ -329,7 +401,7 @@
|
||||
}
|
||||
|
||||
.map-area {
|
||||
height: 360rpx;
|
||||
height: 560rpx;
|
||||
background: #f3f3f3;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
@@ -351,26 +423,32 @@
|
||||
position: absolute;
|
||||
left: 20rpx;
|
||||
right: 20rpx;
|
||||
bottom: 20rpx;
|
||||
bottom: 45rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.eta {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
padding: 10rpx 14rpx;
|
||||
padding: 0rpx 14rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
// line-height: 32rpx;
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
background: #fff;
|
||||
padding: 10rpx 14rpx;
|
||||
padding: 0rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
color: #1e9fff;
|
||||
border: 1rpx solid #dbeeff;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
// line-height: 32rpx;
|
||||
}
|
||||
|
||||
.content {
|
||||
@@ -578,6 +656,10 @@
|
||||
background: #1e9fff;
|
||||
}
|
||||
|
||||
.btn.handover {
|
||||
background: #2ecc71;
|
||||
}
|
||||
|
||||
.remind-popup {
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user