This commit is contained in:
2026-08-25 16:13:58 +08:00
parent e309987199
commit 55583551b5
14 changed files with 953 additions and 286 deletions
+65 -97
View File
@@ -177,7 +177,7 @@
filterable
clearable
:loading="contractPartyLoading"
:disabled="!form.projectId"
@visible-change="visible => visible && loadContractPartyOptions()"
>
<el-option
v-for="item in contractPartyAOptions"
@@ -194,7 +194,7 @@
filterable
clearable
:loading="contractPartyLoading"
:disabled="!form.projectId"
@visible-change="visible => visible && loadContractPartyOptions()"
>
<el-option
v-for="item in contractPartyBOptions"
@@ -329,16 +329,11 @@
<el-table :data="billingPlanRows" border>
<el-table-column type="index" label="序号" width="80" align="center" />
<el-table-column prop="planName" label="方案名称" min-width="220" align="center" />
<el-table-column label="默认方案" width="140" align="center">
<template #default="{ row }">{{ isDefaultBillingPlan(row) ? '是' : '' }}</template>
<el-table-column label="运输方式" min-width="180" align="center">
<template #default="{ row }">{{
row.transportModeLabel || row.transportMode || '-'
}}</template>
</el-table-column>
<el-table-column
prop="remark"
label="备注"
min-width="260"
align="center"
show-overflow-tooltip
/>
<el-table-column label="操作" width="180" align="center" fixed="right">
<template #default="{ row, $index }">
<el-link type="primary" @click="openBillingPlan(row, $index)">编辑</el-link>
@@ -436,14 +431,13 @@
<el-table-column prop="paymentTerm" label="付款笔数" min-width="180" align="center" />
<el-table-column label="付款比例上限" min-width="220" align="center">
<template #default="{ row }">
<el-input-number
<el-input
v-model="row.ratioLimit"
:min="0"
:max="100"
:precision="2"
controls-position="right"
/>
<span class="contract-manage-form__ratio-unit">%</span>
placeholder="请输入"
@input="value => ratioInput(row, value)"
>
<template #append>%</template>
</el-input>
</template>
</el-table-column>
<el-table-column label="备注" min-width="220">
@@ -537,6 +531,7 @@
</template>
<billing-plan-editor
ref="billingPlanEditor"
v-model="billingPlanBox"
:value="billingPlanForm"
:index="billingPlanIndex"
@@ -653,16 +648,11 @@
<el-table :data="detailBillingPlanRows" border>
<el-table-column type="index" label="序号" width="80" align="center" />
<el-table-column prop="planName" label="方案名称" min-width="220" align="center" />
<el-table-column label="默认方案" width="140" align="center">
<template #default="{ row }">{{ isDefaultBillingPlan(row) ? '是' : '' }}</template>
<el-table-column label="运输方式" min-width="180" align="center">
<template #default="{ row }">{{
row.transportModeLabel || row.transportMode || '-'
}}</template>
</el-table-column>
<el-table-column
prop="remark"
label="备注"
min-width="260"
align="center"
show-overflow-tooltip
/>
<el-table-column label="操作" width="120" align="center" fixed="right">
<template #default="{ row, $index }">
<el-link type="primary" @click="openDetailBillingPlan(row, $index)"
@@ -799,10 +789,8 @@ import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import { exportBlob } from '@/api/common';
import * as api from '@/api/business/contract-manage';
import {
getDetail as getProjectDetail,
getList as getProjectList,
} from '@/api/business/project-apply';
import { getList as getProjectList } from '@/api/business/project-apply';
import { getList as getCustomerArchiveList } from '@/api/vehicle/customer-archive';
import { getDeptTree } from '@/api/system/dept';
import { config, option } from '@/option/business/contract-manage';
import { getToken } from '@/utils/auth';
@@ -1463,7 +1451,10 @@ export default {
},
initFormPage() {
this.resetFormState();
if (this.formMode === 'add') return;
if (this.formMode === 'add') {
this.loadContractPartyOptions();
return;
}
const id = this.$route.query.id;
if (!id) return;
this.api.getDetail(id).then(res => this.applyDetail(res.data?.data || {}));
@@ -1521,7 +1512,7 @@ export default {
this.settlementRuleForm = { ...this.preSettlementRuleForm };
this.syncCurrentProjectOption();
this.syncCurrentOrganizationOption();
this.loadContractPartyOptions(detail.projectId, detail, true);
this.loadContractPartyOptions();
},
closeForm() {
this.$router.$avueRouter?.closeTag?.();
@@ -1650,76 +1641,29 @@ export default {
handleProjectChange(projectId) {
const project = this.projectOptions.find(item => String(item.id) === String(projectId));
if (!project) {
Object.assign(this.form, { projectId: '', projectName: '', partyA: '', partyB: '' });
this.contractPartyAOptions = [];
this.contractPartyBOptions = [];
Object.assign(this.form, { projectId: '', projectName: '' });
return;
}
Object.assign(this.form, {
projectId: project.id,
projectName: project.projectName || '',
partyA: '',
partyB: '',
});
this.loadContractPartyOptions(project.id, project, false);
},
partyNames(value, type) {
const names = [];
const append = item => {
if (item === undefined || item === null) return;
if (Array.isArray(item)) return item.forEach(append);
if (typeof item === 'object') {
append(
item[type === 'carrier' ? 'carrier' : 'customer'] ||
item.fullName ||
item.shortName ||
item.customerName ||
item.carrierName ||
item.name
);
return;
}
const text = String(item).trim();
if (!text) return;
try {
const parsed = JSON.parse(text);
if (parsed !== item) return append(parsed);
} catch (error) {
// 普通名称按项目维护时使用的分隔符拆分。
}
text
.split(/[、,;\n]/)
.map(name => name.trim())
.filter(Boolean)
.forEach(name => {
if (!names.includes(name)) names.push(name);
});
};
append(value);
return names;
},
syncContractPartyOptions(project, preserve) {
const customers = this.partyNames(
[project.customerJson, project.customerNames, project.customerName, project.customers],
'customer'
);
const carriers = this.partyNames(
[project.carrierJson, project.carrierNames, project.carrierName, project.carriers],
'carrier'
);
this.contractPartyAOptions = customers.map(name => ({ label: name, value: name }));
this.contractPartyBOptions = carriers.map(name => ({ label: name, value: name }));
if (!preserve) Object.assign(this.form, { partyA: '', partyB: '' });
},
loadContractPartyOptions(projectId, project = {}, preserve = true) {
if (!projectId) return;
loadContractPartyOptions() {
if (this.contractPartyLoading) return;
const requestId = ++this.contractPartyRequestId;
this.syncContractPartyOptions(project, preserve);
this.contractPartyLoading = true;
getProjectDetail(projectId)
getCustomerArchiveList(1, 9999, { status: 1, approvalStatus: 'approved' })
.then(res => {
if (requestId !== this.contractPartyRequestId) return;
this.syncContractPartyOptions({ ...project, ...(res.data?.data || {}) }, preserve);
const names = extractRecords(res)
.map(item => item.fullName || item.shortName || item.customerName || item.customerCode)
.map(name => String(name || '').trim())
.filter(Boolean);
[this.form.partyA, this.form.partyB].filter(Boolean).forEach(name => names.unshift(name));
const options = [...new Set(names)].map(name => ({ label: name, value: name }));
this.contractPartyAOptions = options;
this.contractPartyBOptions = options;
})
.finally(() => {
if (requestId === this.contractPartyRequestId) this.contractPartyLoading = false;
@@ -1822,14 +1766,19 @@ export default {
openBillingPlan(row = {}, index = -1) {
this.billingPlanIndex = index;
this.billingPlanForm =
index < 0 ? { planName: '', defaultPlan: false, remark: '', rules: [] } : clone(row);
index < 0
? { planName: '', transportMode: '', defaultPlan: false, remark: '', rules: [] }
: clone(row);
this.billingPlanBox = true;
this.$nextTick(() => this.$refs.billingPlanEditor?.ensureTransportModes?.());
},
saveBillingPlan(plan, index) {
const nextPlan = clone(plan);
if (this.isDefaultBillingPlan(nextPlan)) {
this.billingPlanRows.forEach((item, itemIndex) => {
if (itemIndex !== index) item.defaultPlan = false;
if (itemIndex !== index && item.transportMode === nextPlan.transportMode) {
item.defaultPlan = false;
}
});
}
if (index < 0) this.billingPlanRows.push(nextPlan);
@@ -1850,9 +1799,18 @@ export default {
},
validateBillingPlanDefault() {
if (!this.billingPlanRows.length) return true;
const count = this.billingPlanRows.filter(this.isDefaultBillingPlan).length;
if (count !== 1) {
this.$message.warning(count ? '请仅保留一个默认计费方案' : '请勾选一个默认计费方案');
const defaultCountByTransportMode = this.billingPlanRows.reduce((result, plan) => {
const transportMode = plan.transportMode || '';
result[transportMode] =
(result[transportMode] || 0) + Number(this.isDefaultBillingPlan(plan));
return result;
}, {});
const invalidTransportMode = Object.entries(defaultCountByTransportMode).find(
([, count]) => count > 1
);
if (invalidTransportMode) {
const [transportMode, count] = invalidTransportMode;
this.$message.warning(`运输方式“${transportMode}”仅支持配置一个默认计费方案`);
return false;
}
return true;
@@ -1936,6 +1894,16 @@ export default {
}
return true;
},
ratioInput(row, value) {
let nextValue = String(value ?? '').replace(/[^\d.]/g, '');
const parts = nextValue.split('.');
if (parts.length > 2) nextValue = `${parts.shift()}.${parts.join('')}`;
const [integerPart, decimalPart] = nextValue.split('.');
nextValue =
decimalPart === undefined ? integerPart : `${integerPart}.${decimalPart.slice(0, 2)}`;
if (Number(nextValue) > 100) nextValue = '100';
row.ratioLimit = nextValue;
},
openDetail(row) {
this.detailBox = true;
this.detailLoading = true;