feat: 正式结算单新增预付汇总栏与付款记录合并展示
结算合计下新增汇总栏(结算合计原金额-已付金额含预付核销-剩余未付);只读付款信息合并展示进度预付-项目预付核销-结算尾款三类记录;预结算转正式自动预填来源预结算核销行;单据状态名提取公共 settlementStatus 工具与预结算编辑器共用
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 结算单预付记录单据状态名(预结算编辑器与正式结算编辑器共用,避免两页状态名不一致)
|
||||
*/
|
||||
export function settlementStatusName(status, displayValue) {
|
||||
const labels = {
|
||||
reviewing: '审批中',
|
||||
approved: '审批通过',
|
||||
paid: '已付款',
|
||||
returned: '已驳回',
|
||||
voided: '已作废',
|
||||
draft: '草稿',
|
||||
};
|
||||
const name = labels[status];
|
||||
if (name) return name;
|
||||
return typeof displayValue === 'function' ? displayValue(status) : status || '-';
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一预付付款记录类型名
|
||||
*/
|
||||
export function settlementRecordTypeName(recordType) {
|
||||
return { progress_advance: '进度预付', project_advance: '项目预付核销' }[recordType] || '';
|
||||
}
|
||||
@@ -177,6 +177,22 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-descriptions
|
||||
v-if="form.settlementType === 'payable'"
|
||||
:column="3"
|
||||
border
|
||||
class="formal-editor__settle-summary"
|
||||
>
|
||||
<el-descriptions-item label="结算合计(原金额)">
|
||||
{{ formatMoney(form.settlementAmount) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="已付金额(含预付、核销)">
|
||||
{{ formatMoney(settlePaidTotal) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="剩余未付金额">
|
||||
{{ formatMoney(settleRemainTotal) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</section-card>
|
||||
|
||||
<section-card title="结算明细">
|
||||
@@ -577,28 +593,27 @@
|
||||
<template #default="{ row }">{{ displayValue(row.claimStatusName) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table v-else :data="paymentApplications" border>
|
||||
<el-table v-else :data="paymentRecords" border>
|
||||
<el-table-column type="index" label="序号" width="64" align="center" />
|
||||
<el-table-column prop="paymentTypeName" label="付款类型" min-width="120" align="center">
|
||||
<template #default="{ row }">{{ displayValue(row.paymentTypeName) }}</template>
|
||||
<el-table-column label="付款类型" min-width="120" align="center">
|
||||
<template #default="{ row }">{{ displayValue(row.typeName) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="付款方式" min-width="140" align="center">
|
||||
<template #default="{ row }">{{ paymentMethodName(row.paymentMethod) }}</template>
|
||||
<template #default="{ row }">{{ row.recordType ? '-' : paymentMethodName(row.paymentMethod) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="paymentNo" label="单据号" min-width="160" align="center" />
|
||||
<el-table-column prop="appliedAmount" label="申请付款金额" min-width="145" align="center">
|
||||
<el-table-column prop="appliedAmount" label="申请/核销金额" min-width="145" align="center">
|
||||
<template #default="{ row }">{{ formatMoney(row.appliedAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="paidAmount" label="已付款金额" min-width="130" align="center">
|
||||
<template #default="{ row }">{{ formatMoney(row.paidAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="approvalStatusName"
|
||||
label="单据状态"
|
||||
min-width="120"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">{{ displayValue(row.approvalStatusName) }}</template>
|
||||
<el-table-column label="单据状态" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.recordType
|
||||
? settlementStatusName(row.billStatus)
|
||||
: displayValue(row.approvalStatusName) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="kingdeeBillNo" label="金蝶单据号" min-width="150" align="center">
|
||||
<template #default="{ row }">{{ displayValue(row.kingdeeBillNo) }}</template>
|
||||
@@ -1054,6 +1069,10 @@ import { InfoFilled } from '@element-plus/icons-vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { normalizeCurrencyCode } from '@/utils/currency';
|
||||
import {
|
||||
settlementRecordTypeName,
|
||||
settlementStatusName,
|
||||
} from '@/utils/settlementStatus';
|
||||
import { downloadFileByUrl } from '@/utils/util';
|
||||
import {
|
||||
downloadKingdeeInvoiceFile,
|
||||
@@ -1097,6 +1116,7 @@ export default {
|
||||
details: [],
|
||||
summaryFees: [],
|
||||
paymentApplications: [],
|
||||
advancePayments: [],
|
||||
receiptClaims: [],
|
||||
adjustments: [],
|
||||
changeRecords: [],
|
||||
@@ -1270,6 +1290,34 @@ export default {
|
||||
summaryTotal() {
|
||||
return this.summaryFees.reduce((total, row) => total + Number(row.settlementAmount || 0), 0);
|
||||
},
|
||||
// 已付金额(含预付、核销):编辑态取来源预结算预付快照 + 当前核销行实时合计(草稿态无尾款申请);只读态用落库值
|
||||
settlePaidTotal() {
|
||||
if (!this.editable) return Number(this.form.paidAmount || 0);
|
||||
const advancePaid = this.sources.reduce(
|
||||
(sum, item) => sum + Number(item.advancePaidAmount || 0),
|
||||
0
|
||||
);
|
||||
const writeOff = this.projectAdvanceWriteOffs.reduce(
|
||||
(sum, row) => sum + Number(row.writeOffAmount || 0),
|
||||
0
|
||||
);
|
||||
return advancePaid + writeOff;
|
||||
},
|
||||
settleRemainTotal() {
|
||||
return Math.max(Number(this.form.settlementAmount || 0) - Number(this.settlePaidTotal || 0), 0);
|
||||
},
|
||||
// 付款记录合并表:预付付款记录(进度预付/项目预付核销)+ 尾款付款申请
|
||||
paymentRecords() {
|
||||
const advances = (this.advancePayments || []).map(row => ({
|
||||
...row,
|
||||
typeName: settlementRecordTypeName(row.recordType),
|
||||
}));
|
||||
const tails = (this.paymentApplications || []).map(row => ({
|
||||
...row,
|
||||
typeName: row.paymentTypeName,
|
||||
}));
|
||||
return [...advances, ...tails];
|
||||
},
|
||||
filteredDetails() {
|
||||
return this.details.filter(row =>
|
||||
Object.entries(this.appliedDetailQuery).every(([field, keyword]) => {
|
||||
@@ -1365,6 +1413,7 @@ export default {
|
||||
this.detailFeeSnapshots = {};
|
||||
this.pendingAdjustments = {};
|
||||
this.paymentApplications = data.paymentApplications || [];
|
||||
this.advancePayments = data.advancePayments || [];
|
||||
if (this.readonly && this.form.settlementType === 'receivable' && !this.publicMode) {
|
||||
this.receiptClaims = this.unwrapData(await getReceiptClaims(id)) || [];
|
||||
}
|
||||
@@ -1408,6 +1457,7 @@ export default {
|
||||
this.adjustments = [];
|
||||
this.changeRecords = [];
|
||||
this.projectAdvanceWriteOffs = [];
|
||||
this.advancePayments = [];
|
||||
this.attachments = [];
|
||||
this.selectedAttachmentRows = [];
|
||||
this.invoices = [];
|
||||
@@ -1556,6 +1606,19 @@ export default {
|
||||
this.sources.map(item => getPreSettlementDetail(item.preSettlementId))
|
||||
);
|
||||
const settlements = responses.map(response => this.unwrapData(response) || {});
|
||||
// 预结算转正式:带出来源预结算已保存的项目预付核销行(后端保存时转移源行)
|
||||
const writeOffRows = settlements.flatMap(settlement => settlement.projectAdvanceWriteOffs || []);
|
||||
const existingWriteOffIds = new Set(
|
||||
this.projectAdvanceWriteOffs.map(row => String(row.paymentApplicationId))
|
||||
);
|
||||
writeOffRows.forEach(row => {
|
||||
if (existingWriteOffIds.has(String(row.paymentApplicationId))) return;
|
||||
existingWriteOffIds.add(String(row.paymentApplicationId));
|
||||
this.projectAdvanceWriteOffs.push({
|
||||
...row,
|
||||
writeOffAmount: Number(row.writeOffAmount || 0),
|
||||
});
|
||||
});
|
||||
this.details = settlements.flatMap(settlement =>
|
||||
(settlement.details || []).map(detail => ({
|
||||
...detail,
|
||||
@@ -1726,7 +1789,7 @@ export default {
|
||||
this.candidate.page.current = 1;
|
||||
this.loadCandidates();
|
||||
},
|
||||
confirmCandidates() {
|
||||
async confirmCandidates() {
|
||||
const merged = [...this.sources, ...this.candidate.selected];
|
||||
const map = new Map(
|
||||
merged.map(item => [
|
||||
@@ -1734,6 +1797,7 @@ export default {
|
||||
{ ...item, preSettlementId: item.preSettlementId || item.id },
|
||||
])
|
||||
);
|
||||
const previousIds = new Set(this.sources.map(item => String(item.preSettlementId || item.id)));
|
||||
this.sources = [...map.values()];
|
||||
this.form.sourcePreSettlementIds = this.sources.map(item => item.preSettlementId);
|
||||
if (this.sources.length) {
|
||||
@@ -1750,6 +1814,26 @@ export default {
|
||||
this.form.localSettlementAmount =
|
||||
this.form.settlementAmount * Number(this.form.exchangeRate || 1);
|
||||
this.candidate.visible = false;
|
||||
// 预结算转正式:带出来源预结算已保存的项目预付核销行(后端保存时转移源行,额度单份占用)
|
||||
const newIds = this.sources
|
||||
.map(item => item.preSettlementId)
|
||||
.filter(id => !previousIds.has(String(id)));
|
||||
if (!newIds.length) return;
|
||||
const responses = await Promise.all(newIds.map(id => getPreSettlementDetail(id)));
|
||||
const rows = responses.flatMap(response =>
|
||||
this.unwrapData(response)?.projectAdvanceWriteOffs || []
|
||||
);
|
||||
const existing = new Set(
|
||||
this.projectAdvanceWriteOffs.map(row => String(row.paymentApplicationId))
|
||||
);
|
||||
rows.forEach(row => {
|
||||
if (existing.has(String(row.paymentApplicationId))) return;
|
||||
existing.add(String(row.paymentApplicationId));
|
||||
this.projectAdvanceWriteOffs.push({
|
||||
...row,
|
||||
writeOffAmount: Number(row.writeOffAmount || 0),
|
||||
});
|
||||
});
|
||||
},
|
||||
removeSource(index) {
|
||||
this.sources.splice(index, 1);
|
||||
@@ -2736,6 +2820,9 @@ export default {
|
||||
};
|
||||
return this.displayValue(labels[value] || value);
|
||||
},
|
||||
settlementStatusName(status) {
|
||||
return settlementStatusName(status, this.displayValue);
|
||||
},
|
||||
unwrapData(response) {
|
||||
const body = response?.data || response || {};
|
||||
return body?.data || body;
|
||||
@@ -3132,6 +3219,9 @@ export default {
|
||||
.formal-editor__negative-amount {
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
.formal-editor__settle-summary {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.formal-editor :deep(.formal-editor__negative-amount .el-input__inner) {
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
@@ -990,6 +990,7 @@ import {
|
||||
} from '@/option/settlement/preSettlementTable';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { normalizeCurrencyCode } from '@/utils/currency';
|
||||
import { settlementStatusName } from '@/utils/settlementStatus';
|
||||
import { downloadFileByUrl } from '@/utils/util';
|
||||
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
|
||||
import * as XLSX from 'xlsx';
|
||||
@@ -2877,15 +2878,7 @@ export default {
|
||||
return value === undefined || value === null || value === '' ? '-' : value;
|
||||
},
|
||||
advanceStatusName(status) {
|
||||
return (
|
||||
{
|
||||
reviewing: '审批中',
|
||||
approved: '审批通过',
|
||||
paid: '已付款',
|
||||
returned: '已驳回',
|
||||
voided: '已作废',
|
||||
}[status] || this.displayValue(status)
|
||||
);
|
||||
return settlementStatusName(status, this.displayValue);
|
||||
},
|
||||
advanceCreateUserName(row) {
|
||||
return this.displayValue(
|
||||
|
||||
Reference in New Issue
Block a user