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

feat:运单列表功能完成

颜琼丽 пре 16 часа
родитељ
комит
599250075f

+ 6 - 2
jd-logistics-ui-v3/.env.development

@@ -1,5 +1,5 @@
 # 页面标题
-VITE_APP_TITLE = 瑞鲸速达平台管理系统
+VITE_APP_TITLE = 瑞鲸速达
 
 # 开发环境配置
 VITE_APP_ENV = 'development'
@@ -7,4 +7,8 @@ VITE_APP_ENV = 'development'
 # 瑞鲸速达平台/开发环境
 VITE_APP_BASE_API = '/dev-api'
 
-VITE_APP_API_BASE_URL = 'http://localhost:8080'
+#朝龙
+VITE_APP_API_BASE_URL = 'http://192.168.100.92:8080'
+#学富
+#VITE_APP_API_BASE_URL = 'http://192.168.101.250:8080'
+

+ 1 - 1
jd-logistics-ui-v3/src/api/logistics/banner.js

@@ -47,7 +47,7 @@ export function delBanner(bannerId) {
 // 查询轮播图列表
 export function listIndexBanner(query) {
   return request({
-    url: '/banner/listByType',
+    url: '/system/banner/listByType',
     method: 'get',
     params: query
   })

+ 7 - 0
jd-logistics-ui-v3/src/api/logistics/book.js

@@ -42,3 +42,10 @@ export function delBook(addressId) {
     method: 'delete'
   })
 }
+export function getDefaultAddress() {
+  return request({
+    url: '/system/book/getDefaultAddress',
+    method: 'get'
+  })
+}
+

+ 22 - 0
jd-logistics-ui-v3/src/api/logistics/order.js

@@ -52,3 +52,25 @@ export function cancelOrder(data) {
     data: data
   })
 }
+
+
+// 查询物流轨迹
+export function deliverTrace(data) {
+  return request({
+    url: '/system/kd100/wxmini/queryExpres',
+    method: 'post',
+    data: data
+  })
+}
+
+
+// 查询物流费用
+export function deliverFree(data) {
+  return request({
+    url: '/system/costDetails/list',
+    method: 'get',
+    params: data
+  })
+}
+
+

+ 74 - 7
jd-logistics-ui-v3/src/components/RegionCascader.vue

@@ -1,12 +1,13 @@
 <!-- @/components/RegionCascader/index.vue -->
 <template>
   <el-cascader
+      ref="cascaderRef"
       v-model="selectedCodes"
       :options="areaOptions"
       :props="cascaderProps"
       :placeholder="placeholder"
       :clearable="clearable"
-      :disabled="disabled"
+      :disabled="isDisabled"
       :filterable="filterable"
       :show-all-levels="showAllLevels"
       :separator="separator"
