1、调整业务模块
This commit is contained in:
@@ -0,0 +1,447 @@
|
||||
<template>
|
||||
<basic-container class="receipt-claim-batch-form-page">
|
||||
<div class="archive-page-form__title">批量认领收款流水</div>
|
||||
<el-form ref="formRef" :model="form" class="receipt-claim-batch-form-page__form">
|
||||
<section-card title="收款信息">
|
||||
<el-table v-loading="loading" :data="flows" border>
|
||||
<el-table-column type="index" label="序号" width="64" align="center" />
|
||||
<el-table-column
|
||||
prop="receiptNoticeNo"
|
||||
label="认领通知单"
|
||||
min-width="160"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column prop="payerName" label="付款人" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="收款金额" min-width="130" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.receiptAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="transactionTime" label="交易时间" min-width="170" />
|
||||
<el-table-column
|
||||
prop="counterpartyName"
|
||||
label="对方户名"
|
||||
min-width="150"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="counterpartyBank"
|
||||
label="对方开户行"
|
||||
min-width="170"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="counterpartyAccount"
|
||||
label="对方账号"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="detailSerialNo"
|
||||
label="明细流水号"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="已认领金额" min-width="130" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.claimedAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="summary" label="摘要" min-width="180" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<el-row :gutter="32" class="receipt-claim-batch-form-page__claim-info">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="认领人">
|
||||
<el-input v-model="claimerName" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="认领日期">
|
||||
<el-input v-model="claimDate" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="认领人部门">
|
||||
<el-input v-model="claimerDeptName" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</section-card>
|
||||
|
||||
<section-card title="结算信息">
|
||||
<div class="receipt-claim-batch-form-page__settlement-toolbar">
|
||||
<el-button type="primary" @click="openSettlementDialog">选择结算单</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
:data="allocationRows"
|
||||
border
|
||||
show-summary
|
||||
:summary-method="summaryMethod"
|
||||
:span-method="settlementSpanMethod"
|
||||
empty-text="请先选择应收正式结算单"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="64" align="center" />
|
||||
<el-table-column label="结算单号" min-width="180">
|
||||
<template #default="{ row }">{{ row.settlement.formalSettlementNo || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结算总金额" min-width="140" align="right">
|
||||
<template #default="{ row }">{{
|
||||
formatMoney(row.settlement.settlementAmount)
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已认领收款金额" min-width="150" align="right">
|
||||
<template #default="{ row }">{{
|
||||
formatMoney(row.settlement.claimedReceiptAmount)
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="认领通知单" min-width="180">
|
||||
<template #default="{ row }">{{ row.flow.receiptNoticeNo || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="收款金额" min-width="140" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.flow.receiptAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="分摊收款金额" min-width="180" align="right">
|
||||
<template #default="{ row }">
|
||||
<el-input-number
|
||||
v-model="row.settlement.allocations[row.flow.id]"
|
||||
:min="0"
|
||||
:max="maxAllocation(row)"
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
@change="handleAllocationChange(row.settlement)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</section-card>
|
||||
|
||||
<section-card title="附件信息">
|
||||
<vehicle-attachment-table v-model="form.attachments" />
|
||||
</section-card>
|
||||
|
||||
<section-card title="备注">
|
||||
<el-form-item class="receipt-claim-batch-form-page__remark">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</section-card>
|
||||
|
||||
<div class="receipt-claim-batch-form-page__actions">
|
||||
<el-button :disabled="submitting" @click="goBack">取消</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="submitClaim">确认</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<el-dialog
|
||||
v-model="settlementDialog.visible"
|
||||
title="选择应收正式结算单"
|
||||
width="86%"
|
||||
append-to-body
|
||||
>
|
||||
<div class="receipt-claim-batch-form-page__dialog-search">
|
||||
<el-input
|
||||
v-model="settlementDialog.keyword"
|
||||
clearable
|
||||
placeholder="结算单号、项目或合同"
|
||||
@keyup.enter="loadSettlementCandidates"
|
||||
/>
|
||||
<el-button type="primary" @click="loadSettlementCandidates">查询</el-button>
|
||||
</div>
|
||||
<el-table v-loading="settlementDialog.loading" :data="settlementDialog.rows" border>
|
||||
<el-table-column prop="formalSettlementNo" label="结算单号" min-width="170" />
|
||||
<el-table-column prop="projectName" label="所属项目" min-width="150" />
|
||||
<el-table-column prop="deptName" label="所属组织" min-width="150" />
|
||||
<el-table-column prop="payerName" label="付款方" min-width="150" />
|
||||
<el-table-column prop="payeeName" label="收款方" min-width="150" />
|
||||
<el-table-column label="结算总金额" min-width="140" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.settlementAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已认领收款金额" min-width="150" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.claimedReceiptAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click="selectSettlement(row)">选择</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<el-button @click="settlementDialog.visible = false">取消</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as api from '@/api/payment/receiptFlow';
|
||||
import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue';
|
||||
|
||||
const emptyForm = () => ({ attachments: [], remark: '' });
|
||||
|
||||
export default {
|
||||
name: 'ReceiptFlowBatchForm',
|
||||
components: { VehicleAttachmentTable },
|
||||
data() {
|
||||
return {
|
||||
form: emptyForm(),
|
||||
flows: [],
|
||||
settlements: [],
|
||||
loading: false,
|
||||
submitting: false,
|
||||
claimerName: '',
|
||||
claimerDeptName: '',
|
||||
claimDate: '',
|
||||
settlementDialog: { visible: false, loading: false, keyword: '', rows: [], selection: [] },
|
||||
};
|
||||
},
|
||||
created() {
|
||||
const userInfo = this.$store.getters.userInfo || {};
|
||||
this.claimerName = userInfo.realName || userInfo.userName || '';
|
||||
this.claimerDeptName = userInfo.deptName || userInfo.dept_name || '';
|
||||
this.claimDate = this.$dayjs().format('YYYY-MM-DD');
|
||||
this.initialize();
|
||||
},
|
||||
computed: {
|
||||
allocationRows() {
|
||||
return this.settlements.flatMap(settlement => this.flows.map(flow => ({ settlement, flow })));
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
unwrapData(response) {
|
||||
const body = response?.data || response || {};
|
||||
return body?.data || body;
|
||||
},
|
||||
async initialize() {
|
||||
const ids = [
|
||||
...new Set(
|
||||
String(this.$route.query.ids || '')
|
||||
.split(',')
|
||||
.filter(Boolean)
|
||||
),
|
||||
];
|
||||
if (!ids.length) {
|
||||
this.$message.error('缺少批量认领流水');
|
||||
this.goBack();
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const details = await Promise.all(ids.map(id => api.getDetail(id)));
|
||||
this.flows = details.map(item => this.unwrapData(item)).filter(Boolean);
|
||||
if (!this.flows.length) throw new Error('没有可认领的收款流水');
|
||||
const first = this.flows[0];
|
||||
const sameParty = this.flows.every(
|
||||
row =>
|
||||
String(row.payerName || '').trim() === String(first.payerName || '').trim() &&
|
||||
String(row.counterpartyAccount || '').trim() ===
|
||||
String(first.counterpartyAccount || '').trim()
|
||||
);
|
||||
if (!sameParty) throw new Error('批量认领所选流水的付款人、对方账号必须一致');
|
||||
} catch (error) {
|
||||
this.$message.error(error?.message || '批量认领流水加载失败');
|
||||
this.goBack();
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async openSettlementDialog() {
|
||||
this.settlementDialog.visible = true;
|
||||
await this.loadSettlementCandidates();
|
||||
},
|
||||
async loadSettlementCandidates() {
|
||||
if (!this.flows.length) return;
|
||||
this.settlementDialog.loading = true;
|
||||
try {
|
||||
this.settlementDialog.rows =
|
||||
this.unwrapData(
|
||||
await api.getSettlementCandidates(this.settlementDialog.keyword, this.flows[0].id)
|
||||
) || [];
|
||||
} finally {
|
||||
this.settlementDialog.loading = false;
|
||||
}
|
||||
},
|
||||
selectSettlement(row) {
|
||||
this.settlementDialog.selection = [row];
|
||||
this.confirmSettlements();
|
||||
},
|
||||
confirmSettlements() {
|
||||
const rows = this.settlementDialog.selection;
|
||||
if (!rows.length) {
|
||||
this.$message.warning('请至少选择一张应收正式结算单');
|
||||
return;
|
||||
}
|
||||
const item = rows[0];
|
||||
this.settlements = [
|
||||
{
|
||||
...item,
|
||||
allocations: this.flows.reduce((result, flow) => {
|
||||
result[flow.id] = 0;
|
||||
return result;
|
||||
}, {}),
|
||||
},
|
||||
];
|
||||
this.settlementDialog.visible = false;
|
||||
},
|
||||
settlementRemaining(row) {
|
||||
return Math.max(Number(row.settlementAmount || 0) - Number(row.claimedReceiptAmount || 0), 0);
|
||||
},
|
||||
settlementAllocatedTotal(row) {
|
||||
return this.flows.reduce((total, flow) => total + Number(row.allocations?.[flow.id] || 0), 0);
|
||||
},
|
||||
flowAllocatedTotal(flowId) {
|
||||
return this.settlements.reduce(
|
||||
(total, row) => total + Number(row.allocations?.[flowId] || 0),
|
||||
0
|
||||
);
|
||||
},
|
||||
maxAllocation(row) {
|
||||
const current = Number(row.settlement.allocations?.[row.flow.id] || 0);
|
||||
const otherTotal = this.settlementAllocatedTotal(row.settlement) - current;
|
||||
return Math.max(this.settlementRemaining(row.settlement) - otherTotal, 0);
|
||||
},
|
||||
handleAllocationChange(settlement) {
|
||||
const total = this.settlementAllocatedTotal(settlement);
|
||||
if (total > this.settlementRemaining(settlement) + 0.001) {
|
||||
this.$message.warning(`结算单${settlement.formalSettlementNo}的分摊金额不能超过可认领金额`);
|
||||
}
|
||||
},
|
||||
summaryMethod({ columns }) {
|
||||
return columns.map((column, index) => {
|
||||
if (index === 0) return '合计';
|
||||
if (index === 6) return this.formatMoney(this.allocatedTotal());
|
||||
return '';
|
||||
});
|
||||
},
|
||||
settlementSpanMethod({ rowIndex, columnIndex }) {
|
||||
if (![1, 2, 3].includes(columnIndex)) return [1, 1];
|
||||
if (!this.flows.length) return [1, 1];
|
||||
if (rowIndex % this.flows.length === 0) return [this.flows.length, 1];
|
||||
return [0, 0];
|
||||
},
|
||||
allocatedTotal() {
|
||||
return this.settlements.reduce((total, row) => total + this.settlementAllocatedTotal(row), 0);
|
||||
},
|
||||
async submitClaim() {
|
||||
if (!this.settlements.length) {
|
||||
this.$message.warning('请至少选择一张应收正式结算单');
|
||||
return;
|
||||
}
|
||||
for (const row of this.settlements) {
|
||||
if (this.settlementAllocatedTotal(row) > this.settlementRemaining(row) + 0.001) {
|
||||
this.$message.warning(`结算单${row.formalSettlementNo}的累计认领金额不能超过结算总金额`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (const flow of this.flows) {
|
||||
const total = this.flowAllocatedTotal(flow.id);
|
||||
const remaining = Math.max(
|
||||
Number(flow.receiptAmount || 0) - Number(flow.claimedAmount || 0),
|
||||
0
|
||||
);
|
||||
if (total > remaining + 0.001) {
|
||||
this.$message.warning(`流水${flow.receiptNoticeNo}的分摊金额不能超过剩余可认领金额`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const requests = this.flows
|
||||
.map(flow => ({
|
||||
flow,
|
||||
settlements: this.settlements
|
||||
.map(row => ({
|
||||
settlementId: row.id,
|
||||
allocatedReceiptAmount: Number(row.allocations?.[flow.id] || 0),
|
||||
}))
|
||||
.filter(row => row.allocatedReceiptAmount > 0),
|
||||
}))
|
||||
.filter(item => item.settlements.length);
|
||||
if (!requests.length) {
|
||||
this.$message.warning('没有需要入库的分摊收款金额');
|
||||
return;
|
||||
}
|
||||
this.submitting = true;
|
||||
try {
|
||||
for (const item of requests) {
|
||||
await api.claim({
|
||||
flowId: item.flow.id,
|
||||
attachmentsJson: JSON.stringify(this.form.attachments || []),
|
||||
remark: this.form.remark,
|
||||
settlements: item.settlements,
|
||||
});
|
||||
}
|
||||
this.$message.success(`批量认领成功,共${requests.length}条流水`);
|
||||
this.goBack();
|
||||
} finally {
|
||||
this.submitting = false;
|
||||
}
|
||||
},
|
||||
goBack() {
|
||||
this.$router.push('/payment/receipt-flow');
|
||||
},
|
||||
formatMoney(value) {
|
||||
return Number(value || 0).toFixed(2);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.receipt-claim-batch-form-page__form {
|
||||
padding-bottom: 72px;
|
||||
}
|
||||
.receipt-claim-batch-form-page__claim-info {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.receipt-claim-batch-form-page__form :deep(.el-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
.receipt-claim-batch-form-page__settlement-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
color: #606266;
|
||||
}
|
||||
.receipt-claim-batch-form-page__notice-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px 8px;
|
||||
}
|
||||
.receipt-claim-batch-form-page__actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
padding: 12px 24px;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
left: 230px;
|
||||
bottom: 0;
|
||||
z-index: 10;
|
||||
background: #fff;
|
||||
border-top: 1px solid #eff1f7;
|
||||
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.receipt-claim-batch-form-page__remark :deep(.el-form-item__content) {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
.receipt-claim-batch-form-page__dialog-search {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.receipt-claim-batch-form-page__dialog-search .el-input {
|
||||
width: 360px;
|
||||
}
|
||||
.receipt-claim-batch-form-page :deep(.el-table) {
|
||||
--el-table-border-color: #eff1f7;
|
||||
}
|
||||
.receipt-claim-batch-form-page :deep(.el-table__row:nth-child(even) > td.el-table__cell) {
|
||||
background: #fafafa;
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.receipt-claim-batch-form-page__actions {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user