Просмотр исходного кода

Merge branch 'zhongqi-delivery'

shish 7 месяцев назад
Родитель
Сommit
ec7b1dbfae

+ 1 - 7
ghsApp/src/admin/billing/affirm.vue

@@ -384,18 +384,12 @@ export default {
     };
     };
   },
   },
   onLoad (option) {
   onLoad (option) {
-
     this.book = this.option.book ? this.option.book : 0
     this.book = this.option.book ? this.option.book : 0
-
     this.kdType = option.kdType
     this.kdType = option.kdType
-
     let that = this
     let that = this
     this.initMerchantInfo().then((data) => {
     this.initMerchantInfo().then((data) => {
-
         uni.setNavigationBarTitle({ title: data.name })
         uni.setNavigationBarTitle({ title: data.name })
-
         that.currentShop = data.shopInfo
         that.currentShop = data.shopInfo
-
     })
     })
 
 
     //默认送货
     //默认送货
@@ -426,9 +420,9 @@ export default {
     }
     }
 	  //#endif
 	  //#endif
 
 
+    // 不主动加载花材,避免影响性能。有执行 takeItem 时会自动加载花材。
     this.listenScanItem()
     this.listenScanItem()
 
 
-
     getStaffInfo().then(res=>{
     getStaffInfo().then(res=>{
       if(res.code == 1){
       if(res.code == 1){
         let staffInfo = res.data.staff?res.data.staff:[]
         let staffInfo = res.data.staff?res.data.staff:[]

+ 1 - 1
ghsApp/src/admin/billing/index2.vue

@@ -233,7 +233,7 @@ export default {
 			let customName = this.option.customName ? this.option.customName : '';
 			let customName = this.option.customName ? this.option.customName : '';
 			let orderId = this.option.orderId  ? this.option.orderId : 0
 			let orderId = this.option.orderId  ? this.option.orderId : 0
 			let book = this.option.book ? this.option.book : 0
 			let book = this.option.book ? this.option.book : 0
-			this.$util.pageTo({ url: '/admin/billing/affirm',type:2,query: {customId:this.option.customId,customName:customName,orderId:orderId,book:book}})
+			this.$util.pageTo({ url: '/admin/billing/affirm', type:2, query: {customId:this.option.customId,customName:customName,orderId:orderId,book:book}})
 		}
 		}
 	}
 	}
 };
 };

+ 22 - 8
ghsApp/src/admin/delivery/allDelivery.vue

@@ -10,6 +10,7 @@
         <view class="address-content">
         <view class="address-content">
           <view class="address-title">{{ senderInfo.name || '门店' }}</view>
           <view class="address-title">{{ senderInfo.name || '门店' }}</view>
           <view class="address-detail">{{ senderInfo.address || '' }}</view>
           <view class="address-detail">{{ senderInfo.address || '' }}</view>
+          <view class="address-detail" style="color:#ada8a8;font-size:26upx;">货拉拉会用此地址,其它以跑腿平台设置的为准</view>
         </view>
         </view>
         <view class="address-arrow">
         <view class="address-arrow">
           <text class="iconfont iconxiangyou"></text>
           <text class="iconfont iconxiangyou"></text>
@@ -100,8 +101,13 @@
       <!-- 没有运力时显示提示 -->
       <!-- 没有运力时显示提示 -->
       <view class="no-delivery-list" v-if="deliveryList.length === 0">
       <view class="no-delivery-list" v-if="deliveryList.length === 0">
         <text class="no-delivery-icon">🛵</text>
         <text class="no-delivery-icon">🛵</text>
-        <text class="no-delivery-text">请点击"加载运力"按钮获取运力</text>
-        <text class="no-delivery-subtext">如无运力请稍后再试</text>
+        <template v-if="!hasAttemptedLoad">
+          <text class="no-delivery-text">请点击"加载运力"获取运力</text>
+          <text class="no-delivery-subtext">如无运力请稍后再试</text>
+        </template>
+        <template v-else>
+          <text class="no-delivery-text">没有可用配送,请击"加载运力"重试</text>
+        </template>
       </view>
       </view>
     </view>
     </view>
 
 
@@ -188,6 +194,8 @@ export default {
         },
         },
         // 加载运力的loading状态
         // 加载运力的loading状态
         isLoadingDelivery: false,
         isLoadingDelivery: false,
+        // 是否已经尝试加载过运力
+        hasAttemptedLoad: false,
         // 重量输入防抖定时器
         // 重量输入防抖定时器
         weightDebounceTimer: null,
         weightDebounceTimer: null,
     };
     };
@@ -203,12 +211,12 @@ export default {
       const item = this.selectedDeliveryItem;
       const item = this.selectedDeliveryItem;
       if (!item) {
       if (!item) {
           if (this.deliveryList && this.deliveryList.length > 0) {
           if (this.deliveryList && this.deliveryList.length > 0) {
-              return this.deliveryList[0].price === '暂无报价' ? '19.00' : this.deliveryList[0].price;
+              return this.deliveryList[0].price === '暂无报价' ? '0.00' : this.deliveryList[0].price;
           }
           }
           return '0.00';
           return '0.00';
       }
       }
       if (item.price === '暂无报价') {
       if (item.price === '暂无报价') {
-        return '19.00';
+        return '0.00';
       }
       }
       return item.price;
       return item.price;
     }
     }
