app
MrShi
2026-04-27 e56792f78e4df0df2f12552d1a61dd8ca1db5c67
app/pages/order-detail/order-detail.vue
@@ -1,14 +1,17 @@
<template>
   <view class="order-detail-page">
   <view class="order-detail-page" v-if="orderDetail">
      <view v-if="!showMapStatus" class="order-detail-page__simple-nav" :style="{ paddingTop: statusBarHeight + 'px' }">
         <view class="order-detail-page__simple-nav-inner">
            <text class="order-detail-page__simple-nav-title">{{ statusTextMap[orderDetail.status] || '订单详情' }}</text>
            <u-icon name="arrow-left" color="#ffffff" size="20" @click="handleBack"></u-icon>
            <text class="order-detail-page__simple-nav-title">订单详情</text>
            <u-icon name="arrow-left" color="#106EFA" size="20"></u-icon>
         </view>
      </view>
      <view v-if="showMapStatus" class="order-detail-page__fixed-top">
         <view class="order-detail-page__map-wrap">
            <map
               id="orderDetailMap"
               class="order-detail-page__map"
               :latitude="mapData.center.latitude"
               :longitude="mapData.center.longitude"
@@ -20,7 +23,7 @@
               :enable-scroll="true"
            ></map>
            <view class="order-detail-page__map-bubble">
               <text class="order-detail-page__map-bubble-text">剩余3.2km,约4分钟</text>
               <text class="order-detail-page__map-bubble-text">{{ distance > 0 ? `剩余${(distance / 1000).toFixed(1)}km,约${Math.ceil(duration / 60)}分钟` : '正在获取位置信息...' }}</text>
            </view>
         </view>
@@ -30,8 +33,8 @@
               <text class="order-detail-page__status-title">{{ statusTextMap[orderDetail.status] || '待取货' }}</text>
            </view>
            <view class="order-detail-page__status-right">
               <text v-if="orderDetail.status === 3" class="order-detail-page__status-cancel">取消订单</text>
               <text class="order-detail-page__status-no">#{{ orderIndex }}</text>
               <text v-if="orderDetail.status === 3" class="order-detail-page__status-cancel" @click="handleCancelOrder">取消订单</text>
               <text class="order-detail-page__status-no" v-if="orderIndex">#{{ orderIndex }}</text>
            </view>
         </view>
      </view>
@@ -42,8 +45,11 @@
               <view v-if="showMapStatus" class="order-detail-page__summary">
                  <view class="order-detail-page__summary-left">
                     <view class="order-detail-page__head-left">
                        <text class="order-detail-page__time">{{ orderDetail.remainMinutes }}</text>
                        <text class="order-detail-page__time-sub">分钟</text>
                        <template v-if="formattedRemainTime">
                           <text class="order-detail-page__time">{{ formattedRemainTime }}内</text>
                           <text class="order-detail-page__time-sub">送达</text>
                        </template>
                        <text class="order-detail-page__time" v-else>配送已超时,请尽快送达</text>
                     </view>
                     <view class="order-detail-page__tags">
@@ -54,8 +60,8 @@
                  </view>
                  <view class="order-detail-page__summary-right">
                     <text class="order-detail-page__price">¥{{ (orderDetail.driverFee / 100).toFixed(1) }}</text>
                     <text v-if="orderDetail.urgentAmount" class="order-detail-page__extra">含加急¥{{ orderDetail.urgentAmount / 100 }}</text>
                     <text class="order-detail-page__price">¥{{ orderDetail.platformRewardAmount ? (orderDetail.driverFee + orderDetail.platformRewardAmount) / 100 : (orderDetail.driverFee / 100).toFixed(2) }}</text>
                     <text v-if="orderDetail.platformRewardAmount" class="order-detail-page__extra">含加急¥{{ (orderDetail.platformRewardAmount / 100).toFixed(2) }}</text>
                  </view>
               </view>
