调整业务模块

This commit is contained in:
2026-09-05 23:26:37 +08:00
parent 3bac9b6472
commit 6a6d10dc79
6 changed files with 437 additions and 138 deletions
@@ -337,11 +337,15 @@
clearable
maxlength="32"
placeholder="请输入发票号码"
@keyup.enter="claimInvoices"
@keyup.enter="openInvoiceClaimDialog"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="invoiceClaimLoading" @click="claimInvoices">
<el-button
type="primary"
:loading="invoiceClaimLoading"
@click="openInvoiceClaimDialog"
>
认领查询
</el-button>
</el-form-item>
@@ -407,6 +411,67 @@
</el-table>
</section-card>
<el-dialog
v-model="invoiceClaimDialog.visible"
title="查询可认领发票"
width="92%"
append-to-body
destroy-on-close
>
<el-table
ref="invoiceClaimTable"
v-loading="invoiceClaimDialog.loading"
:data="invoiceClaimPagedRows"
row-key="invoiceNo"
border
height="520"
@selection-change="invoiceClaimDialog.selected = $event"
>
<el-table-column
type="selection"
width="52"
fixed="left"
align="center"
reserve-selection
/>
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column prop="invoiceNo" label="发票号" min-width="180" align="center" />
<el-table-column prop="invoiceDate" label="开票日期" min-width="130" align="center" />
<el-table-column prop="invoiceType" label="发票类型" min-width="150" align="center" />
<el-table-column prop="issuerName" label="开票单位" min-width="180" align="center" />
<el-table-column prop="receiverName" label="受票单位" min-width="180" align="center" />
<el-table-column
prop="invoiceAmount"
label="发票金额(含税)"
min-width="160"
align="right"
>
<template #default="{ row }">{{ formatMoney(row.invoiceAmount) }}</template>
</el-table-column>
<el-table-column prop="matchedAmount" label="认领金额" min-width="140" align="right">
<template #default="{ row }">{{ formatMoney(row.matchedAmount) }}</template>
</el-table-column>
</el-table>
<div class="formal-editor__pagination">
<el-pagination
v-model:current-page="invoiceClaimDialog.page.current"
v-model:page-size="invoiceClaimDialog.page.size"
:total="invoiceClaimDialog.page.total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
/>
</div>
<template #footer>
<el-button @click="invoiceClaimDialog.visible = false">取消</el-button>
<el-button
type="primary"
:loading="invoiceClaimDialog.confirming"
@click="confirmInvoiceClaims"
>确认认领</el-button
>
</template>
</el-dialog>
<section-card
v-if="readonly"
:title="form.settlementType === 'receivable' ? '收款信息' : '付款信息'"
@@ -523,7 +588,7 @@
<template #default="{ row }">{{ displayValue(row.changeType) }}</template>
</el-table-column>
<el-table-column prop="lineNo" label="行号" min-width="90" align="center">
<template #default="{ row }">{{ displayValue(row.lineNo) }}</template>
<template #default="{ row }">{{ changeRecordLineNo(row) }}</template>
</el-table-column>
<el-table-column prop="operationType" label="类型" min-width="110" align="center">
<template #default="{ row }">{{ displayValue(row.operationType) }}</template>
@@ -843,6 +908,7 @@ import {
getFeeOptions,
getNextNo,
getReceiptClaims,
claimInvoices as claimInvoicesApi,
save,
} from '@/api/settlement/formalSettlement';
import {
@@ -898,6 +964,14 @@ export default {
invoices: [],
invoiceClaimNo: '',
invoiceClaimLoading: false,
invoiceClaimDialog: {
visible: false,
loading: false,
confirming: false,
rows: [],
selected: [],
page: { current: 1, size: 10, total: 0 },
},
attachmentUploadFiles: [],
attachmentTypeOptions: [],
attachmentFileTypes: [
@@ -1034,6 +1108,11 @@ export default {
});
return Array.from(names);
},
invoiceClaimPagedRows() {
const { current, size } = this.invoiceClaimDialog.page;
const start = (current - 1) * size;
return this.invoiceClaimDialog.rows.slice(start, start + size);
},
},
watch: {
modelValue: {
@@ -1103,6 +1182,9 @@ export default {
this.selectedAttachmentRows = [];
this.invoices = [];
this.invoiceClaimNo = '';
this.invoiceClaimDialog.visible = false;
this.invoiceClaimDialog.rows = [];
this.invoiceClaimDialog.selected = [];
this.attachmentUploadFiles = [];
this.billingRuleDialog = {
visible: false,
@@ -1864,6 +1946,78 @@ export default {
this.invoiceClaimLoading = false;
}
},
openInvoiceClaimDialog() {
const stamp = Date.now();
this.invoiceClaimDialog.loading = true;
this.invoiceClaimDialog.rows = Array.from({ length: 80 }, (_, index) => {
const amount = Math.floor(1000 + Math.random() * 49000);
return {
invoiceNo: `MOCK${stamp}${String(index + 1).padStart(3, '0')}`.slice(0, 32),
invoiceDate: this.$dayjs()
.subtract(Math.floor(Math.random() * 90), 'day')
.format('YYYY-MM-DD'),
invoiceType: index % 2 ? '增值税普通发票' : '增值税专用发票',
issuerName: this.form.payerName || 'Mock开票单位',
receiverName: this.form.payeeName || 'Mock受票单位',
invoiceAmount: amount,
availableInvoiceAmount: amount,
matchedAmount: amount,
taxRate: [3, 6, 9, 13][index % 4],
attachmentJson: '',
mockData: true,
};
});
this.invoiceClaimDialog.selected = [];
this.invoiceClaimDialog.page.current = 1;
this.invoiceClaimDialog.page.total = 80;
this.invoiceClaimDialog.visible = true;
this.invoiceClaimDialog.loading = false;
},
async confirmInvoiceClaims() {
if (!this.invoiceClaimDialog.selected.length) {
this.$message.warning('请至少选择一条发票');
return;
}
this.invoiceClaimDialog.confirming = true;
try {
const existingNumbers = new Set(this.invoices.map(item => String(item.invoiceNo)));
let remaining = Math.max(
Number(this.form.settlementAmount || 0) -
this.invoices.reduce((total, item) => total + Number(item.matchedAmount || 0), 0),
0
);
const invoices = this.invoiceClaimDialog.selected
.filter(row => !existingNumbers.has(String(row.invoiceNo)))
.map(row => {
const sourceAmount = Number(row.matchedAmount || 0);
const matchedAmount =
Number(this.form.settlementAmount || 0) > 0
? Math.min(sourceAmount, remaining)
: sourceAmount;
if (Number(this.form.settlementAmount || 0) > 0) {
remaining = Math.max(0, remaining - matchedAmount);
}
return { ...row, matchedAmount };
})
.filter(row => row.matchedAmount > 0);
if (!invoices.length) {
this.$message.warning('当前正式结算单没有可认领的剩余金额');
return;
}
if (!this.form.id) {
this.invoices = [...this.invoices, ...invoices];
this.invoiceClaimDialog.visible = false;
this.$message.success(`已选择${invoices.length}条发票,保存正式结算单后生效`);
return;
}
await claimInvoicesApi({ formalSettlementId: this.form.id, invoices });
await this.loadFormalDetail(this.form.id);
this.invoiceClaimDialog.visible = false;
this.$message.success('发票认领成功,已同步正式结算单及关联付款单据');
} finally {
this.invoiceClaimDialog.confirming = false;
}
},
validateInvoices() {
const invoiceNumbers = new Set();
let matchedTotal = 0;
@@ -2000,7 +2154,8 @@ export default {
return this.$message.warning('请完善手工费用的费用类型和费用项');
}
if (!this.validateInvoices()) return;
if (!this.validateAttachments()) return;
// 附件类型仅做提示,不阻断正式结算单新增/保存提交。
this.validateAttachments();
this.saving = true;
try {
await save(this.buildSavePayload());
@@ -2014,6 +2169,10 @@ export default {
displayValue(value) {
return value === null || value === undefined || value === '' ? '-' : value;
},
changeRecordLineNo(row) {
const lineNo = row?.lineNo;
return lineNo === -1 || String(lineNo) === '-1' ? '' : this.displayValue(lineNo);
},
paymentMethodName(value) {
const labels = {
bank_transfer: '银行转账',