@@ -294,6 +302,7 @@ export default {
     clearDeliveryList() {
     clearDeliveryList() {
       this.deliveryList = [];
       this.deliveryList = [];
       this.selectedDelivery = null;
       this.selectedDelivery = null;
+      this.hasAttemptedLoad = false;
     },
     },
 
 
     // 保存表单数据的当前值
     // 保存表单数据的当前值
@@ -347,6 +356,7 @@ export default {
       }).finally(() => {
       }).finally(() => {
         // 无论成功失败都要关闭加载状态
         // 无论成功失败都要关闭加载状态
         this.isLoadingDelivery = false;
         this.isLoadingDelivery = false;
+        this.hasAttemptedLoad = true;
       });
       });
     },
     },
     selectDelivery(item) {
     selectDelivery(item) {
@@ -398,7 +408,11 @@ export default {
     },
     },
     submitOrder() {
     submitOrder() {
       const selectedItem = this.selectedDeliveryItem;
       const selectedItem = this.selectedDeliveryItem;
-      if (!selectedItem || selectedItem.price === '暂无报价') {
+      if (!selectedItem) {
+          this.$msg('请选择一个配送方式');
+          return;
+      }
+      if(selectedItem.price === 0) {
           this.$msg('该平台暂无报价,请选择其他平台');
           this.$msg('该平台暂无报价,请选择其他平台');
           return;
           return;
       }
       }
@@ -519,15 +533,15 @@ export default {
       flex: 1;
       flex: 1;
 
 
       .address-title {
       .address-title {
-        font-size: 28upx;
+        font-size: 32upx;
         color: #333333;
         color: #333333;
         font-weight: 500;
         font-weight: 500;
         margin-bottom: 5upx;
         margin-bottom: 5upx;
       }
       }
 
 
       .address-detail {
       .address-detail {
-        font-size: 24upx;
-        color: #999999;
+        font-size: 28upx;
+        color: #7c7c7c;
       }
       }
     }
     }
 
 

+ 49 - 12
ghsApp/src/admin/delivery/components/TimePicker.vue

@@ -8,7 +8,7 @@
         </view>
         </view>
       </view>
       </view>
 
 
-      <picker-view v-if="visible" class="picker-view" :indicator-style="indicatorStyle" :value="pickerValue" @change="handleChange">
+      <picker-view v-if="visible" class="picker-view" :indicator-style="indicatorStyle" :value="pickerValue" @change="handleChange" :immediate-change="true">
         <picker-view-column>
         <picker-view-column>
           <view class="picker-item" v-for="(item, index) in days" :key="index">{{ item.label }}</view>
           <view class="picker-item" v-for="(item, index) in days" :key="index">{{ item.label }}</view>
         </picker-view-column>
         </picker-view-column>
@@ -38,6 +38,8 @@ export default {
     return {
     return {
       visible: false, // 控制picker-view的渲染
       visible: false, // 控制picker-view的渲染
       pickerValue: [0, 0, 0],
       pickerValue: [0, 0, 0],
+      tempPickerValue: [0, 0, 0], // 临时存储滚动过程中的值
+      debounceTimer: null,
       days: [],
       days: [],
       hours: [],
       hours: [],
       minutes: [],
       minutes: [],
@@ -73,6 +75,7 @@ export default {
         this.hours = this.generateHours(tomorrow, false);
         this.hours = this.generateHours(tomorrow, false);
         this.minutes = this.generateMinutes(tomorrow, false, this.hours[0].value);
         this.minutes = this.generateMinutes(tomorrow, false, this.hours[0].value);
         this.pickerValue = [1, 0, 0]; // Select "Tomorrow", first hour, first minute
         this.pickerValue = [1, 0, 0]; // Select "Tomorrow", first hour, first minute
+        this.tempPickerValue = [1, 0, 0];
         return;
         return;
       }
       }
 
 
@@ -85,6 +88,7 @@ export default {
       const initialMinuteIndex = 0;
       const initialMinuteIndex = 0;
       
       
       this.pickerValue = [0, initialHourIndex, initialMinuteIndex];
       this.pickerValue = [0, initialHourIndex, initialMinuteIndex];
+      this.tempPickerValue = [0, initialHourIndex, initialMinuteIndex];
     },
     },
 
 
     generateDays() {
     generateDays() {
@@ -135,7 +139,20 @@ export default {
     },
     },
 
 
     handleChange(e) {
     handleChange(e) {
-      const [dayIndex, hourIndex, minuteIndex] = e.detail.value;
+      const val = e.detail.value;
+      this.tempPickerValue = val;
+      
+      if (this.debounceTimer) {
+        clearTimeout(this.debounceTimer);
+      }
+      
+      this.debounceTimer = setTimeout(() => {
+        this.updatePickers(val);
+      }, 100);
+    },
+
+    updatePickers(val, isSync = false) {
+      const [dayIndex, hourIndex, minuteIndex] = val;
       const oldPickerValue = this.pickerValue;
       const oldPickerValue = this.pickerValue;
       
       
       const now = dayjs();
       const now = dayjs();
@@ -150,26 +167,46 @@ export default {
       // Day changed
       // Day changed
       if (oldPickerValue[0] !== dayIndex) {
       if (oldPickerValue[0] !== dayIndex) {
         newHours = this.generateHours(now, isToday);
         newHours = this.generateHours(now, isToday);
-        finalHourIndex = 0;
+        // 修正越界,尽量保持用户的选择,而不是强制归零
+        if (finalHourIndex >= newHours.length) {
+            finalHourIndex = 0;
+        }
       }
       }
       
       
-      // Hour changed (or day changed)
-      if (oldPickerValue[0] !== dayIndex || oldPickerValue[1] !== hourIndex) {
-        const selectedHour = newHours[finalHourIndex].value;
-        newMinutes = this.generateMinutes(now, isToday, selectedHour);
-        finalMinuteIndex = 0;
+      // Calculate selected hour based on current indices
+      const selectedHour = newHours[finalHourIndex] ? newHours[finalHourIndex].value : -1;
+
+      // Always regenerate minutes to ensure correctness (e.g. today/tomorrow switch, or hour switch)
+      // Optimization: we could check if generation parameters actually changed, but it's fast enough.
+      newMinutes = this.generateMinutes(now, isToday, selectedHour);
+      
+      // 修正越界
+      if (finalMinuteIndex >= newMinutes.length) {
+          finalMinuteIndex = 0;
       }
       }
       
       
       this.hours = newHours;
       this.hours = newHours;
       this.minutes = newMinutes;
       this.minutes = newMinutes;
+      this.debounceTimer = null;
 
 
-      // Use setTimeout to avoid visual glitch on picker reset
-      setTimeout(() => {
-        this.pickerValue = [dayIndex, finalHourIndex, finalMinuteIndex];
-      }, 0);
+      const newValue = [dayIndex, finalHourIndex, finalMinuteIndex];
+      
+      if (isSync) {
+        this.pickerValue = newValue;
+      } else {
+        // Use setTimeout to avoid visual glitch on picker reset
+        setTimeout(() => {
+            this.pickerValue = newValue;
+        }, 0);
+      }
     },
     },
 
 
     handleConfirm() {
     handleConfirm() {
+      if (this.debounceTimer) {
+        clearTimeout(this.debounceTimer);
+        this.updatePickers(this.tempPickerValue, true);
+      }
+      
       const [dayIndex, hourIndex, minuteIndex] = this.pickerValue;
       const [dayIndex, hourIndex, minuteIndex] = this.pickerValue;
       const selectedDay = this.days[dayIndex];
       const selectedDay = this.days[dayIndex];
       const selectedHour = this.hours[hourIndex];
       const selectedHour = this.hours[hourIndex];

+ 1 - 1
ghsApp/src/admin/delivery/deliveryManage.vue

@@ -115,7 +115,7 @@ export default {
                 //{ id: 'didi', name: '滴滴', logo: '🚗'},
                 //{ id: 'didi', name: '滴滴', logo: '🚗'},
 		    	//{ id: 'uu', name: 'UU跑腿', logo: '🛵'},
 		    	//{ id: 'uu', name: 'UU跑腿', logo: '🛵'},
                 { id: 'shunfeng', name: '顺丰同城', logo: '🚚'},
                 { id: 'shunfeng', name: '顺丰同城', logo: '🚚'},
-				//{ id: 'dada', name: '达达', logo: '📦'}
+				{ id: 'dada', name: '达达', logo: '📦'}
 	    	];
 	    	];
 	
 	
             // 获取已授权平台的id集合
             // 获取已授权平台的id集合

+ 79 - 8
ghsApp/src/admin/delivery/orderDetail.vue

@@ -14,16 +14,16 @@
         <view class="status-desc" v-if="getStatusDesc()">{{ getStatusDesc() }}</view>
         <view class="status-desc" v-if="getStatusDesc()">{{ getStatusDesc() }}</view>
         
         
         <!-- 取货/收货码 (部分平台有) -->
         <!-- 取货/收货码 (部分平台有) -->
-        <view class="codes-row" v-if="detail.fetch_code || detail.pickupPassword || detail.pickup_code">
-           <view class="code-item" v-if="detail.fetch_code || detail.pickupPassword || detail.pickup_code">
+        <view class="codes-row" v-if="detail.fetch_code || detail.pickupPassword || detail.pickup_code || detail.pickupCode">
+           <view class="code-item" v-if="detail.fetch_code || detail.pickupPassword || detail.pickup_code || detail.pickupCode">
              <text class="label">取货码</text>
              <text class="label">取货码</text>
-             <text class="value">{{ detail.fetch_code || detail.pickupPassword || detail.pickup_code }}</text>
+             <text class="value">{{ detail.fetch_code || detail.pickupPassword || detail.pickup_code || detail.pickupCode }}</text>
            </view>
            </view>
         </view>
         </view>
-        <view class="codes-row" v-if="detail.write_off_code || detail.deliveryPassword || detail.complete_code">
+        <view class="codes-row" v-if="detail.write_off_code || detail.deliveryPassword || detail.complete_code || detail.receiveCode">
            <view class="code-item">
            <view class="code-item">
              <text class="label">收货码</text>
              <text class="label">收货码</text>
-             <text class="value">{{ detail.write_off_code || detail.deliveryPassword || detail.complete_code }}</text>
+             <text class="value">{{ detail.write_off_code || detail.deliveryPassword || detail.complete_code || detail.receiveCode }}</text>
            </view>
            </view>
         </view>
         </view>
       </view>
       </view>
@@ -202,6 +202,13 @@ export default {
              }
              }
           } else {
           } else {
               this.detail = raw;
               this.detail = raw;
+              if (raw.platform === 'dada') {
+                this.platform = 'dada';
+                this.detail = raw.data;
+              } else if (raw.platform === 'didi') {
+                this.platform = 'didi';
+                this.detail = raw.data;
+              }
           }
           }
           
           
           // 特殊处理顺丰 (result)
           // 特殊处理顺丰 (result)
@@ -231,6 +238,10 @@ export default {
       if (data.order_display_id !== undefined || data.order_vehicle_id !== undefined) return 'huolala';
       if (data.order_display_id !== undefined || data.order_vehicle_id !== undefined) return 'huolala';
       // 顺丰特征
       // 顺丰特征
       if ((data.order_id && String(data.order_id).startsWith('JS')) || data.rider_name !== undefined || data.sf_order_id !== undefined) return 'shunfeng';
       if ((data.order_id && String(data.order_id).startsWith('JS')) || data.rider_name !== undefined || data.sf_order_id !== undefined) return 'shunfeng';
+      // 达达特征
+      if (data.platform === 'dada' || (data.transporterName !== undefined && data.deliveryFee !== undefined)) return 'dada';
+      // 滴滴特征
+      if (data.platform === 'didi' || data.didiOrderNo !== undefined) return 'didi';
       
       
       return 'unknown';
       return 'unknown';
     },
     },
@@ -239,7 +250,9 @@ export default {
         'fengniao': '蜂鸟跑腿',
         'fengniao': '蜂鸟跑腿',
         'shansong': '闪送',
         'shansong': '闪送',
         'huolala': '货拉拉',
         'huolala': '货拉拉',
-        'shunfeng': '顺丰同城'
+        'shunfeng': '顺丰同城',
+        'dada': '达达快送',
+        'didi': '滴滴送货'
       };
       };
       return map[this.platform] || '未知平台';
       return map[this.platform] || '未知平台';
     },
     },