@@ -72,44 +78,40 @@
                     <view class="order-detail-page__done-price-row">
                        <text class="order-detail-page__price">¥{{ (orderDetail.driverFee / 100).toFixed(1) }}</text>
                     </view>
                     <text v-if="orderDetail.urgentAmount" class="order-detail-page__extra">含加急¥{{ orderDetail.urgentAmount / 100 }}</text>
                     <text v-if="orderDetail.isUrgent === 1" class="order-detail-page__extra">含加急¥{{ orderDetail.urgentAmount / 100 }}</text>
                  </view>
               </view>
               <view class="order-detail-page__route-list">
                  <view class="order-detail-page__route-item">
                     <view class="order-detail-page__route-left">
                        <text class="order-detail-page__distance-top">{{ orderDetail.takeDistance }}</text>
                        <text class="order-detail-page__distance-unit">m</text>
                        <view class="order-detail-page__route-badge order-detail-page__route-badge--take">取</view>
                        <view class="order-detail-page__route-divider"></view>
                     </view>
                     <view class="order-detail-page__route-main">
                        <view class="order-detail-page__route-texts">
                           <text class="order-detail-page__route-title">{{ orderDetail.takeName }}</text>
                           <text class="order-detail-page__route-desc">{{ orderDetail.depositShopAddress }}</text>
                        </view>
                        <view class="order-detail-page__route-actions">
                           <image class="order-detail-page__route-icon" src="/static/image/ic_c1all@2x.png" mode="aspectFit"></image>
                           <image class="order-detail-page__route-icon" src="/static/image/ic_daohang@2x.png" mode="aspectFit"></image>
                        </view>
                     </view>
                  </view>
                  <view class="order-detail-page__route-item order-detail-page__route-item--end">
                     <view class="order-detail-page__route-left">
                        <view class="order-detail-page__route-pin"></view>
                        <view class="order-detail-page__route-divider order-detail-page__route-divider--light"></view>
                        <text class="order-detail-page__distance-top">{{ orderDetail.depositDistance }}</text>
                        <text class="order-detail-page__distance-unit"></text>
                     </view>
                     <view class="order-detail-page__route-main">
                        <view class="order-detail-page__route-texts">
                           <text class="order-detail-page__route-title">{{ orderDetail.depositShopName }}</text>
                           <text class="order-detail-page__route-desc">{{ orderDetail.depositShopAddress }}</text>
                        </view>
                        <view class="order-detail-page__route-actions">
                           <image class="order-detail-page__route-icon" src="/static/image/ic_c1all@2x.png" mode="aspectFit"></image>
                           <image class="order-detail-page__route-icon" src="/static/image/ic_daohang@2x.png" mode="aspectFit"></image>
                        <view class="order-detail-page__route-actions" v-if="![7,99].includes(orderDetail.status)">
                           <image class="order-detail-page__route-icon" src="/static/image/ic_c1all@2x.png" mode="aspectFit" v-if="[3,4,5].includes(orderDetail.status) && orderDetail.depositShopPhone" @click="makeShopCall('deposit')"></image>
                           <image class="order-detail-page__route-icon" src="/static/image/ic_daohang@2x.png" mode="aspectFit" @click="navigateToAddress('deposit')"></image>
                        </view>
                     </view>
                  </view>
                  <view class="order-detail-page__route-item order-detail-page__route-item--end" style="padding-bottom: 30rpx; box-sizing: border-box; border-bottom: 1px solid #E5E5E5;">
                     <view class="order-detail-page__route-left">
                        <view class="order-detail-page__route-badge order-detail-page__route-badge--send">送</view>
                     </view>
                     <view class="order-detail-page__route-main">
                        <view class="order-detail-page__route-texts">
                           <text class="order-detail-page__route-title">{{ orderDetail.takeName }}</text>
                           <text class="order-detail-page__route-desc">{{ orderDetail.takeAddress }}</text>
                        </view>
                        <view class="order-detail-page__route-actions" v-if="![7,99].includes(orderDetail.status)">
                           <image class="order-detail-page__route-icon" src="/static/image/ic_c1all@2x.png" mode="aspectFit" v-if="[4,5].includes(orderDetail.status) && orderDetail.takeContactPhone" @click="makeShopCall('take')"></image>
                           <image class="order-detail-page__route-icon" src="/static/image/ic_daohang@2x.png" mode="aspectFit" @click="navigateToAddress('take')"></image>
                        </view>
                     </view>
                  </view>
