From 65967226019d64b9998f5d49d2be90bd674cff16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com>
Date: Sun, 18 Oct 2026 14:32:15 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=AD=A3=E5=BC=8F=E7=BB=93=E7=AE=97?=
=?UTF-8?q?=E5=8D=95=E6=96=B0=E5=A2=9E=E9=A2=84=E4=BB=98=E6=B1=87=E6=80=BB?=
=?UTF-8?q?=E6=A0=8F=E4=B8=8E=E4=BB=98=E6=AC=BE=E8=AE=B0=E5=BD=95=E5=90=88?=
=?UTF-8?q?=E5=B9=B6=E5=B1=95=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
结算合计下新增汇总栏(结算合计原金额-已付金额含预付核销-剩余未付);只读付款信息合并展示进度预付-项目预付核销-结算尾款三类记录;预结算转正式自动预填来源预结算核销行;单据状态名提取公共 settlementStatus 工具与预结算编辑器共用
---
src/utils/settlementStatus.js | 23 ++++
.../components/formal-settlement-editor.vue | 116 ++++++++++++++++--
.../components/pre-settlement-editor.vue | 11 +-
3 files changed, 128 insertions(+), 22 deletions(-)
create mode 100644 src/utils/settlementStatus.js
diff --git a/src/utils/settlementStatus.js b/src/utils/settlementStatus.js
new file mode 100644
index 0000000..4fdf2ec
--- /dev/null
+++ b/src/utils/settlementStatus.js
@@ -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] || '';
+}
diff --git a/src/views/settlement/components/formal-settlement-editor.vue b/src/views/settlement/components/formal-settlement-editor.vue
index 3807f0c..acb8277 100644
--- a/src/views/settlement/components/formal-settlement-editor.vue
+++ b/src/views/settlement/components/formal-settlement-editor.vue
@@ -177,6 +177,22 @@
+
+
+ {{ formatMoney(form.settlementAmount) }}
+
+
+ {{ formatMoney(settlePaidTotal) }}
+
+
+ {{ formatMoney(settleRemainTotal) }}
+
+
@@ -577,28 +593,27 @@
{{ displayValue(row.claimStatusName) }}
-
+
-
- {{ displayValue(row.paymentTypeName) }}
+
+ {{ displayValue(row.typeName) }}
- {{ paymentMethodName(row.paymentMethod) }}
+ {{ row.recordType ? '-' : paymentMethodName(row.paymentMethod) }}
-
+
{{ formatMoney(row.appliedAmount) }}
{{ formatMoney(row.paidAmount) }}
-
- {{ displayValue(row.approvalStatusName) }}
+
+
+ {{ row.recordType
+ ? settlementStatusName(row.billStatus)
+ : displayValue(row.approvalStatusName) }}
+
{{ displayValue(row.kingdeeBillNo) }}
@@ -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);
}
diff --git a/src/views/settlement/components/pre-settlement-editor.vue b/src/views/settlement/components/pre-settlement-editor.vue
index 5d5ad8e..22f4832 100644
--- a/src/views/settlement/components/pre-settlement-editor.vue
+++ b/src/views/settlement/components/pre-settlement-editor.vue
@@ -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(