调整收付款问题

This commit is contained in:
2026-08-31 19:29:57 +08:00
parent dea760ea1c
commit 449e4e1884
8 changed files with 149 additions and 51 deletions
+6 -2
View File
@@ -5,8 +5,12 @@ const baseUrl = '/blade-transport/invoice-application';
export const getList = (current, size, params) => export const getList = (current, size, params) =>
request({ url: `${baseUrl}/list`, method: 'get', params: { current, size, ...params } }); request({ url: `${baseUrl}/list`, method: 'get', params: { current, size, ...params } });
export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get', params: { id } }); export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get', params: { id } });
export const getSettlementCandidates = keyword => export const getSettlementCandidates = (current, size, params) =>
request({ url: `${baseUrl}/settlement-candidates`, method: 'get', params: { keyword } }); request({
url: `${baseUrl}/settlement-candidates`,
method: 'get',
params: { current, size, ...params },
});
export const getSettlementDetails = settlementIds => export const getSettlementDetails = settlementIds =>
request({ url: `${baseUrl}/settlement-details`, method: 'get', params: { settlementIds } }); request({ url: `${baseUrl}/settlement-details`, method: 'get', params: { settlementIds } });
export const getReceiverInformation = settlementIds => export const getReceiverInformation = settlementIds =>
+6
View File
@@ -32,6 +32,12 @@ export const syncKingdee = id =>
request({ url: `${baseUrl}/sync-kingdee`, method: 'post', params: { id } }); request({ url: `${baseUrl}/sync-kingdee`, method: 'post', params: { id } });
export const getDetailFees = detailId => export const getDetailFees = detailId =>
request({ url: `${baseUrl}/detail-fees`, method: 'get', params: { detailId } }); request({ url: `${baseUrl}/detail-fees`, method: 'get', params: { detailId } });
export const getReceiptClaims = formalSettlementId =>
request({
url: `${baseUrl}/receipt-claims`,
method: 'get',
params: { formalSettlementId },
});
export const adjustDetail = data => export const adjustDetail = data =>
request({ url: `${baseUrl}/adjust-detail`, method: 'post', data }); request({ url: `${baseUrl}/adjust-detail`, method: 'post', data });
export const applyPayment = data => export const applyPayment = data =>
+2 -2
View File
@@ -11,13 +11,13 @@ export const preSettlementTableColumns = [
{ label: '本位币结算金额', prop: 'localSettlementAmount', minWidth: 150, money: true, precision: 2 }, { label: '本位币结算金额', prop: 'localSettlementAmount', minWidth: 150, money: true, precision: 2 },
{ label: '结算汇率', prop: 'exchangeRate', minWidth: 110, precision: 2 }, { label: '结算汇率', prop: 'exchangeRate', minWidth: 110, precision: 2 },
{ {
label: '申请预付金额(审核中的)', label: '申请预付金额',
prop: 'advanceAppliedAmount', prop: 'advanceAppliedAmount',
minWidth: 190, minWidth: 190,
money: true, money: true,
}, },
{ {
label: '已付款金额(审核通过的)', label: '已付款金额',
prop: 'advancePaidAmount', prop: 'advancePaidAmount',
minWidth: 200, minWidth: 200,
money: true, money: true,
+57 -13
View File
@@ -16,7 +16,7 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="6"> <el-col :span="6">
<el-form-item label="结算单" prop="settlementIds"> <el-form-item label="结算单" prop="settlementIds">
<el-input :model-value="settlementLabel" readonly placeholder="请选择应正式结算单"> <el-input :model-value="settlementLabel" readonly placeholder="请选择应正式结算单">
<template v-if="!readonly" #append> <template v-if="!readonly" #append>
<el-button @click="openSettlementDialog">选择</el-button> <el-button @click="openSettlementDialog">选择</el-button>
</template> </template>
@@ -414,7 +414,7 @@
<el-dialog <el-dialog
v-model="settlementDialog.visible" v-model="settlementDialog.visible"
title="选择应正式结算单" title="选择应正式结算单"
width="86%" width="86%"
append-to-body append-to-body
> >
@@ -423,18 +423,19 @@
v-model="settlementDialog.keyword" v-model="settlementDialog.keyword"
clearable clearable
placeholder="结算单号项目或合同" placeholder="结算单号项目或合同"
@keyup.enter="loadSettlementCandidates" @keyup.enter="handleSettlementSearch"
/> />
<el-button type="primary" @click="loadSettlementCandidates">查询</el-button> <el-button type="primary" @click="handleSettlementSearch">查询</el-button>
</div> </div>
<el-table <el-table
ref="settlementTable" ref="settlementTable"
v-loading="settlementDialog.loading" v-loading="settlementDialog.loading"
:data="settlementDialog.rows" :data="settlementDialog.rows"
row-key="id"
border border
@selection-change="settlementDialog.selection = $event" @selection-change="settlementDialog.selection = $event"
> >
<el-table-column type="selection" width="52" align="center" /> <el-table-column type="selection" width="52" align="center" reserve-selection />
<el-table-column prop="formalSettlementNo" label="结算单号" min-width="170" /> <el-table-column prop="formalSettlementNo" label="结算单号" min-width="170" />
<el-table-column prop="projectName" label="所属项目" min-width="150" /> <el-table-column prop="projectName" label="所属项目" min-width="150" />
<el-table-column prop="deptName" label="所属组织" min-width="150" /> <el-table-column prop="deptName" label="所属组织" min-width="150" />
@@ -454,6 +455,17 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div class="invoice-form-page__dialog-pagination">
<el-pagination
v-model:current-page="settlementDialog.page.current"
v-model:page-size="settlementDialog.page.size"
:total="settlementDialog.page.total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
@current-change="loadSettlementCandidates"
@size-change="handleSettlementSizeChange"
/>
</div>
<template #footer> <template #footer>
<el-button @click="settlementDialog.visible = false">取消</el-button> <el-button @click="settlementDialog.visible = false">取消</el-button>
<el-button type="primary" @click="confirmSettlements">确定</el-button> <el-button type="primary" @click="confirmSettlements">确定</el-button>
@@ -539,6 +551,7 @@ export default {
keyword: '', keyword: '',
rows: [], rows: [],
selection: [], selection: [],
page: { current: 1, size: 10, total: 0 },
}, },
rules: { rules: {
settlementIds: [{ validator: this.validateSettlements, trigger: 'change' }], settlementIds: [{ validator: this.validateSettlements, trigger: 'change' }],
@@ -798,23 +811,49 @@ export default {
}, },
async openSettlementDialog() { async openSettlementDialog() {
this.settlementDialog.visible = true; this.settlementDialog.visible = true;
this.settlementDialog.page.current = 1;
this.settlementDialog.selection = [];
this.$nextTick(() => this.$refs.settlementTable?.clearSelection());
await this.loadSettlementCandidates(); await this.loadSettlementCandidates();
}, },
async loadSettlementCandidates() { async loadSettlementCandidates() {
this.settlementDialog.loading = true; this.settlementDialog.loading = true;
try { try {
const data = this.unwrapData( const data = this.unwrapData(
await api.getSettlementCandidates(this.settlementDialog.keyword) await api.getSettlementCandidates(
this.settlementDialog.page.current,
this.settlementDialog.page.size,
{
keyword: this.settlementDialog.keyword,
contractCategory: '客户合同',
settlementType: 'receivable',
invoiceStatus: 'unreceived',
}
)
);
const rows = Array.isArray(data) ? data : data?.records || [];
this.settlementDialog.rows = rows;
this.settlementDialog.page.total = Number(
Array.isArray(data) ? data.length : data?.total || 0
); );
this.settlementDialog.rows = Array.isArray(data) ? data : data?.records || [];
} finally { } finally {
this.settlementDialog.loading = false; this.settlementDialog.loading = false;
} }
}, },
handleSettlementSearch() {
this.settlementDialog.page.current = 1;
this.settlementDialog.selection = [];
this.$refs.settlementTable?.clearSelection();
this.loadSettlementCandidates();
},
handleSettlementSizeChange() {
this.settlementDialog.page.current = 1;
this.loadSettlementCandidates();
},
async confirmSettlements() { async confirmSettlements() {
const rows = this.settlementDialog.selection; const rows = this.settlementDialog.selection;
if (!rows.length) { if (!rows.length) {
this.$message.warning('请至少选择一张应正式结算单'); this.$message.warning('请至少选择一张应正式结算单');
return; return;
} }
await this.applySettlements(rows); await this.applySettlements(rows);
@@ -962,19 +1001,19 @@ export default {
}, },
handleDetailLink(row, column) { handleDetailLink(row, column) {
if (column.prop === 'documentNo') { if (column.prop === 'documentNo') {
this.openPayableDetail(row); this.openReceivableDetail(row);
return; return;
} }
if (column.prop === 'waybillNo') this.openWaybillDetail(row); if (column.prop === 'waybillNo') this.openWaybillDetail(row);
}, },
async openPayableDetail(row) { async openReceivableDetail(row) {
let detailId = row.sourceDetailId || ''; let detailId = row.sourceDetailId || '';
if (!detailId && row.documentNo) { if (!detailId && row.documentNo) {
try { try {
const data = this.unwrapData( const data = this.unwrapData(
await getReceivablePayableDetailList(1, 1, { await getReceivablePayableDetailList(1, 1, {
documentNo: row.documentNo, documentNo: row.documentNo,
settlementType: 'payable', settlementType: 'receivable',
}) })
); );
detailId = (Array.isArray(data) ? data : data?.records || [])[0]?.id || ''; detailId = (Array.isArray(data) ? data : data?.records || [])[0]?.id || '';
@@ -983,11 +1022,11 @@ export default {
} }
} }
if (!detailId) { if (!detailId) {
this.$message.info('当前记录未找到对应的应明细'); this.$message.info('当前记录未找到对应的应明细');
return; return;
} }
this.$router.push({ this.$router.push({
path: '/settlement/payable-detail', path: '/settlement/receivable-detail',
query: { detailId }, query: { detailId },
}); });
}, },
@@ -1186,6 +1225,11 @@ export default {
.invoice-form-page__dialog-search .el-input { .invoice-form-page__dialog-search .el-input {
width: 360px; width: 360px;
} }
.invoice-form-page__dialog-pagination {
display: flex;
justify-content: flex-end;
margin-top: 12px;
}
.invoice-form-page :deep(.el-table) { .invoice-form-page :deep(.el-table) {
--el-table-border-color: #eff1f7; --el-table-border-color: #eff1f7;
} }
+10 -23
View File
@@ -164,9 +164,11 @@
></el-col> ></el-col>
<el-col :span="6" <el-col :span="6"
><el-form-item label="收款账号" prop="receiptAccountId" ><el-form-item label="收款账号" prop="receiptAccountId"
><span v-if="readonly">{{ form.bankAccount || '-' }}</span
><el-select ><el-select
v-else
v-model="form.receiptAccountId" v-model="form.receiptAccountId"
:disabled="readonly || !form.payeeName" :disabled="!form.payeeName"
:loading="receiptAccountLoading" :loading="receiptAccountLoading"
filterable filterable
clearable clearable
@@ -343,7 +345,7 @@
> >
<div class="payment-form-page__attachment-upload"> <div class="payment-form-page__attachment-upload">
<vehicle-attachment-upload <vehicle-attachment-upload
:model-value="form.attachments" v-model="form.attachments"
:readonly="readonly" :readonly="readonly"
:multiple="true" :multiple="true"
:limit="20" :limit="20"
@@ -351,8 +353,7 @@
:file-types="attachmentFileTypes" :file-types="attachmentFileTypes"
:show-file-list="false" :show-file-list="false"
button-text="上传附件" button-text="上传附件"
@update:model-value="normalizeAttachments" @change="normalizeAttachments"
@success="handleManualAttachmentUpload"
/> />
</div> </div>
</section-card> </section-card>
@@ -2045,6 +2046,9 @@ export default {
}, },
normalizeAttachments(files) { normalizeAttachments(files) {
const existingAttachments = this.form.attachments || []; const existingAttachments = this.form.attachments || [];
const userInfo = this.$store.getters.userInfo || {};
const uploadUserName = userInfo.realName || userInfo.userName || '';
const uploadTime = this.$dayjs().format('YYYY-MM-DD HH:mm:ss');
this.form.attachments = (files || []).map(file => { this.form.attachments = (files || []).map(file => {
const fileUrl = this.attachmentFileUrl(file); const fileUrl = this.attachmentFileUrl(file);
const existingFile = existingAttachments.find(item => { const existingFile = existingAttachments.find(item => {
@@ -2058,28 +2062,11 @@ export default {
attachmentType: attachmentType:
existingFile?.attachmentType || this.resolveAttachmentTypeByFileName(file), existingFile?.attachmentType || this.resolveAttachmentTypeByFileName(file),
description: file.description || existingFile?.description || '', description: file.description || existingFile?.description || '',
uploadUserName: existingFile?.uploadUserName || file.uploadUserName || uploadUserName,
uploadTime: existingFile?.uploadTime || file.uploadTime || uploadTime,
}; };
}); });
}, },
handleManualAttachmentUpload(uploadedFile) {
const uploadedUrl = this.attachmentFileUrl(uploadedFile);
const uploadedUid = uploadedFile?.uid;
const userInfo = this.$store.getters.userInfo || {};
const uploadUserName = userInfo.realName || userInfo.userName || '';
const uploadTime = this.$dayjs().format('YYYY-MM-DD HH:mm:ss');
this.form.attachments = (this.form.attachments || []).map(file => {
const isUploadedFile =
(uploadedUid && file.uid === uploadedUid) ||
(uploadedUrl && this.attachmentFileUrl(file) === uploadedUrl);
return isUploadedFile
? {
...file,
uploadUserName,
uploadTime,
}
: file;
});
},
formatAttachmentSize(file = {}) { formatAttachmentSize(file = {}) {
const rawSize = file.size ?? file.fileSize ?? file.attachSize; const rawSize = file.size ?? file.fileSize ?? file.attachSize;
if (rawSize === undefined || rawSize === null || rawSize === '') return '-'; if (rawSize === undefined || rawSize === null || rawSize === '') return '-';
@@ -407,8 +407,51 @@
</el-table> </el-table>
</section-card> </section-card>
<section-card v-if="readonly" title="付款信息"> <section-card
<el-table :data="paymentApplications" border> v-if="readonly"
:title="form.settlementType === 'receivable' ? '收款信息' : '付款信息'"
>
<el-table
v-if="form.settlementType === 'receivable'"
:data="receiptClaims"
border
empty-text="暂无收款认领数据"
>
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column
prop="receiptNoticeNo"
label="认领通知单"
min-width="160"
align="center"
/>
<el-table-column prop="payerName" label="付款人" min-width="150" align="center">
<template #default="{ row }">{{ displayValue(row.payerName) }}</template>
</el-table-column>
<el-table-column prop="receiptAmount" label="收款金额" min-width="130" align="center">
<template #default="{ row }">{{ formatMoney(row.receiptAmount) }}</template>
</el-table-column>
<el-table-column
prop="allocatedReceiptAmount"
label="本次认领金额"
min-width="145"
align="center"
>
<template #default="{ row }">{{ formatMoney(row.allocatedReceiptAmount) }}</template>
</el-table-column>
<el-table-column prop="transactionTime" label="交易时间" min-width="170" align="center">
<template #default="{ row }">{{ displayValue(row.transactionTime) }}</template>
</el-table-column>
<el-table-column prop="claimerName" label="认领人" min-width="120" align="center">
<template #default="{ row }">{{ displayValue(row.claimerName) }}</template>
</el-table-column>
<el-table-column prop="claimDate" label="认领日期" min-width="130" align="center">
<template #default="{ row }">{{ displayValue(row.claimDate) }}</template>
</el-table-column>
<el-table-column prop="claimStatusName" label="认领状态" min-width="120" align="center">
<template #default="{ row }">{{ displayValue(row.claimStatusName) }}</template>
</el-table-column>
</el-table>
<el-table v-else :data="paymentApplications" border>
<el-table-column type="index" label="序号" width="64" align="center" /> <el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column prop="paymentTypeName" label="付款类型" min-width="120" align="center"> <el-table-column prop="paymentTypeName" label="付款类型" min-width="120" align="center">
<template #default="{ row }">{{ displayValue(row.paymentTypeName) }}</template> <template #default="{ row }">{{ displayValue(row.paymentTypeName) }}</template>
@@ -737,6 +780,7 @@ import {
getDetailFees, getDetailFees,
getFeeOptions, getFeeOptions,
getNextNo, getNextNo,
getReceiptClaims,
save, save,
} from '@/api/settlement/formalSettlement'; } from '@/api/settlement/formalSettlement';
import { getDetail as getPreSettlementDetail } from '@/api/settlement/preSettlement'; import { getDetail as getPreSettlementDetail } from '@/api/settlement/preSettlement';
@@ -779,6 +823,7 @@ export default {
details: [], details: [],
summaryFees: [], summaryFees: [],
paymentApplications: [], paymentApplications: [],
receiptClaims: [],
adjustments: [], adjustments: [],
changeRecords: [], changeRecords: [],
attachments: [], attachments: [],
@@ -958,6 +1003,7 @@ export default {
this.details = []; this.details = [];
this.summaryFees = []; this.summaryFees = [];
this.paymentApplications = []; this.paymentApplications = [];
this.receiptClaims = [];
this.adjustments = []; this.adjustments = [];
this.changeRecords = []; this.changeRecords = [];
this.attachments = []; this.attachments = [];
@@ -1002,6 +1048,9 @@ export default {
this.details = data.details || []; this.details = data.details || [];
this.summaryFees = data.summaryFees || []; this.summaryFees = data.summaryFees || [];
this.paymentApplications = data.paymentApplications || []; this.paymentApplications = data.paymentApplications || [];
if (this.readonly && this.form.settlementType === 'receivable') {
this.receiptClaims = this.unwrapData(await getReceiptClaims(this.recordId)) || [];
}
this.adjustments = data.adjustments || []; this.adjustments = data.adjustments || [];
this.changeRecords = data.changeRecords || []; this.changeRecords = data.changeRecords || [];
this.attachments = this.parseAttachments(data.attachmentsJson); this.attachments = this.parseAttachments(data.attachmentsJson);
@@ -1690,11 +1739,8 @@ export default {
.filter(row => row.pendingDetailAdjustment) .filter(row => row.pendingDetailAdjustment)
.map(row => ({ .map(row => ({
sourcePreSettlementDetailId: sourcePreSettlementDetailId:
row.sourcePreSettlementDetailId || row.sourcePreSettlementDetailId || (row.sourcePreSettlementId ? row.id : undefined),
(row.sourcePreSettlementId ? row.id : undefined), sourceDetailId: row.sourcePreSettlementId ? undefined : row.sourceDetailId || row.id,
sourceDetailId: row.sourcePreSettlementId
? undefined
: row.sourceDetailId || row.id,
adjustAmount: Number(row.adjustAmount || 0), adjustAmount: Number(row.adjustAmount || 0),
})), })),
exchangeRateDate: this.form.exchangeRateDate, exchangeRateDate: this.form.exchangeRateDate,
+3
View File
@@ -131,6 +131,9 @@
<span v-else-if="column.precision !== undefined"> <span v-else-if="column.precision !== undefined">
{{ formatNumber(row[column.prop], column.precision) }} {{ formatNumber(row[column.prop], column.precision) }}
</span> </span>
<span v-else-if="column.prop === 'sourceType'">
{{ row[column.prop] === '应收应付' ? '应付' : displayValue(row[column.prop]) }}
</span>
<span v-else>{{ displayValue(row[column.prop]) }}</span> <span v-else>{{ displayValue(row[column.prop]) }}</span>
</template> </template>
</el-table-column> </el-table-column>
@@ -34,7 +34,12 @@
<div class="settlement-detail-page__toolbar-left"> <div class="settlement-detail-page__toolbar-left">
<el-button type="primary" @click="openGenerateDialog">生成费用</el-button> <el-button type="primary" @click="openGenerateDialog">生成费用</el-button>
<el-button type="primary" plain @click="openUpdateFeeDialog">更新费用</el-button> <el-button type="primary" plain @click="openUpdateFeeDialog">更新费用</el-button>
<el-button v-if="isPayable" type="primary" plain @click="openTransferDialog"> <el-button
v-if="isPayable || isReceivable"
type="primary"
plain
@click="openTransferDialog"
>
批量转结算 批量转结算
</el-button> </el-button>
<el-button type="primary" plain @click="handleExport">导出</el-button> <el-button type="primary" plain @click="handleExport">导出</el-button>
@@ -457,6 +462,7 @@
v-model="transferForm.settlementBillType" v-model="transferForm.settlementBillType"
@change="handleTransferTypeChange" @change="handleTransferTypeChange"
> >
<el-radio v-if="isPayable" label="pre">预结算单</el-radio>
<el-radio label="formal">正式结算单</el-radio> <el-radio label="formal">正式结算单</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
@@ -784,7 +790,7 @@ export default {
billingPlanOptions: [], billingPlanOptions: [],
transferDialog: { visible: false, loading: false, submitting: false }, transferDialog: { visible: false, loading: false, submitting: false },
transferQuery: {}, transferQuery: {},
transferForm: { settlementBillType: 'formal' }, transferForm: { settlementBillType: 'pre' },
transferRows: [], transferRows: [],
transferSelection: [], transferSelection: [],
transferPage: { current: 1, size: 10, total: 0 }, transferPage: { current: 1, size: 10, total: 0 },
@@ -1594,7 +1600,7 @@ export default {
}, },
openTransferDialog() { openTransferDialog() {
this.transferDialog.visible = true; this.transferDialog.visible = true;
this.transferForm = { settlementBillType: 'formal' }; this.transferForm = { settlementBillType: this.isReceivable ? 'formal' : 'pre' };
this.transferQuery = {}; this.transferQuery = {};
this.transferRows = []; this.transferRows = [];
this.transferSelection = []; this.transferSelection = [];
@@ -1724,7 +1730,9 @@ export default {
try { try {
const transferRows = await this.resolveTransferContractIds(this.transferSelection); const transferRows = await this.resolveTransferContractIds(this.transferSelection);
if (!transferRows) return; if (!transferRows) return;
const settlementBillType = this.transferForm.settlementBillType; const settlementBillType = this.isReceivable
? 'formal'
: this.transferForm.settlementBillType;
const transferToken = createSettlementTransfer({ const transferToken = createSettlementTransfer({
settlementBillType, settlementBillType,
settlementType: this.settlementType || transferRows[0]?.settlementType, settlementType: this.settlementType || transferRows[0]?.settlementType,