@@ -124,26 +126,28 @@
               </view>
            </view>
            <view class="order-detail-page__section">
               <text class="order-detail-page__section-title">客户信息</text>
               <view class="order-detail-page__row-info">
                  <text class="order-detail-page__row-text">{{ orderDetail.contactPhone }}</text>
                  <image class="order-detail-page__row-icon" src="/static/image/ic_call@2x.png" mode="aspectFit" @click="makePhoneCall"></image>
               </view>
               <view v-if="orderDetail.status === 7" class="order-detail-page__comment-card">
                  <text class="order-detail-page__comment-title">客户已评价:</text>
                  <view class="order-detail-page__comment-score">
                     <text class="order-detail-page__comment-star">★</text>
                     <text class="order-detail-page__comment-score-text">4.5</text>
            <view class="order-detail-page__section" style="margin-top: 30rpx; padding: 0 30rpx; box-sizing: border-box;">
               <view style="width: 100%; padding-bottom: 30rpx; box-sizing: border-box; border-bottom: 1px solid #E5E5E5;">
                  <text class="order-detail-page__section-title">客户信息</text>
                  <view class="order-detail-page__row-info">
                     <text class="order-detail-page__row-text">{{ orderDetail.customerInfo || '' }}</text>
                     <!-- <image class="order-detail-page__row-icon" v-if="[3,4].includes(orderDetail.status)" src="/static/image/ic_call@2x.png" mode="aspectFit" @click="makePhoneCall"></image> -->
                  </view>
                  <text class="order-detail-page__comment-content">送的很快,东西完好无损</text>
                  <image class="order-detail-page__comment-image" src="/static/logo.png" mode="aspectFill"></image>
                  <view v-if="orderDetail.commentStatus === 1" class="order-detail-page__comment-card">
                     <text class="order-detail-page__comment-title">客户已评价:</text>
                     <view class="order-detail-page__comment-score">
                        <text class="order-detail-page__comment-star">★</text>
                        <text class="order-detail-page__comment-score-text">4.5</text>
                     </view>
                     <text class="order-detail-page__comment-content">{{ orderDetail.commentContent || '' }}</text>
                     <image class="order-detail-page__comment-image" src="/static/logo.png" mode="aspectFill"></image>
                  </view>
               </view>
            </view>
            <view class="order-detail-page__section">
            <view class="order-detail-page__section" style="margin-top: 30rpx; padding: 0 30rpx; box-sizing: border-box;">
               <text class="order-detail-page__section-title">物品清单(共{{ goodsList.length }}件)</text>
               <view class="order-detail-page__goods-list">
               <view class="order-detail-page__goods-list" style="width: 100%; padding-bottom: 30rpx; box-sizing: border-box; border-bottom: 1px solid #E5E5E5;">
                  <view v-for="item in goodsList" :key="item.name" class="order-detail-page__goods-item">
                     <text class="order-detail-page__goods-name" :style="item.isOversized === 1 ? 'color: #FF0020;' : ''">{{ item.name }}</text>
                     <text class="order-detail-page__goods-count">x{{ item.quantity }}</text>
@@ -151,32 +155,48 @@
               </view>
            </view>
            <view class="order-detail-page__section">
            <view class="order-detail-page__section" style="margin-top: 30rpx; padding: 0 30rpx; box-sizing: border-box;">
               <text class="order-detail-page__section-title">物品信息</text>
               <text class="order-detail-page__goods-category">文件</text>
               <text class="order-detail-page__goods-category">{{ orderDetail.goodTypeName || '' }}</text>
               <view class="order-detail-page__photos">
                  <image v-for="(item, index) in photos" :key="index" class="order-detail-page__photo" :src="item" mode="aspectFill"></image>
                  <view class="order-detail-page__photo" v-for="(item, index) in photos" :key="index">
                     <image :src="item" mode="heightFix" @click="previewImage(item)"></image>
                  </view>
               </view>
            </view>
            <view class="order-detail-page__section order-detail-page__section--last">
            <view style="width: 100%; height: 30rpx; background-color: #f9f9f9;"></view>
            <view class="order-detail-page__section order-detail-page__section--last" style="margin-top: 30rpx; padding: 0 30rpx; box-sizing: border-box;">
               <text class="order-detail-page__section-title">订单信息</text>
               <view class="order-detail-page__detail-list">
                  <view class="order-detail-page__detail-item">
                     <text class="order-detail-page__detail-label">订单编号:</text>
                     <text class="order-detail-page__detail-value">{{ orderDetail.code }}</text>
                     <text class="order-detail-page__detail-value">{{ orderDetail.code || '-' }}</text>
                  </view>
                  <view v-if="orderDetail.createTime" class="order-detail-page__detail-item">
                     <text class="order-detail-page__detail-label">下单时间:</text>
                     <text class="order-detail-page__detail-value">{{ orderDetail.createTime }}</text>
                     <text class="order-detail-page__detail-value">{{ orderDetail.createTime || '-' }}</text>
                  </view>
                  <view v-if="orderDetail.acceptTime" class="order-detail-page__detail-item">
                  <view v-if="[3,4,5,6,7,99].includes(orderDetail.status)" class="order-detail-page__detail-item">
                     <text class="order-detail-page__detail-label">接单时间:</text>
                     <text class="order-detail-page__detail-value">{{ orderDetail.acceptTime }}</text>
                     <text class="order-detail-page__detail-value">{{ orderDetail.acceptTime || '-' }}</text>
                  </view>
                  <view class="order-detail-page__detail-item">
                  <view v-if="[3,4,5,6,7,99].includes(orderDetail.status)" class="order-detail-page__detail-item">
                     <text class="order-detail-page__detail-label">订单备注:</text>
                     <text class="order-detail-page__detail-value">{{ orderDetail.remark || '-' }}</text>
                  </view>
                  <view v-if="[4,5,6,7,99].includes(orderDetail.status)" class="order-detail-page__detail-item">
                     <text class="order-detail-page__detail-label">取货时间:</text>
                     <text class="order-detail-page__detail-value">{{ orderDetail.driverTakeTime || '-' }}</text>
                  </view>
                  <view v-if="[5,6,7,99].includes(orderDetail.status)" class="order-detail-page__detail-item">
                     <text class="order-detail-page__detail-label">完成时间:</text>
                     <text class="order-detail-page__detail-value">{{ orderDetail.finishTime || '-' }}</text>
                  </view>
                  <view v-if="orderDetail.isEvaluated === 1" class="order-detail-page__detail-item">
                     <text class="order-detail-page__detail-label">评价时间:</text>
                     <text class="order-detail-page__detail-value">{{ orderDetail.commentTime || '-' }}</text>
                  </view>
               </view>
            </view>
