调整结算模块
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<component
|
||||
v-if="!createPage"
|
||||
:is="standalone ? 'div' : 'el-dialog'"
|
||||
v-model="visible"
|
||||
title="导入运单"
|
||||
@@ -44,7 +45,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="waybill-import-toolbar__actions">
|
||||
<el-button type="primary" @click="openCreate">新建导入</el-button
|
||||
<el-button type="primary" @click="handleCreate">新建导入</el-button
|
||||
><el-button type="danger" plain :disabled="!selected.length" @click="removeBatches"
|
||||
>批量删除</el-button
|
||||
>
|
||||
@@ -84,7 +85,11 @@
|
||||
>
|
||||
<template #default="{ row }"
|
||||
><el-link type="primary" @click="openDetail(row)">查看</el-link
|
||||
><el-link type="primary" @click="editBatch(row)">编辑</el-link
|
||||
><el-link
|
||||
v-if="row.importStatus === 'draft'"
|
||||
type="primary"
|
||||
@click="editBatch(row)"
|
||||
>编辑</el-link
|
||||
><el-link type="danger" @click="removeBatch(row)">删除</el-link></template
|
||||
>
|
||||
</el-table-column>
|
||||
@@ -173,13 +178,14 @@
|
||||
/>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
<component
|
||||
:is="createPage ? 'div' : 'el-dialog'"
|
||||
v-model="createVisible"
|
||||
title="新建导入"
|
||||
width="85%"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
class="waybill-import-create"
|
||||
:class="['waybill-import-create', { 'waybill-import-create--page': createPage }]"
|
||||
>
|
||||
<section class="waybill-import-create__form-panel">
|
||||
<el-form
|
||||
@@ -236,9 +242,12 @@
|
||||
<el-col :span="6">
|
||||
<el-form-item label="承运类型" prop="carrierType">
|
||||
<el-select v-model="form.carrierType" @change="carrierTypeChange">
|
||||
<el-option label="承运商" value="承运商" />
|
||||
<el-option label="自运" value="自运" />
|
||||
<el-option label="网货平台" value="网货平台" />
|
||||
<el-option
|
||||
v-for="item in carrierTypeOptions"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -267,8 +276,12 @@
|
||||
<el-col :span="6">
|
||||
<el-form-item label="导入状态" prop="status">
|
||||
<el-select v-model="form.status">
|
||||
<el-option label="完成" value="completed" />
|
||||
<el-option label="进行中" value="processing" />
|
||||
<el-option
|
||||
v-for="item in importStatusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -307,8 +320,8 @@
|
||||
><el-link type="primary" @click="downloadTemplate">下载模板</el-link></el-form-item
|
||||
>
|
||||
</el-form>
|
||||
<div class="waybill-import-create__form-actions">
|
||||
<el-button @click="createVisible = false">关闭</el-button
|
||||
<div v-if="!createPage" class="waybill-import-create__form-actions">
|
||||
<el-button @click="closeCreate">关闭</el-button
|
||||
><el-button @click="saveDraft">保存草稿</el-button
|
||||
><el-button type="primary" @click="confirmImport">确认导入</el-button>
|
||||
</div>
|
||||
@@ -373,7 +386,8 @@
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择"
|
||||
@change="value => handleEditorChange(column, row, value)" /><el-select
|
||||
@change="value => handleEditorChange(column, row, value)"
|
||||
/><el-select
|
||||
v-else-if="column.editor === 'cargoName'"
|
||||
v-model="row.cargoName"
|
||||
clearable
|
||||
@@ -392,20 +406,24 @@
|
||||
type="date"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择" /><el-input
|
||||
placeholder="请选择"
|
||||
/><el-input
|
||||
v-else-if="column.editor === 'textarea'"
|
||||
v-model="row[column.prop]"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 1, maxRows: 3 }"
|
||||
:placeholder="`请输入${column.label}`" /><el-input
|
||||
:placeholder="`请输入${column.label}`"
|
||||
/><el-input
|
||||
v-else-if="column.editor === 'number'"
|
||||
:model-value="row[column.prop]"
|
||||
inputmode="decimal"
|
||||
:placeholder="`请输入${column.label}`"
|
||||
@input="value => updateEditorValue(column, row, value)" /><el-input
|
||||
v-else
|
||||
@input="value => updateEditorValue(column, row, value)"
|
||||
/><el-input
|
||||
v-else-if="column.editor"
|
||||
v-model="row[column.prop]"
|
||||
:placeholder="`请输入${column.label}`" /></template
|
||||
:placeholder="`请输入${column.label}`"
|
||||
/><span v-else>{{ formatCell(row, column) }}</span></template
|
||||
><span v-else>{{ formatCell(row, column) }}</span></template
|
||||
></el-table-column
|
||||
><el-table-column label="操作" width="180" fixed="right"
|
||||
@@ -421,12 +439,19 @@
|
||||
></el-table
|
||||
>
|
||||
</section>
|
||||
</el-dialog>
|
||||
<div v-if="createPage" class="waybill-import-create__footer">
|
||||
<el-button @click="closeCreate">取消</el-button>
|
||||
<el-button @click="saveDraft">保存草稿</el-button>
|
||||
<el-button type="primary" @click="confirmImport">确认导入</el-button>
|
||||
</div>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import dayjs from 'dayjs';
|
||||
import { getList as getCargoTypeList } from '@/api/base/cargo-type';
|
||||
import { getList as getCommonCargoList } from '@/api/business/common-cargo';
|
||||
import { getList as getContractList } from '@/api/business/contract-manage';
|
||||
@@ -436,19 +461,22 @@ import { getDictionary } from '@/api/system/dictbiz';
|
||||
import * as api from '@/api/business/waybill-manage';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
|
||||
const props = defineProps({ modelValue: Boolean, standalone: Boolean });
|
||||
const props = defineProps({ modelValue: Boolean, standalone: Boolean, createPage: Boolean });
|
||||
const emit = defineEmits(['update:modelValue', 'closed']);
|
||||
const router = useRouter();
|
||||
const visible = computed({
|
||||
get: () => props.modelValue,
|
||||
set: value => emit('update:modelValue', value),
|
||||
});
|
||||
const handleClosed = () => emit('closed');
|
||||
const createVisible = ref(false),
|
||||
const createVisible = ref(props.createPage),
|
||||
detailVisible = ref(false),
|
||||
formRef = ref();
|
||||
const query = reactive({ batchNo: '', carrierId: '', createUser: '', createTimeRange: [] });
|
||||
const detailQuery = reactive({ vehicleNo: '', cargoName: '' });
|
||||
const createDefaultForm = () => ({
|
||||
id: '',
|
||||
batchNo: '',
|
||||
projectId: '',
|
||||
projectName: '',
|
||||
customerId: '',
|
||||
@@ -466,6 +494,14 @@ const createDefaultForm = () => ({
|
||||
file: null,
|
||||
});
|
||||
const form = reactive(createDefaultForm());
|
||||
// 批量导入状态仅保留草稿与导入完成两种,与后端 importStatus 取值一致。
|
||||
const importStatusOptions = [
|
||||
{ label: '草稿', value: 'draft' },
|
||||
{ label: '导入完成', value: 'completed' },
|
||||
];
|
||||
// 编辑草稿时明细已入库,此时不再强制重新上传附件。
|
||||
const validateImportFile = (rule, value, callback) =>
|
||||
form.file || rows.value.length ? callback() : callback(new Error('请上传明细表'));
|
||||
const rules = {
|
||||
projectId: [{ required: true, message: '请选择项目', trigger: 'change' }],
|
||||
customerName: [{ required: true, message: '请选择客户', trigger: 'change' }],
|
||||
@@ -475,8 +511,10 @@ const rules = {
|
||||
carrierContractId: [{ required: true, message: '请选择承运商合同', trigger: 'change' }],
|
||||
status: [{ required: true, message: '请选择导入状态', trigger: 'change' }],
|
||||
importType: [{ required: true, message: '请选择导入类型', trigger: 'change' }],
|
||||
file: [{ required: true, message: '请上传明细表', trigger: 'change' }],
|
||||
file: [{ required: true, validator: validateImportFile, trigger: 'change' }],
|
||||
};
|
||||
// 保存草稿只落库批次与已解析的明细,仅校验后端建批次必填项,不校验附件与明细完整性。
|
||||
const draftRequiredFields = ['projectId', 'contractId', 'carrierType', 'importType'];
|
||||
const batches = ref([]),
|
||||
details = ref([]),
|
||||
rows = ref([]),
|
||||
@@ -501,7 +539,14 @@ const duplicateRows = computed(() => rows.value.filter(row => row._duplicate));
|
||||
const previewRows = computed(() =>
|
||||
previewTab.value === 'duplicate' ? duplicateRows.value : rows.value
|
||||
);
|
||||
const carrierContractsLoaded = ref(false),
|
||||
hasCarrierContracts = ref(null);
|
||||
const carrierTypes = ['承运商', '自运', '网货平台'];
|
||||
const isSelfOperated = computed(() => form.carrierType === '自运');
|
||||
// 项目下没有承运商合同时只允许自运,与运单管理的承运类型收窄规则一致。
|
||||
const carrierTypeOptions = computed(() =>
|
||||
carrierContractsLoaded.value && hasCarrierContracts.value === false ? ['自运'] : carrierTypes
|
||||
);
|
||||
const carrierSelectionValue = computed(() =>
|
||||
isSelfOperated.value ? form.carrierName : form.carrierContractId
|
||||
);
|
||||
@@ -518,46 +563,26 @@ const resetCreateForm = () => {
|
||||
contracts.value = [];
|
||||
carrierContracts.value = [];
|
||||
carrierOptions.value = [];
|
||||
carrierContractsLoaded.value = false;
|
||||
hasCarrierContracts.value = null;
|
||||
};
|
||||
// 运单批次号由系统自动生成,整批共用一个,明细表内只读展示。
|
||||
const detailColumns = [
|
||||
{ prop: 'batchNo', label: '运单批次号', editor: 'input', minWidth: 150 },
|
||||
{ prop: 'batchNo', label: '运单批次号', minWidth: 150 },
|
||||
{ prop: 'originalNo', label: '原始单号', editor: 'input', minWidth: 150 },
|
||||
{ prop: 'vehicleNo', label: '车牌号/航班号/船号/班列号', editor: 'input', minWidth: 220 },
|
||||
{ prop: 'driverName', label: '司机/船长', editor: 'driver', minWidth: 170 },
|
||||
{ prop: 'transportType', label: '运输方式', editor: 'transportType', minWidth: 150 },
|
||||
{ prop: 'cargoType', label: '货物类型', editor: 'cargoType', minWidth: 220 },
|
||||
{ prop: 'transportType', label: '运输类型', editor: 'transportType', minWidth: 150 },
|
||||
{ prop: 'cargoName', label: '货物名称', editor: 'cargoName', minWidth: 220 },
|
||||
{ prop: 'cargoType', label: '货物类型', editor: 'cargoType', minWidth: 220 },
|
||||
{ prop: 'quantity', label: '重量', editor: 'number', minWidth: 130 },
|
||||
{ prop: 'departureAddress', label: '发货地址', editor: 'textarea', minWidth: 260 },
|
||||
{ prop: 'departureContact', label: '发货联系人', editor: 'input', minWidth: 140 },
|
||||
{ prop: 'departurePhone', label: '发货联系人电话', editor: 'input', minWidth: 160 },
|
||||
{ prop: 'arrivalAddress', label: '到货地址', editor: 'textarea', minWidth: 260 },
|
||||
{ prop: 'arrivalContact', label: '收货联系人', editor: 'input', minWidth: 140 },
|
||||
{ prop: 'arrivalPhone', label: '收货联系人电话', editor: 'input', minWidth: 160 },
|
||||
{ prop: 'startDate', label: '开始时间', editor: 'date', minWidth: 150 },
|
||||
{ prop: 'endDate', label: '结束时间', editor: 'date', minWidth: 150 },
|
||||
{ prop: 'unitPrice', label: '单价', editor: 'number', minWidth: 130 },
|
||||
{ prop: 'freight', label: '运费', editor: 'number', minWidth: 130 },
|
||||
{ prop: 'otherFeeTotal', label: '其他费用合计', editor: 'number', minWidth: 150 },
|
||||
{ prop: 'freightTotal', label: '运费合计', editor: 'number', minWidth: 130 },
|
||||
{ prop: 'remark', label: '备注', editor: 'textarea', minWidth: 180 },
|
||||
];
|
||||
const requiredDetailFields = [
|
||||
{ prop: 'vehicleNo', label: '车牌号/航班号/船号/班列号' },
|
||||
{ prop: 'driverName', label: '司机/船长' },
|
||||
{ prop: 'transportType', label: '运输方式' },
|
||||
{ prop: 'transportType', label: '运输类型' },
|
||||
{ prop: 'cargoName', label: '货物名称' },
|
||||
{ prop: 'cargoType', label: '货物类型' },
|
||||
{ prop: 'departureAddress', label: '发货地址' },
|
||||
{ prop: 'departureContact', label: '发货联系人' },
|
||||
{ prop: 'departurePhone', label: '发货联系人电话' },
|
||||
{ prop: 'arrivalAddress', label: '到货地址' },
|
||||
{ prop: 'arrivalContact', label: '到货联系人' },
|
||||
{ prop: 'arrivalPhone', label: '收货联系人电话' },
|
||||
{ prop: 'startDate', label: '开始时间' },
|
||||
{ prop: 'endDate', label: '结束时间' },
|
||||
{ prop: 'unitPrice', label: '单价' },
|
||||
{ prop: 'freight', label: '运费' },
|
||||
];
|
||||
const projectQueryParams = { approvalStatuses: 'approved,change_approved' };
|
||||
const extractRecords = res => {
|
||||
@@ -568,24 +593,62 @@ const extractRecords = res => {
|
||||
if (Array.isArray(data?.data?.records)) return data.data.records;
|
||||
return [];
|
||||
};
|
||||
// 批次号规则:PC + 导入日期 + 当日批次流水号(4 位),如 PC202606010001。
|
||||
const batchNoPrefix = 'PC';
|
||||
const batchNoSequenceLength = 4;
|
||||
const generateBatchNo = async () => {
|
||||
const prefix = `${batchNoPrefix}${dayjs().format('YYYYMMDD')}`;
|
||||
let maxSequence = 0;
|
||||
try {
|
||||
const res = await api.getImportBatches({ current: 1, size: 9999 });
|
||||
extractRecords(res).forEach(item => {
|
||||
const no = String(item.batchNo || '').trim();
|
||||
if (!no.startsWith(prefix)) return;
|
||||
maxSequence = Math.max(maxSequence, Number(no.slice(prefix.length)) || 0);
|
||||
});
|
||||
} catch (error) {
|
||||
maxSequence = 0;
|
||||
}
|
||||
return `${prefix}${String(maxSequence + 1).padStart(batchNoSequenceLength, '0')}`;
|
||||
};
|
||||
// 承运商合同的承运商固定取合同乙方,与运单管理(waybill-manage-page)保持一致。
|
||||
const getCarrierContractPartyName = (contract = {}) =>
|
||||
String(
|
||||
contract.partyB ||
|
||||
contract.partyBName ||
|
||||
contract.contractPartyB ||
|
||||
contract.customerContractPartyB ||
|
||||
contract.secondParty ||
|
||||
contract.secondPartyName ||
|
||||
''
|
||||
).trim();
|
||||
const buildCarrierContractOptions = contractRows => {
|
||||
const validContracts = contractRows.filter(
|
||||
item => String(item.contractCategory || '').trim() === '承运商合同'
|
||||
);
|
||||
const nameCounts = validContracts.reduce((result, item) => {
|
||||
const name = String(item.partyA || item.partyAName || '').trim();
|
||||
const name = getCarrierContractPartyName(item);
|
||||
if (name) result[name] = (result[name] || 0) + 1;
|
||||
return result;
|
||||
}, {});
|
||||
return validContracts
|
||||
.map(contract => {
|
||||
const carrierName = String(contract.partyA || contract.partyAName || '').trim();
|
||||
const carrierName = getCarrierContractPartyName(contract);
|
||||
if (!contract.id || !carrierName) return null;
|
||||
const identifier = contract.contractName || contract.contractNo || contract.id;
|
||||
return {
|
||||
id: contract.partyAId || contract.partyAUserId || contract.customerId || '',
|
||||
id:
|
||||
contract.partyBId ||
|
||||
contract.partyBUserId ||
|
||||
contract.contractPartyBId ||
|
||||
contract.customerContractPartyBId ||
|
||||
contract.secondPartyId ||
|
||||
contract.secondPartyUserId ||
|
||||
contract.carrierId ||
|
||||
'',
|
||||
carrierContractId: contract.id,
|
||||
carrierName,
|
||||
fullName: carrierName,
|
||||
label: nameCounts[carrierName] > 1 ? `${carrierName}(${identifier})` : carrierName,
|
||||
value: contract.id,
|
||||
};
|
||||
@@ -604,7 +667,7 @@ const syncCarrierOptions = () => {
|
||||
const customerContract = contracts.value.find(
|
||||
item => String(item.id) === String(form.contractId)
|
||||
);
|
||||
const carrierName = String(customerContract?.partyB || '').trim();
|
||||
const carrierName = getCarrierContractPartyName(customerContract || {});
|
||||
if (!carrierName) {
|
||||
carrierOptions.value = [];
|
||||
return;
|
||||
@@ -757,6 +820,7 @@ const loadBatches = async () => {
|
||||
};
|
||||
onMounted(() => {
|
||||
if (props.standalone) loadBatches();
|
||||
if (props.createPage) openCreate();
|
||||
});
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
@@ -782,22 +846,50 @@ const loadDetails = async () => {
|
||||
const openCreate = async () => {
|
||||
resetCreateForm();
|
||||
createVisible.value = true;
|
||||
const [projectRes, , optionRes] = await Promise.all([
|
||||
const [projectRes, , optionRes, batchNo] = await Promise.all([
|
||||
getProjectList(1, 9999, projectQueryParams),
|
||||
loadEditorOptions(),
|
||||
api.getImportOptions?.(),
|
||||
generateBatchNo(),
|
||||
]);
|
||||
form.batchNo = batchNo;
|
||||
projects.value = projectRes.data?.data?.records || [];
|
||||
const data = optionRes?.data?.data || {};
|
||||
queryCarriers.value = data.carriers || [];
|
||||
creators.value = data.creators || [];
|
||||
plans.value = data.plans || [];
|
||||
};
|
||||
const handleCreate = () => {
|
||||
if (props.standalone) {
|
||||
router.push({ path: '/business/waybill-import/form' });
|
||||
return;
|
||||
}
|
||||
openCreate();
|
||||
};
|
||||
const closeCreate = () => {
|
||||
if (props.createPage) {
|
||||
router.push({ path: '/business/waybill-import' });
|
||||
return;
|
||||
}
|
||||
createVisible.value = false;
|
||||
};
|
||||
const openDetail = row => {
|
||||
detailQuery.batchId = row.id;
|
||||
detailVisible.value = true;
|
||||
loadDetails();
|
||||
};
|
||||
// 草稿明细已落库为草稿运单,编辑时回填到明细表,避免重新上传附件。
|
||||
const loadBatchRows = async batchId => {
|
||||
if (!batchId) return;
|
||||
const res = await api.getImportDetails({ batchId, current: 1, size: 9999 });
|
||||
rows.value = extractRecords(res).map(({ id, ...item }, index) => ({
|
||||
...item,
|
||||
_key: `${id || 'row'}-${index}`,
|
||||
batchNo: item.batchNo || form.batchNo,
|
||||
}));
|
||||
rowSelection.value = [];
|
||||
previewTab.value = 'all';
|
||||
};
|
||||
const editBatch = async row => {
|
||||
await openCreate();
|
||||
const snapshot = { ...row };
|
||||
@@ -805,6 +897,9 @@ const editBatch = async row => {
|
||||
Object.assign(form, snapshot, {
|
||||
projectId: snapshot.projectId || '',
|
||||
projectName: snapshot.projectName || form.projectName,
|
||||
// 列表返回的是 importStatus,表单沿用 status 字段提交给后端。
|
||||
status: snapshot.importStatus || 'completed',
|
||||
file: null,
|
||||
});
|
||||
const contract = contracts.value.find(item => String(item.id) === String(snapshot.contractId));
|
||||
form.contractId = contract?.id || '';
|
||||
@@ -814,6 +909,7 @@ const editBatch = async row => {
|
||||
const carrierValue =
|
||||
form.carrierType === '自运' ? snapshot.carrierName : snapshot.carrierContractId;
|
||||
if (carrierValue) carrierChange(carrierValue);
|
||||
await loadBatchRows(snapshot.id);
|
||||
};
|
||||
const removeBatches = () =>
|
||||
api.removeImportBatches(selected.value.map(item => item.id).join(',')).then(loadBatches);
|
||||
@@ -829,6 +925,8 @@ const projectChange = async id => {
|
||||
contracts.value = [];
|
||||
carrierContracts.value = [];
|
||||
carrierOptions.value = [];
|
||||
carrierContractsLoaded.value = false;
|
||||
hasCarrierContracts.value = null;
|
||||
clearCarrier();
|
||||
if (!id) return;
|
||||
const [customerContractRes, carrierContractRes] = await Promise.all([
|
||||
@@ -848,12 +946,14 @@ const projectChange = async id => {
|
||||
contract => String(contract.contractCategory || '').trim() === '客户合同'
|
||||
);
|
||||
carrierContracts.value = buildCarrierContractOptions(extractRecords(carrierContractRes));
|
||||
carrierContractsLoaded.value = true;
|
||||
hasCarrierContracts.value = carrierContracts.value.length > 0;
|
||||
if (!carrierContracts.value.length) form.carrierType = '自运';
|
||||
if (contracts.value.length) {
|
||||
form.contractId = contracts.value[0].id;
|
||||
contractChange(form.contractId);
|
||||
} else {
|
||||
syncCarrierOptions();
|
||||
}
|
||||
syncCarrierOptions();
|
||||
};
|
||||
const contractChange = id => {
|
||||
const item = contracts.value.find(row => String(row.id) === String(id));
|
||||
@@ -918,7 +1018,7 @@ const fileChange = async (file, list) => {
|
||||
};
|
||||
const count = new Map();
|
||||
rows.value = source.map((item, index) => {
|
||||
const row = { _key: `${Date.now()}-${index}`, batchNo: '', ...item };
|
||||
const row = { _key: `${Date.now()}-${index}`, ...item, batchNo: form.batchNo };
|
||||
Object.entries(keyMap).forEach(([key, labels]) => {
|
||||
row[key] =
|
||||
labels.map(label => item[label]).find(value => String(value ?? '').trim()) ??
|
||||
@@ -1029,8 +1129,7 @@ const removeSelectedRows = () => {
|
||||
rows.value = rows.value.filter(row => !keys.has(row._key));
|
||||
rowSelection.value = [];
|
||||
};
|
||||
const firstNotEmpty = (...values) =>
|
||||
values.find(value => String(value ?? '').trim()) ?? '';
|
||||
const firstNotEmpty = (...values) => values.find(value => String(value ?? '').trim()) ?? '';
|
||||
const normalizeOptionalImportNumber = (value, emptySentinels = []) => {
|
||||
if (!String(value ?? '').trim()) return null;
|
||||
return emptySentinels.some(sentinel => Number(value) === sentinel) ? null : value;
|
||||
@@ -1052,9 +1151,25 @@ const normalizeImportRow = row => ({
|
||||
row['*运输方式']
|
||||
),
|
||||
});
|
||||
const buildImportPayload = () => ({ ...form, rows: rows.value.map(normalizeImportRow) });
|
||||
const saveDraft = () => api.saveImportDraft(buildImportPayload());
|
||||
const buildImportPayload = (status = form.status) => {
|
||||
const { file, ...batch } = form;
|
||||
return { ...batch, status, rows: rows.value.map(normalizeImportRow) };
|
||||
};
|
||||
// 独立页面下返回批次列表路由,弹窗形态下关闭新建面板并刷新列表。
|
||||
const backToList = () => {
|
||||
closeCreate();
|
||||
if (!props.createPage) loadBatches();
|
||||
};
|
||||
// 保存草稿:批次与已解析明细一并入库,成功后返回批次列表。
|
||||
const saveDraft = async () => {
|
||||
await formRef.value?.validateField(draftRequiredFields);
|
||||
await api.saveImportDraft(buildImportPayload('draft'));
|
||||
ElMessage.success('保存草稿成功');
|
||||
backToList();
|
||||
};
|
||||
const confirmImport = async () => {
|
||||
// 导入状态选择草稿时不生成正式运单,等同于保存草稿。
|
||||
if (form.status === 'draft') return saveDraft();
|
||||
await formRef.value?.validate();
|
||||
if (!validateImportRows()) return;
|
||||
const count = rows.value.filter(row => row._duplicate).length;
|
||||
@@ -1063,8 +1178,7 @@ const confirmImport = async () => {
|
||||
await ElMessageBox.confirm('确认后将同时生成运单、应收应付明细、计结算单,是否继续?', '提示');
|
||||
await api.confirmImport(buildImportPayload());
|
||||
ElMessage.success('导入成功');
|
||||
createVisible.value = false;
|
||||
loadBatches();
|
||||
backToList();
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1133,5 +1247,41 @@ const confirmImport = async () => {
|
||||
:deep(.el-table .el-date-editor) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 230px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
min-height: 64px;
|
||||
box-sizing: border-box;
|
||||
padding: 12px 24px;
|
||||
background: #fff;
|
||||
border-top: 1px solid #eff1f7;
|
||||
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.06);
|
||||
|
||||
// 统一 12px 间距,与全站底部操作栏(去 gap,由相邻按钮 margin 提供)一致
|
||||
.el-button + .el-button {
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&--page {
|
||||
min-height: calc(100vh - 120px);
|
||||
padding: 12px 24px 96px;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
:global(.avue--collapse .waybill-import-create__footer) {
|
||||
left: 60px;
|
||||
}
|
||||
|
||||
:global(.avue-layout--horizontal .waybill-import-create__footer) {
|
||||
left: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user