✨ 评分减分累计与最高扣分、用户部门标签联动树,并修复对账导入与结算调整等
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -244,7 +244,7 @@
|
||||
<el-table-column prop="paymentRatio" label="付款比例(%)" min-width="160">
|
||||
<template #default="{ row }">
|
||||
<el-input-number
|
||||
v-if="multipleSettlementRows && !readonly"
|
||||
v-if="!readonly"
|
||||
:model-value="row.paymentRatio"
|
||||
:min="0"
|
||||
:max="rowPaymentRatioMax(row)"
|
||||
@@ -262,7 +262,7 @@
|
||||
<el-table-column prop="appliedAmount" label="付款金额" min-width="160">
|
||||
<template #default="{ row }">
|
||||
<el-input-number
|
||||
v-if="multipleSettlementRows && !readonly"
|
||||
v-if="!readonly"
|
||||
:model-value="row.appliedAmount"
|
||||
:min="0"
|
||||
:max="Number(row.payableAmount || 0)"
|
||||
@@ -1014,62 +1014,37 @@ export default {
|
||||
referenceSettlementCount() {
|
||||
return this.referenceSettlementNos.length;
|
||||
},
|
||||
multipleSettlementRows() {
|
||||
return this.referenceRows.length > 1;
|
||||
},
|
||||
// 结算单号展示:单张显示单号;多张仅提示数量,明细在下方「结算信息」表,悬停可看全部单号
|
||||
referenceDisplayText() {
|
||||
if (this.referenceSettlementCount > 1) return `已选 ${this.referenceSettlementCount} 张结算单`;
|
||||
return this.referenceLabel;
|
||||
},
|
||||
settlementRows() {
|
||||
if (this.referenceRows.length > 1) {
|
||||
// 多结算单:行内比例/金额独立维护,不回落到表头比例(表头与结算信息不关联)
|
||||
return this.referenceRows.map(item => {
|
||||
const paymentRatio =
|
||||
item.paymentRatio === undefined || item.paymentRatio === null || item.paymentRatio === ''
|
||||
? 0
|
||||
: Number(item.paymentRatio);
|
||||
const appliedAmount = Number(item.appliedAmount || 0);
|
||||
return {
|
||||
...item,
|
||||
paymentRatio,
|
||||
appliedAmount,
|
||||
...this.buildSettlementRatioHint({ ...item, paymentRatio }),
|
||||
};
|
||||
});
|
||||
}
|
||||
if (this.referenceRows.length) {
|
||||
return this.referenceRows.map(item => {
|
||||
const appliedAmount =
|
||||
item.fixedAppliedAmount === true
|
||||
? Number(item.appliedAmount || 0)
|
||||
: Number(
|
||||
(
|
||||
(Number(item.settlementAmount || 0) * Number(this.form.paymentRatio || 0)) /
|
||||
100
|
||||
).toFixed(2)
|
||||
);
|
||||
return {
|
||||
...item,
|
||||
paymentRatio: this.form.paymentRatio,
|
||||
appliedAmount,
|
||||
...this.buildSettlementRatioHint(item),
|
||||
};
|
||||
});
|
||||
}
|
||||
if (!this.referenceLabel) return [];
|
||||
return [
|
||||
{
|
||||
settlementNo: this.referenceLabel,
|
||||
settlementAmount: this.form.settlementAmount,
|
||||
payableAmount: this.form.payableAmount,
|
||||
paymentRatio: this.form.paymentRatio,
|
||||
appliedAmount: this.form.appliedAmount,
|
||||
paymentSequence: 1,
|
||||
...this.buildSettlementRatioHint({ paymentSequence: 1 }),
|
||||
},
|
||||
];
|
||||
const source = this.referenceRows.length
|
||||
? this.referenceRows
|
||||
: this.referenceLabel
|
||||
? [
|
||||
{
|
||||
settlementNo: this.referenceLabel,
|
||||
settlementAmount: this.form.settlementAmount,
|
||||
payableAmount: this.form.payableAmount,
|
||||
paymentRatio: null,
|
||||
appliedAmount: null,
|
||||
paymentSequence: 1,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
// 结算行比例/金额只取行内数据,不回落到付款基本信息
|
||||
return source.map(item => {
|
||||
const paymentRatio = this.nullableNumber(item.paymentRatio);
|
||||
const appliedAmount = this.nullableNumber(item.appliedAmount);
|
||||
return {
|
||||
...item,
|
||||
paymentRatio,
|
||||
appliedAmount,
|
||||
...this.buildSettlementRatioHint({ ...item, paymentRatio }),
|
||||
};
|
||||
});
|
||||
},
|
||||
highRiskPayee() {
|
||||
const level = String(this.payeeCustomerLevel || '')
|
||||
@@ -1127,11 +1102,12 @@ export default {
|
||||
if (
|
||||
this.amountSyncing ||
|
||||
this.form.paymentType === 'project_advance' ||
|
||||
!this.paymentAmountBase
|
||||
!this.paymentAmountBase ||
|
||||
this.nullableNumber(this.form.paymentRatio) === null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// 结算金额变化时按上方比例重算申请付款金额,仍不联动结算信息明细
|
||||
// 结算金额变化时只按上方比例重算申请付款金额,不改结算信息明细
|
||||
this.amountSyncing = true;
|
||||
this.form.appliedAmount = Number(
|
||||
((this.paymentAmountBase * Number(this.form.paymentRatio || 0)) / 100).toFixed(2)
|
||||
@@ -1532,8 +1508,6 @@ export default {
|
||||
paymentSequence: amount.paymentSequence,
|
||||
}),
|
||||
settlementNo: item.formalSettlementNo || item.settlementNo || '',
|
||||
appliedAmount: Number(item.appliedAmount || 0),
|
||||
fixedAppliedAmount: true,
|
||||
};
|
||||
});
|
||||
this.seedMultipleRowPayments(referenceRows);
|
||||
@@ -1545,27 +1519,6 @@ export default {
|
||||
(total, item) => total + Number(item.payableAmount || 0),
|
||||
0
|
||||
);
|
||||
const multiple = referenceRows.length > 1;
|
||||
// 多结算单:表头比例/申请金额独立;单结算单:沿用行金额或按比例计算
|
||||
const paymentRatio = Number(this.form.paymentRatio || 0);
|
||||
const rowsAppliedTotal = referenceRows.reduce(
|
||||
(total, item) => total + Number(item.appliedAmount || 0),
|
||||
0
|
||||
);
|
||||
const headerAppliedAmount = multiple
|
||||
? Number(((settlementAmount * paymentRatio) / 100).toFixed(2))
|
||||
: Number(
|
||||
(
|
||||
rowsAppliedTotal > 0
|
||||
? rowsAppliedTotal
|
||||
: (payableAmount * paymentRatio) / 100
|
||||
).toFixed(2)
|
||||
);
|
||||
const headerPaymentRatio = multiple
|
||||
? paymentRatio
|
||||
: settlementAmount
|
||||
? Number(((headerAppliedAmount / settlementAmount) * 100).toFixed(2))
|
||||
: paymentRatio;
|
||||
const settlementIds = rows.map(item => item.settlementId || item.id).filter(Boolean);
|
||||
this.amountSyncing = true;
|
||||
this.referenceRows = referenceRows;
|
||||
@@ -1592,8 +1545,7 @@ export default {
|
||||
settlementAmount: Number(settlementAmount.toFixed(2)),
|
||||
payableAmount: Number(payableAmount.toFixed(2)),
|
||||
billType: '',
|
||||
paymentRatio: headerPaymentRatio,
|
||||
appliedAmount: headerAppliedAmount,
|
||||
appliedAmount: this.headerAppliedAmountByRatio(settlementAmount),
|
||||
invoices: rows.flatMap(item =>
|
||||
this.createInvoiceRows(item.invoices || [], item.formalSettlementNo || item.settlementNo)
|
||||
),
|
||||
@@ -1649,7 +1601,7 @@ export default {
|
||||
referenceType: isPre ? 'pre' : 'formal',
|
||||
settlementAmount: Number(Number(item.settlementAmount || 0).toFixed(2)),
|
||||
payableAmount: Number(Number(item.payableAmount ?? item.settlementAmount ?? 0).toFixed(2)),
|
||||
appliedAmount: Number(Number(item.appliedAmount || 0).toFixed(2)),
|
||||
appliedAmount: this.nullableNumber(item.appliedAmount),
|
||||
paymentRatio: Number(item.settlementAmount || 0)
|
||||
? Number(
|
||||
(
|
||||
@@ -1658,11 +1610,10 @@ export default {
|
||||
).toFixed(2)
|
||||
)
|
||||
: null,
|
||||
fixedAppliedAmount: this.readonly,
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
if (rows.length > 1) {
|
||||
if (rows.length) {
|
||||
this.form.preSettlementIds = rows.filter(item => item.referenceType === 'pre').map(item => item.id);
|
||||
this.form.settlementIds = rows.filter(item => item.referenceType === 'formal').map(item => item.id);
|
||||
if (this.form.preSettlementIds.length) this.form.preSettlementId = this.form.preSettlementIds[0];
|
||||
@@ -1696,18 +1647,27 @@ export default {
|
||||
settlementAmount: Number(Number(settlementAmount || 0).toFixed(2)),
|
||||
payableAmount: Number(Math.max(0, payableAmount).toFixed(2)),
|
||||
paymentSequence: Number.isFinite(paymentSequence) && paymentSequence > 0 ? paymentSequence : 1,
|
||||
paymentRatio: null,
|
||||
appliedAmount: null,
|
||||
};
|
||||
},
|
||||
nullableNumber(value) {
|
||||
if (value === undefined || value === null || value === '') return null;
|
||||
const amount = Number(value);
|
||||
return Number.isFinite(amount) ? amount : null;
|
||||
},
|
||||
/** 付款基本信息内部:已填写比例时,按结算金额重算申请付款金额;不读取结算行付款金额。 */
|
||||
headerAppliedAmountByRatio(settlementAmount) {
|
||||
if (this.nullableNumber(this.form.paymentRatio) === null) return this.form.appliedAmount;
|
||||
return Number(((Number(settlementAmount || 0) * Number(this.form.paymentRatio)) / 100).toFixed(2));
|
||||
},
|
||||
/**
|
||||
* 按合同付款比例配置,判断当前付款次序是否超上限。
|
||||
* @param {Object} row 结算信息行(含 paymentSequence)
|
||||
*/
|
||||
buildSettlementRatioHint(row = {}) {
|
||||
const sequence = Number(row.paymentSequence || 1);
|
||||
const rawRatio =
|
||||
row.paymentRatio !== undefined && row.paymentRatio !== null && row.paymentRatio !== ''
|
||||
? row.paymentRatio
|
||||
: this.form.paymentRatio;
|
||||
const rawRatio = row.paymentRatio;
|
||||
const paymentRatio = Number(rawRatio);
|
||||
const ratioConfig = this.contractPaymentRatioRows[sequence - 1];
|
||||
const ratioLimitValue = ratioConfig?.ratioLimit;
|
||||
@@ -1850,21 +1810,6 @@ export default {
|
||||
(total, item) => total + Number(item.payableAmount || 0),
|
||||
0
|
||||
);
|
||||
const multiple = this.referenceRows.length > 1;
|
||||
const paymentRatio = Number(this.form.paymentRatio || 0);
|
||||
const rowsAppliedTotal = this.referenceRows.reduce(
|
||||
(total, item) => total + Number(item.appliedAmount || 0),
|
||||
0
|
||||
);
|
||||
// 多结算单:表头申请金额只由上方比例计算;单结算单仍按可付款金额×比例
|
||||
const headerAppliedAmount = multiple
|
||||
? Number(((settlementAmount * paymentRatio) / 100).toFixed(2))
|
||||
: Number(((payableAmount * paymentRatio) / 100).toFixed(2));
|
||||
const headerPaymentRatio = multiple
|
||||
? paymentRatio
|
||||
: settlementAmount && rowsAppliedTotal > 0
|
||||
? Number(((rowsAppliedTotal / settlementAmount) * 100).toFixed(2))
|
||||
: paymentRatio;
|
||||
// 尾款付款场景下选择预付结算单时保留尾款付款类型,不强制改为进度预付
|
||||
this.amountSyncing = true;
|
||||
Object.assign(this.form, {
|
||||
@@ -1890,8 +1835,7 @@ export default {
|
||||
settlementAmount: Number(settlementAmount.toFixed(2)),
|
||||
payableAmount: Number(payableAmount.toFixed(2)),
|
||||
billType: '',
|
||||
paymentRatio: headerPaymentRatio,
|
||||
appliedAmount: headerAppliedAmount,
|
||||
appliedAmount: this.headerAppliedAmountByRatio(settlementAmount),
|
||||
});
|
||||
this.rememberSettlementParties(first.payerName, first.payeeName);
|
||||
this.paymentRecords = [];
|
||||
@@ -3080,22 +3024,54 @@ export default {
|
||||
return Number(Math.min(100, (payableAmount / settlementAmount) * 100).toFixed(2));
|
||||
},
|
||||
/**
|
||||
* 多结算单行金额规范化:仅在行内反算比例,不使用表头比例灌入(表头与结算信息不关联)。
|
||||
* 结算行金额规范化:只在行内反算比例,不使用付款基本信息的比例和申请金额。
|
||||
*/
|
||||
seedMultipleRowPayments(rows = []) {
|
||||
if (rows.length <= 1) return;
|
||||
rows.forEach(item => {
|
||||
const settlementAmount = Number(item.settlementAmount || 0);
|
||||
const payableAmount = Number(item.payableAmount || 0);
|
||||
let applied = Number(item.appliedAmount || 0);
|
||||
if (!Number.isFinite(applied) || applied < 0) applied = 0;
|
||||
if (applied > payableAmount) applied = Number(payableAmount.toFixed(2));
|
||||
item.appliedAmount = Number(applied.toFixed(2));
|
||||
item.paymentRatio = settlementAmount
|
||||
? Number(((item.appliedAmount / settlementAmount) * 100).toFixed(2))
|
||||
: 0;
|
||||
if (this.nullableNumber(item.appliedAmount) === null && this.nullableNumber(item.paymentRatio) === null) {
|
||||
item.appliedAmount = null;
|
||||
item.paymentRatio = null;
|
||||
return;
|
||||
}
|
||||
this.syncRowPayment(item, 'amount');
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 结算行付款比例与付款金额联动。比例 = 付款金额 / 结算总金额。
|
||||
* @param {'ratio'|'amount'} source 以哪一侧为准
|
||||
*/
|
||||
syncRowPayment(row, source) {
|
||||
const settlementAmount = Number(row.settlementAmount || 0);
|
||||
const payableAmount = Number(row.payableAmount || 0);
|
||||
if (source === 'ratio') {
|
||||
const ratio = this.nullableNumber(row.paymentRatio);
|
||||
if (ratio === null) {
|
||||
row.paymentRatio = null;
|
||||
row.appliedAmount = null;
|
||||
return;
|
||||
}
|
||||
let applied = Number(((settlementAmount * ratio) / 100).toFixed(2));
|
||||
if (applied > payableAmount) applied = Number(payableAmount.toFixed(2));
|
||||
row.appliedAmount = applied;
|
||||
row.paymentRatio = settlementAmount
|
||||
? Number(((applied / settlementAmount) * 100).toFixed(2))
|
||||
: Number(ratio.toFixed(2));
|
||||
return;
|
||||
}
|
||||
const appliedValue = this.nullableNumber(row.appliedAmount);
|
||||
if (appliedValue === null) {
|
||||
row.appliedAmount = null;
|
||||
row.paymentRatio = null;
|
||||
return;
|
||||
}
|
||||
let applied = appliedValue;
|
||||
if (applied < 0) applied = 0;
|
||||
if (applied > payableAmount) applied = payableAmount;
|
||||
row.appliedAmount = Number(applied.toFixed(2));
|
||||
row.paymentRatio = settlementAmount
|
||||
? Number(((row.appliedAmount / settlementAmount) * 100).toFixed(2))
|
||||
: 0;
|
||||
},
|
||||
findReferenceRow(row) {
|
||||
return this.referenceRows.find(
|
||||
item =>
|
||||
@@ -3104,55 +3080,19 @@ export default {
|
||||
item.settlementNo === row.settlementNo
|
||||
);
|
||||
},
|
||||
/** 结算信息付款金额合计 */
|
||||
settlementRowsAppliedTotal(rows = this.referenceRows) {
|
||||
return (rows || []).reduce((total, item) => total + Number(item.appliedAmount || 0), 0);
|
||||
},
|
||||
/** 结算信息合计不得超过上方申请付款金额 */
|
||||
ensureSettlementAppliedWithinHeader(showWarning = true) {
|
||||
if (!this.multipleSettlementRows) return true;
|
||||
const headerApplied = Number(this.form.appliedAmount || 0);
|
||||
const rowsTotal = Number(this.settlementRowsAppliedTotal().toFixed(2));
|
||||
if (rowsTotal - headerApplied > 1e-8) {
|
||||
if (showWarning) {
|
||||
this.$message.warning(
|
||||
`结算信息付款金额合计(${rowsTotal.toFixed(2)})不能大于申请付款金额(${headerApplied.toFixed(2)})`
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
handleRowPaymentRatioChange(row, value) {
|
||||
const target = this.findReferenceRow(row);
|
||||
if (!target) return;
|
||||
const settlementAmount = Number(target.settlementAmount || 0);
|
||||
const payableAmount = Number(target.payableAmount || 0);
|
||||
const ratio = value === null || value === undefined || value === '' ? 0 : Number(value);
|
||||
let applied = Number(((settlementAmount * ratio) / 100).toFixed(2));
|
||||
if (applied > payableAmount) applied = Number(payableAmount.toFixed(2));
|
||||
target.appliedAmount = applied;
|
||||
target.paymentRatio = settlementAmount
|
||||
? Number(((applied / settlementAmount) * 100).toFixed(2))
|
||||
: Number(ratio.toFixed(2));
|
||||
// 仅刷新结算金额/可付款金额合计,不回写表头申请金额与比例
|
||||
target.paymentRatio = value;
|
||||
this.syncRowPayment(target, 'ratio');
|
||||
this.syncHeaderSettlementTotalsFromRows();
|
||||
this.ensureSettlementAppliedWithinHeader(true);
|
||||
},
|
||||
handleRowAppliedAmountChange(row, value) {
|
||||
const target = this.findReferenceRow(row);
|
||||
if (!target) return;
|
||||
const settlementAmount = Number(target.settlementAmount || 0);
|
||||
const payableAmount = Number(target.payableAmount || 0);
|
||||
let applied = value === null || value === undefined || value === '' ? 0 : Number(value);
|
||||
if (!Number.isFinite(applied) || applied < 0) applied = 0;
|
||||
if (applied > payableAmount) applied = payableAmount;
|
||||
target.appliedAmount = Number(applied.toFixed(2));
|
||||
target.paymentRatio = settlementAmount
|
||||
? Number(((target.appliedAmount / settlementAmount) * 100).toFixed(2))
|
||||
: 0;
|
||||
target.appliedAmount = value;
|
||||
this.syncRowPayment(target, 'amount');
|
||||
this.syncHeaderSettlementTotalsFromRows();
|
||||
this.ensureSettlementAppliedWithinHeader(true);
|
||||
},
|
||||
/** 多结算单时仅同步结算金额/可付款金额合计,申请付款金额与比例由上方独立维护 */
|
||||
syncHeaderSettlementTotalsFromRows() {
|
||||
@@ -3261,8 +3201,8 @@ export default {
|
||||
settlementLines: (this.referenceRows || []).map(item => ({
|
||||
formalSettlementId: item.referenceType === 'formal' ? item.id : null,
|
||||
preSettlementId: item.referenceType === 'pre' ? item.id : null,
|
||||
paymentRatio: item.paymentRatio,
|
||||
appliedAmount: item.appliedAmount,
|
||||
paymentRatio: this.nullableNumber(item.paymentRatio),
|
||||
appliedAmount: this.nullableNumber(item.appliedAmount),
|
||||
})),
|
||||
paymentMethod,
|
||||
billLedgerId,
|
||||
@@ -3323,21 +3263,22 @@ export default {
|
||||
ElMessage.warning('申请付款金额必填且必须大于0');
|
||||
return false;
|
||||
}
|
||||
if (this.multipleSettlementRows) {
|
||||
const invalidRow = this.referenceRows.find(
|
||||
item => Number(item.appliedAmount || 0) > Number(item.payableAmount || 0)
|
||||
);
|
||||
if (this.isSettlementRelatedType && this.referenceRows.length) {
|
||||
const invalidRow = this.referenceRows.find(item => {
|
||||
const rowApplied = Number(item.appliedAmount || 0);
|
||||
return !Number.isFinite(rowApplied) || rowApplied <= 0;
|
||||
});
|
||||
if (invalidRow) {
|
||||
this.clearMessages();
|
||||
ElMessage.warning(`${invalidRow.settlementNo || '结算单'}付款金额不能超过可付款金额`);
|
||||
ElMessage.warning(`${invalidRow.settlementNo || '结算单'}请填写付款金额,且必须大于0`);
|
||||
return false;
|
||||
}
|
||||
const rowsTotal = Number(this.settlementRowsAppliedTotal().toFixed(2));
|
||||
if (rowsTotal - appliedAmount > 1e-8) {
|
||||
const exceededRow = this.referenceRows.find(
|
||||
item => Number(item.appliedAmount || 0) > Number(item.payableAmount || 0)
|
||||
);
|
||||
if (exceededRow) {
|
||||
this.clearMessages();
|
||||
ElMessage.warning(
|
||||
`结算信息付款金额合计(${rowsTotal.toFixed(2)})不能大于申请付款金额(${appliedAmount.toFixed(2)})`
|
||||
);
|
||||
ElMessage.warning(`${exceededRow.settlementNo || '结算单'}付款金额不能超过可付款金额`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user