@@ -184,17 +204,47 @@
      </scroll-view>
      <view v-if="footerButtons.length" class="order-detail-page__footer">
         <button
            v-for="button in footerButtons"
            :key="button.text"
            class="order-detail-page__footer-btn"
            :class="button.primary ? 'order-detail-page__footer-btn--primary' : 'order-detail-page__footer-btn--ghost'"
            hover-class="order-detail-page__footer-btn--hover"
            @click="handleFooterAction(button)"
         >
            {{ button.text }}
         </button>
         <view></view>
         <view style="display: flex; align-items: center; gap: 20rpx;">
            <button
               v-for="button in footerButtons"
               :key="button.text"
               class="order-detail-page__footer-btn"
               :class="button.primary ? 'order-detail-page__footer-btn--primary' : 'order-detail-page__footer-btn--ghost'"
               hover-class="order-detail-page__footer-btn--hover"
               @click="handleFooterAction(button)"
            >
               {{ button.text }}
            </button>
         </view>
      </view>
      <u-modal
         :show="showCancelModal"
         showCancelButton
         @cancel="showCancelModal = false"
         cancelColor="#666666"
         confirmColor="#0055FF"
         title="取消订单确认"
         @confirm="confirmCancelOrder">
         <view style="text-align: center;color: #333333;font-size: 28rpx;font-weight: 400;">
            您今日还可取消 {{ cancelRemain }} 次订单,次数用尽后今日将无法接单,是否确认取消?
         </view>
      </u-modal>
      <u-modal
         :show="showGrabModal"
         showCancelButton
         @cancel="showGrabModal = false"
         cancelColor="#666666"
         confirmColor="#0055FF"
         title="温馨提示"
         @confirm="confirmGrabOrder">
         <view style="text-align: center;color: #333333;font-size: 28rpx;font-weight: 400;">
            {{ orderDetail && orderDetail.hasOversized === 1 ? '本订单有特大件尺寸行李,请确认是否继续抢单?' : '是否确认接单?' }}
         </view>
      </u-modal>
      <u-popup :show="showPhotoPopup" round="20" mode="bottom" @close="closePhotoPopup">
         <view class="photo-popup">
