From 6a6d10dc7939dfd3148c01b92568891a8b29aa71 Mon Sep 17 00:00:00 2001 From: b2894lxlx <517289602@qq.com> Date: Sat, 5 Sep 2026 23:26:37 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=B8=9A=E5=8A=A1=E6=A8=A1?= =?UTF-8?q?=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/settlement/formalSettlement.js | 2 + .../components/waybill-import-dialog.vue | 12 +- .../components/waybill-manage-page.vue | 28 +- .../components/formal-settlement-editor.vue | 167 +++++++- .../components/pre-settlement-editor.vue | 362 ++++++++++++------ src/views/settlement/formal-settlement.vue | 4 +- 6 files changed, 437 insertions(+), 138 deletions(-) diff --git a/src/api/settlement/formalSettlement.js b/src/api/settlement/formalSettlement.js index 78aa78b..9c7992a 100644 --- a/src/api/settlement/formalSettlement.js +++ b/src/api/settlement/formalSettlement.js @@ -44,3 +44,5 @@ export const applyPayment = data => request({ url: `${baseUrl}/apply-payment`, method: 'post', data }); export const applyPayments = data => request({ url: `${baseUrl}/apply-payments`, method: 'post', data }); +export const claimInvoices = data => + request({ url: `${baseUrl}/claim-invoices`, method: 'post', data }); diff --git a/src/views/business/components/waybill-import-dialog.vue b/src/views/business/components/waybill-import-dialog.vue index c85786b..e2034a5 100644 --- a/src/views/business/components/waybill-import-dialog.vue +++ b/src/views/business/components/waybill-import-dialog.vue @@ -571,17 +571,17 @@ const buildCarrierContractOptions = contractRows => { item => String(item.contractCategory || '').trim() === '承运商合同' ); const nameCounts = validContracts.reduce((result, item) => { - const name = String(item.partyB || '').trim(); + const name = String(item.partyA || item.partyAName || '').trim(); if (name) result[name] = (result[name] || 0) + 1; return result; }, {}); return validContracts .map(contract => { - const carrierName = String(contract.partyB || '').trim(); + const carrierName = String(contract.partyA || contract.partyAName || '').trim(); if (!contract.id || !carrierName) return null; const identifier = contract.contractName || contract.contractNo || contract.id; return { - id: contract.partyBId || contract.customerId || '', + id: contract.partyAId || contract.partyAUserId || contract.customerId || '', carrierContractId: contract.id, carrierName, label: nameCounts[carrierName] > 1 ? `${carrierName}(${identifier})` : carrierName, @@ -607,7 +607,11 @@ const syncCarrierOptions = () => { carrierOptions.value = []; return; } - const carrierId = customerContract?.partyBId || customerContract?.customerId || ''; + const carrierId = + customerContract?.partyBId || + customerContract?.partyBUserId || + customerContract?.customerId || + ''; carrierOptions.value = [{ id: carrierId, carrierName, label: carrierName, value: carrierName }]; form.carrierId = carrierId; form.carrierIds = carrierId ? [carrierId] : []; diff --git a/src/views/business/components/waybill-manage-page.vue b/src/views/business/components/waybill-manage-page.vue index b04dcae..71faec1 100644 --- a/src/views/business/components/waybill-manage-page.vue +++ b/src/views/business/components/waybill-manage-page.vue @@ -5413,8 +5413,8 @@ export default { } }, fillSelfOperatedCarrierFromContract(contract = {}) { - if (this.form.carrierType !== '自运' || this.waybillHasCarrierContracts === true) return; - const carrierName = String(contract.partyB || '').trim(); + if (this.form.carrierType !== '自运') return; + const carrierName = String(contract.partyB || contract.partyBName || '').trim(); if (!carrierName) return; const exists = this.taskCarrierOptions.some( item => String(item.value || item.carrierName || '') === carrierName @@ -5462,17 +5462,18 @@ export default { }, getWaybillCarrierContractOptions(contracts = []) { const carrierNameCounts = contracts.reduce((counts, contract) => { - const carrierName = String(contract.partyB || '').trim(); + const carrierName = String(contract.partyA || contract.partyAName || '').trim(); if (carrierName) counts[carrierName] = (counts[carrierName] || 0) + 1; return counts; }, {}); return contracts .map(contract => { - const carrierName = String(contract.partyB || '').trim(); + const carrierName = String(contract.partyA || contract.partyAName || '').trim(); if (!carrierName || !contract.id) return null; const contractIdentifier = contract.contractName || contract.contractNo || contract.id; return { id: contract.id, + carrierId: contract.partyAId || contract.partyAUserId || contract.customerId || '', value: contract.id, label: carrierNameCounts[carrierName] > 1 @@ -5581,28 +5582,15 @@ export default { return Promise.all([contractPromise, detailPromise]) .then(([carrierContractOptions, options]) => { if (requestId !== this.taskCarrierRequestId) return this.taskCarrierOptions; - if (carrierTypeAtRequest === '自运' && carrierContractOptions?.length) { - const selfCarrierOptions = carrierContractOptions.map(item => ({ - ...item, - value: item.carrierName, - })); - this.taskCarrierOptions = selfCarrierOptions; - const hasCurrentCarrier = selfCarrierOptions.some( - item => String(item.value || '') === String(this.form.carrierName || '') - ); - if (!hasCurrentCarrier) { - this.form.carrierName = selfCarrierOptions[0].carrierName; - this.form.carrierId = ''; - } - return selfCarrierOptions; - } - this.taskCarrierOptions = options || []; if (carrierTypeAtRequest === '自运') { + this.taskCarrierOptions = []; const customerContract = this.contractOptions.find( item => String(item.id) === String(this.form.contractId) ); this.fillSelfOperatedCarrierFromContract(customerContract); + return this.taskCarrierOptions; } + this.taskCarrierOptions = options || []; return this.taskCarrierOptions; }) .finally(() => { diff --git a/src/views/settlement/components/formal-settlement-editor.vue b/src/views/settlement/components/formal-settlement-editor.vue index 21e8427..dd3e17c 100644 --- a/src/views/settlement/components/formal-settlement-editor.vue +++ b/src/views/settlement/components/formal-settlement-editor.vue @@ -337,11 +337,15 @@ clearable maxlength="32" placeholder="请输入发票号码" - @keyup.enter="claimInvoices" + @keyup.enter="openInvoiceClaimDialog" /> - + 认领查询 @@ -407,6 +411,67 @@ + + + + + + + + + + + + + + + + +
+ +
+ +
+ {{ displayValue(row.changeType) }} - + @@ -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: '银行转账', diff --git a/src/views/settlement/components/pre-settlement-editor.vue b/src/views/settlement/components/pre-settlement-editor.vue index 8d1b40a..d624e8a 100644 --- a/src/views/settlement/components/pre-settlement-editor.vue +++ b/src/views/settlement/components/pre-settlement-editor.vue @@ -82,12 +82,7 @@ 添加费用 - + {{ formatDetailMileage(row[column.prop]) }} - + {{ transportTypeName(row[column.prop]) }} {{ displayValue(row[column.prop]) }} @@ -374,6 +369,12 @@ {{ advanceStatusName(row.billStatus) }} + + {{ advanceCreateUserName(row) }} + + + {{ advanceCreateTime(row) }} + {{ displayValue(row[column.prop]) }} @@ -381,7 +382,7 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + +