1、新增应付明细
2、新增应收明细 3、新增异常处置 4、新增风险处置 5、新增在途追踪 6、修复业务模块bug
This commit is contained in:
@@ -34,19 +34,24 @@
|
||||
<el-dialog v-model="createVisible" title="新建导入" width="85%" append-to-body destroy-on-close class="waybill-import-create">
|
||||
<section class="waybill-import-create__form-panel">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="right" label-width="auto" class="archive-form">
|
||||
<el-row :gutter="20"><el-col :span="6"><el-form-item label="项目" prop="projectId"><el-select v-model="form.projectId" filterable clearable placeholder="模糊查询后选择" @change="projectChange"><el-option v-for="item in projects" :key="item.id" :label="item.projectName" :value="item.id" /></el-select></el-form-item></el-col><el-col :span="6"><el-form-item label="客户" prop="customerName"><el-input v-model="form.customerName" disabled placeholder="自动带出" /></el-form-item></el-col><el-col :span="6"><el-form-item label="客户合同" prop="contractId"><el-select v-model="form.contractId" filterable clearable placeholder="自动带出"><el-option v-for="item in contracts" :key="item.id" :label="item.contractName" :value="item.id" /></el-select></el-form-item></el-col><el-col :span="6"><el-form-item label="承运类型" prop="carrierType"><el-select v-model="form.carrierType"><el-option label="承运商" value="承运商" /><el-option label="自运" value="自运" /><el-option label="网货平台" value="网货平台" /></el-select></el-form-item></el-col><el-col :span="6"><el-form-item label="承运商"><el-select v-model="form.carrierIds" multiple filterable placeholder="自动带出,多个需选择"><el-option v-for="item in carriers" :key="item.id" :label="item.name" :value="item.id" /></el-select></el-form-item></el-col><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-select></el-form-item></el-col><el-col :span="6"><el-form-item label="导入类型" prop="importType"><el-select v-model="form.importType"><el-option label="运单" value="waybill" /><el-option label="结算单" value="settlement" /></el-select></el-form-item></el-col><el-col :span="6"><el-form-item label="发货计划"><el-select v-model="form.planId" clearable filterable placeholder="请选择"><el-option v-for="item in plans" :key="item.id" :label="item.planName" :value="item.id" /></el-select></el-form-item></el-col></el-row>
|
||||
<el-row :gutter="20"><el-col :span="6"><el-form-item label="项目" prop="projectId"><el-select v-model="form.projectId" filterable clearable placeholder="模糊查询后选择" @change="projectChange"><el-option v-for="item in projects" :key="item.id" :label="item.projectName" :value="item.id" /></el-select></el-form-item></el-col><el-col :span="6"><el-form-item label="客户" prop="customerName"><el-input v-model="form.customerName" disabled placeholder="自动带出" /></el-form-item></el-col><el-col :span="6"><el-form-item label="客户合同" prop="contractId"><el-select v-model="form.contractId" filterable clearable placeholder="自动带出" @change="contractChange"><el-option v-for="item in contracts" :key="item.id" :label="item.contractName" :value="item.id" /></el-select></el-form-item></el-col><el-col :span="6"><el-form-item label="承运类型" prop="carrierType"><el-select v-model="form.carrierType"><el-option label="承运商" value="承运商" /><el-option label="自运" value="自运" /><el-option label="网货平台" value="网货平台" /></el-select></el-form-item></el-col><el-col :span="6"><el-form-item label="承运商"><el-select v-model="form.carrierIds" multiple filterable placeholder="自动带出,多个需选择"><el-option v-for="item in carriers" :key="item.id" :label="item.name" :value="item.id" /></el-select></el-form-item></el-col><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-select></el-form-item></el-col><el-col :span="6"><el-form-item label="导入类型" prop="importType"><el-select v-model="form.importType"><el-option label="运单" value="waybill" /><el-option label="结算单" value="settlement" /></el-select></el-form-item></el-col><el-col :span="6"><el-form-item label="计划名称"><el-select v-model="form.planId" clearable filterable placeholder="请选择"><el-option v-for="item in plans" :key="item.id" :label="item.planName" :value="item.id" /></el-select></el-form-item></el-col></el-row>
|
||||
<el-form-item label="运单明细表" prop="file"><el-upload action="#" accept=".xls,.xlsx" :auto-upload="false" :limit="1" :file-list="files" :on-change="fileChange" :on-remove="fileRemove"><el-button type="primary">添加附件</el-button></el-upload><span class="waybill-import-create__file-tip">请上传运单明细表,仅支持 excel 格式</span><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><el-button @click="saveDraft">保存草稿</el-button><el-button type="primary" @click="confirmImport">确认导入</el-button></div>
|
||||
</section>
|
||||
<section class="waybill-import-create__detail-panel" v-if="rows.length"><div class="waybill-import-create__detail-head"><div class="dialog-section-title">导入数据明细</div><el-button type="danger" plain :disabled="!rowSelection.length" @click="removeSelectedRows">批量删除</el-button></div><el-tabs v-model="previewTab"><el-tab-pane :label="`运单数(${rows.length})`" name="all" /><el-tab-pane :label="`疑似重复(${duplicateRows.length})`" name="duplicate" /></el-tabs><el-table :data="previewRows" border max-height="440" @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" :key="column.prop" :prop="column.prop" :label="column.label" min-width="140" show-overflow-tooltip /><el-table-column label="操作" width="180" fixed="right"><template #default="{ row }"><el-link type="primary" @click="cancelRow(row)">取消</el-link><el-link type="primary" @click="saveRow(row)">保存</el-link><el-link type="primary" @click="editRow(row)">编辑</el-link><el-link type="danger" @click="deleteRow(row)">删除</el-link></template></el-table-column></el-table></section>
|
||||
<section class="waybill-import-create__detail-panel" v-if="rows.length"><div class="waybill-import-create__detail-head"><div class="dialog-section-title">导入数据明细</div><el-button type="danger" plain :disabled="!rowSelection.length" @click="removeSelectedRows">批量删除</el-button></div><el-tabs v-model="previewTab"><el-tab-pane :label="`运单数(${rows.length})`" name="all" /><el-tab-pane :label="`疑似重复(${duplicateRows.length})`" name="duplicate" /></el-tabs><el-table :data="previewRows" border max-height="440" @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" :key="column.prop" :prop="column.prop" :label="column.label" :min-width="column.minWidth || 150" show-overflow-tooltip><template #default="{ row }"><template v-if="row._editing"><el-select v-if="column.editor === 'transportType'" v-model="row.transportType" clearable filterable placeholder="请选择"><el-option v-for="item in transportTypeOptions" :key="item.value" :label="item.label" :value="item.value" /></el-select><el-select v-else-if="column.editor === 'driver'" v-model="row.driverName" clearable filterable placeholder="请选择" @change="value => handleEditorChange(column, row, value)"><el-option v-for="item in driverOptions" :key="item.id || item.driverName || item.name" :label="item.driverName || item.name" :value="item.driverName || item.name" /></el-select><el-cascader v-else-if="column.editor === 'cargoType'" :model-value="resolveCargoTypePath(row)" :options="cargoTypeOptions" :props="{ label: 'cargoName', value: 'id', children: 'children', emitPath: true }" clearable filterable placeholder="请选择" @change="value => handleEditorChange(column, row, value)" /><el-select v-else-if="column.editor === 'cargoName'" v-model="row.cargoName" clearable filterable placeholder="请选择" @visible-change="visible => visible && loadCommonCargoOptions(row)" @change="value => handleEditorChange(column, row, value)"><el-option v-for="item in getCommonCargoOptions(row)" :key="item.id || item.cargoName || item.name" :label="formatCargoTypeLabel(item)" :value="formatCargoTypeLabel(item)" /></el-select><el-date-picker v-else-if="column.editor === 'datetime'" v-model="row[column.prop]" type="datetime" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" 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 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 v-model="row[column.prop]" :placeholder="`请输入${column.label}`" /></template><span v-else>{{ formatCell(row, column) }}</span></template></el-table-column><el-table-column label="操作" width="180" fixed="right"><template #default="{ row }"><template v-if="row._editing"><el-link type="primary" @click="saveRow(row)">保存</el-link><el-link type="primary" @click="cancelRow(row)">取消</el-link></template><template v-else><el-link type="primary" @click="editRow(row)">编辑</el-link><el-link type="danger" @click="deleteRow(row)">删除</el-link></template></template></el-table-column></el-table></section>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, reactive, ref } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
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';
|
||||
import { getList as getProjectList } from '@/api/business/project-apply';
|
||||
import { getList as getDriverList } from '@/api/transportCapacity/driver';
|
||||
import { getDictionary } from '@/api/system/dictbiz';
|
||||
import * as api from '@/api/business/waybill-manage';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
|
||||
@@ -56,21 +61,162 @@ const visible = computed({ get: () => props.modelValue, set: value => emit('upda
|
||||
const createVisible = ref(false), detailVisible = ref(false), formRef = ref();
|
||||
const query = reactive({ batchNo: '', carrierId: '', createUser: '', createTimeRange: [] });
|
||||
const detailQuery = reactive({ vehicleNo: '', cargoName: '' });
|
||||
const form = reactive({ projectId: '', customerName: '', contractId: '', carrierType: '承运商', carrierIds: [], status: 'completed', importType: 'waybill', planId: '', file: null });
|
||||
const form = reactive({ projectId: '', customerName: '', contractId: '', contractName: '', carrierType: '承运商', carrierIds: [], status: 'completed', importType: 'waybill', planId: '', file: null });
|
||||
const rules = { projectId: [{ required: true, message: '请选择项目' }], customerName: [{ required: true, message: '客户不能为空' }], contractId: [{ required: true, message: '请选择客户合同' }], carrierType: [{ required: true, message: '请选择承运类型' }], status: [{ required: true, message: '请选择导入状态' }], importType: [{ required: true, message: '请选择导入类型' }], file: [{ required: true, message: '请上传明细表' }] };
|
||||
const batches = ref([]), details = ref([]), rows = ref([]), selected = ref([]), files = ref([]), projects = ref([]), contracts = ref([]), carriers = ref([]), creators = ref([]), plans = ref([]);
|
||||
const transportTypeOptions = ref([]), cargoTypeOptions = ref([]), cargoTypeFlatOptions = ref([]), commonCargoOptionsMap = ref({}), commonCargoLoadingMap = ref({}), driverOptions = 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 page = reactive({ current: 1, size: 10, total: 0 }), detailPage = reactive({ current: 1, size: 10, total: 0 });
|
||||
const detailColumns = [{ prop: 'batchNo', label: '运单批次号' }, { prop: 'originalNo', label: '原始单号' }, { prop: 'vehicleNo', label: '车牌号/航班号/船号/班列号' }, { prop: 'driverName', label: '司机/船长' }, { prop: 'transportType', label: '运输类型' }, { prop: 'cargoName', label: '货物名称' }, { prop: 'cargoType', label: '货物类型' }, { prop: 'quantity', 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: '运费' }, { prop: 'otherFeeTotal', label: '其他费用合计' }, { prop: 'freightTotal', label: '运费合计' }, { prop: 'remark', label: '备注' }];
|
||||
const detailColumns = [
|
||||
{ prop: 'batchNo', label: '运单批次号', editor: 'input', 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: 'cargoName', label: '货物名称', editor: 'cargoName', 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: 'datetime', minWidth: 190 },
|
||||
{ prop: 'endDate', label: '结束时间', editor: 'datetime', minWidth: 190 },
|
||||
{ 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: '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 => {
|
||||
const data = res?.data || res;
|
||||
if (Array.isArray(data)) return data;
|
||||
if (Array.isArray(data?.records)) return data.records;
|
||||
if (Array.isArray(data?.data)) return data.data;
|
||||
if (Array.isArray(data?.data?.records)) return data.data.records;
|
||||
return [];
|
||||
};
|
||||
const formatCargoTypeLabel = item => item?.cargoName || item?.name || item?.typeName || item?.label || '';
|
||||
const buildCargoTypeTree = cargoTypes => {
|
||||
const flatCargoTypes = [];
|
||||
const collectCargoTypes = list => {
|
||||
(list || []).forEach(item => {
|
||||
flatCargoTypes.push({ ...item, children: undefined });
|
||||
if (item.children?.length) collectCargoTypes(item.children);
|
||||
});
|
||||
};
|
||||
collectCargoTypes(cargoTypes);
|
||||
const nodeMap = new Map();
|
||||
const codeMap = new Map();
|
||||
flatCargoTypes.forEach(item => {
|
||||
const id = item.id ?? item.cargoCode ?? item.code;
|
||||
if (id === undefined || id === null) return;
|
||||
const node = {
|
||||
...item,
|
||||
id: String(id),
|
||||
cargoName: formatCargoTypeLabel(item),
|
||||
cargoCode: item.cargoCode || item.code || '',
|
||||
parentId: item.parentId === undefined || item.parentId === null ? '' : String(item.parentId),
|
||||
parentCargoCode: item.parentCargoCode || item.parentCode || '',
|
||||
children: [],
|
||||
};
|
||||
nodeMap.set(node.id, node);
|
||||
if (node.cargoCode) codeMap.set(String(node.cargoCode), node);
|
||||
});
|
||||
const rootNodes = [];
|
||||
nodeMap.forEach(node => {
|
||||
const parent = nodeMap.get(node.parentId) || codeMap.get(String(node.parentCargoCode || '')) || codeMap.get(String(node.parentId || ''));
|
||||
if (parent && parent !== node && Number(node.typeLevel) !== 1) parent.children.push(node);
|
||||
else rootNodes.push(node);
|
||||
});
|
||||
const normalize = (cargoType, level = 1, parentPath = []) => {
|
||||
if (level > 2) return null;
|
||||
const id = String(cargoType.id);
|
||||
const path = [...parentPath, id];
|
||||
const children = level === 1 ? (cargoType.children || []).map(item => normalize(item, level + 1, path)).filter(Boolean) : [];
|
||||
return { ...cargoType, id, cargoName: formatCargoTypeLabel(cargoType), path, leaf: level === 2, children: children.length ? children : undefined };
|
||||
};
|
||||
return rootNodes.map(item => normalize(item, 1)).filter(Boolean);
|
||||
};
|
||||
const flattenCargoTypeOptions = options => {
|
||||
const result = [];
|
||||
const collect = list => (list || []).forEach(item => {
|
||||
result.push(item);
|
||||
if (item.children?.length) collect(item.children);
|
||||
});
|
||||
collect(options);
|
||||
return result;
|
||||
};
|
||||
const getCargoTypePathLabels = path => {
|
||||
let options = cargoTypeOptions.value;
|
||||
const labels = [];
|
||||
(path || []).forEach(value => {
|
||||
const option = (options || []).find(item => String(item.id) === String(value));
|
||||
if (!option) return;
|
||||
labels.push(option.cargoName || '');
|
||||
options = option.children || [];
|
||||
});
|
||||
return labels.filter(Boolean);
|
||||
};
|
||||
const findCargoTypeByPath = path => {
|
||||
const id = Array.isArray(path) ? path[path.length - 1] : path;
|
||||
return cargoTypeFlatOptions.value.find(item => String(item.id) === String(id));
|
||||
};
|
||||
const resolveCargoTypePath = row => {
|
||||
if (Array.isArray(row.cargoTypePath) && row.cargoTypePath.length) return row.cargoTypePath;
|
||||
const cargoType = cargoTypeFlatOptions.value.find(item => [item.cargoName, item.name, item.typeName, item.cargoCode].some(value => String(value || '') === String(row.cargoType || row.cargoTypeCode || '')));
|
||||
return cargoType?.path || [];
|
||||
};
|
||||
const commonCargoKey = row => {
|
||||
const path = resolveCargoTypePath(row);
|
||||
const cargoType = findCargoTypeByPath(path);
|
||||
return String(cargoType?.cargoCode || cargoType?.code || path.join('/'));
|
||||
};
|
||||
const getCommonCargoOptions = row => commonCargoOptionsMap.value[commonCargoKey(row)] || [];
|
||||
const loadCommonCargoOptions = async row => {
|
||||
const path = resolveCargoTypePath(row);
|
||||
const cargoType = findCargoTypeByPath(path);
|
||||
const key = commonCargoKey(row);
|
||||
if (!key || commonCargoLoadingMap.value[key]) return;
|
||||
commonCargoLoadingMap.value = { ...commonCargoLoadingMap.value, [key]: true };
|
||||
try {
|
||||
const labels = getCargoTypePathLabels(path);
|
||||
const res = await getCommonCargoList(1, 500, {
|
||||
secondCargoTypeName: labels[1] || row.cargoType || '',
|
||||
secondCargoTypeCode: cargoType?.cargoCode || cargoType?.code || '',
|
||||
allDept: 0,
|
||||
});
|
||||
commonCargoOptionsMap.value = { ...commonCargoOptionsMap.value, [key]: extractRecords(res) };
|
||||
} finally {
|
||||
commonCargoLoadingMap.value = { ...commonCargoLoadingMap.value, [key]: false };
|
||||
}
|
||||
};
|
||||
const loadEditorOptions = async () => {
|
||||
const [dictRes, cargoTypeRes, driverRes] = await Promise.all([
|
||||
getDictionary({ code: 'transport_type' }),
|
||||
getCargoTypeList(1, 9999),
|
||||
getDriverList(1, 9999, {}),
|
||||
]);
|
||||
transportTypeOptions.value = extractRecords(dictRes).map(item => ({
|
||||
label: item.dictValue || item.label,
|
||||
value: item.dictKey || item.value,
|
||||
}));
|
||||
cargoTypeOptions.value = buildCargoTypeTree(extractRecords(cargoTypeRes));
|
||||
cargoTypeFlatOptions.value = flattenCargoTypeOptions(cargoTypeOptions.value);
|
||||
driverOptions.value = extractRecords(driverRes);
|
||||
};
|
||||
const loadBatches = async () => { const res = await api.getImportBatches({ ...query, current: page.current, size: page.size }); batches.value = res.data?.data?.records || []; page.total = res.data?.data?.total || 0; };
|
||||
const resetQuery = () => { Object.assign(query, { batchNo: '', carrierId: '', createUser: '', createTimeRange: [] }); page.current = 1; loadBatches(); };
|
||||
const loadDetails = async () => { const res = await api.getImportDetails({ batchId: detailQuery.batchId, ...detailQuery, current: detailPage.current, size: detailPage.size }); details.value = res.data?.data?.records || []; detailPage.total = res.data?.data?.total || 0; };
|
||||
const openCreate = async () => {
|
||||
createVisible.value = true;
|
||||
const projectRes = await getProjectList(1, 9999, {});
|
||||
const [projectRes] = await Promise.all([getProjectList(1, 9999, projectQueryParams), loadEditorOptions()]);
|
||||
projects.value = projectRes.data?.data?.records || [];
|
||||
api.getImportOptions?.().then(res => {
|
||||
const data = res.data?.data || {};
|
||||
@@ -84,7 +230,27 @@ const openDetail = row => { detailQuery.batchId = row.id; detailVisible.value =
|
||||
const editBatch = row => { openCreate(); Object.assign(form, row); };
|
||||
const removeBatches = () => api.removeImportBatches(selected.value.map(item => item.id).join(',')).then(loadBatches);
|
||||
const removeBatch = row => api.removeImportBatches(row.id).then(loadBatches);
|
||||
const projectChange = id => { const item = projects.value.find(row => row.id === id); form.customerName = item?.customerName || ''; api.getImportContracts?.(id).then(res => { contracts.value = res.data?.data || []; }); };
|
||||
const projectChange = async id => {
|
||||
const item = projects.value.find(row => row.id === id);
|
||||
form.customerName = item?.customerName || item?.customerNames || item?.customer || '';
|
||||
form.contractId = '';
|
||||
form.contractName = '';
|
||||
contracts.value = [];
|
||||
if (!id) return;
|
||||
const res = await getContractList(1, 9999, {
|
||||
projectId: id,
|
||||
projectName: item?.projectName,
|
||||
});
|
||||
contracts.value = res.data?.data?.records || [];
|
||||
if (contracts.value.length) {
|
||||
form.contractId = contracts.value[0].id;
|
||||
form.contractName = contracts.value[0].contractName || '';
|
||||
}
|
||||
};
|
||||
const contractChange = id => {
|
||||
const item = contracts.value.find(row => row.id === id);
|
||||
form.contractName = item?.contractName || '';
|
||||
};
|
||||
const fileChange = async (file, list) => {
|
||||
files.value = list.slice(-1); form.file = file.raw;
|
||||
const XLSX = await import('xlsx');
|
||||
@@ -96,6 +262,44 @@ const fileChange = async (file, list) => {
|
||||
rows.value.forEach(row => { row._duplicate = count.get(row._duplicateKey) > 1; });
|
||||
};
|
||||
const fileRemove = () => { files.value = []; form.file = null; };
|
||||
const formatCell = (row, column) => row[column.prop] || '';
|
||||
const updateEditorValue = (column, row, value) => {
|
||||
if (column.editor === 'number') {
|
||||
const [integer = '', decimal = ''] = String(value || '').replace(/[^\d.]/g, '').split('.');
|
||||
row[column.prop] = decimal || String(value || '').includes('.') ? `${integer}.${decimal.slice(0, 2)}` : integer;
|
||||
return;
|
||||
}
|
||||
row[column.prop] = value;
|
||||
};
|
||||
const handleEditorChange = (column, row, value) => {
|
||||
if (column.editor === 'driver') {
|
||||
const driver = driverOptions.value.find(item => [item.driverName, item.name].some(name => String(name || '') === String(value || '')));
|
||||
row.driverName = value || '';
|
||||
if (driver) row.driverPhone = driver.mobile || driver.phone || driver.driverPhone || row.driverPhone || '';
|
||||
}
|
||||
if (column.editor === 'cargoType') {
|
||||
const path = Array.isArray(value) ? value : [];
|
||||
const cargoType = findCargoTypeByPath(path);
|
||||
const labels = getCargoTypePathLabels(path);
|
||||
row.cargoTypePath = path;
|
||||
row.cargoType = labels.at(-1) || '';
|
||||
row.cargoTypeCode = cargoType?.cargoCode || cargoType?.code || cargoType?.id || '';
|
||||
row.cargoName = '';
|
||||
row.specification = '';
|
||||
row.model = '';
|
||||
loadCommonCargoOptions(row);
|
||||
}
|
||||
if (column.editor === 'cargoName') {
|
||||
const cargo = getCommonCargoOptions(row).find(item => formatCargoTypeLabel(item) === value);
|
||||
row.cargoName = value || '';
|
||||
if (cargo) {
|
||||
row.specification = cargo.specification || cargo.spec || row.specification || '';
|
||||
row.model = cargo.model || cargo.modelName || row.model || '';
|
||||
row.packageType = cargo.packageType || row.packageType || '';
|
||||
row.brand = cargo.brand || row.brand || '';
|
||||
}
|
||||
}
|
||||
};
|
||||
const downloadTemplate = async () => {
|
||||
try {
|
||||
const res = await api.exportImportTemplate();
|
||||
@@ -119,9 +323,9 @@ const validateImportRows = () => {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const editRow = row => { row._editing = true; };
|
||||
const saveRow = row => { row._editing = false; };
|
||||
const cancelRow = row => { row._cancelled = true; };
|
||||
const editRow = row => { row._editSnapshot = JSON.parse(JSON.stringify(row)); row._editing = true; };
|
||||
const saveRow = row => { row._editing = false; delete row._editSnapshot; };
|
||||
const cancelRow = row => { if (row._editSnapshot) Object.assign(row, row._editSnapshot); row._editing = false; delete row._editSnapshot; };
|
||||
const deleteRow = row => { rows.value = rows.value.filter(item => item !== row); };
|
||||
const removeSelectedRows = () => { const keys = new Set(rowSelection.value.map(row => row._key)); rows.value = rows.value.filter(row => !keys.has(row._key)); rowSelection.value = []; };
|
||||
const saveDraft = () => api.saveImportDraft({ ...form, rows: rows.value });
|
||||
@@ -163,5 +367,12 @@ const confirmImport = async () => { await formRef.value?.validate(); if (!valida
|
||||
&__form-actions { display: flex; justify-content: flex-end; gap: 12px; margin-top: 8px; }
|
||||
&__detail-head { display: flex; align-items: center; gap: 24px; margin-bottom: 8px; }
|
||||
&__file-tip { margin: 0 24px; color: #606266; }
|
||||
|
||||
:deep(.el-table .el-input),
|
||||
:deep(.el-table .el-select),
|
||||
:deep(.el-table .el-cascader),
|
||||
:deep(.el-table .el-date-editor) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user