@@ -237,22 +287,32 @@
</template>
<script>
import image from 'uview-ui/libs/config/props/image';
   export default {
      data() {
         return {
            orderId: null,
            orderIndex: null,
            orderDetail: {},
            orderDetail: null,
            statusBarHeight: 0,
            topFixedHeight: 0,
            showPhotoPopup: false,
            photoPopupMode: '',
            photoRemark: '',
            uploadedPhotos: [],
            showCancelModal: false,
            cancelRemain: 0,
            showGrabModal: false,
            currentLocation: null,
            routePoints: [],
            distance: 0,
            duration: 0,
            statusTextMap: {
               2: '待接单',
               3: '待取货',
               4: '配送中',
               5: '已送达',
               7: '已完成',
               99: '已取消'
            },
@@ -261,13 +321,68 @@
         }
      },
      computed: {
         formattedRemainTime() {
            const minutes = this.orderDetail.remainMinutes
            if (!minutes) return null
            if (minutes >= 60) {
               const hours = Math.floor(minutes / 60)
               const mins = minutes % 60
               return mins > 0 ? `${hours}小时${mins}分钟` : `${hours}小时`
            }
            return `${minutes}分钟`
         },
         showMapStatus() {
            return this.orderDetail.status === 2 || this.orderDetail.status === 3 || this.orderDetail.status === 4
            return this.orderDetail.status === 3 || this.orderDetail.status === 4
         },
         mapData() {
            const startPoint = { latitude: 31.829512, longitude: 117.239211 }
            const endPoint = { latitude: 31.841268, longitude: 117.278695 }
            const routePoints = [
            const startPoint = this.currentLocation || { latitude: 31.829512, longitude: 117.239211 }
            const hasEndPoint = this.orderDetail.navigateLat && this.orderDetail.navigateLng
            const endPoint = hasEndPoint
               ? { latitude: this.orderDetail.navigateLng, longitude: this.orderDetail.navigateLat }
               : { latitude: 31.841268, longitude: 117.278695 }
            let center
            let scale = 12
            if (this.currentLocation && hasEndPoint) {
               const latSpan = Math.abs(this.currentLocation.latitude - endPoint.latitude)
               const lngSpan = Math.abs(this.currentLocation.longitude - endPoint.longitude)
               const maxSpan = Math.max(latSpan, lngSpan)
               center = {
                  latitude: (this.currentLocation.latitude + endPoint.latitude) / 2,
                  longitude: (this.currentLocation.longitude + endPoint.longitude) / 2
               }
               if (maxSpan > 0.3) {
                  scale = 9
               } else if (maxSpan > 0.15) {
                  scale = 10
               } else if (maxSpan > 0.08) {
                  scale = 11
               } else if (maxSpan > 0.04) {
                  scale = 12
               } else if (maxSpan > 0.02) {
                  scale = 13
               } else if (maxSpan > 0.01) {
                  scale = 14
               } else if (maxSpan > 0.005) {
                  scale = 15
               } else if (maxSpan > 0.002) {
                  scale = 16
               } else {
                  scale = 17
               }
            } else if (this.currentLocation) {
               center = this.currentLocation
            } else {
               center = { latitude: 31.83539, longitude: 117.258953 }
            }
            const markers = [
               { id: 1, latitude: startPoint.latitude, longitude: startPoint.longitude, iconPath: '/static/image/start.png', width: 32, height: 38, anchor: { x: 0.5, y: 1 } },
               { id: 2, latitude: endPoint.latitude, longitude: endPoint.longitude, iconPath: '/static/image/end.png', width: 32, height: 38, anchor: { x: 0.5, y: 1 } },
               { id: 3, latitude: startPoint.latitude, longitude: startPoint.longitude, iconPath: '/static/image/dizhi.png', width: 12, height: 12, anchor: { x: 0.5, y: 0.5 } }
            ]
            const routePoints = this.routePoints.length > 0 ? this.routePoints : [
               startPoint,
               { latitude: 31.831624, longitude: 117.247836 },
               { latitude: 31.834918, longitude: 117.255467 },
@@ -276,25 +391,25 @@
               endPoint
            ]
            return {
               center: { latitude: 31.83539, longitude: 117.258953 },
               markers: [
                  { id: 1, latitude: startPoint.latitude, longitude: startPoint.longitude, iconPath: '/static/image/map_marker_start.svg', width: 32, height: 38, anchor: { x: 0.5, y: 1 } },
                  { id: 2, latitude: endPoint.latitude, longitude: endPoint.longitude, iconPath: '/static/image/map_marker_end.svg', width: 32, height: 38, anchor: { x: 0.5, y: 1 } }
            const result = {
               center,
               markers,
               polyline: this.routePoints.length > 0 ? [
                  { points: routePoints, color: '#05be76', width: 25, arrowLine: true, dottedLine: false }
               ] : [
                  { points: routePoints, color: '#05be76', width: 25, arrowLine: true, dottedLine: true }
               ],
               polyline: [
                  { points: routePoints, color: '#00c67a', width: 20, arrowLine: true, dottedLine: true, borderColor: '#469972', borderWidth: 10 }
               ],
               includePoints: routePoints,
               scale: 12
               includePoints: [startPoint, endPoint],
               scale
            }
            return result
         },
         bodyStyle() {
            const footerHeight = uni.upx2px(116)
            const simpleNavHeight = this.statusBarHeight + uni.upx2px(88)
            return {
               paddingTop: (this.showMapStatus ? this.topFixedHeight : simpleNavHeight) + 'px',
               height: `calc(100vh - ${this.footerButtons.length ? footerHeight : 0}px)`
               height: `calc(100vh - ${this.footerButtons.length ? footerHeight + 20 : 20}px)`
            }
         },
         footerButtons() {
@@ -338,34 +453,139 @@
         const systemInfo = uni.getSystemInfoSync()
         this.statusBarHeight = systemInfo.statusBarHeight || 0
         this.orderId = options.id || pageOptions.id
         this.orderIndex = options.index || pageOptions.index
         this.orderIndex = options.index
         this.topFixedHeight = uni.upx2px(500 + 92)
         if (this.orderId) {
            this.getOrderDetail()
         }
      },
      methods: {
         handleBack() {
            uni.navigateBack({ delta: 1 });
         },
         getOrderDetail() {
            console.log('getOrderDetail', this.orderId)
            this.$u.api.orderDetail({ orderId: this.orderId }).then(res => {
               console.log(res)
               if (res.code === 200) {
                  console.log('orderDetail:', res.data)
                  this.orderDetail = res.data
                  console.log(this.orderDetail)
                  this.goodsList = res.data.items || []
                  this.photos = res.data.photos || []
                  this.photos = res.data.orderImages || []
                  if ((this.orderDetail.status === 3 || this.orderDetail.status === 4) && this.orderDetail.navigateLat && this.orderDetail.navigateLng) {
                     this.getCurrentLocation()
                  } else {
                     console.log('Skipping getCurrentLocation - status or coordinates not available')
                  }
               }
            }).catch(err => {
               console.log('err', err)
            })
         },
         makePhoneCall() {
            if (this.orderDetail.contactPhone) {
         getCurrentLocation() {
            uni.getLocation({
               type: 'gcj02',
               success: (res) => {
                  this.currentLocation = {
                     latitude: res.latitude,
                     longitude: res.longitude
                  }
                  this.getRoutePlan()
               },
               fail: (err) => {
                  console.log('获取位置失败', err)
               }
            })
         },
         getRoutePlan() {
            if (!this.currentLocation || !this.orderDetail.navigateLat || !this.orderDetail.navigateLng) {
               console.log('Skipping route plan - missing data')
               return
            }
            const from = `${this.currentLocation.latitude},${this.currentLocation.longitude}`
            const to = `${this.orderDetail.navigateLng},${this.orderDetail.navigateLat}`
            this.$u.api.directionInfo({
               from,
               to,
               mode: 'driving'
            }).then(res => {
               console.log('directionInfo success:', res)
               if (res && res.paths && res.paths.length > 0) {
                  const path = res.paths[0]
                  this.distance = path.distance
                  this.duration = path.duration
                  const points = []
                  path.steps.forEach(step => {
                     const polylineStr = step.polyline
                     const coordinates = polylineStr.split(';')
                     coordinates.forEach(coord => {
                        const [lng, lat] = coord.split(',')
                        points.push({
                           latitude: parseFloat(lat),
                           longitude: parseFloat(lng)
                        })
                     })
                  })
                  this.routePoints = points
                  this.$forceUpdate()
               } else {
                  console.log('No route data returned:', res)
               }
            }).catch(err => {
               console.log('路径规划失败', err)
            })
         },
         // makePhoneCall() {
         //    if (this.orderDetail.contactPhone) {
         //       uni.makePhoneCall({
         //          phoneNumber: this.orderDetail.contactPhone
         //       })
         //    }
         // },
         makeShopCall(type) {
            const phone = type === 'take' ? this.orderDetail.takeContactPhone : this.orderDetail.depositShopPhone
            if (phone) {
               uni.makePhoneCall({
                  phoneNumber: this.orderDetail.contactPhone
                  phoneNumber: phone
               })
            }
         },
         navigateToAddress(type) {
            let latitude, longitude, name, address
            if (type === 'deposit') {
               latitude = this.orderDetail.depositShopLat
               longitude = this.orderDetail.depositShopLng
               name = this.orderDetail.depositShopName
               address = this.orderDetail.depositShopAddress
            } else {
               latitude = this.orderDetail.takeLat
               longitude = this.orderDetail.takeLng
               name = this.orderDetail.takeName
               address = this.orderDetail.takeAddress
            }
            if (!latitude || !longitude) {
               uni.showToast({ title: '地址坐标缺失', icon: 'none' })
               return
            }
            uni.openLocation({
               latitude,
               longitude,
               name,
               address,
               success: () => {},
               fail: (err) => {
                  uni.showToast({ title: '打开地图失败', icon: 'none' })
                  console.error('openLocation fail:', err)
               }
            })
         },
         previewImage(current) {
            uni.previewImage({
               current,
               urls: this.photos
            })
         },
         handleFooterAction(button) {
@@ -390,43 +610,42 @@
            }
         },
         handleCancelOrder() {
            uni.showModal({
               title: '温馨提示',
               content: '确定要取消订单吗?',
               confirmColor: '#0055FF',
               cancelColor: '#666666',
               success: (res) => {
                  if (res.confirm) {
                     this.$u.api.cancelOrder({ orderId: this.orderId }).then(res => {
                        if (res.code === 200) {
                           uni.showToast({ title: '取消成功', icon: 'success' })
                           this.getOrderDetail()
                        } else {
                           uni.showToast({ title: res.msg || '取消失败', icon: 'none' })
                        }
                     })
                  }
            this.$u.api.cancelLimit().then(res => {
               if (res.code === 200) {
                  this.cancelRemain = res.data.remain
               }
            }).finally(() => {
               this.showCancelModal = true
            })
         },
         confirmCancelOrder() {
            this.$u.api.cancelOrder({ orderId: this.orderId }).then(res => {
               this.showCancelModal = false
               if (res.code === 200) {
                  uni.showToast({ title: '取消成功', icon: 'success' })
                  this.getOrderDetail()
               }
            }).finally(() => {
               this.showCancelModal = false
            })
         },
         handleGrabOrder() {
            uni.showModal({
               title: '温馨提示',
               content: '是否确认接单?',
               confirmColor: '#0055FF',
               cancelColor: '#666666',
               success: (res) => {
                  if (res.confirm) {
                     this.$u.api.grabOrder({ orderId: this.orderId }).then(res => {
                        if (res.code === 200) {
                           uni.showToast({ title: '接单成功', icon: 'success' })
                           uni.navigateBack()
                        } else {
                           uni.showToast({ title: res.msg || '接单失败', icon: 'none' })
                        }
                     })
                  }
            this.showGrabModal = true
         },
         confirmGrabOrder() {
            this.$u.api.grabOrder({ orderId: this.orderId }).then(res => {
               this.showGrabModal = false
               if (res.code === 200) {
                  uni.showToast({ title: '接单成功', icon: 'success' })
                  this.getOrderDetail()
                  setTimeout(() => {
                     uni.navigateBack()
                  }, 1500)
               } else {
                  uni.showToast({ title: res.msg || '接单失败', icon: 'none' })
               }
            }).catch(() => {
               this.showGrabModal = false
            })
         },
         closePhotoPopup() {
@@ -477,7 +696,6 @@
            })
            Promise.all(uploadTasks).then(images => {
               console.log(images)
               const api = this.photoPopupMode === 'deliver' ? 'confirmDeliver' : 'confirmPickup'
               const params = {
                  images: images.map(img => img.imgaddr),
@@ -505,9 +723,7 @@
<style lang="scss" scoped>
   .order-detail-page {
      height: 100vh;
      background: #f6f8fc;
      overflow: hidden;
      background: #ffffff;
      &__simple-nav {
         position: fixed;
@@ -522,7 +738,9 @@
         height: 88rpx;
         display: flex;
         align-items: center;
         padding: 0 24rpx;
         justify-content: space-between;
         padding: 0 30rpx;
         box-sizing: border-box;
      }
      &__simple-nav-title {
@@ -544,14 +762,15 @@
         position: relative;
         margin: 0;
         height: 500rpx;
         width: 750rpx;
         border-radius: 0;
         overflow: hidden;
         background: #dbe8ff;
      }
      &__map {
         width: 100%;
         height: 100%;
         width: 750rpx;
         height: 500rpx;
      }
      &__map-bubble {
@@ -615,13 +834,11 @@
      }
      &__content {
         padding: 16rpx 0 calc(env(safe-area-inset-bottom) + 26rpx);
         // padding: 16rpx 0 calc(env(safe-area-inset-bottom) + 26rpx);
      }
      &__section {
         margin: 16rpx 20rpx 0;
         padding: 26rpx 22rpx;
         border-radius: 20rpx;
         // margin: 16rpx 20rpx 0;
         background: #ffffff;
         &--main {
@@ -637,13 +854,18 @@
         display: flex;
         justify-content: space-between;
         align-items: flex-start;
         padding: 30rpx;
         box-sizing: border-box;
      }
      &__done-summary {
         padding: 30rpx;
         box-sizing: border-box;
         display: flex;
         justify-content: space-between;
         align-items: flex-start;
         gap: 20rpx;
         background: #F6F9FF;
      }
      &__done-summary-left {
@@ -699,9 +921,9 @@
      }
      &__time {
         font-size: 42rpx;
         font-weight: 700;
         color: #ff972c;
         font-size: 34rpx;
         font-weight: 600;
         color: #FA8010;
      }
      &__time-sub,
@@ -722,7 +944,7 @@
      }
      &__price {
         font-size: 44rpx;
         font-size: 26rpx;
         font-weight: 700;
         color: #ff4132;
      }
@@ -751,22 +973,25 @@
      &__tag-text {
         padding: 5rpx 12rpx;
         border-radius: 8rpx;
         background: #ff9c45;
         background: linear-gradient(319deg, #EE9D0E 0%, #FF4E4E 100%);
         font-size: 22rpx;
         font-weight: 600;
         color: #ffffff;
      }
      &__route-list {
         margin-top: 22rpx;
         margin-top: 36rpx;
         padding: 0 30rpx;
         box-sizing: border-box;
      }
      &__route-item {
         display: flex;
         align-items: flex-start;
         align-items: stretch;
         position: relative;
         &--end {
            margin-top: 24rpx;
            margin-top: 20rpx;
         }
      }
@@ -776,38 +1001,37 @@
         flex-direction: column;
         align-items: center;
         flex-shrink: 0;
         position: relative;
      }
      &__distance-top {
         font-size: 28rpx;
      &__route-badge {
         width: 44rpx;
         height: 44rpx;
         border-radius: 50%;
         display: flex;
         align-items: center;
         justify-content: center;
         font-size: 24rpx;
         font-weight: 600;
         color: #515866;
      }
         color: #ffffff;
         position: relative;
         z-index: 1;
      &__distance-unit {
         font-size: 22rpx;
         color: #939aa6;
      }
         &--take {
            background: #10B2FA;
         }
      &__route-divider {
         width: 4rpx;
         height: 42rpx;
         margin-top: 8rpx;
         border-radius: 999rpx;
         background: #d7dbe2;
         &--light {
            height: 18rpx;
            margin: 8rpx 0;
         &--send {
            background: #FA8010;
         }
      }
      &__route-pin {
         width: 18rpx;
         height: 18rpx;
         margin-top: 4rpx;
         border-radius: 50%;
         background: #888f9b;
      &__route-divider {
         position: absolute;
         top: 64rpx;
         bottom: 0;
         width: 0;
         border-left: 2rpx dashed #d7dbe2;
      }
      &__route-main {
@@ -815,6 +1039,7 @@
         display: flex;
         justify-content: space-between;
         gap: 18rpx;
         margin-left: 10rpx;
      }
      &__route-texts {
@@ -824,16 +1049,19 @@
      &__route-title {
         display: block;
         font-size: 38rpx;
         font-weight: 700;
         font-weight: 600;
         font-size: 34rpx;
         color: #222222;
         line-height: 1.3;
         color: #2b3139;
      }
      &__route-desc {
         display: block;
         margin-top: 8rpx;
         line-height: 1.5;
         font-weight: 400;
         font-size: 26rpx;
         color: #999999;
      }
      &__route-actions {
@@ -853,7 +1081,7 @@
         display: flex;
         flex-direction: column;
         align-items: center;
         padding-top: 30rpx;
         margin-top: 30rpx;
      }
      &__qrcode-box {
@@ -871,14 +1099,17 @@
      }
      &__qrcode-value {
         margin-top: 16rpx;
         font-size: 40rpx;
         font-weight: 700;
         color: #303640;
         margin-top: 32rpx;
         font-weight: 600;
         font-size: 36rpx;
         color: #222222;
      }
      &__qrcode-label {
         margin-top: 6rpx;
         margin-top: 12rpx;
         font-weight: 400;
         font-size: 26rpx;
         color: #999999;
      }
      &__section-title {
@@ -968,14 +1199,23 @@
      &__photos {
         display: flex;
         gap: 16rpx;
         margin-top: 18rpx;
         flex-wrap: wrap;
         gap: 20rpx;
         margin-top: 30rpx;
         padding-bottom: 30rpx;
         box-sizing: border-box;
      }
      &__photo {
         width: 92rpx;
         height: 92rpx;
         border-radius: 10rpx;
         width: 120rpx;
         height: 120rpx;
         border-radius: 8rpx;
         overflow: hidden;
         image {
            width: 100%;
            height: 100%;
         }
      }
      &__detail-label {
@@ -992,7 +1232,7 @@
         right: 0;
         bottom: 0;
         display: flex;
         justify-content: flex-end;
         justify-content: space-between;
         gap: 20rpx;
         padding: 14rpx 20rpx calc(env(safe-area-inset-bottom) + 14rpx);
         background: #ffffff;
@@ -1103,9 +1343,8 @@
      &__upload-card,
      &__preview-card {
         position: relative;
         width: 160rpx;
         height: 160rpx;
         border-radius: 8rpx;
         width: 144rpx;
         height: 144rpx;
         overflow: hidden;
      }
@@ -1114,7 +1353,6 @@
         flex-direction: column;
         align-items: center;
         justify-content: center;
         border: 2rpx solid #ebedf2;
         background: #f8f9fb;
      }