@@ -257,6 +270,10 @@ export default {
         case 'shunfeng':
         case 'shunfeng':
            // 1:创建, 2:取消, 10:接单, 12:到店, 15:配送中, 17:完成, 31:取消中
            // 1:创建, 2:取消, 10:接单, 12:到店, 15:配送中, 17:完成, 31:取消中
            return this.detail.status_desc || '';
            return this.detail.status_desc || '';
+        case 'dada':
+           return this.detail.statusMsg || '';
+        case 'didi':
+           return this.detail.status || '';
         default:
         default:
           return '未知';
           return '未知';
       }
       }
@@ -266,6 +283,7 @@ export default {
       if (this.platform === 'fengniao') return this.detail.abnormal_desc || '';
       if (this.platform === 'fengniao') return this.detail.abnormal_desc || '';
       if (this.platform === 'shansong') return this.detail.subOrderStatusDesc || '';
       if (this.platform === 'shansong') return this.detail.subOrderStatusDesc || '';
       if (this.platform === 'huolala') return this.detail.remark || ''; // 货拉拉似乎没有额外的状态描述
       if (this.platform === 'huolala') return this.detail.remark || ''; // 货拉拉似乎没有额外的状态描述
+      if (this.platform === 'dada') return this.detail.statusMsg || '';
       return '';
       return '';
     },
     },
     hasDriverInfo() {
     hasDriverInfo() {
@@ -278,6 +296,11 @@ export default {
         case 'shansong': return this.detail.courier ? this.detail.courier.name : '';
         case 'shansong': return this.detail.courier ? this.detail.courier.name : '';
         case 'huolala': return this.detail.driver_info ? this.detail.driver_info.name : '';
         case 'huolala': return this.detail.driver_info ? this.detail.driver_info.name : '';
         case 'shunfeng': return this.detail.rider_name;
         case 'shunfeng': return this.detail.rider_name;
+        case 'dada': return this.detail.transporterName;
+        case 'didi': {
+            const driver = Array.isArray(this.detail.driverInfo) ? this.detail.driverInfo[0] : this.detail.driverInfo;
+            return driver ? driver.driverName : '';
+        }
         default: return '';
         default: return '';
       }
       }
     },
     },
@@ -288,6 +311,11 @@ export default {
         case 'shansong': return this.detail.courier ? this.detail.courier.mobile : '';
         case 'shansong': return this.detail.courier ? this.detail.courier.mobile : '';
         case 'huolala': return this.detail.driver_info ? (this.detail.driver_info.driver_phone_no || this.detail.driver_info.phone_no) : '';
         case 'huolala': return this.detail.driver_info ? (this.detail.driver_info.driver_phone_no || this.detail.driver_info.phone_no) : '';
         case 'shunfeng': return this.detail.rider_phone;
         case 'shunfeng': return this.detail.rider_phone;
+        case 'dada': return this.detail.transporterPhone;
+        case 'didi': {
+            const driver = Array.isArray(this.detail.driverInfo) ? this.detail.driverInfo[0] : this.detail.driverInfo;
+            return driver ? driver.driverPhone : '';
+        }
         default: return '';
         default: return '';
       }
       }
     },
     },
@@ -299,6 +327,10 @@ export default {
          if (this.platform === 'fengniao' && this.detail.temperature) {
          if (this.platform === 'fengniao' && this.detail.temperature) {
              return this.detail.temperature;
              return this.detail.temperature;
          }
          }
+         if (this.platform === 'didi') {
+             const driver = Array.isArray(this.detail.driverInfo) ? this.detail.driverInfo[0] : this.detail.driverInfo;
+             return driver ? driver.carLicense : '';
+         }
          return '';
          return '';
     },
     },
     getDriverLocation() {
     getDriverLocation() {
@@ -306,6 +338,9 @@ export default {
          if (this.platform === 'shansong' && this.detail.courier && this.detail.courier.estimateDeliveryTimeTip) {
          if (this.platform === 'shansong' && this.detail.courier && this.detail.courier.estimateDeliveryTimeTip) {
              return this.detail.courier.estimateDeliveryTimeTip;
              return this.detail.courier.estimateDeliveryTimeTip;
          }
          }
+         if (this.platform === 'dada' && this.detail.transporterLng && this.detail.transporterLat) {
+             return '骑手位置: ' + this.detail.transporterLng + ',' + this.detail.transporterLat;
+         }
          // 经纬度展示略过,直接展示文本信息
          // 经纬度展示略过,直接展示文本信息
          return '';
          return '';
     },
     },
@@ -322,6 +357,8 @@ export default {
         case 'shansong': return this.detail.orderNo || this.detail.issOrderNo;
         case 'shansong': return this.detail.orderNo || this.detail.issOrderNo;
         case 'huolala': return this.detail.order_display_id;
         case 'huolala': return this.detail.order_display_id;
         case 'shunfeng': return this.detail.order_id;
         case 'shunfeng': return this.detail.order_id;
+        case 'dada': return this.detail.orderId;
+        case 'didi': return this.detail.didiOrderNo || this.detail.outOrderNo;
         default: return '';
         default: return '';
       }
       }
     },
     },