@@ -23,7 +24,7 @@ import { areaData } from '@/utils/area-data.js'
 
 const props = defineProps({
   modelValue: {
-    type: Array,
+    type: [Array, String],
     default: () => []
   },
   placeholder: {
@@ -54,14 +55,24 @@ const props = defineProps({
     type: String,
     default: 'default',
     validator: (value) => ['large', 'default', 'small'].includes(value)
+  },
+  // 新增:是否只读模式
+  readonly: {
+    type: Boolean,
+    default: false
   }
 })
 
 const emit = defineEmits(['update:modelValue', 'change'])
 
-// 选中的地区代码
+const cascaderRef = ref(null)
 const selectedCodes = ref([])
 
+// 计算禁用状态
+const isDisabled = computed(() => {
+  return props.disabled || props.readonly
+})
+
 // 级联选择器配置
 const cascaderProps = {
   expandTrigger: 'hover',
@@ -70,7 +81,8 @@ const cascaderProps = {
   lazy: false,
   value: 'code',
   label: 'name',
-  children: 'children'
+  children: 'children',
+  disabled: 'disabled' // 允许数据中有disabled字段控制禁用
 }
 
 // 根据 code 获取地区信息
@@ -128,9 +140,15 @@ const areaOptions = computed(() => {
   }
 })
 
-
 // 处理变化事件
 const handleChange = (codes) => {
+  // 如果禁用或只读,阻止选择
+  if (isDisabled.value) {
+    // 恢复原来的值
+    selectedCodes.value = props.modelValue || []
+    return
+  }
+
   selectedCodes.value = codes
 
   // 构建完整的地区信息
@@ -179,23 +197,72 @@ const buildAreaInfo = (codes) => {
   }
 }
 
-
 const getAreaNameByCode = (code) => {
   if (!code) return ''
   const area = areaData.find(item => item.code === code)
   return area ? area.name : ''
 }
 
+// 处理初始值,支持字符串形式的code(如"110000")或数组形式
+const initSelectedCodes = () => {
+  const value = props.modelValue
+
+  if (!value || value.length === 0) {
+    selectedCodes.value = []
+    return
+  }
+
+  // 如果是字符串,尝试转换为数组
+  if (typeof value === 'string') {
+    // 如果是逗号分隔的字符串
+    if (value.includes(',')) {
+      selectedCodes.value = value.split(',').map(item => item.trim())
+    } else {
+      // 单个code,但级联选择器需要数组格式
+      selectedCodes.value = [value]
+    }
+  } else if (Array.isArray(value)) {
+    selectedCodes.value = [...value]
+  } else {
+    selectedCodes.value = []
+  }
+}
 
 // 监听外部值变化
 watch(() => props.modelValue, (newVal) => {
   if (JSON.stringify(selectedCodes.value) !== JSON.stringify(newVal || [])) {
-    selectedCodes.value = newVal || []
+    initSelectedCodes()
   }
 }, { immediate: true, deep: true })
 
+// 监听disabled状态变化
+watch(() => props.disabled, (newVal) => {
+  console.log('RegionCascader disabled状态变化:', newVal)
+  if (cascaderRef.value && newVal) {
+    // 确保级联选择器被正确禁用
+    cascaderRef.value.blur()
+  }
+})
+
 // 组件挂载时初始化
 onMounted(() => {
+  initSelectedCodes()
   console.log('RegionCascader组件已加载,省份数量:', areaOptions.value.length)
+  console.log('RegionCascader disabled状态:', props.disabled)
+  console.log('RegionCascader readonly状态:', props.readonly)
+})
+
+// 暴露方法给父组件
+defineExpose({
+  getSelectedCodes: () => selectedCodes.value,
+  clearSelection: () => {
+    selectedCodes.value = []
+    emit('update:modelValue', [])
+    emit('change', buildAreaInfo([]))
+  },
+  setDisabled: (disabled) => {
+    // 这个方法可以通过ref调用
+    console.log('设置禁用状态:', disabled)
+  }
 })
 </script>

+ 1 - 1
jd-logistics-ui-v3/src/views/index.vue

@@ -249,7 +249,7 @@ const handleQueryClick = (item) => {
 const getBannerList = () =>{
   // const params = {sysType:0,delFlag:0 } //系统类型(0PC管理、1小程) 删除标志(0代表存在 2代表删除
   listIndexBanner().then(response => {
-    bannerList.value = response.rows
+    bannerList.value = response.data
     startAutoPlay()
   })
 }

+ 16 - 1
jd-logistics-ui-v3/src/views/logistics/order/createOrder.vue

@@ -479,7 +479,7 @@ const { proxy } = getCurrentInstance()
 const { jd_logistics_product_code, sf_logistics_product_code } = proxy.useDict("jd_logistics_product_code", "sf_logistics_product_code")
 
 import { useRoute } from 'vue-router';
-import {updateBook} from "../../../api/logistics/book.js";
+import {updateBook,getDefaultAddress} from "../../../api/logistics/book.js";
 
 const route = useRoute();
 
@@ -1183,6 +1183,20 @@ const submitOrder = async () => {
   }
 }
 
+ const getDefaultAddressFun = async () => {
+  try {
+    const response = await getDefaultAddress()
+    if(response.code == 200){
+      console.log('订单提交成功:', response.data)
+      addressBookType.value = 'sender'
+      applyAddress(response.data)
+    } else {
+    }
+  } catch (error) {
+    console.error('订单提交失败:', error)
+  }
+}
+
 // 初始化加载
 onMounted(() => {
   console.log('快递下单页面已加载')
@@ -1190,6 +1204,7 @@ onMounted(() => {
 
   productType.value = route.query.productType || '1';
   console.log("===productType=", productType.value)
+  getDefaultAddressFun()
 })
 </script>
 

+ 880 - 7
jd-logistics-ui-v3/src/views/logistics/order/index.vue

@@ -115,7 +115,7 @@
       <el-table-column label="快递类型" align="center" prop="productCode" width="120">
         <template #default="scope">
           <dict-tag
-              :options="scope.row.orderType == '1' ? jd_logistics_product_code : sf_logistics_product_code"
+              :options="scope.row.orderType == 2 ? sf_logistics_product_code : jd_logistics_product_code"
               :value="scope.row.productCode"
           />
         </template>
@@ -192,7 +192,7 @@
     />
 
     <!-- 运单详情对话框 -->
-    <el-dialog :title="title" v-model="open" width="900px" append-to-body>
+    <el-dialog :title="title" v-model="open" width="1100px" append-to-body>
       <el-form ref="orderRef" :model="form" :rules="rules" label-width="100px" :disabled="isViewMode">
         <el-tabs v-model="activeTab">
           <el-tab-pane label="基本信息" name="basic">
@@ -278,6 +278,7 @@
                   :clearable="true"
                   @change="handleSenderRegionChange"
                   :disable="isViewMode"
+                  :readonly="isViewMode"
               />
             </el-form-item>
 
@@ -307,6 +308,7 @@
                   :clearable="true"
                   @change="handleReceiverRegionChange"
                   :disable="isViewMode"
+                  :readonly="isViewMode"
               />
             </el-form-item>
 
@@ -343,6 +345,274 @@
             </el-row>
           </el-tab-pane>
 
+          <!-- 修改后的增值服务tab页 -->
+          <el-tab-pane label="增值服务" name="addedService">
+            <div class="value-services-container">
+              <div class="form-content">
+                <div class="value-services-grid">
+                  <!-- 包装服务 -->
+                  <div class="service-item" v-if="form.orderType == '1' || form.orderType == '2'">
+                    <span class="service-label">包装服务</span>
+                    <div class="service-value">
+                      <el-switch
+                          v-model="addedServiceData.isPack"
+                          size="large"
+                          active-color="#1890ff"
+                          :disabled="isViewMode"
+                      />
+                    </div>
+                  </div>
+
+                  <!-- 保价 -->
+                  <div class="service-item" v-if="form.orderType == '1'">
+                    <span class="service-label">保价</span>
+                    <div class="insurance-wrapper">
+                      <el-switch
+                          v-model="insuranceEnabled"
+                          size="large"
+                          active-color="#1890ff"
+                          @change="handleInsuranceChange"
+                          :disabled="isViewMode"
+                      />
+                      <div class="insurance-input-wrapper" v-if="insuranceEnabled">
+                        <el-input
+                            v-model="addedServiceData.guaranteeMoney"
+                            placeholder="请输入保价金额"
+                            size="large"
+                            class="insurance-input fixed-input"
+                            @input="validateInsuranceAmount"
+                            maxlength="10"
+                            :disabled="isViewMode"
+                        >
+                          <template #append>元</template>
+                        </el-input>
+                        <div v-if="insuranceAmountError" class="error-message">
+                          {{ insuranceAmountError }}
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+
+                  <!-- 超长超重 -->
+                  <div class="service-item">
+                    <span class="service-label">超长超重</span>
+                    <div class="service-value">
+                      <el-switch
+                          v-model="addedServiceData.isOverLongWeight"
+                          size="large"
+                          active-color="#1890ff"
+                          :disabled="isViewMode"
+                      />
+                    </div>
+                  </div>
+
+                  <!-- 签单返还 -->
+                  <div class="service-item" v-if="form.orderType == '1' || form.orderType == '2'">
+                    <span class="service-label">签单返还</span>
+                    <div class="sign-return-wrapper">
+                      <el-switch
+                          v-model="signReturnEnabled"
+                          size="large"
+                          active-color="#1890ff"
+                          @change="handleSignReturnChange"
+                          :disabled="isViewMode"
+                      />
+                      <!-- 顺丰订单的签单返还类型选择 -->
+                      <div class="sign-return-select-wrapper fixed-input" v-if="signReturnEnabled && form.orderType == '2'">
+                        <el-select
+                            v-model="addedServiceData.isReceiptCollect"
+                            placeholder="请选择凭证类型"
+                            size="large"
+                            class="fixed-input sign-return-select"
+                            :disabled="isViewMode"
+                        >
+                          <el-option
+                              v-for="option in signReturnOptions"
+                              :key="option.value"
+                              :label="option.label"
+                              :value="option.value"
+                          />
+                        </el-select>
+
+                        <div v-if="signReturnTypeError" class="error-message">
+                          {{ signReturnTypeError }}
+                        </div>
+                      </div>
+                      <!-- 京东订单的签单返还只显示开关状态 -->
+                      <div v-if="signReturnEnabled && form.orderType == '1'" class="sign-return-value">
+                        已开启
+                      </div>
+                    </div>
+                  </div>
+
+                  <!-- 打木架 -->
+                  <div class="service-item" v-if="form.orderType == '2'">
+                    <span class="service-label">打木架</span>
+                    <div class="service-value">
+                      <el-switch
+                          v-model="addedServiceData.isWoodenCrate"
+                          size="large"
+                          active-color="#1890ff"
+                          :disabled="isViewMode"
+                      />
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </el-tab-pane>
+
+<!--          &lt;!&ndash; 新增物流轨迹标签页 &ndash;&gt;-->
+<!--          <el-tab-pane label="物流轨迹" name="logistics">-->
+<!--            <div class="logistics-trace-container">-->
+<!--              <div v-if="deliverTraceLoading" class="loading-container">-->
+<!--                <el-icon class="loading-icon"><Loading /></el-icon>-->
+<!--                <span>正在查询物流信息...</span>-->
+<!--              </div>-->
+<!--              <div v-else-if="deliverTraceData.length === 0" class="empty-container">-->
+<!--                <el-icon><Box /></el-icon>-->
+<!--                <span>暂无物流信息</span>-->
+<!--              </div>-->
+<!--              <div v-else class="trace-timeline">-->
+<!--                <el-timeline>-->
+<!--                  <el-timeline-item-->
+<!--                      v-for="(item, index) in deliverTraceData"-->
+<!--                      :key="index"-->
+<!--                      :timestamp="item.time"-->
+<!--                      placement="top"-->
+<!--                      :type="getTimelineType(index)"-->
+<!--                      size="large"-->
+<!--                  >-->
+<!--                    <div class="trace-item">-->
+<!--                      <div class="trace-content">{{ item.context }}</div>-->
+<!--                      <div class="trace-time">{{ item.ftime }}</div>-->
+<!--                    </div>-->
+<!--                  </el-timeline-item>-->
+<!--                </el-timeline>-->
+<!--              </div>-->
+<!--            </div>-->
+<!--          </el-tab-pane>-->
+
+          <!-- 新增费用信息标签页 -->
+          <el-tab-pane label="费用信息" name="fee">
+            <div class="fee-info-container">
+              <div v-if="deliverFreeLoading" class="loading-container">
+                <el-icon class="loading-icon"><Loading /></el-icon>
+                <span>正在查询费用信息...</span>
+              </div>
+              <div v-else-if="deliverFreeData.length === 0" class="empty-container">
+                <el-icon><Money /></el-icon>
+                <span>暂无费用信息</span>
+              </div>
+              <div v-else>
+                <!-- 费用汇总信息放在表格上方 -->
+                <div class="fee-summary" v-if="deliverFreeData.length > 0">
+                  <el-descriptions :column="4" border>
+                    <el-descriptions-item label="总原始金额">
+                      <span class="summary-amount">{{ formatCurrency(totalOriginalAmount) }}</span> 元
+                    </el-descriptions-item>
+                    <el-descriptions-item label="总费率金额">
+                      <span class="summary-amount">{{ formatCurrency(totalRateAmount) }}</span> 元
+                    </el-descriptions-item>
+                    <el-descriptions-item label="总调整金额">
+                      <span class="summary-amount">{{ formatCurrency(totalAdjustAmount) }}</span> 元
+                    </el-descriptions-item>
+                    <el-descriptions-item label="实际总金额">
+                      <span class="summary-amount total">{{ formatCurrency(actualTotalAmount) }}</span> 元
+                    </el-descriptions-item>
+                  </el-descriptions>
+                </div>
+
+                <!-- 费用信息表格 -->
+                <el-table
+                    :data="deliverFreeData"
+                    style="width: 100%; margin-top: 20px"
+                    border
+                    class="fee-table"
+                >
+                  <el-table-column
+                      prop="feeItemCode"
+                      label="费用代码"
+                      width="120"
+                      align="center"
+                  />
+                  <el-table-column
+                      prop="feeItemName"
+                      label="费用项名称"
+                      width="150"
+                      align="center"
+                  />
+                  <el-table-column
+                      prop="feeName"
+                      label="费用名称"
+                      width="120"
+                      align="center"
+                  />
+                  <el-table-column
+                      prop="amount"
+                      label="原始金额(元)"
+                      width="120"
+                      align="right"
+                  >
+                    <template #default="scope">
+                      {{ formatCurrency(scope.row.amount) }}
+                    </template>
+                  </el-table-column>
+                  <el-table-column
+                      prop="rateAmount"
+                      label="费率金额(元)"
+                      width="120"
+                      align="right"
+                  >
+                    <template #default="scope">
+                      {{ formatCurrency(scope.row.rateAmount) }}
+                    </template>
+                  </el-table-column>
+                  <el-table-column
+                      prop="adjustAmount"
+                      label="调整金额(元)"
+                      width="120"
+                      align="right"
+                  >
+                    <template #default="scope">
+                      {{ formatCurrency(scope.row.adjustAmount) }}
+                    </template>
+                  </el-table-column>
+                  <el-table-column
+                      prop="createTime"
+                      label="创建时间"
+                      width="180"
+                      align="center"
+                  />
+                  <el-table-column
+                      label="操作"
+                      width="100"
+                      align="center"
+                      v-if="!isViewMode"
+                  >
+                    <template #default="scope">
+                      <el-button
+                          link
+                          type="primary"
+                          icon="Edit"
+                          @click="handleEditFee(scope.row)"
+                      >调整</el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+
+                <!-- 费用信息分页 -->
+                <pagination
+                    v-show="deliverFreeTotal > 0"
+                    :total="deliverFreeTotal"
+                    v-model:page="deliverFreeParams.pageNum"
+                    v-model:limit="deliverFreeParams.pageSize"
+                    @pagination="handleDeliverFreePagination"
+                />
+              </div>
+            </div>
+          </el-tab-pane>
+
           <el-tab-pane label="时间信息" name="time">
             <el-row :gutter="20">
               <el-col :span="12">
@@ -450,10 +720,11 @@
 </template>
 
 <script setup name="Order">
-import { listOrder, getOrder, delOrder, addOrder, updateOrder, cancelOrder } from "@/api/logistics/order"
+import { listOrder, getOrder, delOrder, addOrder, updateOrder, cancelOrder,deliverTrace ,deliverFree} from "@/api/logistics/order"
 import RegionCascader from '@/components/RegionCascader.vue'
 import { getCodesByNames } from '@/utils/area-data.js'
-import { ref, reactive, toRefs, watch } from 'vue'
+import { ref, reactive, toRefs, watch, computed } from 'vue'
+import { Loading, Box, Money, Edit } from '@element-plus/icons-vue'
 
 const { proxy } = getCurrentInstance()
 const { order_status, jd_logistics_product_code, sf_logistics_product_code } = proxy.useDict(
@@ -475,6 +746,89 @@ const isViewMode = ref(false)
 const activeTab = ref('basic')
 const productCodeOptions = ref([]) // 快递类型选项
 
+// 物流轨迹数据
+const deliverTraceData = ref([])
+const deliverTraceLoading = ref(false)
+
+// 费用信息数据
+const deliverFreeData = ref([])
+const deliverFreeTotal = ref(0)
+const deliverFreeLoading = ref(false)
+const deliverFreeParams = ref({
+  pageNum: 1,
+  pageSize: 10,
+  waybillId: null
+})
+
+// 签单返还选项(顺丰使用)
+const signReturnOptions = ref([
+  { value: 1, label: '运单原件' },
+  { value: 2, label: '复印件' },
+  { value: 3, label: '照片' }
+])
+
+// 增值服务相关数据
+const addedServiceData = ref({
+  isPack: false,
+  guaranteeMoney: null,
+  isOverLongWeight: false,
+  isReceiptCollect: null,
+  isWoodenCrate: false
+})
+
+const insuranceAmountError = ref('')
+const signReturnTypeError = ref('')
+
+// 计算属性:保价开关是否开启
+const insuranceEnabled = computed({
+  get() {
+    return addedServiceData.value.guaranteeMoney !== null && addedServiceData.value.guaranteeMoney !== ''
+  },
+  set(value) {
+    if (!value) {
+      addedServiceData.value.guaranteeMoney = null
+    } else {
+      addedServiceData.value.guaranteeMoney = 0
+    }
+  }
+})
+
+// 计算属性:签单返还开关是否开启
+const signReturnEnabled = computed({
+  get() {
+    return addedServiceData.value.isReceiptCollect !== null
+  },
+  set(value) {
+    if (!value) {
+      addedServiceData.value.isReceiptCollect = null
+    } else {
+      // 如果是京东,设为true;如果是顺丰,设为默认值1
+      if (form.value.orderType == '1') {
+        addedServiceData.value.isReceiptCollect = true
+      } else if (form.value.orderType == '2') {
+        addedServiceData.value.isReceiptCollect = 1
+      }
+    }
+  }
+})
+
+// 计算属性:费用汇总信息
+const totalOriginalAmount = computed(() => {
+  return deliverFreeData.value.reduce((sum, item) => sum + (Number(item.amount) || 0), 0)
+})
+
+const totalRateAmount = computed(() => {
+  return deliverFreeData.value.reduce((sum, item) => sum + (Number(item.rateAmount) || 0), 0)
+})
+
+const totalAdjustAmount = computed(() => {
+  return deliverFreeData.value.reduce((sum, item) => sum + (Number(item.adjustAmount) || 0), 0)
+})
+
+const actualTotalAmount = computed(() => {
+  return totalRateAmount.value + totalAdjustAmount.value
+})
+
 const data = reactive({
   form: {},
   queryParams: {
@@ -532,6 +886,23 @@ const handleOrderTypeChange = (value) => {
   // 切换订单类型时,重置快递类型
   form.value.productCode = ''
   updateProductCodeOptions()
+
+  // 重置增值服务中与订单类型相关的字段
+  if (value == '1') {
+    // 京东订单:重置顺丰特有字段
+    addedServiceData.value.isWoodenCrate = false
+    // 如果签单返还开启,且原来是数字类型,改为true
+    if (addedServiceData.value.isReceiptCollect !== null && typeof addedServiceData.value.isReceiptCollect === 'number') {
+      addedServiceData.value.isReceiptCollect = true
+    }
+  } else if (value == '2') {
+    // 顺丰订单:重置京东特有字段
+    // 保价金额可以保留
+    // 如果签单返还开启,且原来是true,改为默认值1
+    if (addedServiceData.value.isReceiptCollect === true) {
+      addedServiceData.value.isReceiptCollect = 1
+    }
+  }
 }
 
 /** 获取订单状态文本 */
@@ -599,8 +970,36 @@ function reset() {
     createBy: null,
     updateBy: null,
     deptId: null,
-    userId: null
+    userId: null,
+    addedService: null
+  }
+
+  // 重置增值服务数据
+  addedServiceData.value = {
+    isPack: false,
+    guaranteeMoney: null,
+    isOverLongWeight: false,
+    isReceiptCollect: null,
+    isWoodenCrate: false
+  }
+
+  // 重置物流轨迹数据
+  deliverTraceData.value = []
+  deliverTraceLoading.value = false
+
+  // 重置费用信息数据
+  deliverFreeData.value = []
+  deliverFreeTotal.value = 0
+  deliverFreeLoading.value = false
+  deliverFreeParams.value = {
+    pageNum: 1,
+    pageSize: 10,
+    waybillId: null
   }
+
+  insuranceAmountError.value = ''
+  signReturnTypeError.value = ''
+
   activeTab.value = 'basic'
   proxy.resetForm("orderRef")
 }
@@ -638,16 +1037,180 @@ function handleView(row) {
       data.receiverRegion = getCodesByNames(data.receiverProvince, data.receiverCity, data.receiverCounty)
     }
     data.orderStatus = data.orderStatus + ''
+
+    // 处理增值服务数据
+    if (data.addedService && typeof data.addedService === 'string') {
+      try {
+        const parsedService = JSON.parse(data.addedService)
+        // 更新增值服务数据
+        addedServiceData.value = {
+          isPack: parsedService.isPack || false,
+          guaranteeMoney: parsedService.guaranteeMoney,
+          isOverLongWeight: parsedService.isOverLongWeight || false,
+          isReceiptCollect: parsedService.isReceiptCollect,
+          isWoodenCrate: parsedService.isWoodenCrate || false
+        }
+        data.addedService = parsedService
+      } catch (e) {
+        console.error('解析增值服务数据失败:', e)
+        // 使用默认值
+        addedServiceData.value = {
+          isPack: false,
+          guaranteeMoney: null,
+          isOverLongWeight: false,
+          isReceiptCollect: null,
+          isWoodenCrate: false
+        }
+      }
+    } else if (data.addedService && typeof data.addedService === 'object') {
+      // 如果已经是对象,直接使用
+      addedServiceData.value = {
+        isPack: data.addedService.isPack || false,
+        guaranteeMoney: data.addedService.guaranteeMoney,
+        isOverLongWeight: data.addedService.isOverLongWeight || false,
+        isReceiptCollect: data.addedService.isReceiptCollect,
+        isWoodenCrate: data.addedService.isWoodenCrate || false
+      }
+    } else {
+      // 没有增值服务数据,使用默认值
+      addedServiceData.value = {
+        isPack: false,
+        guaranteeMoney: null,
+        isOverLongWeight: false,
+        isReceiptCollect: null,
+        isWoodenCrate: false
+      }
+    }
+
     form.value = data
     open.value = true
     isViewMode.value = true
     title.value = "查看运单详情"
 
+    // 查询物流轨迹
+    getDeliverTrace(data.externalWaybillNo)
+
+    // 查询费用信息
+    deliverFreeParams.value.waybillId = data.waybillId
+    deliverFreeParams.value.pageNum = 1 // 重置为第一页
+    getDeliverFree()
+
     // 根据订单类型更新快递类型选项
     updateProductCodeOptions()
   })
 }
 
+/** 查询物流轨迹 */
+const getDeliverTrace = (externalWaybillNo) => {
+  if (!externalWaybillNo) {
+    deliverTraceData.value = []
+    return
+  }
+
+  deliverTraceLoading.value = true
+  const params = {
+    number: externalWaybillNo,
+    company: form.value.orderType == '1' ? 'jd' : 'sf'
+  }
+
+  deliverTrace(params).then(response => {
+    const data = response.data
+    if (response.code === 200 && data.data ) {
+      // 获取物流轨迹数据,按时间倒序排列(最新的在前面)
+      deliverTraceData.value = data.data.sort((a, b) => {
+        return new Date(b.time) - new Date(a.time)
+      })
+    } else {
+      deliverTraceData.value = []
+      // proxy.$modal.msgWarning("未查询到物流信息")
+    }
+    deliverTraceLoading.value = false
+  }).catch(error => {
+    console.error('查询物流轨迹失败:', error)
+    deliverTraceData.value = []
+    deliverTraceLoading.value = false
+    proxy.$modal.msgError("查询物流信息失败")
+  })
+}
+
+/** 查询费用信息 */
+const getDeliverFree = () => {
+  if (!deliverFreeParams.value.waybillId) {
+    deliverFreeData.value = []
+    return
+  }
+
+  deliverFreeLoading.value = true
+
+  // 构建查询参数,确保传递分页参数
+  const params = {
+    waybillId: deliverFreeParams.value.waybillId,
+    pageNum: deliverFreeParams.value.pageNum,
+    pageSize: deliverFreeParams.value.pageSize
+  }
+
+  console.log('查询费用信息参数:', params) // 调试用,可以查看传递的参数
+
+  deliverFree(params).then(response => {
+    console.log('费用信息响应:', response) // 调试用,查看返回的数据
+    if (response.code === 200) {
+      deliverFreeData.value = response.rows || []
+      deliverFreeTotal.value = response.total || 0
+    } else {
+      deliverFreeData.value = []
+      deliverFreeTotal.value = 0
+      proxy.$modal.msgWarning(response.msg || "未查询到费用信息")
+    }
+    deliverFreeLoading.value = false
+  }).catch(error => {
+    console.error('查询费用信息失败:', error)
+    deliverFreeData.value = []
+    deliverFreeTotal.value = 0
+    deliverFreeLoading.value = false
+    proxy.$modal.msgError("查询费用信息失败")
+  })
+}
+
+/** 费用信息分页处理 */
+const handleDeliverFreePagination = (pagination) => {
+  deliverFreeParams.value.pageNum = pagination.page
+  deliverFreeParams.value.pageSize = pagination.limit
+  getDeliverFree()
+}
+
+/** 格式化货币金额 */
+const formatCurrency = (value) => {
+  if (value === null || value === undefined) return '0.00'
+  const num = Number(value)
+  if (isNaN(num)) return '0.00'
+  return num.toFixed(2)
+}
+
+/** 编辑费用项 */
+const handleEditFee = (row) => {
+  // 这里可以打开一个弹窗来编辑费用项
+  proxy.$modal.msgInfo(`编辑费用项:${row.feeItemName},ID:${row.waybillDetailId}`)
+  // 你可以根据业务需求实现具体的编辑逻辑
+  // 例如:
+  // proxy.$modal.prompt('请输入调整金额', '调整费用', {
+  //   confirmButtonText: '确定',
+  //   cancelButtonText: '取消',
+  //   inputPattern: /^\d+(\.\d{1,2})?$/,
+  //   inputErrorMessage: '请输入正确的金额'
+  // }).then(({ value }) => {
+  //   // 调用更新接口
+  // }).catch(() => {})
+}
+
+/** 获取时间轴样式类型 */
+const getTimelineType = (index) => {
+  // 第一条数据(最新的)显示为primary
+  if (index === 0) return 'primary'
+  // 根据状态判断:已送达显示success,其他显示info
+  if (deliverTraceData.value[0]?.context?.includes('已送达')) return 'success'
+  return 'info'
+}
+
 /** 发件地址省市区变更处理 */
 const handleSenderRegionChange = (regionInfo) => {
   console.log('发件地区信息:', regionInfo)
@@ -666,6 +1229,44 @@ const handleReceiverRegionChange = (regionInfo) => {
   form.value.receiverRegion = [regionInfo.provinceCode, regionInfo.cityCode, regionInfo.districtCode]
 }
 
+/** 保价开关变化处理 */
+const handleInsuranceChange = (value) => {
+  if (!value) {
+    addedServiceData.value.guaranteeMoney = null
+    insuranceAmountError.value = ''
+  } else {
+    addedServiceData.value.guaranteeMoney = 0
+  }
+}
+
+/** 验证保价金额 */
+const validateInsuranceAmount = () => {
+  if (insuranceEnabled.value && addedServiceData.value.guaranteeMoney !== null) {
+    const amount = parseFloat(addedServiceData.value.guaranteeMoney)
+    if (isNaN(amount) || amount <= 0) {
+      insuranceAmountError.value = '保价金额必须大于0'
+    } else {
+      insuranceAmountError.value = ''
+    }
+  } else {
+    insuranceAmountError.value = ''
+  }
+}
+
+/** 签单返还开关变化处理 */
+const handleSignReturnChange = (value) => {
+  if (!value) {
+    addedServiceData.value.isReceiptCollect = null
+    signReturnTypeError.value = ''
+  } else {
+    if (form.value.orderType == '1') {
+      addedServiceData.value.isReceiptCollect = true
+    } else if (form.value.orderType == '2') {
+      addedServiceData.value.isReceiptCollect = 1
+    }
+  }
+}
+
 /** 取消下单操作 */
 function handleCancelOrder(row) {
   proxy.$prompt('请输入取消原因', '取消下单', {
@@ -691,16 +1292,34 @@ function handleCancelOrder(row) {
 
 /** 提交表单 */
 function submitForm() {
+  // 验证保价金额
+  if (insuranceEnabled.value && (!addedServiceData.value.guaranteeMoney || addedServiceData.value.guaranteeMoney <= 0)) {
+    proxy.$modal.msgError("请填写正确的保价金额")
+    return
+  }
+
+  // 验证签单返还类型(顺丰)
+  if (signReturnEnabled.value && form.value.orderType == '2' && !addedServiceData.value.isReceiptCollect) {
+    proxy.$modal.msgError("请选择签单返还凭证类型")
+    return
+  }
+
   proxy.$refs["orderRef"].validate(valid => {
     if (valid) {
+      // 准备提交的数据
+      const submitData = { ...form.value }
+
+      // 将增值服务数据转换为JSON字符串
+      submitData.addedService = JSON.stringify(addedServiceData.value)
+
       if (form.value.waybillId != null) {
-        updateOrder(form.value).then(() => {
+        updateOrder(submitData).then(() => {
           proxy.$modal.msgSuccess("修改成功")
           open.value = false
           getList()
         })
       } else {
-        addOrder(form.value).then(() => {
+        addOrder(submitData).then(() => {
           proxy.$modal.msgSuccess("新增成功")
           open.value = false
           getList()
@@ -798,5 +1417,259 @@ getList()
 
 :deep(.el-dialog__body) {
   padding: 20px;
+  max-height: 70vh;
+  overflow-y: auto;
+}
+
+/* 增值服务样式 */
+.value-services-container {
+  padding: 10px;
+}
+
+.form-card {
+  background: #fff;
+  border-radius: 8px;
+  overflow: hidden;
+  margin-bottom: 20px;
+}
+
+.form-card.full-width {
+  width: 100%;
+}
+
+.card-header.with-blue-line {
+  display: flex;
+  align-items: center;
+  padding: 16px 20px;
+  background-color: #f8fafc;
+  border-bottom: 1px solid #e8e8e8;
+}
+
+.blue-line {
+  width: 4px;
+  height: 16px;
+  background-color: #1890ff;
+  margin-right: 12px;
+  border-radius: 2px;
+}
+
+.header-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #333;
+}
+
+.form-content {
+  padding: 20px;
+}
+
+.value-services-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+  gap: 20px;
+}
+
+.service-item {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 12px 16px;
+  background-color: #f9f9f9;
+  border-radius: 6px;
+  border: 1px solid #e8e8e8;
+}
+
+.service-label {
+  font-size: 14px;
+  font-weight: 500;
+  color: #333;
+}
+
+.service-value {
+  display: flex;
+  align-items: center;
+}
+
+.insurance-wrapper {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-end;
+  gap: 8px;
+}
+
+.insurance-input-wrapper {
+  width: 200px;
+}
+
+.insurance-input.fixed-input {
+  width: 100%;
+}
+
+.sign-return-wrapper {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-end;
+  gap: 8px;
+}
+
+.sign-return-select-wrapper {
+  width: 200px;
+}
+
+.sign-return-select.fixed-input {
+  width: 100%;
+}
+
+.sign-return-value {
+  font-size: 14px;
+  color: #1890ff;
+  font-weight: 500;
+  padding: 8px 12px;
+  background-color: #f0f7ff;
+  border-radius: 4px;
+  border: 1px solid #91d5ff;
+}
+
+.error-message {
+  font-size: 12px;
+  color: #ff4d4f;
+  margin-top: 4px;
+}
+
+/* 物流轨迹样式 */
+.logistics-trace-container {
+  padding: 20px;
+  max-height: 500px;
+  overflow-y: auto;
+}
+
+/* 费用信息样式 */
+.fee-info-container {
+  padding: 10px;
+  max-height: 500px;
+  overflow-y: auto;
+}
+
+.fee-table {
+  margin-bottom: 20px;
+}
+
+.fee-summary {
+  margin-bottom: 20px;
+  padding: 15px;
+  background-color: #f8f9fa;
+  border-radius: 8px;
+}
+
+.summary-amount {
+  font-weight: bold;
+  color: #333;
+}
+
+.summary-amount.total {
+  color: #1890ff;
+  font-size: 16px;
+}
+
+:deep(.el-descriptions__body) {
+  background-color: transparent;
+}
+
+.loading-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 300px;
+  color: #909399;
+}
+
+.loading-icon {
+  font-size: 48px;
+  margin-bottom: 20px;
+  animation: rotate 2s linear infinite;
+}
+
+@keyframes rotate {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+.empty-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 300px;
+  color: #909399;
+}
+
+.empty-container .el-icon {
+  font-size: 48px;
+  margin-bottom: 20px;
+}
+
+.trace-timeline {
+  padding: 10px 0;
+}
+
+.trace-item {
+  padding: 8px 0;
+}
+
+.trace-content {
+  font-size: 14px;
+  line-height: 1.5;
+  color: #333;
+  margin-bottom: 4px;
+}
+
+.trace-time {
+  font-size: 12px;
+  color: #999;
+}
+
+/* 时间轴样式优化 */
+:deep(.el-timeline-item__node) {
+  background-color: #1890ff;
+}
+
+:deep(.el-timeline-item__node--primary) {
+  background-color: #1890ff;
+}
+
+:deep(.el-timeline-item__node--success) {
+  background-color: #67c23a;
+}
+
+:deep(.el-timeline-item__node--info) {
+  background-color: #909399;
+}
+
+:deep(.el-timeline-item__tail) {
+  border-left-color: #e4e7ed;
+}
+
+/* 只读模式下的样式 */
+:deep(.el-switch.is-disabled) {
+  opacity: 0.6;
+}
+
+:deep(.el-input.is-disabled .el-input__inner) {
+  background-color: #f5f5f5;
+  border-color: #e4e7ed;
+  color: #606266;
+  cursor: not-allowed;
+}
+
+:deep(.el-select.is-disabled .el-input__inner) {
+  background-color: #f5f5f5;
+  border-color: #e4e7ed;
+  color: #606266;
+  cursor: not-allowed;
 }
 </style>