完善收付款管理
This commit is contained in:
@@ -83,66 +83,6 @@
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="开户行">
|
||||
<el-input v-model="form.bankName" disabled placeholder="从金蝶票据池带出" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="开户账号">
|
||||
<el-input v-model="form.bankAccount" disabled placeholder="从金蝶票据池带出" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="开票行">
|
||||
<el-input v-model="form.issuingBank" disabled placeholder="从金蝶票据池带出" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="电话">
|
||||
<el-input v-model="form.phone" :disabled="readonly" maxlength="50" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="客户邮箱" prop="customerEmails">
|
||||
<el-select
|
||||
v-model="form.customerEmails"
|
||||
:disabled="readonly"
|
||||
multiple
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
:multiple-limit="3"
|
||||
>
|
||||
<el-option
|
||||
v-for="email in customerEmailOptions"
|
||||
:key="email"
|
||||
:label="email"
|
||||
:value="email"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="部门邮箱" prop="departmentEmails">
|
||||
<el-select
|
||||
v-model="form.departmentEmails"
|
||||
:disabled="readonly"
|
||||
multiple
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
:multiple-limit="3"
|
||||
>
|
||||
<el-option
|
||||
v-for="email in departmentEmailOptions"
|
||||
:key="email"
|
||||
:label="email"
|
||||
:value="email"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</section-card>
|
||||
|
||||
@@ -178,52 +118,7 @@
|
||||
</section-card>
|
||||
|
||||
<section-card title="附件信息">
|
||||
<template #extra>
|
||||
<el-button
|
||||
v-if="form.attachments.length"
|
||||
type="primary"
|
||||
plain
|
||||
:icon="Download"
|
||||
@click="downloadAttachments"
|
||||
>批量下载</el-button
|
||||
>
|
||||
</template>
|
||||
<el-table :data="form.attachments" border>
|
||||
<el-table-column type="index" label="序号" width="64" align="center" />
|
||||
<el-table-column label="文件名" min-width="220">
|
||||
<template #default="{ row }">{{ row.originalName || row.name || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="附件描述" min-width="240">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.description" :disabled="readonly" maxlength="200" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="size" label="文件大小" width="120" />
|
||||
<el-table-column prop="uploadUserName" label="上传人" width="140" />
|
||||
<el-table-column prop="uploadTime" label="上传时间" width="170" />
|
||||
<el-table-column label="操作" width="120" align="center">
|
||||
<template #default="{ row, $index }">
|
||||
<div class="receipt-form-page__links">
|
||||
<el-link type="primary" :href="row.url || row.link" target="_blank">查看</el-link>
|
||||
<el-link v-if="!readonly" type="danger" @click="form.attachments.splice($index, 1)"
|
||||
>删除</el-link
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<vehicle-attachment-upload
|
||||
v-model="form.attachments"
|
||||
:readonly="readonly"
|
||||
:multiple="true"
|
||||
:limit="20"
|
||||
:max-size="500"
|
||||
:file-types="attachmentFileTypes"
|
||||
:show-file-list="false"
|
||||
button-text="上传附件"
|
||||
class="receipt-form-page__uploader"
|
||||
@change="normalizeAttachments"
|
||||
/>
|
||||
<vehicle-attachment-table v-model="form.attachments" :readonly="readonly" />
|
||||
</section-card>
|
||||
|
||||
<section-card title="备注">
|
||||
@@ -289,6 +184,11 @@
|
||||
<template #default="{ row }">{{ formatMoney(row.taxAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="kingdeeBillNo" label="金蝶单据号" min-width="150" />
|
||||
<el-table-column label="操作" width="100" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click.stop="confirmInvoice(row)">选择</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<el-button @click="invoiceDialog.visible = false">取消</el-button>
|
||||
@@ -331,6 +231,11 @@
|
||||
<el-table-column label="已收票金额" min-width="140" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.receivedInvoiceAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click.stop="selectSettlement(row)">选择</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<el-button @click="settlementDialog.visible = false">取消</el-button>
|
||||
@@ -341,9 +246,70 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Download, Search } from '@element-plus/icons-vue';
|
||||
import { Search } from '@element-plus/icons-vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import * as api from '@/api/payment/invoiceReceipt';
|
||||
import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue';
|
||||
|
||||
const invoicePoolMockRows = [
|
||||
{
|
||||
id: 90000001,
|
||||
invoiceNo: '25312000000000000101',
|
||||
invoiceDate: '2026-08-25',
|
||||
invoiceType: '增值税专用发票',
|
||||
taxRate: 9,
|
||||
invoiceAmount: 109000,
|
||||
taxAmount: 9000,
|
||||
receiverName: '华东供应链管理有限公司',
|
||||
issuerName: '上海安捷运输有限公司',
|
||||
bankName: '中国工商银行上海分行',
|
||||
bankAccount: '1001000100000000019',
|
||||
issuingBank: '中国工商银行上海分行营业部',
|
||||
phone: '021-66880001',
|
||||
customerEmails: 'finance@huadong.example.com',
|
||||
departmentEmails: 'transport@huadong.example.com',
|
||||
attachmentsJson: '[]',
|
||||
kingdeeBillNo: 'KD-FP-20260825001',
|
||||
},
|
||||
{
|
||||
id: 90000002,
|
||||
invoiceNo: '25312000000000000102',
|
||||
invoiceDate: '2026-08-26',
|
||||
invoiceType: '增值税普通发票',
|
||||
taxRate: 6,
|
||||
invoiceAmount: 53000,
|
||||
taxAmount: 3000,
|
||||
receiverName: '华东供应链管理有限公司',
|
||||
issuerName: '江苏联运物流有限公司',
|
||||
bankName: '中国建设银行南京分行',
|
||||
bankAccount: '3201000100000000026',
|
||||
issuingBank: '中国建设银行南京城南支行',
|
||||
phone: '025-66880002',
|
||||
customerEmails: 'finance@huadong.example.com',
|
||||
departmentEmails: 'logistics@huadong.example.com',
|
||||
attachmentsJson: '[]',
|
||||
kingdeeBillNo: 'KD-FP-20260826002',
|
||||
},
|
||||
{
|
||||
id: 90000003,
|
||||
invoiceNo: '25312000000000000103',
|
||||
invoiceDate: '2026-08-27',
|
||||
invoiceType: '增值税专用发票',
|
||||
taxRate: 3,
|
||||
invoiceAmount: 20600,
|
||||
taxAmount: 600,
|
||||
receiverName: '华东供应链管理有限公司',
|
||||
issuerName: '浙江通达物流有限公司',
|
||||
bankName: '招商银行杭州分行',
|
||||
bankAccount: '5719000100000000033',
|
||||
issuingBank: '招商银行杭州高新支行',
|
||||
phone: '0571-66880003',
|
||||
customerEmails: 'finance@huadong.example.com',
|
||||
departmentEmails: 'settlement@huadong.example.com',
|
||||
attachmentsJson: '[]',
|
||||
kingdeeBillNo: 'KD-FP-20260827003',
|
||||
},
|
||||
];
|
||||
|
||||
const emptyForm = () => ({
|
||||
id: null,
|
||||
@@ -359,6 +325,8 @@ const emptyForm = () => ({
|
||||
bankName: '',
|
||||
bankAccount: '',
|
||||
issuingBank: '',
|
||||
kingdeeBillNo: '',
|
||||
kingdeeStatus: 'unsynced',
|
||||
phone: '',
|
||||
customerEmails: [],
|
||||
departmentEmails: [],
|
||||
@@ -373,29 +341,15 @@ const emptyForm = () => ({
|
||||
|
||||
export default {
|
||||
name: 'InvoiceReceiptForm',
|
||||
components: {
|
||||
VehicleAttachmentTable,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
Download,
|
||||
Search,
|
||||
form: emptyForm(),
|
||||
customerEmailOptions: [],
|
||||
departmentEmailOptions: [],
|
||||
attachmentFileTypes: [
|
||||
'pdf',
|
||||
'bmp',
|
||||
'jpeg',
|
||||
'png',
|
||||
'jpg',
|
||||
'doc',
|
||||
'docx',
|
||||
'ppt',
|
||||
'pptx',
|
||||
'xlsx',
|
||||
'xls',
|
||||
'eml',
|
||||
'msg',
|
||||
'zip',
|
||||
],
|
||||
invoiceDialog: { visible: false, loading: false, keyword: '', rows: [], current: null },
|
||||
settlementDialog: {
|
||||
visible: false,
|
||||
@@ -433,12 +387,6 @@ export default {
|
||||
settlementIds() {
|
||||
return this.form.settlements.map(item => item.formalSettlementId || item.settlementId);
|
||||
},
|
||||
allocatedTotal() {
|
||||
return this.form.settlements.reduce(
|
||||
(total, item) => total + Number(item.allocatedInvoiceAmount || 0),
|
||||
0
|
||||
);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.initialize();
|
||||
@@ -523,25 +471,37 @@ export default {
|
||||
async loadInvoicePool() {
|
||||
this.invoiceDialog.loading = true;
|
||||
try {
|
||||
this.invoiceDialog.rows =
|
||||
this.unwrapData(await api.getInvoicePool(this.invoiceDialog.keyword)) || [];
|
||||
if (!this.recordId) {
|
||||
this.invoiceDialog.rows = this.filterInvoicePoolMockRows(this.invoiceDialog.keyword);
|
||||
return;
|
||||
}
|
||||
const data = this.unwrapData(await api.getInvoicePool(this.invoiceDialog.keyword));
|
||||
this.invoiceDialog.rows = Array.isArray(data) ? data : data?.records || [];
|
||||
} finally {
|
||||
this.invoiceDialog.loading = false;
|
||||
}
|
||||
},
|
||||
filterInvoicePoolMockRows(keyword) {
|
||||
const normalizedKeyword = String(keyword || '')
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (!normalizedKeyword) return invoicePoolMockRows.map(item => ({ ...item }));
|
||||
return invoicePoolMockRows
|
||||
.filter(item =>
|
||||
[item.invoiceNo, item.issuerName, item.receiverName].some(value =>
|
||||
String(value || '')
|
||||
.toLowerCase()
|
||||
.includes(normalizedKeyword)
|
||||
)
|
||||
)
|
||||
.map(item => ({ ...item }));
|
||||
},
|
||||
confirmInvoice(row, options = {}) {
|
||||
const selected = row?.id ? row : this.invoiceDialog.current;
|
||||
if (!selected) {
|
||||
this.$message.warning('请选择一张金蝶票据池发票');
|
||||
return;
|
||||
}
|
||||
if (this.form.settlements.length) {
|
||||
const first = this.form.settlements[0];
|
||||
if (selected.receiverName !== first.payerName || selected.issuerName !== first.payeeName) {
|
||||
this.$message.warning('金蝶发票的开票单位、受票单位与结算单收付款方不一致');
|
||||
return;
|
||||
}
|
||||
}
|
||||
const preserveUserInput = options.preserveUserInput === true;
|
||||
Object.assign(this.form, {
|
||||
kingdeeInvoicePoolId: selected.id,
|
||||
@@ -556,6 +516,8 @@ export default {
|
||||
bankName: selected.bankName,
|
||||
bankAccount: selected.bankAccount,
|
||||
issuingBank: selected.issuingBank,
|
||||
kingdeeBillNo: selected.kingdeeBillNo || '',
|
||||
kingdeeStatus: selected.kingdeeStatus || 'unsynced',
|
||||
phone: preserveUserInput ? this.form.phone : selected.phone || '',
|
||||
customerEmails: preserveUserInput
|
||||
? this.form.customerEmails
|
||||
@@ -608,13 +570,6 @@ export default {
|
||||
this.$message.warning('关联结算单必须属于同一项目、组织及收付款方');
|
||||
return;
|
||||
}
|
||||
if (
|
||||
this.form.kingdeeInvoicePoolId &&
|
||||
(this.form.receiverName !== first.payerName || this.form.issuerName !== first.payeeName)
|
||||
) {
|
||||
this.$message.warning('金蝶发票的开票单位、受票单位与结算单收付款方不一致');
|
||||
return;
|
||||
}
|
||||
this.form.settlements = rows.map(item => ({
|
||||
...item,
|
||||
formalSettlementId: item.id,
|
||||
@@ -629,6 +584,10 @@ export default {
|
||||
await this.loadReferenceInformation();
|
||||
this.$refs.formRef?.validateField('settlementIds').catch(() => {});
|
||||
},
|
||||
async selectSettlement(row) {
|
||||
this.settlementDialog.selection = [row];
|
||||
await this.confirmSettlements();
|
||||
},
|
||||
async loadReferenceInformation() {
|
||||
const data = this.unwrapData(await api.getReferenceInformation(this.settlementIds.join(',')));
|
||||
this.customerEmailOptions = data.customerEmails || [];
|
||||
@@ -645,28 +604,6 @@ export default {
|
||||
0
|
||||
);
|
||||
},
|
||||
normalizeAttachments(files) {
|
||||
const userInfo = this.$store.getters.userInfo || {};
|
||||
const userName = userInfo.realName || userInfo.userName || '';
|
||||
const time = this.$dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
this.form.attachments = (files || []).map(file => ({
|
||||
...file,
|
||||
description: file.description || '',
|
||||
uploadUserName: file.uploadUserName || userName,
|
||||
uploadTime: file.uploadTime || time,
|
||||
}));
|
||||
},
|
||||
downloadAttachments() {
|
||||
this.form.attachments.forEach(file => {
|
||||
const url = file.url || file.link;
|
||||
if (!url) return;
|
||||
const anchor = document.createElement('a');
|
||||
anchor.href = url;
|
||||
anchor.download = file.originalName || file.name || '';
|
||||
anchor.target = '_blank';
|
||||
anchor.click();
|
||||
});
|
||||
},
|
||||
openSettlementDetail(row) {
|
||||
const id = row.formalSettlementId || row.settlementId || row.id;
|
||||
if (!id) return;
|
||||
@@ -678,9 +615,6 @@ export default {
|
||||
validateBusiness() {
|
||||
const invoiceAmount = Number(this.form.invoiceAmount || 0);
|
||||
if (invoiceAmount <= 0) throw new Error('开票金额必须大于0');
|
||||
if (Math.abs(this.allocatedTotal - invoiceAmount) > 0.001) {
|
||||
throw new Error('分摊发票金额总和必须等于开票金额');
|
||||
}
|
||||
for (const row of this.form.settlements) {
|
||||
const allocated = Number(row.allocatedInvoiceAmount);
|
||||
if (!Number.isFinite(allocated) || allocated < 0) {
|
||||
@@ -695,6 +629,19 @@ export default {
|
||||
return {
|
||||
id: this.form.id,
|
||||
kingdeeInvoicePoolId: this.form.kingdeeInvoicePoolId,
|
||||
invoiceNo: this.form.invoiceNo,
|
||||
invoiceDate: this.form.invoiceDate,
|
||||
invoiceType: this.form.invoiceType,
|
||||
taxRate: this.form.taxRate,
|
||||
invoiceAmount: this.form.invoiceAmount,
|
||||
taxAmount: this.form.taxAmount,
|
||||
receiverName: this.form.receiverName,
|
||||
issuerName: this.form.issuerName,
|
||||
bankName: this.form.bankName,
|
||||
bankAccount: this.form.bankAccount,
|
||||
issuingBank: this.form.issuingBank,
|
||||
kingdeeBillNo: this.form.kingdeeBillNo,
|
||||
kingdeeStatus: this.form.kingdeeStatus,
|
||||
phone: this.form.phone,
|
||||
customerEmails: this.form.customerEmails.join(';'),
|
||||
departmentEmails: this.form.departmentEmails.join(';'),
|
||||
@@ -731,7 +678,10 @@ export default {
|
||||
this.$message.warning('请先选择金蝶票据池发票');
|
||||
return;
|
||||
}
|
||||
const rows = this.unwrapData(await api.getInvoicePool(this.form.invoiceNo)) || [];
|
||||
const data = this.recordId
|
||||
? this.unwrapData(await api.getInvoicePool(this.form.invoiceNo))
|
||||
: this.filterInvoicePoolMockRows(this.form.invoiceNo);
|
||||
const rows = Array.isArray(data) ? data : data?.records || [];
|
||||
const invoice = rows.find(item => item.invoiceNo === this.form.invoiceNo);
|
||||
if (!invoice) {
|
||||
this.$message.warning('金蝶票据池中未查询到该发票');
|
||||
@@ -762,18 +712,9 @@ export default {
|
||||
.receipt-form-page__form :deep(.el-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
.receipt-form-page__links {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.receipt-form-page__remark :deep(.el-form-item__content) {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
.receipt-form-page__uploader {
|
||||
margin-top: 12px;
|
||||
}
|
||||
.receipt-form-page__actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
Reference in New Issue
Block a user