@@ -329,6 +366,7 @@ export default {
         if (!this.detail) return '';
         if (!this.detail) return '';
         if (this.platform === 'fengniao' && this.detail.order_distance) return (this.detail.order_distance / 1000).toFixed(2) + 'km'; // 米
         if (this.platform === 'fengniao' && this.detail.order_distance) return (this.detail.order_distance / 1000).toFixed(2) + 'km'; // 米
         if (this.platform === 'shunfeng' && this.detail.delivery_distance_meter) return (this.detail.delivery_distance_meter / 1000).toFixed(2) + 'km';
         if (this.platform === 'shunfeng' && this.detail.delivery_distance_meter) return (this.detail.delivery_distance_meter / 1000).toFixed(2) + 'km';
+        if (this.platform === 'dada' && this.detail.distance) return (this.detail.distance / 1000).toFixed(2) + 'km';
         return '';
         return '';
     },
     },
     getWeight() {
     getWeight() {
@@ -340,6 +378,7 @@ export default {
         if (!this.detail) return '';
         if (!this.detail) return '';
         if (this.platform === 'huolala' && this.detail.create_time) return this.$util.$formatDate(this.detail.create_time); // unix timestamp seconds
         if (this.platform === 'huolala' && this.detail.create_time) return this.$util.$formatDate(this.detail.create_time); // unix timestamp seconds
         if (this.platform === 'shunfeng' && this.detail.push_time) return this.$util.$formatDate(this.detail.push_time);
         if (this.platform === 'shunfeng' && this.detail.push_time) return this.$util.$formatDate(this.detail.push_time);
+        if (this.platform === 'dada' && this.detail.createTime) return this.detail.createTime;
         // 其他平台可能需要从日志中获取或未提供明确的创建时间字段
         // 其他平台可能需要从日志中获取或未提供明确的创建时间字段
         return '';
         return '';
     },
     },
@@ -347,6 +386,7 @@ export default {
         if (!this.detail) return '';
         if (!this.detail) return '';
         if (this.platform === 'fengniao' && this.detail.estimate_arrive_time) return this.$util.$formatDate(this.detail.estimate_arrive_time, 'YYYY-MM-DD HH:mm', true); // ms
         if (this.platform === 'fengniao' && this.detail.estimate_arrive_time) return this.$util.$formatDate(this.detail.estimate_arrive_time, 'YYYY-MM-DD HH:mm', true); // ms
         if (this.platform === 'shunfeng' && this.detail.expect_time) return this.$util.$formatDate(this.detail.expect_time); // seconds
         if (this.platform === 'shunfeng' && this.detail.expect_time) return this.$util.$formatDate(this.detail.expect_time); // seconds
+        if (this.platform === 'dada' && this.detail.finishTime) return this.detail.finishTime; // 如果已送达
         return '';
         return '';
     },
     },
     getActualPrice() {
     getActualPrice() {
@@ -357,6 +397,7 @@ export default {
             case 'shansong': fen = this.detail.totalFeeAfterSave; break;
             case 'shansong': fen = this.detail.totalFeeAfterSave; break;
             case 'huolala': fen = this.detail.total_price_fen; break; // 货拉拉 total_price_fen 似乎是总价,need check if unpaid_price_fen is better
             case 'huolala': fen = this.detail.total_price_fen; break; // 货拉拉 total_price_fen 似乎是总价,need check if unpaid_price_fen is better
             case 'shunfeng': fen = this.detail.real_pay_money; break;
             case 'shunfeng': fen = this.detail.real_pay_money; break;
+            case 'dada': return this.detail.actualFee.toFixed(2);
         }
         }
         return (fen / 100).toFixed(2);
         return (fen / 100).toFixed(2);
     },
     },
@@ -368,6 +409,7 @@ export default {
             case 'shansong': fen = this.detail.totalAmount; break;
             case 'shansong': fen = this.detail.totalAmount; break;
             case 'huolala': fen = this.detail.total_price_fen; break;
             case 'huolala': fen = this.detail.total_price_fen; break;
             case 'shunfeng': fen = this.detail.total_pay_money; break;
             case 'shunfeng': fen = this.detail.total_pay_money; break;
+            case 'dada': return this.detail.deliveryFee.toFixed(2);
         }
         }
         return (fen / 100).toFixed(2);
         return (fen / 100).toFixed(2);
     },
     },
@@ -398,6 +440,11 @@ export default {
         } else if (this.platform === 'shunfeng') {
         } else if (this.platform === 'shunfeng') {
             if (this.detail.overflow_fee) list.push({ name: '爆单费', amount: (this.detail.overflow_fee/100).toFixed(2) });
             if (this.detail.overflow_fee) list.push({ name: '爆单费', amount: (this.detail.overflow_fee/100).toFixed(2) });
             if (this.detail.coupons_total_fee) list.push({ name: '优惠券', amount: '-' + (this.detail.coupons_total_fee/100).toFixed(2) });
             if (this.detail.coupons_total_fee) list.push({ name: '优惠券', amount: '-' + (this.detail.coupons_total_fee/100).toFixed(2) });
+        } else if (this.platform === 'dada') {
+            if (this.detail.tips > 0) list.push({ name: '小费', amount: this.detail.tips.toFixed(2) });
+            if (this.detail.couponFee > 0) list.push({ name: '优惠券', amount: '-' + this.detail.couponFee.toFixed(2) });
+            if (this.detail.insuranceFee > 0) list.push({ name: '保价费', amount: this.detail.insuranceFee.toFixed(2) });
+            if (this.detail.deductFee > 0) list.push({ name: '违约金', amount: this.detail.deductFee.toFixed(2) });
         }
         }
         return list;
         return list;
     },
     },
