Преглед изворни кода

1. 修正之前理解错误的包邮需求 -- 真实情况是:没有包邮,但是如果配送距离小于等于 hsFreeKm,那么免跑腿费

2. 添加跑腿订单详情页
shizhongqi пре 8 месеци
родитељ
комит
069baca8ef

+ 10 - 10
ghsApp/src/admin/delivery/allDelivery.vue

@@ -614,14 +614,14 @@ export default {
       background-color: #f9f9f9;
       
       .control-btn {
-        width: 60upx;
-        height: 60upx;
+        width: 60rpx;
+        height: 60rpx;
         display: flex;
         align-items: center;
         justify-content: center;
         background-color: #f5f5f5;
         color: #666666;
-        font-size: 32upx;
+        font-size: 36rpx;
         font-weight: bold;
         transition: all 0.2s;
         user-select: none;
@@ -631,28 +631,28 @@ export default {
         }
         
         &.minus-btn {
-          border-right: 1upx solid #e0e0e0;
+          border-right: 1rpx solid #e0e0e0;
         }
         
         &.plus-btn {
-          border-left: 1upx solid #e0e0e0;
+          border-left: 1rpx solid #e0e0e0;
         }
       }
       
       input {
         flex: 1;
-        width: 100upx;
-        height: 60upx;
-        font-size: 28upx;
+        width: 100rpx;
+        height: 60rpx;
+        font-size: 28rpx;
         color: #333333;
         border: none;
         background-color: #ffffff;
         text-align: center;
-        padding: 0 10upx;
+        padding: 0 10rpx;
         
         &::placeholder {
           color: #999999;
-          font-size: 24upx;
+          font-size: 24rpx;
         }
       }
     }

+ 625 - 0
ghsApp/src/admin/delivery/orderDetail.vue

