✨ 完善运单导入编辑回填、分批校验与运费录入

导入编辑进入独立页面并回填数据,确认导入按每批100条校验后统一导出失败明细,完整录入运费信息按数量单位联动单价单位。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-27 22:54:33 +08:00
parent 98fbf123f5
commit f3a33b1a04
12 changed files with 668 additions and 133 deletions
@@ -492,6 +492,7 @@
v-model="row.quantityUnit"
clearable
:disabled="dialogReadonly"
@change="handleTransportCargoQuantityUnitChange"
@visible-change="visible => visible && loadTaskQuantityUnitOptions()"
>
<el-option
@@ -1091,20 +1092,6 @@
</template>
</el-input>
</el-form-item>
<el-form-item label="数量合计">
<el-input :model-value="taskFullFreightGroupQuantity(group)" disabled>
<template #append>
<el-select
:model-value="group.quantityUnit"
class="waybill-manage-page__append-select waybill-manage-page__append-select--wide"
placeholder="单位"
disabled
>
<el-option :label="fixedQuantityUnit" :value="fixedQuantityUnit" />
</el-select>
</template>
</el-input>
</el-form-item>
<el-form-item label="运费">
<el-input
:model-value="taskFullFreightGroupAmount(group)"
@@ -1117,11 +1104,6 @@
</el-input>
</el-form-item>
</template>
<el-form-item label="运费合计">
<el-input :model-value="taskFullFreightTotal" disabled>
<template #suffix>{{ taskFreightCurrencyLabel }}</template>
</el-input>
</el-form-item>
<el-form-item label="其他运费合计">
<el-input
v-model="form.otherFeeTotal"
@@ -1133,6 +1115,11 @@
<template #suffix>{{ taskFreightCurrencyLabel }}</template>
</el-input>
</el-form-item>
<el-form-item label="运费合计">
<el-input :model-value="taskFullFreightTotal" disabled>
<template #suffix>{{ taskFreightCurrencyLabel }}</template>
</el-input>
</el-form-item>
</el-form>
</div>
</div>
@@ -1317,7 +1304,7 @@
@change="handleTaskCargoTypeChange"
/>
</el-form-item>
<el-form-item label="货物名称">
<el-form-item label="货物名称" required>
<el-autocomplete
v-model="form.cargoName"
placeholder="请输入货物名称"
@@ -1347,7 +1334,7 @@
:disabled="dialogReadonly"
/>
</el-form-item>
<el-form-item label="型号">
<el-form-item label="型号" required>
<el-input
v-model="form.model"
placeholder="选择货物自动回填"
@@ -1355,7 +1342,7 @@
:disabled="dialogReadonly"
/>
</el-form-item>
<el-form-item label="数量">
<el-form-item label="数量" required>
<el-input
v-model="form.quantity"
placeholder="请输入数量"
@@ -1962,7 +1949,7 @@
>
</div>
<div class="waybill-manage-page__waybill-detail-field">
<span>航班号/船次号/班列号</span>
<span>船班号/船次号/班次号</span>
<strong>{{ detailRow.vehicleNo || '-' }}</strong>
</div>
<div class="waybill-manage-page__waybill-detail-field">
@@ -2162,8 +2149,12 @@
label="批量补录"
name="batchSupplement"
>
<voucher-execution-detail
v-if="waybillIsCarrier(detailRow)"
:waybill-id="detailRow.id"
/>
<div
v-if="waybillVoucherFolderView"
v-else-if="waybillVoucherFolderView"
class="waybill-manage-page__voucher-folder-toolbar"
>
<el-button text type="primary" @click="backToWaybillVoucherFolders">
@@ -2172,6 +2163,7 @@
<span>{{ waybillVoucherFolderName(waybillVoucherFolder) }}</span>
</div>
<div
v-if="!waybillIsCarrier(detailRow)"
v-loading="waybillVoucherImagesLoading"
class="waybill-manage-page__voucher-image-grid"
>
@@ -3135,6 +3127,7 @@ import {
getVoucherImages as getProcessConfigVoucherImages,
} from '@/api/business/process-config';
import { getPunchRecords as getWaybillPunchRecords, locateVehicle, trackVehicle } from '@/api/business/waybill-manage';
import VoucherExecutionDetail from './voucher-execution-detail.vue';
import { getMkPublicDetail } from '@/api/mk-process';
import { getList as getDriverList } from '@/api/transportCapacity/driver';
import {
@@ -3332,6 +3325,7 @@ export default {
WarnTriangleFilled,
ElImageViewer,
OpenFileViewer,
VoucherExecutionDetail,
},
name: 'WaybillManagePage',
props: {
@@ -3804,7 +3798,7 @@ export default {
return !this.isRoadTransport;
},
transportVehicleNoLabel() {
return this.isRoadTransport ? '车牌号' : '船/航/班列号';
return this.isRoadTransport ? '车牌号' : '船班号/船次号/班次号';
},
actionButtonLikeSearch() {
return this.config.actionButtonLikeSearch === true;
@@ -3873,9 +3867,6 @@ export default {
if (!total) return '';
return Number.isInteger(total) ? String(total) : String(Number(total.toFixed(3)));
},
fixedQuantityUnit() {
return WAYBILL_QUANTITY_UNIT;
},
taskFreightAmount() {
const quantity = Number(this.taskCargoQuantityTotal || this.form.quantity || 0);
const unitPrice = Number(this.form.unitPrice || 0);
@@ -4617,7 +4608,7 @@ export default {
return text.slice(0, 10);
},
waybillVehicleNoLabel(row = {}) {
return this.waybillIsRoadTransport(row) ? '车牌号' : '船/航/班列号';
return this.waybillIsRoadTransport(row) ? '车牌号' : '船班号/船次号/班次号';
},
waybillUnitPrice(row = {}) {
const price = row.unitPrice || row.price || '';
@@ -6408,14 +6399,11 @@ export default {
if (!rows.length) return false;
const quantityUnits = rows.map(row => String(row.quantityUnit || '').trim());
if (quantityUnits.some(unit => !unit) || new Set(quantityUnits).size !== 1) return false;
const quantityUnit = quantityUnits[0];
return rows.every(row => {
const priceUnit = String(row.priceUnit || '').trim();
const separatorIndex = Math.max(priceUnit.lastIndexOf('/'), priceUnit.lastIndexOf('/'));
const priceQuantityUnit =
separatorIndex >= 0 ? priceUnit.slice(separatorIndex + 1).trim() : priceUnit;
return !this.isBillingFieldEmpty(row.unitPrice) && priceQuantityUnit === quantityUnit;
});
const expectedPriceUnit = this.resolvePriceUnitByQuantityUnit(quantityUnits[0]);
if (!expectedPriceUnit) return false;
return rows.every(
row => !this.isBillingFieldEmpty(row.unitPrice) && String(row.priceUnit || '').trim() === expectedPriceUnit
);
},
taskFullFreightQuantity(index) {
return this.formatTaskFullFreightNumber(this.transportCargoRows[index]?.quantity || 0);
@@ -6431,10 +6419,6 @@ export default {
Number(cargo.unitPrice || 0) * Number(cargo.quantity || 0)
);
},
taskFullFreightGroupQuantity(group = {}) {
const total = (group.rows || []).reduce((sum, cargo) => sum + Number(cargo.quantity || 0), 0);
return this.formatTaskFullFreightNumber(total);
},
taskFullFreightGroupUnitPrice(group = {}) {
const prices = (group.rows || [])
.map(cargo => String(cargo.unitPrice ?? '').trim())
@@ -6443,7 +6427,11 @@ export default {
return prices[0];
},
taskFullFreightGroupPriceUnit(group = {}) {
return group.rows?.[0]?.priceUnit || (group.quantityUnit ? `元/${group.quantityUnit}` : '');
return (
group.rows?.[0]?.priceUnit ||
this.resolvePriceUnitByQuantityUnit(group.rows?.[0]?.quantityUnit) ||
''
);
},
taskFullFreightGroupAmount(group = {}) {
const total = (group.rows || []).reduce(
@@ -7174,6 +7162,11 @@ export default {
requiredFields.push(['driverName', '司机']);
requiredFields.push(['driverPhone', '手机号']);
}
if (!this.isTaskFullMode) {
requiredFields.push(['cargoName', '货物名称']);
requiredFields.push(['model', '型号']);
requiredFields.push(['quantity', '数量']);
}
const emptyField = requiredFields.find(([prop]) => this.isBillingFieldEmpty(row[prop]));
if (emptyField) {
this.$message.warning(`请选择或输入${emptyField[1]}`);
@@ -7208,7 +7201,7 @@ export default {
}
} else {
const invalidLengthField = [
['vehicleNo', '船/航/班列号', 30],
['vehicleNo', '船班号/船次号/班次号', 30],
['captainName', '船长', 20],
['cabinNo', '舱位', 30],
['containerNo', '箱号', 30],
@@ -7466,6 +7459,24 @@ export default {
parts.length > 1 ? `${parts[0]}.${parts.slice(1).join('').slice(0, 3)}` : parts[0];
this.syncTransportCargoJson();
},
resolvePriceUnitByQuantityUnit(quantityUnit) {
return (
{
吨: '元/吨',
方: '元/立方',
件: '元/件',
}[String(quantityUnit || '').trim()] || ''
);
},
handleTransportCargoQuantityUnitChange(quantityUnit) {
const priceUnit = this.resolvePriceUnitByQuantityUnit(quantityUnit);
if (!priceUnit) return;
(this.transportCargoRows || []).forEach(cargo => {
cargo.priceUnit = priceUnit;
});
this.form.priceUnit = priceUnit;
this.syncTransportCargoJson();
},
handleTransportCargoTypeChange(row, value) {
const path = this.normalizeCargoTypePath(value);
const cargoType = this.findCargoTypeByPath(path);
@@ -9787,10 +9798,16 @@ export default {
}
&--road {
grid-template-columns: repeat(3, minmax(0, 1fr));
column-gap: 56px;
grid-template-columns: repeat(4, minmax(0, 1fr));
column-gap: 24px;
row-gap: 16px;
:deep(.el-form-item__content > .el-input),
:deep(.el-form-item__content > .el-select) {
width: 100%;
max-width: 100%;
}
:deep(.waybill-manage-page__append-select) {
width: 112px;
}