@@ -8,8 +8,20 @@ export const preSettlementFormFields = [
|
||||
{ label: '合同名称', prop: 'contractId', type: 'contract', required: true },
|
||||
{ label: '合同编号', prop: 'contractNo', readonly: true },
|
||||
{ label: '项目名称', prop: 'projectName', readonly: true },
|
||||
{ label: '收款方', prop: 'payeeName', readonly: true },
|
||||
{ label: '付款方', prop: 'payerName', readonly: true },
|
||||
{
|
||||
label: '收款方',
|
||||
prop: 'payeeName',
|
||||
type: 'select',
|
||||
optionsKey: 'payeeOptions',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '付款方',
|
||||
prop: 'payerName',
|
||||
type: 'select',
|
||||
optionsKey: 'payerOptions',
|
||||
required: true,
|
||||
},
|
||||
{ label: '结算类型', prop: 'settlementType', readonly: true },
|
||||
{ label: '结算金额', prop: 'settlementAmount', readonly: true, money: true },
|
||||
{ label: '业务模式', prop: 'businessModel', type: 'select', optionsKey: 'businessModelOptions' },
|
||||
@@ -24,6 +36,8 @@ export const preSettlementFormFields = [
|
||||
|
||||
export const preSettlementFormRules = {
|
||||
contractId: [{ required: true, message: '请选择合同名称', trigger: 'change' }],
|
||||
payeeName: [{ required: true, message: '请选择收款方', trigger: 'change' }],
|
||||
payerName: [{ required: true, message: '请选择付款方', trigger: 'change' }],
|
||||
exchangeRateDate: [
|
||||
{
|
||||
validator: (_rule, value, callback, source) => {
|
||||
|
||||
@@ -989,6 +989,7 @@ import {
|
||||
save,
|
||||
submit,
|
||||
} from '@/api/settlement/preSettlement';
|
||||
import { getDetail as getContractDetail } from '@/api/business/contract-manage';
|
||||
import { calculateAdjustedFee, getFeeDetail } from '@/api/settlement/receivable-payable-detail';
|
||||
import {
|
||||
resolveReceivablePayableDetailId,
|
||||
@@ -1072,6 +1073,8 @@ export default {
|
||||
changeTableColumns: changeRecordColumns,
|
||||
candidateColumns: candidateDetailColumns,
|
||||
contractOptions: [],
|
||||
payerOptions: [],
|
||||
payeeOptions: [],
|
||||
contractCategoryOptions,
|
||||
signTypeOptions,
|
||||
effectiveTypeOptions,
|
||||
@@ -1391,18 +1394,34 @@ export default {
|
||||
const first = rows[0];
|
||||
const settlementType = this.initialData.settlementType || first.settlementType || 'payable';
|
||||
const contractId = first.contractId || '';
|
||||
let contractPartyA = first.payerName || '';
|
||||
let contractPartyB = first.payeeName || '';
|
||||
if (contractId && (!contractPartyA || !contractPartyB)) {
|
||||
let contractPartyA = '';
|
||||
let contractPartyB = '';
|
||||
let contractPartyAJson = '';
|
||||
let contractPartyBJson = '';
|
||||
if (contractId) {
|
||||
try {
|
||||
const { data } = await getContractOptions(first.contractNo || '');
|
||||
const matched = (data?.data || []).find(item => String(item.id) === String(contractId));
|
||||
contractPartyA = contractPartyA || matched?.partyA || '';
|
||||
contractPartyB = contractPartyB || matched?.partyB || '';
|
||||
const contractDetail = await this.fetchContractPartyDetail(contractId);
|
||||
if (contractDetail) {
|
||||
contractPartyA = contractDetail.partyA || '';
|
||||
contractPartyB = contractDetail.partyB || '';
|
||||
contractPartyAJson = contractDetail.partyAJson || '';
|
||||
contractPartyBJson = contractDetail.partyBJson || '';
|
||||
}
|
||||
} catch (error) {
|
||||
contractPartyA = '';
|
||||
contractPartyB = '';
|
||||
}
|
||||
if (!contractPartyA && !contractPartyB) {
|
||||
try {
|
||||
const { data } = await getContractOptions(first.contractNo || '');
|
||||
const matched = (data?.data || []).find(item => String(item.id) === String(contractId));
|
||||
contractPartyA = matched?.partyA || '';
|
||||
contractPartyB = matched?.partyB || '';
|
||||
} catch (error) {
|
||||
contractPartyA = first.payerName || '';
|
||||
contractPartyB = first.payeeName || '';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this.contractOptions.some(item => String(item.id) === String(contractId))) {
|
||||
this.contractOptions.push({
|
||||
@@ -1416,6 +1435,8 @@ export default {
|
||||
settlementType,
|
||||
partyA: contractPartyA,
|
||||
partyB: contractPartyB,
|
||||
partyAJson: contractPartyAJson,
|
||||
partyBJson: contractPartyBJson,
|
||||
});
|
||||
}
|
||||
this.handleContractChange(contractId);
|
||||
@@ -1427,12 +1448,12 @@ export default {
|
||||
projectName: first.projectName || this.form.projectName,
|
||||
deptId: first.deptId || this.form.deptId,
|
||||
deptName: first.deptName || this.form.deptName,
|
||||
payerName: this.form.payerName || contractPartyA,
|
||||
payeeName: this.form.payeeName || contractPartyB,
|
||||
settlementType,
|
||||
currency: first.currency || 'RMB',
|
||||
localCurrency: first.localCurrency || 'RMB',
|
||||
});
|
||||
// 明细带入的收付方若为单值且在选项中,优先保留;多方拼接值由下拉默认首项承接
|
||||
this.applyPartySelection(first.payerName, first.payeeName);
|
||||
this.details = rows.map(row => this.normalizeSourceDetail(row));
|
||||
this.detailPage.current = 1;
|
||||
this.loading = true;
|
||||
@@ -1516,6 +1537,8 @@ export default {
|
||||
this.billingRuleDialog.visible = false;
|
||||
this.billingRuleDialog.rule = null;
|
||||
this.contractOptions = [];
|
||||
this.payerOptions = [];
|
||||
this.payeeOptions = [];
|
||||
this.contractDialog.visible = false;
|
||||
this.contractDialog.expanded = false;
|
||||
this.contractDialog.rows = [];
|
||||
@@ -1552,21 +1575,20 @@ export default {
|
||||
this.attachments = this.parseAttachments(detail.attachmentsJson);
|
||||
this.sortAttachments();
|
||||
this.selectedAttachmentRows = [];
|
||||
if (
|
||||
detail.contractId &&
|
||||
!this.contractOptions.some(item => item.id === detail.contractId)
|
||||
) {
|
||||
this.contractOptions.push({
|
||||
id: detail.contractId,
|
||||
if (detail.contractId) {
|
||||
await this.ensureContractPartyOptions(detail.contractId, {
|
||||
contractNo: detail.contractNo,
|
||||
contractName: detail.contractName,
|
||||
projectId: detail.projectId,
|
||||
projectName: detail.projectName,
|
||||
deptId: detail.deptId,
|
||||
deptName: detail.deptName,
|
||||
partyA: detail.payerName,
|
||||
partyB: detail.payeeName,
|
||||
settlementType: detail.settlementType,
|
||||
});
|
||||
this.applyPartySelection(detail.payerName, detail.payeeName);
|
||||
} else {
|
||||
this.payerOptions = [];
|
||||
this.payeeOptions = [];
|
||||
}
|
||||
if (this.publicMode && detail.detailFees) {
|
||||
Object.entries(detail.detailFees).forEach(([detailId, feeRows]) => {
|
||||
@@ -1640,6 +1662,8 @@ export default {
|
||||
deptName: row.deptName || row.organizationName,
|
||||
partyA: row.partyA || row.payerName,
|
||||
partyB: row.partyB || row.payeeName,
|
||||
partyAJson: row.partyAJson || '',
|
||||
partyBJson: row.partyBJson || '',
|
||||
settlementType:
|
||||
row.settlementType || (row.contractCategory === '客户合同' ? 'receivable' : 'payable'),
|
||||
};
|
||||
@@ -1649,7 +1673,7 @@ export default {
|
||||
this.handleContractChange(contract.id);
|
||||
this.contractDialog.visible = false;
|
||||
this.contractDialog.current = null;
|
||||
this.$refs.formRef?.clearValidate('contractId');
|
||||
this.$refs.formRef?.clearValidate(['contractId', 'payerName', 'payeeName']);
|
||||
},
|
||||
contractCategoryName(value) {
|
||||
return (
|
||||
@@ -1714,6 +1738,8 @@ export default {
|
||||
this.form.deptName = '';
|
||||
this.form.payerName = '';
|
||||
this.form.payeeName = '';
|
||||
this.payerOptions = [];
|
||||
this.payeeOptions = [];
|
||||
this.summaryFees = [];
|
||||
this.projectAdvanceWriteOffs = [];
|
||||
return;
|
||||
@@ -1726,9 +1752,8 @@ export default {
|
||||
this.form.deptId = contract.deptId;
|
||||
this.form.deptName = contract.deptName;
|
||||
this.form.settlementType = contract.settlementType || 'payable';
|
||||
// 部分候选合同只带 id/名称,缺甲方乙方;此时保留已带出的收付方,不要清成 undefined
|
||||
if (contract.partyA) this.form.payerName = contract.partyA;
|
||||
if (contract.partyB) this.form.payeeName = contract.partyB;
|
||||
this.syncPartyOptionsFromContract(contract);
|
||||
this.applyPartySelection('', '');
|
||||
this.form.currency = contract.settlementCurrency || 'RMB';
|
||||
this.summaryFees = [];
|
||||
this.projectAdvanceWriteOffs = [];
|
||||
@@ -1737,6 +1762,152 @@ export default {
|
||||
this.fetchBfiExchangeRate();
|
||||
}
|
||||
},
|
||||
parsePartyNames(partyJson, fallbackName) {
|
||||
try {
|
||||
const parsed = partyJson ? JSON.parse(partyJson) : [];
|
||||
if (Array.isArray(parsed) && parsed.length) {
|
||||
const names = parsed
|
||||
.map(item => String(item?.customerName || '').trim())
|
||||
.filter(Boolean);
|
||||
if (names.length) return [...new Set(names)];
|
||||
}
|
||||
} catch (error) {
|
||||
// JSON 解析失败时回退到名称拆分
|
||||
}
|
||||
return [
|
||||
...new Set(
|
||||
String(fallbackName || '')
|
||||
.split(/[、,,]/)
|
||||
.map(name => name.trim())
|
||||
.filter(Boolean)
|
||||
),
|
||||
];
|
||||
},
|
||||
buildPartySelectOptions(names) {
|
||||
return (names || []).map(name => ({ dictKey: name, dictValue: name }));
|
||||
},
|
||||
resolveContractPartyNames(contract) {
|
||||
const settlementType = contract?.settlementType || this.form.settlementType || 'payable';
|
||||
const partyANames = this.parsePartyNames(contract?.partyAJson, contract?.partyA);
|
||||
const partyBNames = this.parsePartyNames(contract?.partyBJson, contract?.partyB);
|
||||
if (settlementType === 'receivable') {
|
||||
return { payerNames: partyBNames, payeeNames: partyANames };
|
||||
}
|
||||
return { payerNames: partyANames, payeeNames: partyBNames };
|
||||
},
|
||||
syncPartyOptionsFromContract(contract) {
|
||||
const { payerNames, payeeNames } = this.resolveContractPartyNames(contract || {});
|
||||
this.payerOptions = this.buildPartySelectOptions(payerNames);
|
||||
this.payeeOptions = this.buildPartySelectOptions(payeeNames);
|
||||
},
|
||||
isJoinedPartyName(value) {
|
||||
return /[、,,]/.test(String(value || ''));
|
||||
},
|
||||
pickPartyValue(names, currentValue) {
|
||||
const options = Array.isArray(names) ? names : [];
|
||||
const current = String(currentValue || '').trim();
|
||||
if (!options.length) {
|
||||
// 无线上选项时(如公开查看拉不到合同),保留已有单值,丢弃多方拼接脏值
|
||||
return this.isJoinedPartyName(current) ? '' : current;
|
||||
}
|
||||
if (current && !this.isJoinedPartyName(current) && options.includes(current)) {
|
||||
return current;
|
||||
}
|
||||
return options[0] || '';
|
||||
},
|
||||
applyPartySelection(payerName, payeeName) {
|
||||
const payerNames = this.payerOptions.map(item => item.dictKey);
|
||||
const payeeNames = this.payeeOptions.map(item => item.dictKey);
|
||||
this.form.payerName = this.pickPartyValue(payerNames, payerName);
|
||||
this.form.payeeName = this.pickPartyValue(payeeNames, payeeName);
|
||||
// 编辑历史单值不在合同多方中时,仍保留展示,避免下拉空白
|
||||
if (
|
||||
this.form.payerName &&
|
||||
!this.payerOptions.some(item => item.dictKey === this.form.payerName)
|
||||
) {
|
||||
this.payerOptions = [
|
||||
...this.payerOptions,
|
||||
{ dictKey: this.form.payerName, dictValue: this.form.payerName },
|
||||
];
|
||||
}
|
||||
if (
|
||||
this.form.payeeName &&
|
||||
!this.payeeOptions.some(item => item.dictKey === this.form.payeeName)
|
||||
) {
|
||||
this.payeeOptions = [
|
||||
...this.payeeOptions,
|
||||
{ dictKey: this.form.payeeName, dictValue: this.form.payeeName },
|
||||
];
|
||||
}
|
||||
},
|
||||
async fetchContractPartyDetail(contractId) {
|
||||
if (!contractId) return null;
|
||||
const { data } = await getContractDetail(contractId);
|
||||
return data?.data || null;
|
||||
},
|
||||
async ensureContractPartyOptions(contractId, fallback = {}) {
|
||||
if (!contractId) {
|
||||
this.payerOptions = [];
|
||||
this.payeeOptions = [];
|
||||
return null;
|
||||
}
|
||||
let contract = this.contractOptions.find(item => String(item.id) === String(contractId));
|
||||
const needDetail =
|
||||
!contract ||
|
||||
!(contract.partyAJson || contract.partyBJson) ||
|
||||
this.isJoinedPartyName(contract.partyA) ||
|
||||
this.isJoinedPartyName(contract.partyB) ||
|
||||
(!contract.partyA && !contract.partyB);
|
||||
if (needDetail) {
|
||||
try {
|
||||
const detail = await this.fetchContractPartyDetail(contractId);
|
||||
if (detail) {
|
||||
contract = {
|
||||
...(contract || {}),
|
||||
id: contractId,
|
||||
contractNo: detail.contractNo || fallback.contractNo || contract?.contractNo,
|
||||
contractName: detail.contractName || fallback.contractName || contract?.contractName,
|
||||
projectId: detail.projectId || fallback.projectId || contract?.projectId,
|
||||
projectName: detail.projectName || fallback.projectName || contract?.projectName,
|
||||
deptId:
|
||||
detail.organizationId ||
|
||||
detail.deptId ||
|
||||
fallback.deptId ||
|
||||
contract?.deptId,
|
||||
deptName:
|
||||
detail.organizationName ||
|
||||
detail.deptName ||
|
||||
fallback.deptName ||
|
||||
contract?.deptName,
|
||||
partyA: detail.partyA || contract?.partyA || '',
|
||||
partyB: detail.partyB || contract?.partyB || '',
|
||||
partyAJson: detail.partyAJson || contract?.partyAJson || '',
|
||||
partyBJson: detail.partyBJson || contract?.partyBJson || '',
|
||||
settlementType:
|
||||
fallback.settlementType ||
|
||||
contract?.settlementType ||
|
||||
(detail.contractCategory === '客户合同' ? 'receivable' : 'payable'),
|
||||
settlementCurrency: detail.settlementCurrency || contract?.settlementCurrency,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
// 合同详情失败时仍用现有快照拆分多方名称
|
||||
}
|
||||
}
|
||||
if (!contract) {
|
||||
contract = {
|
||||
id: contractId,
|
||||
...fallback,
|
||||
partyA: fallback.partyA || '',
|
||||
partyB: fallback.partyB || '',
|
||||
};
|
||||
}
|
||||
const index = this.contractOptions.findIndex(item => String(item.id) === String(contractId));
|
||||
if (index >= 0) this.contractOptions.splice(index, 1, contract);
|
||||
else this.contractOptions.push(contract);
|
||||
this.syncPartyOptionsFromContract(contract);
|
||||
return contract;
|
||||
},
|
||||
async saveDraft(shouldSubmit) {
|
||||
await this.$refs.formRef?.validate();
|
||||
if (shouldSubmit && !this.details.length) {
|
||||
|
||||
Reference in New Issue
Block a user