@@ -0,0 +1,625 @@
+<template>
+  <view class="page-container">
+    <view v-if="loading" class="loading-container">
+      <text>加载中...</text>
+    </view>
+    
+    <block v-else-if="detail">
+      <!-- 状态卡片 -->
+      <view class="status-card">
+        <view class="status-header">
+          <text class="status-text">{{ getStatusText() }}</text>
+          <text class="platform-tag">{{ getPlatformName() }}</text>
+        </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">
+             <text class="label">取货码</text>
+             <text class="value">{{ detail.fetch_code || detail.pickupPassword || detail.pickup_code }}</text>
+           </view>
+        </view>
+        <view class="codes-row" v-if="detail.write_off_code || detail.deliveryPassword || detail.complete_code">
+           <view class="code-item">
+             <text class="label">收货码</text>
+             <text class="value">{{ detail.write_off_code || detail.deliveryPassword || detail.complete_code }}</text>
+           </view>
+        </view>
+      </view>
+
+      <!-- 骑手信息 -->
+      <view class="card" v-if="hasDriverInfo()">
+        <view class="card-title">骑手信息</view>
+        <view class="driver-info">
+          <view class="info-main">
+            <text class="name">{{ getDriverName() || '待接单' }}</text>
+            <text class="phone" v-if="getDriverPhone()" @click="callDriver">{{ getDriverPhone() }}</text>
+          </view>
+          <view class="info-sub" v-if="getDriverExtra()">
+            {{ getDriverExtra() }}
+          </view>
+          <view class="driver-location" v-if="getDriverLocation()">
+            <text class="location-text">{{ getDriverLocation() }}</text>
+          </view>
+        </view>
+      </view>
+
+      <!-- 订单信息 -->
+      <view class="card">
+        <view class="card-title">订单信息</view>
+        <view class="info-row">
+          <text class="label">平台订单号</text>
+          <text class="value copy-btn" @click="copyText(getOrderId())">{{ getOrderId() }}</text>
+        </view>
+        <view class="info-row" v-if="detail.partner_order_code || detail.thirdOrderNo || detail.out_order_id">
+          <text class="label">商家订单号</text>
+          <text class="value">{{ detail.partner_order_code || detail.thirdOrderNo || detail.out_order_id }}</text>
+        </view>
+        <view class="info-row" v-if="getDistance()">
+          <text class="label">配送距离</text>
+          <text class="value">{{ getDistance() }}</text>
+        </view>
+         <view class="info-row" v-if="getWeight()">
+          <text class="label">物品重量</text>
+          <text class="value">{{ getWeight() }}</text>
+        </view>
+        <view class="info-row" v-if="getCreateTime()">
+          <text class="label">下单时间</text>
+          <text class="value">{{ getCreateTime() }}</text>
+        </view>
+        <view class="info-row" v-if="getExpectTime()">
+          <text class="label">预计送达</text>
+          <text class="value">{{ getExpectTime() }}</text>
+        </view>
+      </view>
+
+      <!-- 费用信息 -->
+      <view class="card">
+        <view class="card-title">费用明细</view>
+        <view class="info-row main-price">
+          <text class="label">实际支付</text>
+          <text class="value price">¥{{ getActualPrice() }}</text>
+        </view>
+        <view class="info-row" v-if="getTotalPrice() != getActualPrice()">
+          <text class="label">原价</text>
+          <text class="value">¥{{ getTotalPrice() }}</text>
+        </view>
+        
+        <!-- 费用列表展开 -->
+        <view class="fee-list" v-if="getFeeList().length > 0">
+          <view class="fee-item" v-for="(item, index) in getFeeList()" :key="index">
+            <text class="fee-name">{{ item.name }}</text>
+            <text class="fee-amount">¥{{ item.amount }}</text>
+          </view>
+        </view>
+      </view>
+
+      <!-- 追踪/日志 -->
+      <view class="card" v-if="getLogs().length > 0">
+        <view class="card-title">订单追踪</view>
+        <view class="log-list">
+          <view class="log-item" v-for="(log, index) in getLogs()" :key="index">
+            <view class="log-time">{{ log.time }}</view>
+            <view class="log-content">
+              <view class="log-status">{{ log.status }}</view>
+              <view class="log-desc" v-if="log.desc">{{ log.desc }}</view>
+            </view>
+          </view>
+        </view>
+      </view>
+
+    </block>
+    <block v-else>
+        <view class="empty-container">
+            <text>暂无数据</text>
+        </view>
+    </block>
+  </view>
+</template>
+
+<script>
+import { deliveryOrderDetail } from '@/api/express/delivery';
+
+export default {
+  name: 'orderDetail',
+  data() {
+    return {
+      detail: null,
+      loading: true,
+      platform: '', // fengniao, shansong, huolala, shunfeng
+    };
+  },
+  onLoad(options) {
+    console.log('options', options);
+    // 兼容从订单详情页跳转过来的参数
+    // platform: 配送单ID (detailInfo.deliveryId)
+    // orderId: 订单ID (detailInfo.id)
+    if (options.platform) {
+      this.platform = options.platform;
+    }
+    
+    if (options.orderId) {
+      this.orderId = options.orderId;
+    }
+
+    if (options.orderSn) {
+      this.orderSn = options.orderSn;
+    }
+    
+    if (this.platform && this.orderId) {
+      this.getData();
+    } else {
+        this.$msg('参数错误');
+        setTimeout(() => {
+            uni.navigateBack();
+        }, 1500);
+    }
+  },
+  methods: {
+    getData() {
+      this.loading = true;
+      // 构造请求参数,优先传 id (配送单ID),也传 order_id 供后端备用
+      const params = {};
+      if (this.platform) params.platform = this.platform;
+      if (this.orderId) params.orderId = this.orderId;
+      if (this.orderSn) params.orderSn = this.orderSn;
+      deliveryOrderDetail(params).then(res => {
+        this.loading = false;
+        if (res.code === 1) {
+          // 处理不同平台的嵌套结构
+          // 假设 res.data 是平台返回的原始数据或者包含在 res.data.data 中
+          // 根据 prompt, 某些平台数据在 res.data.data (如 huolala, shansong 可能是 res.data.data)
+          // 我们先尝试判断
+          let raw = res.data;
+          
+          // 尝试检测平台
+          this.platform = this.detectPlatform(raw);
+          
+          // 如果检测不到,尝试在 .data 中查找 (针对 huolala, shansong 这种结构 {"code":1, "data": {"ret":0, "data": ...}})
+          if (this.platform === 'unknown' && raw.data) {
+             let inner = raw.data;
+             let innerPlatform = this.detectPlatform(inner);
+             if (innerPlatform !== 'unknown') {
+                 this.platform = innerPlatform;
+                 this.detail = inner;
+             } else if (raw.result) { // 顺丰
+                 this.platform = 'shunfeng';
+                 this.detail = raw.result;
+             } else if (raw.data && typeof raw.data === 'object') {
+                 // 可能是 shansong, huolala 的嵌套
+                 this.detail = raw.data; // 此时 detail 可能是 huolala 的 data 字典
+                 // 再次检测
+                 this.platform = this.detectPlatform(this.detail);
+                 
+                 // 如果还是 unknown,可能需要修正 detail 指向
+                 if (this.platform === 'unknown' && raw.data && raw.data.data) {
+                      // 针对 huolala: {"ret":0, "data": {...}}
+                      this.detail = raw.data.data;
+                      this.platform = this.detectPlatform(this.detail);
+                 }
+             }
+          } else {
+              this.detail = raw;
+          }
+          
+          // 特殊处理顺丰 (result)
+          if (this.platform === 'unknown' && raw.result) {
+              this.platform = 'shunfeng';
+              this.detail = raw.result;
+          }
+
+          console.log('Detected platform:', this.platform);
+          console.log('Detail data:', this.detail);
+        } else {
+          this.$msg(res.msg || '获取详情失败');
+        }
+      }).catch(err => {
+        this.loading = false;
+        console.error(err);
+        this.$msg('请求异常');
+      });
+    },
+    detectPlatform(data) {
+      if (!data) return 'unknown';
+      // 蜂鸟特征
+      if (data.partner_order_code !== undefined && (data.carrier_driver_name !== undefined || data.order_actual_amount_cent !== undefined)) return 'fengniao';
+      // 闪送特征
+      if (data.issOrderNo !== undefined || (data.courier !== undefined && data.orderNo !== undefined)) return 'shansong';
+      // 货拉拉特征
+      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';
+      
+      return 'unknown';
+    },
+    getPlatformName() {
+      const map = {
+        'fengniao': '蜂鸟跑腿',
+        'shansong': '闪送',
+        'huolala': '货拉拉',
+        'shunfeng': '顺丰同城'
+      };
+      return map[this.platform] || '未知平台';
+    },
+    getStatusText() {
+      if (!this.detail) return '';
+      switch (this.platform) {
+        case 'fengniao':
+          // 0:生成, 1:运单生成, 20:骑手接单, 80:骑手到店, 2:配送中, 3:已完成, 4:取消, 5:异常
+          const fnMap = {0:'待接单', 1:'待接单', 20:'已接单', 80:'已到店', 2:'配送中', 3:'已完成', 4:'已取消', 5:'异常'};
+          return fnMap[this.detail.order_status] || '未知状态';
+        case 'shansong':
+          return this.detail.orderStatusDesc || this.detail.statusDesc || '';
+        case 'huolala':
+           return this.detail.order_status_name || '';
+        case 'shunfeng':
+           // 1:创建, 2:取消, 10:接单, 12:到店, 15:配送中, 17:完成, 31:取消中
+           return this.detail.status_desc || '';
+        default:
+          return '未知';
+      }
+    },
+    getStatusDesc() {
+      if (!this.detail) return '';
+      if (this.platform === 'fengniao') return this.detail.abnormal_desc || '';
+      if (this.platform === 'shansong') return this.detail.subOrderStatusDesc || '';
+      if (this.platform === 'huolala') return this.detail.remark || ''; // 货拉拉似乎没有额外的状态描述
+      return '';
+    },
+    hasDriverInfo() {
+        return this.getDriverName() || this.getDriverPhone();
+    },
+    getDriverName() {
+      if (!this.detail) return '';
+      switch (this.platform) {
+        case 'fengniao': return this.detail.carrier_driver_name;
+        case 'shansong': return this.detail.courier ? this.detail.courier.name : '';
+        case 'huolala': return this.detail.driver_info ? this.detail.driver_info.name : '';
+        case 'shunfeng': return this.detail.rider_name;
+        default: return '';
+      }
+    },
+    getDriverPhone() {
+      if (!this.detail) return '';
+      switch (this.platform) {
+        case 'fengniao': return this.detail.carrier_driver_phone;
+        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 'shunfeng': return this.detail.rider_phone;
+        default: return '';
+      }
+    },
+    getDriverExtra() {
+         if (!this.detail) return '';
+         if (this.platform === 'huolala' && this.detail.driver_info) {
+             return [this.detail.driver_info.physics_vehicle_name, this.detail.driver_info.license_plate].filter(x=>x).join(' | ');
+         }
+         if (this.platform === 'fengniao' && this.detail.temperature) {
+             return this.detail.temperature;
+         }
+         return '';
+    },
+    getDriverLocation() {
+         if (!this.detail) return '';
+         if (this.platform === 'shansong' && this.detail.courier && this.detail.courier.estimateDeliveryTimeTip) {
+             return this.detail.courier.estimateDeliveryTimeTip;
+         }
+         // 经纬度展示略过,直接展示文本信息
+         return '';
+    },
+    callDriver() {
+      const phone = this.getDriverPhone();
+      if (phone) {
+        uni.makePhoneCall({ phoneNumber: phone });
+      }
+    },
+    getOrderId() {
+      if (!this.detail) return '';
+      switch (this.platform) {
+        case 'fengniao': return this.detail.partner_order_code || this.detail.order_id; // 优先外部
+        case 'shansong': return this.detail.orderNo || this.detail.issOrderNo;
+        case 'huolala': return this.detail.order_display_id;
+        case 'shunfeng': return this.detail.order_id;
+        default: return '';
+      }
+    },
+    getDistance() {
+        if (!this.detail) return '';
+        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';
+        return '';
+    },
+    getWeight() {
+        if (!this.detail) return '';
+        if (this.platform === 'shunfeng' && this.detail.weight_gram) return (this.detail.weight_gram / 1000).toFixed(1) + 'kg';
+        return '';
+    },
+    getCreateTime() {
+        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 === 'shunfeng' && this.detail.push_time) return this.$util.$formatDate(this.detail.push_time);
+        // 其他平台可能需要从日志中获取或未提供明确的创建时间字段
+        return '';
+    },
+    getExpectTime() {
+        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 === 'shunfeng' && this.detail.expect_time) return this.$util.$formatDate(this.detail.expect_time); // seconds
+        return '';
+    },
+    getActualPrice() {
+        if (!this.detail) return '0.00';
+        let fen = 0;
+        switch (this.platform) {
+            case 'fengniao': fen = this.detail.order_actual_amount_cent; 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 'shunfeng': fen = this.detail.real_pay_money; break;
+        }
+        return (fen / 100).toFixed(2);
+    },
+    getTotalPrice() {
+        if (!this.detail) return '0.00';
+        let fen = 0;
+        switch (this.platform) {
+            case 'fengniao': fen = this.detail.order_total_amount_cent; break;
+            case 'shansong': fen = this.detail.totalAmount; break;
+            case 'huolala': fen = this.detail.total_price_fen; break;
+            case 'shunfeng': fen = this.detail.total_pay_money; break;
+        }
+        return (fen / 100).toFixed(2);
+    },
+    getFeeList() {
+        if (!this.detail) return [];
+        let list = [];
+        if (this.platform === 'fengniao' && this.detail.price_detail) {
+            const p = this.detail.price_detail;
+            // map keys
+            const map = {
+                start_price_cent: '起送价',
+                distance_price_cent: '距离加价',
+                weight_price_cent: '重量加价',
+                time_period_surcharge_cent: '时段加价',
+                tip_amount_cent: '小费'
+            };
+            for (let k in p) {
+                if (map[k] && p[k] > 0) list.push({ name: map[k], amount: (p[k]/100).toFixed(2) });
+            }
+        } else if (this.platform === 'shansong' && this.detail.feeInfoList) {
+            this.detail.feeInfoList.forEach(item => {
+                list.push({ name: item.des, amount: (item.fee/100).toFixed(2) });
+            });
+        } else if (this.platform === 'huolala' && this.detail.price_info) {
+            this.detail.price_info.forEach(item => {
+                 list.push({ name: item.bill_type_name, amount: (item.amount_fen/100).toFixed(2) });
+            });
+        } else if (this.platform === 'shunfeng') {
+            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) });
+        }
+        return list;
+    },
+    getLogs() {
+        if (!this.detail) return [];
+        let logs = [];
+        if (this.platform === 'fengniao' && this.detail.event_log_details) {
+            logs = this.detail.event_log_details.map(item => ({
+                time: this.$util.$formatDate(item.occur_time, 'YYYY-MM-DD HH:mm', true),
+                status: item.order_status, // 需转义,暂略
+                desc: item.carrier_driver_name ? `骑手: ${item.carrier_driver_name}` : ''
+            }));
+        } else if (this.platform === 'shansong' && this.detail.statusChangeLog) {
+            logs = this.detail.statusChangeLog.map(item => ({
+                time: item.updateTime,
+                status: item.orderStatus // 需转义
+            }));
+        }
+        // 货拉拉和顺丰示例未提供详细日志列表
+        return logs;
+    },
+    copyText(text) {
+        if(!text) return;
+        uni.setClipboardData({
+            data: String(text),
+            success: () => {
+                this.$msg('复制成功');
+            }
+        });
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.page-container {
+  min-height: 100vh;
+  background-color: #f5f5f5;
+  padding: 20upx;
+  padding-bottom: 100upx;
+}
+.loading-container {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    height: 500upx;
+    color: #999;
+}
+.empty-container {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    height: 500upx;
+    color: #999;
+}
+
+.status-card {
+  background: linear-gradient(to right, #3385FF, #5aa0ff);
+  border-radius: 16upx;
+  padding: 40upx 30upx;
+  color: white;
+  margin-bottom: 20upx;
+  box-shadow: 0 4upx 10upx rgba(51, 133, 255, 0.2);
+
+  .status-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 10upx;
+    
+    .status-text {
+        font-size: 40upx;
+        font-weight: bold;
+    }
+    .platform-tag {
+        font-size: 24upx;
+        background-color: rgba(255,255,255,0.2);
+        padding: 4upx 12upx;
+        border-radius: 8upx;
+    }
+  }
+  
+  .status-desc {
+      font-size: 28upx;
+      opacity: 0.9;
+      margin-bottom: 20upx;
+  }
+  
+  .codes-row {
+      display: flex;
+      margin-top: 30upx;
+      .code-item {
+          margin-right: 40upx;
+          display: flex;
+          flex-direction: column;
+          
+          .label {
+              font-size: 24upx;
+              opacity: 0.8;
+              margin-bottom: 4upx;
+          }
+          .value {
+              font-size: 36upx;
+              font-weight: bold;
+          }
+      }
+  }
+}
+
+.card {
+  background-color: white;
+  border-radius: 16upx;
+  padding: 30upx;
+  margin-bottom: 20upx;
+  
+  .card-title {
+    font-size: 30upx;
+    font-weight: bold;
+    margin-bottom: 20upx;
+    color: #333;
+    border-left: 6upx solid #3385FF;
+    padding-left: 14upx;
+    line-height: 1;
+  }
+  
+  .info-row {
+      display: flex;
+      justify-content: space-between;
+      padding: 16upx 0;
+      border-bottom: 1upx solid #f9f9f9;
+      font-size: 28upx;
+      
+      &:last-child {
+          border-bottom: none;
+      }
+      
+      .label {
+          color: #666;
+      }
+      .value {
+          color: #333;
+          &.price {
+              color: #ff5500;
+              font-weight: bold;
+          }
+          &.copy-btn {
+              color: #3385FF;
+          }
+      }
+  }
+  
+  .driver-info {
+      .info-main {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 10upx;
+          .name {
+              font-size: 32upx;
+              font-weight: bold;
+          }
+          .phone {
+              color: #3385FF;
+              border: 1upx solid #3385FF;
+              padding: 4upx 16upx;
+              border-radius: 30upx;
+              font-size: 24upx;
+          }
+      }
+      .info-sub {
+          color: #666;
+          font-size: 26upx;
+          margin-bottom: 10upx;
+      }
+      .driver-location {
+          font-size: 24upx;
+          color: #999;
+          margin-top: 10upx;
+          background-color: #f5f5f5;
+          padding: 10upx;
+          border-radius: 8upx;
+      }
+  }
+  
+  .fee-list {
+      margin-top: 20upx;
+      padding-top: 20upx;
+      border-top: 1upx solid #eee;
+      
+      .fee-item {
+          display: flex;
+          justify-content: space-between;
+          font-size: 26upx;
+          color: #666;
+          margin-bottom: 10upx;
+      }
+  }
+  
+  .log-list {
+      .log-item {
+          display: flex;
+          margin-bottom: 20upx;
+          
+          .log-time {
+              width: 140upx;
+              font-size: 24upx;
+              color: #999;
+              margin-right: 20upx;
+          }
+          .log-content {
+              flex: 1;
+              .log-status {
+                  font-size: 28upx;
+                  color: #333;
+                  margin-bottom: 4upx;
+              }
+              .log-desc {
+                  font-size: 24upx;
+                  color: #999;
+              }
+          }
+      }
+  }
+}
+</style>
+

+ 1 - 1
ghsApp/src/admin/home/components/OrderItem.vue

@@ -151,7 +151,7 @@
         <block v-else-if="[0, 1, 2, 3, 4, 10, 20, 30].includes(item.sendStatus)">
           <view class="text-center"><button class="admin-button-com" @click="cancelExpressOrder(item)">取消跑腿</button></view>
         </block>
-        <block v-else-if="item.sendStatus == 3">
+        <block v-else-if="item.sendStatus == -1">
           <view class="text-center"><button class="admin-button-com" @click="callIntraCity(item)">重叫跑腿</button></view>
         </block>
         <view class="text-center"><button class="admin-button-com" @click="addExpress(item)">顺丰下单</button></view>

+ 9 - 1
ghsApp/src/api/express/delivery.js

@@ -21,6 +21,13 @@ export const createDeliveryOrder = data => {
 	return https.post('/delivery/create-order', data)
 }
 
+/**
+ * 获取配送单详情
+ */
+export const deliveryOrderDetail = data => {
+	return https.get('/delivery/order-detail', data)
+}
+
 /**
  * 取消配送单
  */
@@ -61,4 +68,5 @@ export const cancelAuth = data => {
  */
 export const addTip = data => {
 	return https.post('/delivery/add-tip', data)
-}
+}
+

+ 37 - 5
ghsApp/src/pagesOrder/detail.vue

@@ -21,7 +21,12 @@
 				<button class="admin-button-com default middle" style="position: absolute;top:180upx;right:28upx;" @click.stop="modifyAddress(detailInfo)">修改地址</button>
 			</view>
 
-			<view class="flex-space title" v-if="Number(detailInfo.sendStatus)>-4">配送进度</view>
+			<view class="flex-space title" v-if="Number(detailInfo.sendStatus)>-4">
+				配送进度
+				<view class="flex" style="color: #3385ff;font-weight: 400">
+					<view @click.stop="deliveryDetail(detailInfo)" style="margin-left:0upx;">详情</view>
+				</view>
+			</view>
 			<view class="content-box" v-if="Number(detailInfo.sendStatus)>-4">
 				<view class="order-msg-blo" style="padding: 20upx;">
 					<view class="msg-list">
@@ -912,6 +917,11 @@ export default {
 				this.$msg('添加小费失败');
 			});
 		},
