This commit is contained in:
2026-08-25 00:10:45 +08:00
parent e1bade226f
commit 1ef050dda6
35 changed files with 2041 additions and 263 deletions
@@ -709,18 +709,33 @@ export default {
if (!rows.length) return;
const first = rows[0];
const settlementType = this.initialData.settlementType || first.settlementType || 'payable';
const contractId = first.contractId || null;
const matchedContract = this.allContracts.find(
item =>
(first.contractId && String(item.id) === String(first.contractId)) ||
(first.contractNo && String(item.contractNo) === String(first.contractNo))
);
const contractId = first.contractId || matchedContract?.id || null;
const projectId = first.projectId || matchedContract?.projectId || null;
const projectName = first.projectName || matchedContract?.projectName || '';
this.contracts = this.allContracts.filter(
item => projectId && String(item.projectId) === String(projectId)
);
if (projectId && !this.projects.some(item => String(item.id) === String(projectId))) {
this.projects.push({ id: projectId, name: projectName });
}
if (!this.contracts.some(item => String(item.id) === String(contractId))) {
this.contracts.push({
id: contractId,
contractNo: first.contractNo,
contractName: first.contractName,
projectId: first.projectId,
projectName: first.projectName,
deptId: first.deptId,
deptName: first.deptName,
projectId,
projectName,
deptId: first.deptId || matchedContract?.deptId,
deptName: first.deptName || matchedContract?.deptName,
payerName: first.payerName,
payeeName: first.payeeName,
partyA: matchedContract?.partyA,
partyB: matchedContract?.partyB,
settlementType,
});
}
@@ -729,8 +744,8 @@ export default {
contractId,
contractNo: first.contractNo || this.form.contractNo,
contractName: first.contractName || this.form.contractName,
projectId: first.projectId || this.form.projectId,
projectName: first.projectName || this.form.projectName,
projectId: projectId || this.form.projectId,
projectName: projectName || this.form.projectName,
deptId: first.deptId || this.form.deptId,
deptName: first.deptName || this.form.deptName,
payerName: first.payerName || this.form.payerName,
@@ -1035,10 +1050,7 @@ export default {
return columns.map((column, index) => {
if (index === 0) return '合计';
if (!sumProps.includes(column.property)) return '';
const total = data.reduce(
(sum, row) => sum + Number(row[column.property] || 0),
0
);
const total = data.reduce((sum, row) => sum + Number(row[column.property] || 0), 0);
return this.formatMoney(total);
});
},
@@ -1010,6 +1010,15 @@ export default {
this.$message.warning('请至少选择一条结算明细');
return;
}
const invalidManualFeeIndex = this.summaryFees.findIndex(
row =>
Number(row.manualFlag) === 1 &&
(!String(row.feeType || '').trim() || !String(row.feeItem || '').trim())
);
if (invalidManualFeeIndex >= 0) {
this.$message.warning(`请完善结算合计第${invalidManualFeeIndex + 1}行的费用类型和费用项`);
return;
}
const stateKey = shouldSubmit ? 'submitting' : 'saving';
this[stateKey] = true;
try {
@@ -1040,7 +1049,7 @@ export default {
sourceDetailIds: this.details.map(row => row.sourceDetailId || row.id),
summaryFees: this.summaryFees.map(row => ({
id: row.id || undefined,
feeType: row.feeType,
feeType: row.feeType || '',
feeItem: row.feeItem,
adjustAmount: Number(row.adjustAmount || 0),
remark: row.remark,
@@ -1067,7 +1076,7 @@ export default {
return this.feeOptions.find(item => item.feeType === feeType)?.feeItems || [];
},
feeCategoryName(value) {
if (value === undefined || value === null || value === '') return '-';
if (value === undefined || value === null || value === '') return '';
const option = this.feeCategoryOptions.find(
item => String(item.dictKey) === String(value) || String(item.dictValue) === String(value)
);
@@ -318,7 +318,7 @@
<el-form-item label="转结算类型">
<el-radio-group
v-model="transferForm.settlementBillType"
@change="loadTransferCandidates"
@change="handleTransferTypeChange"
>
<el-radio label="pre">预结算单</el-radio>
<el-radio label="formal">正式结算单</el-radio>
@@ -343,18 +343,26 @@
<el-input v-else v-model="transferQuery[field.prop]" clearable placeholder="请输入" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadTransferCandidates">查询</el-button>
<el-button type="primary" @click="handleTransferSearch">查询</el-button>
</el-form-item>
</el-form>
</div>
<el-table
ref="transferTableRef"
v-loading="transferDialog.loading"
:data="transferRows"
row-key="id"
border
@selection-change="transferSelectionChange"
>
<el-table-column type="selection" width="52" align="center" />
<el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column type="selection" width="52" align="center" reserve-selection />
<el-table-column
type="index"
label="序号"
width="70"
align="center"
:index="transferIndexMethod"
/>
<el-table-column
v-for="column in tableColumns.slice(0, 13)"
:key="column.prop"
@@ -367,6 +375,17 @@
<template #default="{ row }">{{ formatColumnValue(row, column) }}</template>
</el-table-column>
</el-table>
<div class="settlement-detail-page__pagination">
<el-pagination
v-model:current-page="transferPage.current"
v-model:page-size="transferPage.size"
:total="transferPage.total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next, jumper"
@current-change="loadTransferCandidates"
@size-change="handleTransferSizeChange"
/>
</div>
<template #footer>
<el-button @click="transferDialog.visible = false">取消</el-button>
<el-button type="primary" :loading="transferDialog.submitting" @click="submitTransfer">
@@ -593,6 +612,7 @@ export default {
transferForm: { settlementBillType: 'formal' },
transferRows: [],
transferSelection: [],
transferPage: { current: 1, size: 10, total: 0 },
generateDialog: { visible: false, loading: false },
generateQuery: {},
generateRows: [],
@@ -1029,11 +1049,12 @@ export default {
this.transferQuery = {};
this.transferRows = [];
this.transferSelection = [];
this.transferPage = { current: 1, size: 10, total: 0 };
this.$nextTick(() => this.$refs.transferTableRef?.clearSelection());
this.loadTransferCandidates();
},
async loadTransferCandidates() {
this.transferDialog.loading = true;
this.transferSelection = [];
try {
const params = this.buildRequestParams(
this.normalizeQuery(
@@ -1043,20 +1064,46 @@ export default {
'generateEndDate'
)
);
const res = await api.getTransferCandidates(1, 50, {
...params,
settlementStatus: 'pending',
settlementType: this.settlementType || undefined,
settlementBillType: this.transferForm.settlementBillType,
});
const res = await api.getTransferCandidates(
this.transferPage.current,
this.transferPage.size,
{
...params,
settlementStatus: 'pending',
settlementType: this.settlementType || undefined,
settlementBillType: this.transferForm.settlementBillType,
}
);
const data = this.unwrapPage(res);
this.transferRows = (data.records || [])
.filter(row => this.isTransferCandidate(row))
.map(this.decorateRow);
this.transferPage.total = data.total || 0;
} finally {
this.transferDialog.loading = false;
}
},
resetTransferSelection() {
this.transferSelection = [];
this.$nextTick(() => this.$refs.transferTableRef?.clearSelection());
},
handleTransferSearch() {
this.transferPage.current = 1;
this.resetTransferSelection();
this.loadTransferCandidates();
},
handleTransferTypeChange() {
this.transferPage.current = 1;
this.resetTransferSelection();
this.loadTransferCandidates();
},
handleTransferSizeChange() {
this.transferPage.current = 1;
this.loadTransferCandidates();
},
transferIndexMethod(index) {
return (this.transferPage.current - 1) * this.transferPage.size + index + 1;
},
isTransferCandidate(row) {
const hasValue = value => {
if (Array.isArray(value)) return value.length > 0;
@@ -1151,16 +1198,38 @@ export default {
}
},
async resolveTransferContractIds(rows) {
if (rows.every(item => item.contractId)) return rows;
if (rows.every(item => item.contractId && item.projectId)) return rows;
const contractId = rows.find(item => item.contractId)?.contractId;
const contractNo = rows.find(item => item.contractNo)?.contractNo;
const { data } = await getSettlementContractOptions(contractNo);
const contracts = data?.data || [];
const contract = contracts.find(item => String(item.contractNo) === String(contractNo));
if (!contract?.id) {
this.$message.warning('未找到所选明细对应的有效合同,无法转结算');
const contract = contracts.find(
item =>
(contractId && String(item.id) === String(contractId)) ||
(contractNo && String(item.contractNo) === String(contractNo))
);
if (!contract?.id || !contract.projectId) {
this.$message.warning('未找到所选明细对应的合同或项目信息,无法转结算');
return null;
}
return rows.map(item => ({ ...item, contractId: item.contractId || contract.id }));
return rows.map(item => {
const settlementType =
item.settlementType || this.settlementType || contract.settlementType;
return {
...item,
contractId: item.contractId || contract.id,
contractNo: item.contractNo || contract.contractNo,
contractName: item.contractName || contract.contractName,
projectId: item.projectId || contract.projectId,
projectName: item.projectName || contract.projectName,
deptId: item.deptId || contract.deptId,
deptName: item.deptName || contract.deptName,
payerName:
item.payerName || (settlementType === 'receivable' ? contract.partyB : contract.partyA),
payeeName:
item.payeeName || (settlementType === 'receivable' ? contract.partyA : contract.partyB),
};
});
},
openGenerateDialog() {
this.generateDialog.visible = true;