@@ -405,16 +452,40 @@ export default {
         if (!this.detail) return [];
         if (!this.detail) return [];
         let logs = [];
         let logs = [];
         if (this.platform === 'fengniao' && this.detail.event_log_details) {
         if (this.platform === 'fengniao' && this.detail.event_log_details) {
+            const statusMap = {
+                0: '订单生成',
+                1: '运单生成成功',
+                20: '骑手接单',
+                80: '骑手到店',
+                2: '配送中',
+                3: '已完成',
+                4: '已取消',
+                5: '配送异常'
+            };
             logs = this.detail.event_log_details.map(item => ({
             logs = this.detail.event_log_details.map(item => ({
                 time: this.$util.$formatDate(item.occur_time, 'YYYY-MM-DD HH:mm', true),
                 time: this.$util.$formatDate(item.occur_time, 'YYYY-MM-DD HH:mm', true),
-                status: item.order_status, // 需转义,暂略
+                status: statusMap[item.order_status] || item.order_status,
                 desc: item.carrier_driver_name ? `骑手: ${item.carrier_driver_name}` : ''
                 desc: item.carrier_driver_name ? `骑手: ${item.carrier_driver_name}` : ''
             }));
             }));
         } else if (this.platform === 'shansong' && this.detail.statusChangeLog) {
         } else if (this.platform === 'shansong' && this.detail.statusChangeLog) {
+            const ssMap = {
+                20: '派单中',
+                30: '待取货',
+                40: '闪送中',
+                50: '已完成',
+                60: '已取消'
+            };
             logs = this.detail.statusChangeLog.map(item => ({
             logs = this.detail.statusChangeLog.map(item => ({
                 time: item.updateTime,
                 time: item.updateTime,
-                status: item.orderStatus // 需转义
+                status: ssMap[item.orderStatus] || item.orderStatus
             }));
             }));
+        } else if (this.platform === 'dada') {
+            if (this.detail.createTime) logs.push({time: this.detail.createTime, status: '已下单'});
+            if (this.detail.acceptTime) logs.push({time: this.detail.acceptTime, status: '已接单'});
+            if (this.detail.fetchTime) logs.push({time: this.detail.fetchTime, status: '已取货'});
+            if (this.detail.finishTime) logs.push({time: this.detail.finishTime, status: '已送达'});
+            if (this.detail.cancelTime) logs.push({time: this.detail.cancelTime, status: '已取消'});
+            logs.sort((a, b) => new Date(b.time) - new Date(a.time));
         }
         }
         // 货拉拉和顺丰示例未提供详细日志列表
         // 货拉拉和顺丰示例未提供详细日志列表
         return logs;
         return logs;

+ 4 - 2
ghsApp/src/admin/home/components/OrderItem.vue

@@ -131,15 +131,17 @@
         <block v-if="item.sendStatus == -4">
         <block v-if="item.sendStatus == -4">
           <view class="text-center"><button class="admin-button-com" @click="callIntraCity(item)">呼叫跑腿</button></view>
           <view class="text-center"><button class="admin-button-com" @click="callIntraCity(item)">呼叫跑腿</button></view>
         </block>
         </block>
-        <block v-else-if="[0, 1, 2, 3, 4, 10, 20, 30].includes(item.sendStatus)">
+        <block v-else-if="[0, 1, 2, 3, 4, 10, 20, 30].includes(Number(item.sendStatus))">
           <view class="text-center"><button class="admin-button-com" @click="cancelExpressOrder(item)">取消跑腿</button></view>
           <view class="text-center"><button class="admin-button-com" @click="cancelExpressOrder(item)">取消跑腿</button></view>
         </block>
         </block>
-        <block v-else-if="item.sendStatus == -1">
+        <block v-else-if="[-1, -2].includes(item.sendStatus)">
           <view class="text-center"><button class="admin-button-com" @click="callIntraCity(item)">重叫跑腿</button></view>
           <view class="text-center"><button class="admin-button-com" @click="callIntraCity(item)">重叫跑腿</button></view>
         </block>
         </block>
+        <!--
         <view class="text-center"><button class="admin-button-com" @click="addExpress(item)">顺丰下单</button></view>
         <view class="text-center"><button class="admin-button-com" @click="addExpress(item)">顺丰下单</button></view>
         <view class="text-center"><button class="admin-button-com" @click="cancelExpress(item)">取消顺丰订单</button></view>
         <view class="text-center"><button class="admin-button-com" @click="cancelExpress(item)">取消顺丰订单</button></view>
         <view class="text-center"><button class="admin-button-com" @click="fillNoFh(item)">填单发货</button></view>
         <view class="text-center"><button class="admin-button-com" @click="fillNoFh(item)">填单发货</button></view>
+        -->
         <view class="text-center"><button class="admin-button-com default" @click="closeMore">取消</button></view>
         <view class="text-center"><button class="admin-button-com default" @click="closeMore">取消</button></view>
       </view>
       </view>
     </uni-popup>
     </uni-popup>

+ 7 - 0
ghsApp/src/mixins/product.js

@@ -501,6 +501,13 @@ export default {
 			let current = null
 			let current = null
 			let unitPrice = 0
 			let unitPrice = 0
 			let unitName = ''
 			let unitName = ''
+
+			if(this.globalAllProduct.length == 0){
+				this.listenScanItem()
+				
+				// this.$msg('请先载入花材(此功能已关闭,请联系管理员)')
+				// return false
+			}
 			//花材
 			//花材
 			current = this.globalAllProduct.find(function(val){
 			current = this.globalAllProduct.find(function(val){
 				return Number(val.itemId) == Number(code)
 				return Number(val.itemId) == Number(code)

+ 23 - 6
ghsApp/src/pagesOrder/detail.vue

@@ -35,12 +35,12 @@
 					</view>
 					</view>
 					<view class="msg-list express-progress-row">
 					<view class="msg-list express-progress-row">
 						<view class="label">配送进度:</view>
 						<view class="label">配送进度:</view>
-						<view class="value" :style="detailInfo.sendStatus == '3' ? 'color:#ff2842;font-weight:bold;' : detailInfo.sendStatus == '2' ? 'color:#07c160;font-weight:bold;' : ''">
+						<view class="value" :style="detailInfo.sendStatus == 3 ? 'color:#ff2842;font-weight:bold;' : detailInfo.sendStatus == 2 ? 'color:#07c160;font-weight:bold;' : ''">
 							{{ getSendStatusText(detailInfo.sendStatus) }}
 							{{ getSendStatusText(detailInfo.sendStatus) }}
 						</view>
 						</view>
 						<view class="express-actions">
 						<view class="express-actions">
 							<button class="admin-button-com mini-btn btn-danger" v-if="canCancelExpress(detailInfo.sendStatus)" @click.stop="cancelMyExpress(detailInfo.id, detailInfo.deliveryId)">取消跑腿</button>
 							<button class="admin-button-com mini-btn btn-danger" v-if="canCancelExpress(detailInfo.sendStatus)" @click.stop="cancelMyExpress(detailInfo.id, detailInfo.deliveryId)">取消跑腿</button>
-							<button class="admin-button-com mini-btn" v-if="detailInfo.sendStatus == '-1'" @click.stop="openExpressPage()">重叫跑腿</button>
+							<button class="admin-button-com mini-btn" v-if="[-1, -2].includes(detailInfo.sendStatus)" @click.stop="openExpressPage()">重叫跑腿</button>
 						</view>
 						</view>
 					</view>
 					</view>
 <!--
 <!--
@@ -453,8 +453,8 @@
 			<!-- #ifdef APP-PLUS -->
 			<!-- #ifdef APP-PLUS -->
 			<button class="admin-button-com middle blue" @click="shareOrder()">分享</button>
 			<button class="admin-button-com middle blue" @click="shareOrder()">分享</button>
 			<!-- #endif -->
 			<!-- #endif -->
-			<button class="admin-button-com middle blue" v-if="detailInfo.sendStatus == '-4' && detailInfo.payStatus == 1" @click.stop="openExpressPage()">呼叫跑腿</button>
-			<button class="admin-button-com middle blue" v-if="detailInfo.sendStatus == '-1'" @click.stop="openExpressPage()">重叫跑腿</button>
+			<button class="admin-button-com middle blue" v-if="detailInfo.sendStatus == -4 && detailInfo.payStatus == 1" @click.stop="openExpressPage()">呼叫跑腿</button>
+			<button class="admin-button-com middle blue" v-if="[-1, -2].includes(detailInfo.sendStatus)" @click.stop="openExpressPage()">重叫跑腿</button>
 			<button class="admin-button-com middle blue" style="background-color: green;border-color: green;" v-if="detailInfo.status != 1 && detailInfo.status != 5" @click="printOrder(detailInfo)">打印(无价格)</button>
 			<button class="admin-button-com middle blue" style="background-color: green;border-color: green;" v-if="detailInfo.status != 1 && detailInfo.status != 5" @click="printOrder(detailInfo)">打印(无价格)</button>
 
 
 			<template v-for="s in detailInfo.buttonList">
 			<template v-for="s in detailInfo.buttonList">
@@ -568,7 +568,7 @@
 							<view class="reason-text">{{ item.order_cancel_desc }}</view>
 							<view class="reason-text">{{ item.order_cancel_desc }}</view>
 						</label>
 						</label>
 					</radio-group>
 					</radio-group>
-					<textarea v-if="selectedCancelReasonCode === 0 || selectedCancelReasonCode === 313" v-model="otherCancelReason" placeholder="请输入其他原因" class="reason-textarea"></textarea>
+					<textarea v-if="selectedCancelReasonCode === 0 || selectedCancelReasonCode === 313 || selectedCancelReasonCode === 10000" v-model="otherCancelReason" placeholder="请输入其他原因" class="reason-textarea"></textarea>
 				</scroll-view>
 				</scroll-view>
 				<view class="popup-actions">
 				<view class="popup-actions">
 					<button @click="closeCancelReasonPopup" class="action-btn cancel">取消</button>
 					<button @click="closeCancelReasonPopup" class="action-btn cancel">取消</button>
@@ -801,6 +801,23 @@ export default {
 				this.selectedCancelReasonCode = null;
 				this.selectedCancelReasonCode = null;
 				this.otherCancelReason = '';
 				this.otherCancelReason = '';
 				this.$refs.cancelReasonPopup.open();
 				this.$refs.cancelReasonPopup.open();
+			} else if(deliveryId == 'dada'){
+				this.cancelReasonList = [
+					{ order_cancel_code: 1, order_cancel_desc: '没有配送员接单' },
+					{ order_cancel_code: 2, order_cancel_desc: '配送员没来取货' },
+					{ order_cancel_code: 3, order_cancel_desc: '配送员态度太差' },
+					{ order_cancel_code: 4, order_cancel_desc: '顾客取消订单' },
+					{ order_cancel_code: 5, order_cancel_desc: '订单填写错误' },
+					{ order_cancel_code: 34, order_cancel_desc: '配送员让我取消此单' },
+					{ order_cancel_code: 35, order_cancel_desc: '配送员不愿上门取货' },
+					{ order_cancel_code: 36, order_cancel_desc: '我不需要配送了' },
+					{ order_cancel_code: 37, order_cancel_desc: '配送员以各种理由表示无法完成订单' },
+					{ order_cancel_code: 10000, order_cancel_desc: '其他' }
+				];
+				this.currentExpressInfo = { orderId, deliveryId };
+				this.selectedCancelReasonCode = null;
+				this.otherCancelReason = '';
+				this.$refs.cancelReasonPopup.open();
 			} else if(deliveryId == 'huolala'){
 			} else if(deliveryId == 'huolala'){
 				getCancelReason({ghsOrderId: orderId, platform: deliveryId}).then(res => {
 				getCancelReason({ghsOrderId: orderId, platform: deliveryId}).then(res => {
 					if (res.code == 1 && res.data) {
 					if (res.code == 1 && res.data) {
@@ -839,7 +856,7 @@ export default {
 			let reason = this.cancelReasonList.find(item => item.order_cancel_code === this.selectedCancelReasonCode);
 			let reason = this.cancelReasonList.find(item => item.order_cancel_code === this.selectedCancelReasonCode);
 			let reason_desc = reason.order_cancel_desc;
 			let reason_desc = reason.order_cancel_desc;
 		
 		
-			if (this.selectedCancelReasonCode === 0 || this.selectedCancelReasonCode === 313) {
+			if (this.selectedCancelReasonCode === 0 || this.selectedCancelReasonCode === 313 || this.selectedCancelReasonCode === 10000) {
 				if (this.$util.isEmpty(this.otherCancelReason)) {
 				if (this.$util.isEmpty(this.otherCancelReason)) {
 					this.$msg('请输入其他原因');
 					this.$msg('请输入其他原因');
 					return;
 					return;

+ 37 - 37
hdApp/src/admin/billing/affirmGhs.vue

@@ -138,7 +138,7 @@
 							<button class="admin-button-com middle" :class="[form.sendType == 3 ? 'blue' : 'default']" style="width:115upx;height:100upx;line-height:60upx;" @click="changeSendType(3)" v-if="ghsInfo.shopId != 14248">物流</button>
 							<button class="admin-button-com middle" :class="[form.sendType == 3 ? 'blue' : 'default']" style="width:115upx;height:100upx;line-height:60upx;" @click="changeSendType(3)" v-if="ghsInfo.shopId != 14248">物流</button>
 						</tui-list-cell>
 						</tui-list-cell>
 
 
-						<tui-list-cell class="line-cell" :hover="false" :arrow="false">
+						<tui-list-cell v-if="form.sendType != 2" class="line-cell" :hover="false" :arrow="false">
 
 
 							<view v-if="form.sendType == 0">
 							<view v-if="form.sendType == 0">
 								<block v-if="ghsInfo.shopId == 40312">
 								<block v-if="ghsInfo.shopId == 40312">
@@ -174,10 +174,6 @@
 							<view v-if="form.sendType == 1">
 							<view v-if="form.sendType == 1">
 								<text style="color: #3385FF;width:100%;">到店自取,没有配送费</text>
 								<text style="color: #3385FF;width:100%;">到店自取,没有配送费</text>
 							</view>
 							</view>
-							<view v-if="form.sendType == 2">
-								<text v-if="ghsInfo.openIntraCity == 0" style="color: #3385FF;width:100%;font-size:34upx;font-weight:bold;">运费自理或到付(请联系客服)</text>
-								<text v-if="ghsInfo.openIntraCity == 2" style="color: red;width:100%;font-size:34upx;font-weight:bold;">跑腿配送暂不可用,请选其它方式</text>
-							</view>
 							<view v-if="form.sendType == 3">
 							<view v-if="form.sendType == 3">
 								<text style="color: #3385FF;width:100%;">运费到付</text>
 								<text style="color: #3385FF;width:100%;">运费到付</text>
 							</view>
 							</view>
@@ -186,13 +182,13 @@
 							</view>
 							</view>
 						</tui-list-cell>
 						</tui-list-cell>
 
 
-							<tui-list-cell class="line-cell" :hover="false" :arrow="false" v-if="needAddPackCost == true">
-								<view>
-									<text style="color: red;width:100%;">
-									当天订单不满{{lackExpend}}元,加纸箱包装费{{ form.packCost }}元
-									</text>
-								</view>
-							</tui-list-cell>
+						<tui-list-cell class="line-cell" :hover="false" :arrow="false" v-if="needAddPackCost == true">
+							<view>
+								<text style="color: red;width:100%;">
+								当天订单不满{{lackExpend}}元,加纸箱包装费{{ form.packCost }}元
+								</text>
+							</view>
+						</tui-list-cell>
 
 
 						<block v-if="$util.isEmpty(wlList)">
 						<block v-if="$util.isEmpty(wlList)">
 							<tui-list-cell class="line-cell" :hover="false" v-if="form.sendType == 3">
 							<tui-list-cell class="line-cell" :hover="false" v-if="form.sendType == 3">
@@ -211,6 +207,12 @@
 						</block>
 						</block>
 					</block>
 					</block>
 
 
+					<tui-list-cell v-if="form.sendType == 2 && ghsInfo.openIntraCity != 1" class="line-cell" :hover="false" :arrow="false">
+						<view>
+							<text v-if="ghsInfo.openIntraCity == 0" style="color: #3385FF;width:100%;font-size:30upx;font-weight:bold;">运费自理或到付(请联系客服)</text>
+							<text v-if="ghsInfo.openIntraCity == 2" style="color: red;width:100%;font-size:30upx;font-weight:bold;">跑腿配送暂不可用,请选其它方式</text>
+						</view>
+					</tui-list-cell>
 					<tui-list-cell class="line-cell" :hover="false" :arrow="true" v-if="displayAddress == true" @click="modifyAddress">
 					<tui-list-cell class="line-cell" :hover="false" :arrow="true" v-if="displayAddress == true" @click="modifyAddress">
 						<view class="tui-title">收花地址</view>
 						<view class="tui-title">收花地址</view>
 						<view v-if="!$util.isEmpty(shopInfo.address)">
 						<view v-if="!$util.isEmpty(shopInfo.address)">
@@ -222,31 +224,29 @@
 						</view>
 						</view>
 					</tui-list-cell>
 					</tui-list-cell>
 
 
-					<tui-list-cell class="line-cell" :hover="false" :arrow="false">
-						<view v-if="form.sendType == 2">
-							<!-- 跑腿平台报价列表 -->
-							<view v-if="ghsInfo.openIntraCity == 1 && deliveryQuotes.length > 0" class="delivery-quotes-container">
-								<view class="delivery-quotes-grid">
-									<view 
-										v-for="(item, index) in deliveryQuotes" 
-										:key="index"
-										class="delivery-quote-item"
-										:class="{ 
-											'active': selectedDeliveryIndex === index, 
-											'disabled': !item.isAble,
-											'fixed-width': deliveryQuotes.length <= 2
-										}"
-										@click="selectDelivery(item, index)"
-									>
-										<view class="platform-name">{{ item.displayName || item.name }}</view>
-										<view class="platform-price">{{ item.priceText }}元</view>
-										<view v-if="item.type" class="platform-type">{{ item.type }}</view>
-									</view>
+					<tui-list-cell v-if="form.sendType == 2 && ghsInfo.openIntraCity == 1" class="line-cell" :hover="false" :arrow="false">
+						<!-- 跑腿平台报价列表 -->
+						<view v-if="ghsInfo.openIntraCity == 1 && deliveryQuotes.length > 0" class="delivery-quotes-container">
+							<view class="delivery-quotes-grid">
+								<view 
+									v-for="(item, index) in deliveryQuotes" 
+									:key="index"
+									class="delivery-quote-item"
+									:class="{ 
+										'active': selectedDeliveryIndex === index, 
+										'disabled': !item.isAble,
+										'fixed-width': deliveryQuotes.length <= 2
+									}"
+									@click="selectDelivery(item, index)"
+								>
+									<view class="platform-name">{{ item.displayName || item.name }}</view>
+									<view class="platform-price">{{ item.priceText }}元</view>
+									<view v-if="item.type" class="platform-type">{{ item.type }}</view>
 								</view>
 								</view>
 							</view>
 							</view>
-							<view v-else style="text-align: center; padding: 20upx 0;">
-								<text v-if="validAddress">正在获取运费...</text><text v-else style="color:red;font-weight:bold;font-size:32upx;">上面地址缺失或有问题,请修改</text>
-							</view>
+						</view>
+						<view v-else style="text-align: center; padding: 20upx 0;">
+							<text v-if="validAddress">正在获取运费...</text><text v-else style="color:red;font-weight:bold;font-size:32upx;">上面地址缺失或有问题,请修改</text>
 						</view>
 						</view>
 					</tui-list-cell>
 					</tui-list-cell>
 
 
@@ -314,7 +314,7 @@
 
 
 		<uni-popup ref="deliveryPolicyPopup" type="center" background-color="#fff">
 		<uni-popup ref="deliveryPolicyPopup" type="center" background-color="#fff">
 			<view class="policy-popup-content">
 			<view class="policy-popup-content">
-				<view class="policy-title">包配送政策</view>
+				<view class="policy-title">免费配送条件</view>
 				<scroll-view scroll-y="true" class="policy-scroll">
 				<scroll-view scroll-y="true" class="policy-scroll">
 					<view class="policy-list">
 					<view class="policy-list">
 						<block v-for="(item, index) in deliveryPolicyList" :key="index">
 						<block v-for="(item, index) in deliveryPolicyList" :key="index">
@@ -1536,7 +1536,7 @@ export default {
 .delivery-policy-link {
 .delivery-policy-link {
 	color: rgb(201, 52, 52);
 	color: rgb(201, 52, 52);
 	font-size: 28upx;
 	font-size: 28upx;
-	margin-left: 5upx;
+	margin-left: 12upx;
 	text-decoration: underline;
 	text-decoration: underline;
 }
 }
 
 

+ 13 - 4
hdApp/src/admin/delivery/allDelivery.vue

@@ -10,6 +10,7 @@
         <view class="address-content">
         <view class="address-content">
           <view class="address-title">{{ senderInfo.name || '门店' }}</view>
           <view class="address-title">{{ senderInfo.name || '门店' }}</view>
           <view class="address-detail">{{ senderInfo.address || '' }}</view>
           <view class="address-detail">{{ senderInfo.address || '' }}</view>
+          <view class="address-detail" style="color:#ada8a8;font-size:26upx;">货拉拉会用此地址,其它以跑腿平台设置的为准</view>
         </view>
         </view>
         <view class="address-arrow">
         <view class="address-arrow">
           <text class="iconfont iconxiangyou"></text>
           <text class="iconfont iconxiangyou"></text>
@@ -436,9 +437,17 @@ export default {
         if (res && res.code === 1) {
         if (res && res.code === 1) {
           this.$msg('下单成功');
           this.$msg('下单成功');
           uni.$emit('updateOrderStatus', this.orderId, 3, 0);
           uni.$emit('updateOrderStatus', this.orderId, 3, 0);
+
           //this.pageTo({url: '/pagesOrder/detail?id=' + this.orderId, type: 2 }); 
           //this.pageTo({url: '/pagesOrder/detail?id=' + this.orderId, type: 2 }); 
           // 为了能正常返回,需要使用navigateBack
           // 为了能正常返回,需要使用navigateBack
           uni.navigateBack({ delta: 1 });
           uni.navigateBack({ delta: 1 });
+
+          // 改变订单详情页的跑腿状态为已叫跑腿
+          let pages = getCurrentPages();
+          let prevPage = pages.find(p => p.route.includes('admin/order/detail'));
+          if (prevPage && prevPage.$vm && prevPage.$vm.orderInfo) {
+            prevPage.$vm.orderInfo.sendStatus = 0;
+          }
         }
         }
       }).catch(err => {
       }).catch(err => {
         this.$msg(res.msg);
         this.$msg(res.msg);
@@ -522,15 +531,15 @@ export default {
       flex: 1;
       flex: 1;
 
 
       .address-title {
       .address-title {
-        font-size: 28upx;
-        color: #333333;
+        font-size: 32upx;
+        color: black;
         font-weight: 500;
         font-weight: 500;
         margin-bottom: 5upx;
         margin-bottom: 5upx;
       }
       }
 
 
       .address-detail {
       .address-detail {
-        font-size: 24upx;
-        color: #999999;
+        font-size: 28upx;
+        color: #7c7c7c;
       }
       }
     }
     }
 
 

+ 49 - 12
hdApp/src/admin/delivery/components/TimePicker.vue

@@ -8,7 +8,7 @@
         </view>
         </view>
       </view>
       </view>
 
 
-      <picker-view v-if="visible" class="picker-view" :indicator-style="indicatorStyle" :value="pickerValue" @change="handleChange">
+      <picker-view v-if="visible" class="picker-view" :indicator-style="indicatorStyle" :value="pickerValue" @change="handleChange" :immediate-change="true">
         <picker-view-column>
         <picker-view-column>
           <view class="picker-item" v-for="(item, index) in days" :key="index">{{ item.label }}</view>
           <view class="picker-item" v-for="(item, index) in days" :key="index">{{ item.label }}</view>
         </picker-view-column>
         </picker-view-column>
@@ -38,6 +38,8 @@ export default {
     return {
     return {
       visible: false, // 控制picker-view的渲染
       visible: false, // 控制picker-view的渲染
       pickerValue: [0, 0, 0],
       pickerValue: [0, 0, 0],
+      tempPickerValue: [0, 0, 0], // 临时存储滚动过程中的值
+      debounceTimer: null,
       days: [],
       days: [],
       hours: [],
       hours: [],
       minutes: [],
       minutes: [],
@@ -73,6 +75,7 @@ export default {
         this.hours = this.generateHours(tomorrow, false);
         this.hours = this.generateHours(tomorrow, false);
         this.minutes = this.generateMinutes(tomorrow, false, this.hours[0].value);
         this.minutes = this.generateMinutes(tomorrow, false, this.hours[0].value);
         this.pickerValue = [1, 0, 0]; // Select "Tomorrow", first hour, first minute
         this.pickerValue = [1, 0, 0]; // Select "Tomorrow", first hour, first minute
+        this.tempPickerValue = [1, 0, 0];
         return;
         return;
       }
       }
 
 
@@ -85,6 +88,7 @@ export default {
       const initialMinuteIndex = 0;
       const initialMinuteIndex = 0;
       
       
       this.pickerValue = [0, initialHourIndex, initialMinuteIndex];
       this.pickerValue = [0, initialHourIndex, initialMinuteIndex];
+      this.tempPickerValue = [0, initialHourIndex, initialMinuteIndex];
     },
     },
 
 
     generateDays() {
     generateDays() {
@@ -135,7 +139,20 @@ export default {
     },
     },
 
 
     handleChange(e) {
     handleChange(e) {
-      const [dayIndex, hourIndex, minuteIndex] = e.detail.value;
+      const val = e.detail.value;
+      this.tempPickerValue = val;
+      
+      if (this.debounceTimer) {
+        clearTimeout(this.debounceTimer);
+      }
+      
+      this.debounceTimer = setTimeout(() => {
+        this.updatePickers(val);
+      }, 100);
+    },
+
+    updatePickers(val, isSync = false) {
+      const [dayIndex, hourIndex, minuteIndex] = val;
       const oldPickerValue = this.pickerValue;
       const oldPickerValue = this.pickerValue;
       
       
       const now = dayjs();
       const now = dayjs();
@@ -150,26 +167,46 @@ export default {
       // Day changed
       // Day changed
       if (oldPickerValue[0] !== dayIndex) {
       if (oldPickerValue[0] !== dayIndex) {
         newHours = this.generateHours(now, isToday);
         newHours = this.generateHours(now, isToday);
-        finalHourIndex = 0;
+        // 修正越界,尽量保持用户的选择,而不是强制归零
+        if (finalHourIndex >= newHours.length) {
+            finalHourIndex = 0;
+        }
       }
       }
       
       
-      // Hour changed (or day changed)
-      if (oldPickerValue[0] !== dayIndex || oldPickerValue[1] !== hourIndex) {
-        const selectedHour = newHours[finalHourIndex].value;
-        newMinutes = this.generateMinutes(now, isToday, selectedHour);
-        finalMinuteIndex = 0;
+      // Calculate selected hour based on current indices
+      const selectedHour = newHours[finalHourIndex] ? newHours[finalHourIndex].value : -1;
+
+      // Always regenerate minutes to ensure correctness (e.g. today/tomorrow switch, or hour switch)
+      // Optimization: we could check if generation parameters actually changed, but it's fast enough.
+      newMinutes = this.generateMinutes(now, isToday, selectedHour);
+      
+      // 修正越界
+      if (finalMinuteIndex >= newMinutes.length) {
+          finalMinuteIndex = 0;
       }
       }
       
       
       this.hours = newHours;
       this.hours = newHours;
       this.minutes = newMinutes;
       this.minutes = newMinutes;
+      this.debounceTimer = null;
 
 
-      // Use setTimeout to avoid visual glitch on picker reset
-      setTimeout(() => {
-        this.pickerValue = [dayIndex, finalHourIndex, finalMinuteIndex];
-      }, 0);
+      const newValue = [dayIndex, finalHourIndex, finalMinuteIndex];
+      
+      if (isSync) {
+        this.pickerValue = newValue;
+      } else {
+        // Use setTimeout to avoid visual glitch on picker reset
+        setTimeout(() => {
+            this.pickerValue = newValue;
+        }, 0);
+      }
     },
     },
 
 
     handleConfirm() {
     handleConfirm() {
+      if (this.debounceTimer) {
+        clearTimeout(this.debounceTimer);
+        this.updatePickers(this.tempPickerValue, true);
+      }
+      
       const [dayIndex, hourIndex, minuteIndex] = this.pickerValue;
       const [dayIndex, hourIndex, minuteIndex] = this.pickerValue;
       const selectedDay = this.days[dayIndex];
       const selectedDay = this.days[dayIndex];
       const selectedHour = this.hours[hourIndex];
       const selectedHour = this.hours[hourIndex];

+ 5 - 5
hdApp/src/admin/home/order.vue

@@ -85,10 +85,10 @@
                 <!-- <view class="admin-button-com middle default" @click.stop="">呼叫跑腿</view> -->
                 <!-- <view class="admin-button-com middle default" @click.stop="">呼叫跑腿</view> -->
               </block>
               </block>
               <block v-else>
               <block v-else>
-                <view class="admin-button-com middle" v-if="item.sendStatus == '-4'" @click.stop="openExpressPage(item.id)">呼叫跑腿</view>
-                <view class="admin-button-com middle" v-else-if="item.sendStatus == '-1'" @click.stop="openExpressPage(item.id)">重叫跑腿</view>
-                <view class="admin-button-com default" v-else-if="item.sendStatus == '5'">跑腿完成</view>
-                <view class="admin-button-com default" v-else-if="['0', '1', '2', '3', '4', '10', '20', '30'].includes(item.sendStatus) && item.payStatus == 1">已发跑腿</view>
+                <view class="admin-button-com middle" v-if="item.sendStatus == -4" @click.stop="openExpressPage(item.id)">呼叫跑腿</view>
+                <view class="admin-button-com middle" v-else-if="[-1, -2].includes(Number(item.sendStatus))" @click.stop="openExpressPage(item.id)">重叫跑腿</view>
+                <view class="admin-button-com default" v-else-if="item.sendStatus == 5">跑腿完成</view>
+                <view class="admin-button-com default" v-else-if="[0, 1, 2, 3, 4, 10, 20, 30].includes(Number(item.sendStatus)) && item.payStatus == 1">已发跑腿</view>
               </block>
               </block>
 
 
             </view>
             </view>
@@ -488,7 +488,7 @@ export default {
         const item = this.list.data.find(item => item.id == orderId);
         const item = this.list.data.find(item => item.id == orderId);
         if (item) {
         if (item) {
           item.status = orderStatus;
           item.status = orderStatus;
-          item.sendStatus = String(sendStatus);
+          item.sendStatus = Number(sendStatus);
         }
         }
       }
       }
     },
     },

+ 26 - 5
hdApp/src/admin/order/detail.vue

@@ -22,11 +22,12 @@
             <view class="msg-list express-progress-row">
             <view class="msg-list express-progress-row">
               <view class="label">配送进度:</view>
               <view class="label">配送进度:</view>
               <view class="value">
               <view class="value">
-							  {{ orderInfo.sendStatus==-1?'已取消': orderInfo.sendStatus==0?'订单生成':orderInfo.sendStatus==1?'跑腿已接单':orderInfo.sendStatus==2?'派单中':orderInfo.sendStatus==3?'待取货':orderInfo.sendStatus==4?'配送中':orderInfo.sendStatus==5?'已送达':orderInfo.sendStatus==10?'改派中':orderInfo.sendStatus==20?'已分配骑手':orderInfo.sendStatus==30?'骑手已到店':'未知'}}
+							  {{ getSendStatusText(orderInfo.sendStatus) }}
               </view>
               </view>
               <view class="express-actions">
               <view class="express-actions">
-                <button class="admin-button-com mini-btn btn-danger" v-if="['0', '1', '2', '3', '4', '10', '20', '30'].includes(String(orderInfo.sendStatus))" @click.stop="cancelMyExpress(orderInfo.id, orderInfo.deliveryId)">取消跑腿</button>
-                <button class="admin-button-com mini-btn" v-if="orderInfo.sendStatus == '-1'" @click.stop="openExpressPage(orderInfo.id)">重叫跑腿</button>
+                <button class="admin-button-com mini-btn btn-danger" v-if="[0, 1, 2, 3, 4, 10, 20, 30].includes(Number(orderInfo.sendStatus))" @click.stop="cancelMyExpress(orderInfo.id, orderInfo.deliveryId)">取消跑腿</button>
+
+                <button class="admin-button-com mini-btn" v-if="[-1, -2].includes(Number(orderInfo.sendStatus))" @click.stop="openExpressPage(orderInfo.id)">重叫跑腿</button>
               </view>
               </view>
             </view>
             </view>
           </view>
           </view>
@@ -368,7 +369,7 @@
         <button class="admin-button-com middle" @click.stop="sendWork(orderInfo)" v-if="orderInfo.payStatus == 1 && (orderInfo.hasWork == 0 || orderInfo.hasWork == 2)">通知制作</button>
         <button class="admin-button-com middle" @click.stop="sendWork(orderInfo)" v-if="orderInfo.payStatus == 1 && (orderInfo.hasWork == 0 || orderInfo.hasWork == 2)">通知制作</button>
         <button class="admin-button-com middle" @click.stop="cancelFn(orderInfo)" v-if="orderInfo.status == 1"> 取消 </button>
         <button class="admin-button-com middle" @click.stop="cancelFn(orderInfo)" v-if="orderInfo.status == 1"> 取消 </button>
         <button class="admin-button-com middle" @click.stop="goScan(orderInfo)" v-if="orderInfo.status == 1"> 扫码收款 </button>
         <button class="admin-button-com middle" @click.stop="goScan(orderInfo)" v-if="orderInfo.status == 1"> 扫码收款 </button>
-        <button class="admin-button-com middle" v-if="orderInfo.sendStatus == '-4' && orderInfo.payStatus == 1" @click.stop="openExpressPage(orderInfo.id)">呼叫跑腿</button>
+        <button class="admin-button-com middle" v-if="orderInfo.sendStatus == -4 && orderInfo.payStatus == 1" @click.stop="openExpressPage(orderInfo.id)">呼叫跑腿</button>
         <button class="admin-button-com middle" @click.stop="printOrder(orderInfo)" v-if="orderInfo.payStatus == 1"> 打印 </button>
         <button class="admin-button-com middle" @click.stop="printOrder(orderInfo)" v-if="orderInfo.payStatus == 1"> 打印 </button>
       </view>
       </view>
     </view>
     </view>
@@ -435,7 +436,7 @@ const commonUtil = require("@/utils/common.js");
 import { confirmSettle } from "@/api/settle/index"
 import { confirmSettle } from "@/api/settle/index"
 import { refundAmount } from "@/api/refund";
 import { refundAmount } from "@/api/refund";
 import { expressDetail } from "@/api/express";
 import { expressDetail } from "@/api/express";
-import { cancelExpressOrder,mockNotify } from '@/api/shop-express'
+import { cancelExpressOrder, mockNotify } from '@/api/shop-express'
 import { cancelDeliveryOrder, getCancelReason, addTip as addTipApi } from '@/api/express/delivery'
 import { cancelDeliveryOrder, getCancelReason, addTip as addTipApi } from '@/api/express/delivery'
 import { needWork } from "@/api/work"
 import { needWork } from "@/api/work"
 import { CURRENT_ENV } from "@/config"
 import { CURRENT_ENV } from "@/config"
@@ -503,6 +504,26 @@ export default {
       }
       }
       return platformMap[platform] || platform
       return platformMap[platform] || platform
     },
     },
+
+    /**
+     * 转换配送状态为中文显示
+     */
+    getSendStatusText(status) {
+      const statusStr = String(status);
+      const statusMap = {
+        '-1': '已取消',
+        '0': '跑腿订单生成',
+        '1': '跑腿已接单',
+        '2': '派单中',
+        '3': '待取货',
+        '4': '配送中',
+        '5': '已送达',
+        '10': '改派中',
+        '20': '已分配骑手',
+        '30': '骑手已到店',
+      }
+      return statusMap[statusStr] || '未知';
+    },
     
     
     goPreOrder(info) {
     goPreOrder(info) {
       if (!this.$util.isEmpty(info.forwardMap)) {
       if (!this.$util.isEmpty(info.forwardMap)) {