+		//配送详情
+		deliveryDetail(detailInfo) {
+			console.log("detailInfo", detailInfo);
+			this.pageTo({url: '/admin/delivery/orderDetail?platform=' + detailInfo.deliveryId + '&orderId=' + detailInfo.id + '&orderSn=' + detailInfo.orderSn});
+		},
 		//获取配送状态文本
 		getSendStatusText(status) {
 			const statusStr = String(status);
@@ -1620,10 +1630,32 @@ export default {
 		}
 	}
 	& > .title {
-		color: #666666;
-		font-size: 28upx;
-		font-weight: 600;
-		padding: 30upx 3upx;
+		color: #333333;
+		font-size: 30upx;
+		font-weight: bold;
+		padding: 24upx 20upx;
+		background-color: #ffffff;
+		border-radius: 16upx 16upx 0 0;
+		margin-top: 20upx;
+		border-bottom: 1upx solid #f5f5f5;
+		position: relative;
+
+		&::before {
+			content: '';
+			position: absolute;
+			left: 0;
+			top: 50%;
+			transform: translateY(-50%);
+			width: 8upx;
+			height: 46upx;
+			background-color: #3385ff;
+			border-radius: 0 6upx 6upx 0;
+		}
+	}
+
+	& > .title + .content-box {
+		border-top-left-radius: 0;
+		border-top-right-radius: 0;
 	}
 	& .address-des_bx {
 		position: relative;

+ 16 - 17
mallApp/src/pages/billing/affirmGhs.vue

@@ -106,10 +106,13 @@
 					</tui-list-cell>
 					<tui-list-cell class="line-cell" :hover="false" v-if="displaySendCost == true">
 						<view class="tui-title">跑腿费</view>
-						<view>
+						<view v-if="form.openIntraCity == 1">
 							<text :class="isFreeDelivery ? 'delivery-price-free' : 'delivery-price-normal'">¥ {{ form.sendCost }}</text>
 							<text v-if="isFreeDelivery" class="free-delivery-tag">【免跑腿费】</text>
 						</view>
+						<view v-else>
+							<text style="color: #3385FF">不支持跑腿,运费自理</text>
+						</view>
 					</tui-list-cell>
 
 					<tui-list-cell class="line-cell" :hover="false" :arrow="true" v-if="form.sendType == 2 || form.sendType == 0" @click="modifyAddress">
@@ -195,7 +198,7 @@ export default {
 				packCost:0,
 				sendCost:0,
 				showAddress:'',
-				openIntraCity:0
+				openIntraCity:0 // 是否支持跑腿送: 0不支持 1支持
 			},
 			userInfo:{},
 			shopInfo:{},
@@ -388,8 +391,10 @@ export default {
 			if(num == 2){
 				//计算运费
 				//this.calcSendCost()
-				console.log('calcSendCost')
-				this.getDeliveryQuotes()
+				
+				if(Number(that.form.openIntraCity) == 1){
+					that.getDeliveryQuotes()
+				}
 			} else {
 				// 切换到其他配送方式时清空报价数据
 				this.deliveryQuotes = []
@@ -552,10 +557,6 @@ export default {
 				}
 			}
 			if(this.form.sendType == 2) {
-				if(this.form.openIntraCity == 0){
-					this.$msg('跑腿送已停用,请换其它方式')
-					return false
-				}
 				if(Number(this.form.sendCost) <= 0){
 					this.$msg('没有获取到跑腿费')
 					return false
@@ -715,7 +716,6 @@ export default {
 /* 跑腿平台报价样式 */
 .delivery-quotes-container {
 	width: 100%;
-	margin-top: 10upx;
 }
 
 .delivery-quotes-grid {
@@ -731,14 +731,13 @@ export default {
 	flex-direction: column;
 	align-items: center;
 	justify-content: center;
-	flex: 0 0 calc(33% - 7upx);
-	width: calc(33% - 7upx);
-	min-height: 140upx;
-	padding: 16upx 10upx;
-	margin-bottom: 5upx;
+	flex: 0 0 calc(33% - 8rpx);
+	width: calc(33% - 8rpx);
+	min-height: 140rpx;
+	padding: 16rpx 10rpx;
 	background: #FFFFFF;
-	border: 2upx solid #DDDDDD;
-	border-radius: 8upx;
+	border: 2rpx solid #DDDDDD;
+	border-radius: 8rpx;
 	box-sizing: border-box;
 	transition: all 0.3s;
 	
@@ -749,7 +748,7 @@ export default {
 	}
 	
 	.platform-name {
-		font-size: 26upx;
+		font-size: 26rpx;
 		color: #333;
 		font-weight: bold;
 		margin-bottom: 8upx;

+ 10 - 18
mallApp/src/pages/order/buy.vue

@@ -85,8 +85,9 @@ export default {
       showDistance: 0,
       goodsTotalPrice: 0,
       hasMap: 0, // 是否具备定位功能 0不具备 1具备
-      // 是否收配送费
+      // 是否收配送费: True-收配送费  False-在配送范围内(小于 hsFreeKm),不收配送费
       isFreight: false,
+      // 是否支持跑腿送: 0不支持 1支持
       openIntraCity: 0,
       // 花束多少公里内免费配送
       hsFreeKm: 0,
@@ -108,8 +109,8 @@ export default {
      * @returns {boolean}
      */
     isFreeDelivery(){
-      // 不是跑腿送或不收配送费时,不需要判断
-      if(this.form.sendType != 2 || !this.isFreight){
+      // 不是跑腿送,不需要判断
+      if(this.form.sendType != 2){
         return false
       }
       
@@ -127,13 +128,12 @@ export default {
     },
     mayPayAmount(){
       let price = (this.goodsInfo.price || 0) * (this.goodsInfo.buyNum || 0)
-      // 收配送费时,商品价格加上配送费
-      if(this.isFreight){
-        // 如果不是免跑腿费,则加上跑腿费
-        if(!this.isFreeDelivery){
-          price = Number(this.freightPrice)+Number(price)
-        }
+     
+      // 如果不是免跑腿费,则加上跑腿费
+      if(!this.isFreeDelivery){
+        price = Number(this.freightPrice)+Number(price)
       }
+      
       return parseFloat(price.toFixed(2))
     }
   },
@@ -176,11 +176,7 @@ export default {
       }
 		},
     countFreight(data = {}) {
-      if(this.isFreight){
-        this.freightPrice = data.sendCost || 0
-      } else {
-        this.freightPrice = 0
-      }
+      this.freightPrice = data.sendCost || 0
       this.showDistance = data.distance ? parseFloat((data.distance / 1000).toFixed(2)) : 0;
       this.deliveryPlatform = data.deliveryPlatform || '';
       this.deliveryPrice = data.deliveryPrice || 0;
@@ -198,10 +194,6 @@ export default {
       this.form.sendCost = this.freightPrice
     },
     formSubmit() {
-      if(this.form.sendType == 2 && this.openIntraCity == 0){
-        this.$msg('跑腿暂不可用,请选它方式下单')
-        return
-      }
       this.createOrderFn()
     },
     createOrderFn() {

+ 3 - 14
mallApp/src/pages/order/components/app-delivery.vue

@@ -97,7 +97,7 @@
         </tui-list-cell>
         
         <!-- 跑腿平台报价列表 -->
-        <tui-list-cell v-if="isFreight && deliveryQuotes.length > 0" class="line-cell" :hover="false" :arrow="false">
+        <tui-list-cell v-if="deliveryQuotes.length > 0" class="line-cell" :hover="false" :arrow="false">
           <view class="delivery-quotes-container">
             <view class="delivery-quotes-grid">
               <view 
@@ -118,7 +118,7 @@
             </view>
           </view>
         </tui-list-cell>
-        <tui-list-cell  v-else-if="isFreight && deliveryQuotesLoading" class="line-cell" :hover="false" :arrow="false">
+        <tui-list-cell  v-else-if="deliveryQuotesLoading" class="line-cell" :hover="false" :arrow="false">
           <view style="text-align: center; padding: 20rpx 0; color: #999;">正在获取报价...</view>
         </tui-list-cell>
       </block>
@@ -166,7 +166,7 @@ export default {
     },
     /**
      * 是否收配送费
-     * @type {Boolean} True:收配送费  False:不收配送费
+     * @type {Boolean} True:收配送费  False:在配送范围内(即距离小于 hsFreeKm),不收配送费
      * @default false
      */
     isFreight: {
@@ -228,9 +228,6 @@ export default {
     ...mapGetters({ orderShop: "getOrderShop" }),
     ...mapGetters({ shopUser: "getShopUser" }),
     isFreeDelivery(){
-      // 如果父组件isFreight为false,则直接判定为免运费
-      if(!this.isFreight) return true;
-      
       const distanceInKm = Number(this.showDistance) || 0;
       const freeKm = Number(this.hsFreeKm) || 0;
       
@@ -246,12 +243,6 @@ export default {
      * 新规则:距离 <= 免费公里数时免费,距离 > 免费公里数时按超出部分计费
      */
     calculatedDeliveryCost(){
-      // 如果不收配送费,返回0
-      if(!this.isFreight) return 0;
-      
-      // 如果满足免费条件,返回0
-      if(this.isFreeDelivery) return 0;
-      
       const distanceInKm = Number(this.showDistance) || 0;
       const freeKm = Number(this.hsFreeKm) || 0;
       const addFee = Number(this.hsAddFee) || 0;
@@ -352,8 +343,6 @@ export default {
       return 0;
     },
     triggerGetDeliveryQuotes() {
-      if(!this.isFreight) return;
-
       if (this.form.receiveUserName && this.form.receiveMobile && this.form.address) {
         this.getDeliveryQuotes();
       }