✨ 运单导入新增与已有运单重复页签
This commit is contained in:
@@ -484,20 +484,24 @@
|
||||
</div>
|
||||
<el-tabs v-model="previewTab"
|
||||
><el-tab-pane :label="`运单数(${rows.length})`" name="all" /><el-tab-pane
|
||||
:label="`疑似重复(${duplicateRows.length})`"
|
||||
name="duplicate" /></el-tabs
|
||||
:label="`Excel内重复(${duplicateRows.length})`"
|
||||
name="duplicate" /><el-tab-pane
|
||||
:label="`与已有运单重复(${historyDuplicateRows.length})`"
|
||||
name="history" /></el-tabs
|
||||
><el-table
|
||||
:data="previewRows"
|
||||
border
|
||||
max-height="440"
|
||||
:row-class-name="({ row }) => (row._duplicate ? 'is-duplicate-row' : '')"
|
||||
:row-class-name="
|
||||
({ row }) => (row._duplicate || row._historyWaybillNo ? 'is-duplicate-row' : '')
|
||||
"
|
||||
@selection-change="rowSelection = $event"
|
||||
><el-table-column type="selection" width="55" /><el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="65"
|
||||
/><el-table-column
|
||||
v-for="column in detailColumns"
|
||||
v-for="column in previewColumns"
|
||||
:key="column.prop"
|
||||
:prop="column.prop"
|
||||
:label="column.label"
|
||||
@@ -583,8 +587,6 @@
|
||||
><el-link type="primary" @click="saveRow(row)">保存</el-link
|
||||
><el-link type="primary" @click="cancelRow(row)">取消</el-link></template
|
||||
><template v-else
|
||||
><el-link v-if="row._duplicate" type="primary" @click="confirmDuplicateRow(row)"
|
||||
>确认</el-link
|
||||
><el-link type="primary" @click="editRow(row)">编辑</el-link
|
||||
><el-link type="danger" @click="deleteRow(row)">删除</el-link></template
|
||||
></div
|
||||
@@ -716,9 +718,12 @@ const transportTypeOptions = ref([]),
|
||||
const rowSelection = ref([]),
|
||||
previewTab = ref('all');
|
||||
const duplicateRows = computed(() => rows.value.filter(row => row._duplicate));
|
||||
const previewRows = computed(() =>
|
||||
previewTab.value === 'duplicate' ? duplicateRows.value : rows.value
|
||||
);
|
||||
const historyDuplicateRows = computed(() => rows.value.filter(row => row._historyWaybillNo));
|
||||
const previewRows = computed(() => {
|
||||
if (previewTab.value === 'duplicate') return duplicateRows.value;
|
||||
if (previewTab.value === 'history') return historyDuplicateRows.value;
|
||||
return rows.value;
|
||||
});
|
||||
const carrierContractsLoaded = ref(false),
|
||||
hasCarrierContracts = ref(null);
|
||||
const carrierTypes = ['承运商', '自运'];
|
||||
@@ -795,6 +800,16 @@ const detailColumns = [
|
||||
{ prop: 'remark', label: '备注', editor: 'textarea', minWidth: 200 },
|
||||
{ prop: 'waybillIdentifier', label: '同一运单标识号', editor: 'input', minWidth: 150 },
|
||||
];
|
||||
// 与已有运单重复页签的列与明细一致,只在运单批次号后多一列已有运单号。
|
||||
const previewColumns = computed(() =>
|
||||
previewTab.value === 'history'
|
||||
? [
|
||||
detailColumns[0],
|
||||
{ prop: '_historyWaybillNo', label: '已有运单号', minWidth: 220 },
|
||||
...detailColumns.slice(1),
|
||||
]
|
||||
: detailColumns
|
||||
);
|
||||
const requiredDetailFields = [
|
||||
{ prop: 'vehicleNo', label: '车牌号/船班号/船次号/班次号' },
|
||||
{ prop: 'transportType', label: '运输方式' },
|
||||
@@ -1187,6 +1202,7 @@ const loadBatchRows = async batchId => {
|
||||
batchNo: item.batchNo || form.batchNo,
|
||||
}));
|
||||
refreshDuplicateFlags();
|
||||
await refreshHistoryDuplicates();
|
||||
rowSelection.value = [];
|
||||
previewTab.value = 'all';
|
||||
};
|
||||
@@ -1509,6 +1525,8 @@ const fileChange = async (file, list) => {
|
||||
if (isValid) {
|
||||
// 校验通过,填充表格数据
|
||||
rows.value = parsedRows;
|
||||
// 传 rows.value(响应式代理),否则后续写入不触发重新渲染
|
||||
await refreshHistoryDuplicates(rows.value);
|
||||
} else {
|
||||
// 校验失败,清空数据
|
||||
rows.value = [];
|
||||
@@ -1526,16 +1544,12 @@ const IMPORT_BATCH_SIZE = 100;
|
||||
|
||||
const importFieldText = value => String(value ?? '').trim();
|
||||
|
||||
/** 同一运单批次号下,全部导入字段一致时标记为疑似重复。已在线确认的行不再标为重复。 */
|
||||
/** 同一运单批次号下,全部导入字段一致时标记为 Excel 内重复。 */
|
||||
const refreshDuplicateFlags = (list = rows.value) => {
|
||||
const groups = new Map();
|
||||
list.forEach(row => {
|
||||
const signature = detailColumns.map(column => importFieldText(row[column.prop])).join('\u0001');
|
||||
const batchNo = importFieldText(row.batchNo || form.batchNo);
|
||||
if (row._duplicateConfirmed && row._duplicateSignature !== signature) {
|
||||
row._duplicateConfirmed = false;
|
||||
}
|
||||
row._duplicateSignature = signature;
|
||||
const groupKey = `${batchNo}\u0002${signature}`;
|
||||
const group = groups.get(groupKey) || [];
|
||||
group.push(row);
|
||||
@@ -1544,19 +1558,39 @@ const refreshDuplicateFlags = (list = rows.value) => {
|
||||
groups.forEach(group => {
|
||||
const duplicated = group.length > 1;
|
||||
group.forEach(row => {
|
||||
row._duplicate = duplicated && !row._duplicateConfirmed;
|
||||
row._duplicate = duplicated;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const confirmDuplicateRow = row => {
|
||||
row._duplicateConfirmed = true;
|
||||
refreshDuplicateFlags();
|
||||
ElMessage.success('已确认,该行将按正常数据导入');
|
||||
/** 逐行提交给后端与项目下已有运单比对,命中的行带上已有运单号。比对失败不影响导入。 */
|
||||
const refreshHistoryDuplicates = async (list = rows.value) => {
|
||||
if (!list.length || !form.projectId) {
|
||||
list.forEach(row => {
|
||||
row._historyWaybillNo = '';
|
||||
});
|
||||
return;
|
||||
}
|
||||
let duplicates = [];
|
||||
try {
|
||||
const res = await api.checkImportDuplicates(buildImportPayload(form.status, list));
|
||||
const data = res?.data?.data ?? res?.data ?? res;
|
||||
duplicates = Array.isArray(data) ? data : [];
|
||||
} catch (error) {
|
||||
console.error('与已有运单重复校验失败:', error);
|
||||
duplicates = [];
|
||||
}
|
||||
const numbersByRow = new Map(
|
||||
duplicates.map(item => [item.rowIndex, (item.waybillNos || []).filter(Boolean)])
|
||||
);
|
||||
list.forEach((row, index) => {
|
||||
row._historyWaybillNo = (numbersByRow.get(index) || []).join('、');
|
||||
});
|
||||
};
|
||||
|
||||
const stripInternalRowFields = row => {
|
||||
const { _key, _duplicate, _duplicateKey, _duplicateConfirmed, _duplicateSignature, _editing, _editSnapshot, ...data } = row;
|
||||
const { _key, _duplicate, _duplicateKey, _editing, _editSnapshot, _historyWaybillNo, ...data } =
|
||||
row;
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -1771,6 +1805,7 @@ const saveRow = row => {
|
||||
row._editing = false;
|
||||
delete row._editSnapshot;
|
||||
refreshDuplicateFlags();
|
||||
refreshHistoryDuplicates();
|
||||
};
|
||||
const cancelRow = row => {
|
||||
if (row._editSnapshot) Object.assign(row, row._editSnapshot);
|
||||
@@ -1780,12 +1815,14 @@ const cancelRow = row => {
|
||||
const deleteRow = row => {
|
||||
rows.value = rows.value.filter(item => item !== row);
|
||||
refreshDuplicateFlags();
|
||||
refreshHistoryDuplicates();
|
||||
};
|
||||
const removeSelectedRows = () => {
|
||||
const keys = new Set(rowSelection.value.map(row => row._key));
|
||||
rows.value = rows.value.filter(row => !keys.has(row._key));
|
||||
rowSelection.value = [];
|
||||
refreshDuplicateFlags();
|
||||
refreshHistoryDuplicates();
|
||||
};
|
||||
const normalizeOptionalPlanId = value => {
|
||||
if (value === undefined || value === null || value === '') return null;
|
||||
@@ -1849,7 +1886,11 @@ const confirmImport = async () => {
|
||||
await formRef.value?.validate();
|
||||
if (!validateImportRows()) return;
|
||||
const count = rows.value.filter(row => row._duplicate).length;
|
||||
if (count) await ElMessageBox.confirm(`当前导入有${count}条疑似重复数据,是否确认导入?`, '提示');
|
||||
if (count)
|
||||
await ElMessageBox.confirm(`当前导入有${count}条Excel内重复数据,是否确认导入?`, '提示');
|
||||
const historyCount = rows.value.filter(row => row._historyWaybillNo).length;
|
||||
if (historyCount)
|
||||
await ElMessageBox.confirm(`当前导入有${historyCount}条与已有运单重复,是否确认导入?`, '提示');
|
||||
if (form.importType === 'settlement' && form.status === 'completed')
|
||||
await ElMessageBox.confirm('确认后将同时生成运单、应收应付明细、计结算单,是否继续?', '提示');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user