|
|
@@ -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>
|
|
|
+
|
|
|
+<!-- <!– 新增物流轨迹标签页 –>-->
|
|
|
+<!-- <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>
|