✨ 结算汇率反算、开票合计填报、配载承运商交集与车辆组织悬停

外币结算按本位币/汇率反算;开票改填合计金额并反算不含税单价;配载展示承运商合同并按乙方交集限选;评分加减分封顶15分;车辆所有组织/使用部门悬停显示完整路径。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-26 10:50:58 +08:00
parent fa78a68df6
commit e1d87f5788
10 changed files with 431 additions and 131 deletions
+36 -2
View File
@@ -27,8 +27,14 @@
/>
</el-select>
</el-form-item>
<el-form-item label="合同编号">
<el-input v-model="form.contractNo" disabled />
<el-form-item label="合同编号" prop="contractNo">
<el-input
v-model="form.contractNo"
maxlength="100"
clearable
placeholder="请输入合同编号"
:disabled="isSettlementRuleChange"
/>
</el-form-item>
<el-form-item label="合同名称" prop="contractName">
<el-input
@@ -662,6 +668,24 @@ export default {
'按数量',
],
rules: {
contractNo: [
{
validator: (rule, value, callback) => {
if (this.isSettlementRuleChange) {
return callback();
}
const contractNo = String(value || '').trim();
if (!contractNo) {
return callback(new Error('请输入合同编号'));
}
if (contractNo.length > 100) {
return callback(new Error('合同编号不能超过100个字符'));
}
callback();
},
trigger: 'blur',
},
],
contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }],
contractAmount: [
{ required: true, message: '请输入合同金额', trigger: 'blur' },
@@ -956,6 +980,16 @@ export default {
}
await this.$refs.formRef.validate();
if (!this.isSettlementRuleChange) {
const contractNo = String(this.form.contractNo || '').trim();
if (!contractNo) {
this.$message.warning('请输入合同编号');
return;
}
if (contractNo.length > 100) {
this.$message.warning('合同编号不能超过100个字符');
return;
}
this.form.contractNo = contractNo;
const total = this.paymentRatioRows.reduce((sum, row) => sum + Number(row.ratioLimit || 0), 0);
if (this.paymentRatioRows.length && Math.abs(total - 100) > 0.0001) {
this.$message.warning('付款比例上限合计必须等于100%');
+51 -4
View File
@@ -901,7 +901,7 @@
<div class="loading-manage-dialog__admission-tip">
<div class="loading-manage-dialog__admission-title">可配载条件</div>
<div class="loading-manage-dialog__admission-text">
同时满足以下条件的运单可被配载:运输方式为「公路」;运单状态为「待执行」或「进行中」;未关联其他有效配载单。
同时满足以下条件的运单可被配载:运输方式为「公路」;运单状态为「待执行」或「进行中」;未关联其他有效配载单;同一配载单的子运单须属同一项目,且承运商合同乙方须存在共同可选值(按各子单客户合同甲方匹配后取交集)。
</div>
<div class="loading-manage-dialog__admission-title">配载后状态说明</div>
<div class="loading-manage-dialog__admission-text">
@@ -1193,6 +1193,16 @@
min-width="160"
show-overflow-tooltip
/>
<el-table-column
prop="carrierContractName"
label="承运商合同"
min-width="160"
show-overflow-tooltip
>
<template #default="{ row }">
{{ row.carrierContractName || '-' }}
</template>
</el-table-column>
<el-table-column
prop="planName"
label="计划名称"
@@ -3896,6 +3906,7 @@ export default {
async loadCandidateWaybills() {
this.candidateLoading = true;
try {
const selectedProjectId = this.selectedWaybillRows.map(row => row.projectId).find(Boolean);
const query = {
...this.buildQueryParams(this.candidateQuery),
// 公路、待执行、未配载的判定都在后端可配载开关内
@@ -3905,6 +3916,10 @@ export default {
// 其余账户限定本组织(不展开下级)
allDept: 0,
};
// 已选运单后,候选列表优先限定同一项目,便于再按承运商合同乙方交集筛选
if (selectedProjectId && !query.projectId && !query.projectName) {
query.projectId = selectedProjectId;
}
const res = await getWaybillList(
this.candidatePage.currentPage,
this.candidatePage.pageSize,
@@ -3966,7 +3981,10 @@ export default {
];
if (projectIds.length) {
try {
const response = await loadingApi.getCarrierContracts(projectIds);
const waybillIds = [...this.selectedWaybillRows, ...selectedRows]
.map(row => row.id)
.filter(Boolean);
const response = await loadingApi.getCarrierContracts(projectIds, waybillIds);
const contracts = response?.data?.data || response?.data || [];
const stillAllowed = (Array.isArray(contracts) ? contracts : []).some(
item => String(item.id) === String(contractId)
@@ -4015,6 +4033,19 @@ export default {
exists.add(key);
}
});
// 承运商类型:新增后须仍存在共同的承运商合同乙方(按客户合同甲方匹配后取交集)
if (
String(this.dialogForm.carrierType || '').trim() === '承运商' &&
nextRows.length > this.selectedWaybillRows.length
) {
const compatible = await this.hasCompatibleCarrierContracts(nextRows);
if (!compatible) {
this.$message.warning(
'所选运单在同一项目下没有共同的承运商合同乙方,不能加入同一配载单'
);
return;
}
}
const prevRouteNodes = [...this.routeNodes];
this.selectedWaybillRows = nextRows;
if (this.isRunningEdit) {
@@ -4028,6 +4059,18 @@ export default {
this.candidateAdding = false;
}
},
async hasCompatibleCarrierContracts(rows = []) {
const projectId = (rows || []).map(row => row.projectId).find(Boolean);
const waybillIds = (rows || []).map(row => row.id).filter(Boolean);
if (!projectId || waybillIds.length < 2) return true;
try {
const response = await loadingApi.getCarrierContracts([projectId], waybillIds);
const contracts = response?.data?.data || response?.data || [];
return (Array.isArray(contracts) ? contracts : []).length > 0;
} catch (error) {
return true;
}
},
async addSelectedWaybills() {
await this.addWaybillRows(this.candidateSelection);
},
@@ -4711,9 +4754,13 @@ export default {
}
this.taskCarrierLoading = true;
try {
// 配载单只有一个项目,承运商合同也必须属于该项目
// 配载单只有一个项目;传入子运单后按客户合同甲方匹配并取承运商合同乙方交集
const projectId = this.selectedWaybillRows.map(row => row.projectId).find(Boolean);
const response = await loadingApi.getCarrierContracts(projectId ? [projectId] : []);
const waybillIds = this.selectedWaybillRows.map(row => row.id).filter(Boolean);
const response = await loadingApi.getCarrierContracts(
projectId ? [projectId] : [],
waybillIds
);
if (requestId !== this.taskCarrierRequestId) return [];
const contracts = response.data?.data || response.data || [];
if (this.dialogForm.carrierType !== '自运') {