Merge remote-tracking branch 'origin/master' into feature/20261016-settlement-adjustment-kingdee

This commit is contained in:
刘泉佳
2026-10-18 15:14:38 +08:00
40 changed files with 1511 additions and 537 deletions
@@ -459,7 +459,7 @@
</section-card>
<section-card v-if="form.id && readonly" title="变更记录">
<el-table :data="adjustChangeRecords" border>
<el-table :data="changeRecords" border>
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column
v-for="column in changeTableColumns"
@@ -753,20 +753,6 @@
<el-table-column type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column prop="cargoName" label="货物名称" min-width="140" align="center" />
<el-table-column prop="cargoType" label="货物类型" min-width="130" align="center" />
<el-table-column label="计费规则" min-width="190" align="center">
<template #default="{ row }">
<div class="pre-settlement-editor__billing-rule-cell">
<span>{{ displayValue(billingRuleName(row)) }}</span>
<el-icon
class="pre-settlement-editor__billing-rule-icon"
title="查看计费规则详情"
@click="openBillingRuleInfo(row)"
>
<InfoFilled />
</el-icon>
</div>
</template>
</el-table-column>
<el-table-column label="运输总量" min-width="150" align="center">
<template #default="{ row }">
<span v-if="adjustDialog.readonly">{{ formatQuantity(row) }}</span>
@@ -809,11 +795,33 @@
v-for="feeItem in adjustFeeItemNames"
:key="feeItem"
:label="feeItem"
min-width="140"
min-width="160"
align="center"
>
<template #default="{ row }">
<div
v-if="isFreightFeeItem(feeItem)"
class="pre-settlement-editor__billing-rule-cell"
>
<el-input-number
v-model="row.feeItems[feeItem]"
:min="0"
:precision="2"
:controls="false"
:disabled="adjustDialog.readonly"
@change="recalculateAdjustRow(row, feeItem)"
/>
<el-icon
v-if="hasBillingRule(row)"
class="pre-settlement-editor__billing-rule-icon"
title="查看计费规则详情"
@click="openBillingRuleInfo(row)"
>
<InfoFilled />
</el-icon>
</div>
<el-input-number
v-else
v-model="row.feeItems[feeItem]"
:min="0"
:precision="2"
@@ -833,11 +841,6 @@
/>
</template>
</el-table-column>
<el-table-column label="备注" min-width="200" align="center">
<template #default="{ row }">
<el-input v-model="row.remark" maxlength="200" :disabled="adjustDialog.readonly" />
</template>
</el-table-column>
</el-table>
<el-form
v-if="!adjustDialog.readonly"
@@ -846,7 +849,7 @@
label-width="auto"
class="pre-settlement-editor__adjust-reason"
>
<el-form-item label="调整原因">
<el-form-item label="备注">
<el-input
v-model="adjustDialog.reason"
type="textarea"
@@ -885,12 +888,6 @@
<template v-if="billingRuleDialog.rule">
<div class="dialog-section-title">计费规则</div>
<el-descriptions :column="2" border class="pre-settlement-editor__billing-rule-detail">
<el-descriptions-item label="规则名称">
{{ displayValue(billingRuleDialog.rule.name) }}
</el-descriptions-item>
<el-descriptions-item label="费用类型">
{{ displayValue(billingRuleDialog.rule.feeType) }}
</el-descriptions-item>
<el-descriptions-item label="费用项">
{{ displayValue(billingRuleDialog.rule.feeItem) }}
</el-descriptions-item>
@@ -926,8 +923,8 @@
<el-descriptions-item label="目的地">
{{ displayValue(billingRuleDialog.rule.matchCondition.destination) }}
</el-descriptions-item>
<el-descriptions-item label="运输方式">
{{ displayValue(billingRuleDialog.rule.matchCondition.transportMode) }}
<el-descriptions-item label="货物名称">
{{ displayValue(billingRuleDialog.rule.matchCondition.cargoName) }}
</el-descriptions-item>
<el-descriptions-item label="货物类型">
{{ displayValue(billingRuleDialog.rule.matchCondition.cargoType) }}
@@ -1203,8 +1200,8 @@ export default {
return this.editable && this.hasPermission('pre_settlement_adjust');
},
dialogTitle() {
if (this.readonly) return '查看预结算单';
return this.form.id ? '编辑预结算单' : '新增预结算单';
if (this.readonly) return '查看预付结算单';
return this.form.id ? '编辑预付结算单' : '新增预付结算单';
},
settlementTypeName() {
return this.form.settlementType === 'receivable' ? '应收' : '应付';
@@ -1286,13 +1283,6 @@ export default {
});
return Array.from(names);
},
adjustChangeRecords() {
return this.changeRecords.filter(
row =>
row.changeType === '结算明细项' &&
String(row.lineNo ?? '') === String(this.adjustDialog.detailLineNo ?? '')
);
},
},
watch: {
modelValue: {
@@ -1866,7 +1856,25 @@ export default {
});
const manualFees = this.summaryFees.filter(row => Number(row.manualFlag) === 1);
this.summaryFees = [...summaryMap.values(), ...manualFees];
const nextFeeMap = new Map();
summaryMap.forEach((row, key) => nextFeeMap.set(`0\u0000${key}`, row));
manualFees.forEach(row => {
const key = `1\u0000${row.feeType}\u0000${row.feeItem}`;
nextFeeMap.set(key, row);
});
// 按编辑前顺序回填,新增费用项追加到末尾,避免手工费用被统一挤到最后。
const orderedFees = [];
const previousKeys = this.summaryFees.map(
row => `${Number(row.manualFlag) === 1 ? 1 : 0}\u0000${row.feeType}\u0000${row.feeItem}`
);
previousKeys.forEach(key => {
const row = nextFeeMap.get(key);
if (!row) return;
orderedFees.push(row);
nextFeeMap.delete(key);
});
nextFeeMap.forEach(row => orderedFees.push(row));
this.summaryFees = orderedFees;
this.recalculateLocalAmount();
},
// 每条明细对应的费用行:[调整前基准行, 调整后当前行],缺少来源费用快照时退化为明细自身的汇总行。
@@ -2054,7 +2062,7 @@ export default {
}
},
async removeDetailRow(row) {
await this.$confirm('确认将该明细踢出预结算单?', '提示', { type: 'warning' });
await this.$confirm('确认将该明细踢出预付结算单?', '提示', { type: 'warning' });
if (!this.form.id || !row.id || row.id === row.sourceDetailId) {
this.details = this.details.filter(item => item !== row);
this.buildSummaryFeesFromDetails();
@@ -2229,7 +2237,11 @@ export default {
: '';
const sourceDetailId = String(this.adjustDialog.sourceDetailId || '');
const pending = sourceDetailId ? this.pendingAdjustments[sourceDetailId] : null;
this.adjustDialog.reason = pending?.reason || '';
// 底部备注回显结算明细备注;暂存过的调整优先取暂存备注
this.adjustDialog.reason =
pending?.reason !== undefined && pending?.reason !== null
? pending.reason
: detailRow.remark || '';
try {
// 已暂存的调整结果优先回显,避免重新打开时又回到调整前的数据。
if (pending?.rows?.length) {
@@ -2296,8 +2308,19 @@ export default {
this.adjustChangeRecordDetailRows = this.buildAdjustChangeRecordRows(row);
this.adjustChangeRecordVisible = true;
},
billingRuleName(row) {
return this.normalizeBillingRule(row).name;
hasBillingRule(row) {
const rule = this.normalizeBillingRule(row);
return Boolean(
rule.feeItem ||
rule.billingElement ||
rule.billingType ||
rule.unitPrice ||
rule.rules?.length ||
rule.matchCondition?.origin ||
rule.matchCondition?.destination ||
rule.matchCondition?.cargoName ||
rule.matchCondition?.cargoType
);
},
openBillingRuleInfo(row) {
this.billingRuleDialog.rule = this.normalizeBillingRule(row);
@@ -2324,27 +2347,8 @@ export default {
const matchCondition = this.parseObject(
source.matchCondition ?? source.billingMatchCondition ?? rule.matchCondition
);
const ruleNames = matchedRules
.map(item => item.ruleName || item.name || item.billingRuleName || item.feeItem)
.filter(Boolean);
const name =
source.billingRuleName ||
source.feeRuleName ||
source.ruleName ||
source.billingPlanRuleName ||
source.billingPlanName ||
rule.name ||
rule.ruleName ||
rule.billingRuleName ||
rule.planName ||
rule.billingPlanName ||
ruleNames.join('、') ||
rule.feeItem ||
'';
return {
...rule,
name,
feeType: source.billingFeeType || source.feeType || rule.feeType,
feeItem: source.billingFeeItem || source.feeItem || rule.feeItem,
billingElement:
source.billingElement ||
@@ -2362,7 +2366,11 @@ export default {
...matchCondition,
origin: matchCondition.origin || matchCondition.originName,
destination: matchCondition.destination || matchCondition.destinationName,
transportMode: matchCondition.transportMode || matchCondition.transportType,
cargoName:
matchCondition.cargoName ||
matchCondition.cargoNameLabel ||
source.cargoName ||
rule.cargoName,
cargoType: matchCondition.cargoType || matchCondition.cargoTypeName,
},
};
@@ -2452,9 +2460,13 @@ export default {
reason: this.adjustDialog.reason,
rows: this.adjustRows.map(row => ({ ...row, feeItems: { ...row.feeItems } })),
};
this.applyLocalAdjustment(this.adjustDialog.sourceDetailId, this.adjustRows);
this.applyLocalAdjustment(
this.adjustDialog.sourceDetailId,
this.adjustRows,
this.adjustDialog.reason
);
this.adjustDialog.visible = false;
this.$message.success('结算明细调整已暂存,保存预结算单后生效');
this.$message.success('结算明细调整已暂存,保存预付结算单后生效');
return;
}
await adjustDetail({
@@ -2469,7 +2481,6 @@ export default {
feeItems: row.feeItems,
settlementAmountTax: row.settlementAmountTax,
settlementAmountNoTax: row.settlementAmountNoTax,
remark: row.remark,
})),
});
this.adjustDialog.visible = false;
@@ -2480,12 +2491,12 @@ export default {
this.adjustDialog.saving = false;
}
},
applyLocalAdjustment(sourceDetailId, rows) {
applyLocalAdjustment(sourceDetailId, rows, detailRemark) {
const detail = this.details.find(
item => String(item.sourceDetailId || item.id) === String(sourceDetailId)
);
if (!detail) return;
// 原金额以进入预结算单时的费用快照为基准,调整金额 = 结算金额 - 原金额。
// 原金额以进入预付结算单时的费用快照为基准,调整金额 = 结算金额 - 原金额。
const baseRows = this.sourceFeeSnapshots[String(sourceDetailId)] || [];
const originalAmount = baseRows.length
? baseRows.reduce((sum, row) => sum + Number(row.settlementAmountTax || 0), 0)
@@ -2494,20 +2505,48 @@ export default {
(sum, row) => sum + Number(row.settlementAmountTax || 0),
0
);
const settlementAmountNoTax = rows.reduce(
(sum, row) => sum + Number(row.settlementAmountNoTax || 0),
0
);
const hasSettlementAmountNoTax = rows.some(
row => row.settlementAmountNoTax !== undefined && row.settlementAmountNoTax !== null
);
const freightAmount = rows.reduce((sum, row) => sum + Number(row.freightAmount || 0), 0);
const transportQuantity = rows.reduce(
(sum, row) => sum + Number(row.transportQuantity || 0),
0
);
const mileage = rows.reduce((sum, row) => sum + Number(row.mileage || 0), 0);
const feeItems = {};
rows.forEach(row =>
Object.entries(row.feeItems || {}).forEach(([name, amount]) => {
feeItems[name] = Number((Number(feeItems[name] || 0) + Number(amount || 0)).toFixed(2));
})
);
const firstRow = rows[0] || {};
Object.assign(detail, {
transportQuantity: Number(transportQuantity.toFixed(2)),
mileage: Number(mileage.toFixed(2)),
unitPrice: Number(firstRow.unitPrice || 0),
originalAmount: Number(originalAmount.toFixed(2)),
adjustAmount: Number((settlementAmountTax - originalAmount).toFixed(2)),
settlementAmountTax: Number(settlementAmountTax.toFixed(2)),
settlementAmountNoTax: hasSettlementAmountNoTax
? Number(settlementAmountNoTax.toFixed(2))
: detail.settlementAmountNoTax,
freightAmount: Number(freightAmount.toFixed(2)),
feeItemsJson: JSON.stringify(feeItems),
// 底部备注写入结算明细备注
remark: detailRemark ?? '',
});
// 暂存调整后同步费用缓存,保证货物名称/类型拼接与列表展示一致。
if (detail.id) {
this.detailFeeCache[detail.id] = rows.map(row => ({
...row,
feeItems: { ...row.feeItems },
}));
}
this.buildSummaryFeesFromDetails();
},
async persistPendingAdjustments() {
@@ -2535,11 +2574,14 @@ export default {
feeItems: pendingRow.feeItems,
settlementAmountTax: pendingRow.settlementAmountTax,
settlementAmountNoTax: pendingRow.settlementAmountNoTax,
remark: pendingRow.remark,
};
});
if (rows.length) {
await adjustDetail({ detailId: detail.id, changeReason: pending.reason, rows });
await adjustDetail({
detailId: detail.id,
changeReason: pending.reason,
rows,
});
}
}
this.pendingAdjustments = {};
@@ -2611,7 +2653,7 @@ export default {
XLSX.utils.book_append_sheet(workbook, sheet, '结算明细');
XLSX.writeFile(
workbook,
`${this.form.preSettlementNo || '预结算单'}结算明细${this.$dayjs().format(
`${this.form.preSettlementNo || '预付结算单'}结算明细${this.$dayjs().format(
'YYYY-MM-DD HH-mm-ss'
)}.xlsx`
);