✨ 金蝶票池选票统一查镜像前端接线(新增统一选票弹窗组件,替换收票与结算认领弹窗并删除Mock)
This commit is contained in:
@@ -149,62 +149,15 @@
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<el-dialog v-model="invoiceDialog.visible" title="查询金蝶票据池" width="86%" append-to-body>
|
||||
<div class="receipt-form-page__dialog-search">
|
||||
<el-input
|
||||
v-model="invoiceDialog.keyword"
|
||||
clearable
|
||||
placeholder="发票号码、开票单位或受票单位"
|
||||
@keyup.enter="loadInvoicePool"
|
||||
/>
|
||||
<el-button type="primary" @click="loadInvoicePool">查询</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
v-loading="invoiceDialog.loading"
|
||||
:data="invoiceDialog.rows"
|
||||
border
|
||||
empty-text="暂无票据数据"
|
||||
highlight-current-row
|
||||
@current-change="invoiceDialog.current = $event"
|
||||
@row-dblclick="confirmInvoice"
|
||||
>
|
||||
<el-table-column prop="invoiceNo" label="发票号码" min-width="180" />
|
||||
<el-table-column prop="invoiceDate" label="开票日期" min-width="120" />
|
||||
<el-table-column prop="invoiceType" label="发票类型" min-width="130" />
|
||||
<el-table-column prop="issuerName" label="开票单位" min-width="170" />
|
||||
<el-table-column prop="receiverName" label="受票单位" min-width="170" />
|
||||
<el-table-column label="开票金额" min-width="130" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.invoiceAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="税率" min-width="100" align="center">
|
||||
<template #default="{ row }">{{ formatRate(row.taxRate) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="税额" min-width="120" align="right">
|
||||
<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>
|
||||
<div class="receipt-form-page__dialog-pagination">
|
||||
<el-pagination
|
||||
v-model:current-page="invoiceDialog.page.current"
|
||||
v-model:page-size="invoiceDialog.page.size"
|
||||
:total="invoiceDialog.page.total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@current-change="refreshInvoicePoolPage"
|
||||
@size-change="handleInvoicePoolSizeChange"
|
||||
/>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="invoiceDialog.visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmInvoice()">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<kingdee-invoice-pool-dialog
|
||||
v-model="invoiceDialog.visible"
|
||||
title="查询金蝶票据池"
|
||||
:initial-invoice-no="form.invoiceNo"
|
||||
:query-api="apiQueryInvoicePool"
|
||||
:fetch-api="apiFetchInvoicePool"
|
||||
:sync-api="apiSyncInvoicePool"
|
||||
@confirm="handleInvoicePicked"
|
||||
/>
|
||||
|
||||
<el-dialog
|
||||
v-model="settlementDialog.visible"
|
||||
@@ -259,77 +212,9 @@
|
||||
import { Search } from '@element-plus/icons-vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import * as api from '@/api/payment/invoiceReceipt';
|
||||
import { getList as getCustomerList } from '@/api/vehicle/customer-archive';
|
||||
import KingdeeInvoicePoolDialog from '@/components/kingdee-invoice-pool-dialog/main.vue';
|
||||
import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue';
|
||||
|
||||
const mockInvoiceTypes = ['增值税专用发票', '增值税普通发票'];
|
||||
const mockTaxRates = [3, 6, 9, 13];
|
||||
const mockBankNames = ['中国工商银行', '中国农业银行', '中国银行', '中国建设银行', '招商银行'];
|
||||
|
||||
const randomDigits = length =>
|
||||
Array.from({ length }, () => Math.floor(Math.random() * 10)).join('');
|
||||
|
||||
const formatMockDate = date => {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
};
|
||||
|
||||
const customerName = customer =>
|
||||
customer.fullName || customer.shortName || customer.customerCode || `客商${customer.id}`;
|
||||
|
||||
const customerEmail = (customer, index) => {
|
||||
const prefix = String(customer.customerCode || customer.id || `customer${index + 1}`)
|
||||
.replace(/[^a-zA-Z0-9_-]/g, '')
|
||||
.toLowerCase();
|
||||
return `finance@${prefix || `customer${index + 1}`}.example.com`;
|
||||
};
|
||||
|
||||
const createInvoicePoolMockRows = (customers, counterpartyName, departmentEmail) => {
|
||||
const rows = [];
|
||||
const baseId = Date.now();
|
||||
customers.forEach((customer, customerIndex) => {
|
||||
const name = customerName(customer);
|
||||
['issuer', 'receiver'].forEach((role, roleIndex) => {
|
||||
const count = 3 + Math.floor(Math.random() * 5);
|
||||
for (let index = 0; index < count; index += 1) {
|
||||
const rowIndex = rows.length;
|
||||
const invoiceDateValue = new Date();
|
||||
invoiceDateValue.setDate(invoiceDateValue.getDate() - Math.floor(Math.random() * 90));
|
||||
const invoiceDate = formatMockDate(invoiceDateValue);
|
||||
const taxRate = mockTaxRates[(customerIndex + roleIndex + index) % mockTaxRates.length];
|
||||
const invoiceAmount = Math.floor(10000 + Math.random() * 190000);
|
||||
const taxAmount = Number(
|
||||
((invoiceAmount * Number(taxRate)) / (100 + Number(taxRate))).toFixed(2)
|
||||
);
|
||||
const bankName = mockBankNames[(customerIndex + index) % mockBankNames.length];
|
||||
rows.push({
|
||||
id: baseId + rowIndex,
|
||||
invoiceNo: `25${randomDigits(18)}`,
|
||||
invoiceDate,
|
||||
invoiceType: mockInvoiceTypes[(customerIndex + index) % mockInvoiceTypes.length],
|
||||
taxRate,
|
||||
invoiceAmount,
|
||||
taxAmount,
|
||||
receiverName: role === 'receiver' ? name : counterpartyName,
|
||||
issuerName: role === 'issuer' ? name : counterpartyName,
|
||||
bankName,
|
||||
bankAccount: randomDigits(19),
|
||||
issuingBank: `${bankName}营业部`,
|
||||
phone: customer.contactPhone || '',
|
||||
customerEmails: customerEmail(customer, customerIndex),
|
||||
departmentEmails: departmentEmail || '',
|
||||
attachmentsJson: '[]',
|
||||
kingdeeBillNo: `KD-FP-${invoiceDate.replaceAll('-', '')}${randomDigits(5)}`,
|
||||
kingdeeStatus: 'unsynced',
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return rows;
|
||||
};
|
||||
|
||||
const emptyForm = () => ({
|
||||
id: null,
|
||||
kingdeeInvoicePoolId: null,
|
||||
@@ -361,24 +246,17 @@ const emptyForm = () => ({
|
||||
export default {
|
||||
name: 'InvoiceReceiptForm',
|
||||
components: {
|
||||
KingdeeInvoicePoolDialog,
|
||||
VehicleAttachmentTable,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
Search,
|
||||
form: emptyForm(),
|
||||
invoicePoolMockRows: [],
|
||||
invoicePoolMockLoaded: false,
|
||||
customerEmailOptions: [],
|
||||
departmentEmailOptions: [],
|
||||
invoiceDialog: {
|
||||
visible: false,
|
||||
loading: false,
|
||||
keyword: '',
|
||||
sourceRows: [],
|
||||
rows: [],
|
||||
current: null,
|
||||
page: { current: 1, size: 10, total: 0 },
|
||||
},
|
||||
settlementDialog: {
|
||||
visible: false,
|
||||
@@ -421,6 +299,18 @@ export default {
|
||||
this.initialize();
|
||||
},
|
||||
methods: {
|
||||
apiQueryInvoicePool(params) {
|
||||
return api.queryInvoicePool(params);
|
||||
},
|
||||
apiFetchInvoicePool(invoiceNo) {
|
||||
return api.fetchInvoicePoolByNo(invoiceNo);
|
||||
},
|
||||
apiSyncInvoicePool() {
|
||||
return api.syncInvoicePool();
|
||||
},
|
||||
handleInvoicePicked(rows) {
|
||||
this.confirmInvoice(rows[0]);
|
||||
},
|
||||
hasPermission(code) {
|
||||
return this.permission?.[code] !== false;
|
||||
},
|
||||
@@ -492,92 +382,11 @@ export default {
|
||||
}
|
||||
callback();
|
||||
},
|
||||
async openInvoiceDialog() {
|
||||
openInvoiceDialog() {
|
||||
this.invoiceDialog.visible = true;
|
||||
this.invoiceDialog.keyword = this.form.invoiceNo || '';
|
||||
await this.loadInvoicePool();
|
||||
},
|
||||
async loadInvoicePool() {
|
||||
this.invoiceDialog.loading = true;
|
||||
this.invoiceDialog.page.current = 1;
|
||||
this.invoiceDialog.current = null;
|
||||
try {
|
||||
if (!this.recordId) {
|
||||
if (!this.invoicePoolMockLoaded) await this.loadInvoicePoolMockRows();
|
||||
this.invoiceDialog.sourceRows = this.filterInvoicePoolMockRows(
|
||||
this.invoiceDialog.keyword
|
||||
);
|
||||
this.refreshInvoicePoolPage();
|
||||
return;
|
||||
}
|
||||
const data = this.unwrapData(await api.getInvoicePool(this.invoiceDialog.keyword));
|
||||
this.invoiceDialog.sourceRows = Array.isArray(data) ? data : data?.records || [];
|
||||
this.refreshInvoicePoolPage();
|
||||
} finally {
|
||||
this.invoiceDialog.loading = false;
|
||||
}
|
||||
},
|
||||
async loadInvoicePoolMockRows() {
|
||||
const pageSize = 500;
|
||||
const firstData = this.unwrapData(await getCustomerList(1, pageSize, {}));
|
||||
const firstRows = Array.isArray(firstData) ? firstData : firstData?.records || [];
|
||||
const total = Number(firstData?.total || firstRows.length);
|
||||
const pageCount = Math.ceil(total / pageSize);
|
||||
const remainingPages = await Promise.all(
|
||||
Array.from({ length: Math.max(pageCount - 1, 0) }, (_, index) =>
|
||||
getCustomerList(index + 2, pageSize, {})
|
||||
)
|
||||
);
|
||||
const customers = [
|
||||
...firstRows,
|
||||
...remainingPages.flatMap(response => {
|
||||
const data = this.unwrapData(response);
|
||||
return Array.isArray(data) ? data : data?.records || [];
|
||||
}),
|
||||
].filter(
|
||||
(customer, index, rows) =>
|
||||
rows.findIndex(item => String(item.id) === String(customer.id)) === index
|
||||
);
|
||||
const userInfo = this.$store.getters.userInfo || {};
|
||||
const counterpartyName = userInfo.deptName || userInfo.dept_name || '本企业';
|
||||
this.invoicePoolMockRows = createInvoicePoolMockRows(
|
||||
customers,
|
||||
counterpartyName,
|
||||
userInfo.email || ''
|
||||
);
|
||||
this.invoicePoolMockLoaded = true;
|
||||
},
|
||||
refreshInvoicePoolPage() {
|
||||
const page = this.invoiceDialog.page;
|
||||
const total = this.invoiceDialog.sourceRows.length;
|
||||
const maxPage = Math.max(Math.ceil(total / page.size), 1);
|
||||
if (page.current > maxPage) page.current = maxPage;
|
||||
const start = (page.current - 1) * page.size;
|
||||
page.total = total;
|
||||
this.invoiceDialog.current = null;
|
||||
this.invoiceDialog.rows = this.invoiceDialog.sourceRows.slice(start, start + page.size);
|
||||
},
|
||||
handleInvoicePoolSizeChange() {
|
||||
this.invoiceDialog.page.current = 1;
|
||||
this.refreshInvoicePoolPage();
|
||||
},
|
||||
filterInvoicePoolMockRows(keyword) {
|
||||
const normalizedKeyword = String(keyword || '')
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (!normalizedKeyword) return this.invoicePoolMockRows.map(item => ({ ...item }));
|
||||
return this.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;
|
||||
const selected = row;
|
||||
if (!selected) {
|
||||
this.$message.warning('请选择一张金蝶票据池发票');
|
||||
return;
|
||||
@@ -758,16 +567,8 @@ export default {
|
||||
this.$message.warning('请先选择金蝶票据池发票');
|
||||
return;
|
||||
}
|
||||
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('金蝶票据池中未查询到该发票');
|
||||
return;
|
||||
}
|
||||
if (!this.confirmInvoice(invoice, { preserveUserInput: true })) return;
|
||||
const invoice = this.unwrapData(await api.fetchInvoicePoolByNo(this.form.invoiceNo));
|
||||
if (!invoice || !this.confirmInvoice(invoice, { preserveUserInput: true })) return;
|
||||
if (this.settlementIds.length) await this.loadReferenceInformation();
|
||||
this.$message.success('同步成功');
|
||||
},
|
||||
@@ -827,11 +628,6 @@ export default {
|
||||
.receipt-form-page__dialog-search .el-input {
|
||||
width: 360px;
|
||||
}
|
||||
.receipt-form-page__dialog-pagination {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.receipt-form-page :deep(.el-table) {
|
||||
--el-table-border-color: #eff1f7;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user