1、调整配载、总单
2、新增收付款模块
This commit is contained in:
@@ -0,0 +1,537 @@
|
||||
<template>
|
||||
<basic-container class="receipt-claim-form-page">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-position="right"
|
||||
label-width="auto"
|
||||
class="receipt-claim-form-page__form"
|
||||
>
|
||||
<section class="receipt-claim-form-page__section">
|
||||
<div class="receipt-claim-form-page__section-title">收款信息</div>
|
||||
<el-row :gutter="32">
|
||||
<el-col :span="12"
|
||||
><el-form-item label="认领通知单"
|
||||
><el-input v-model="form.receiptNoticeNo" disabled /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="付款人"
|
||||
><el-input v-model="form.payerName" disabled /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="收款金额"
|
||||
><el-input :model-value="formatMoney(form.receiptAmount)" disabled /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="交易时间"
|
||||
><el-input v-model="form.transactionTime" disabled /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="对方户名"
|
||||
><el-input v-model="form.counterpartyName" disabled /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="对方开户行"
|
||||
><el-input v-model="form.counterpartyBank" disabled /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="对方账号"
|
||||
><el-input v-model="form.counterpartyAccount" disabled /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="明细流水号"
|
||||
><el-input v-model="form.detailSerialNo" disabled /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="已认领金额"
|
||||
><el-input :model-value="formatMoney(form.claimedAmount)" disabled /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="摘要"><el-input v-model="form.summary" disabled /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="关联结算单" prop="settlementIds"
|
||||
><el-input
|
||||
:model-value="settlementLabel"
|
||||
readonly
|
||||
placeholder="请选择已审批通过的应收正式结算单"
|
||||
><template #append
|
||||
><el-button
|
||||
:icon="Search"
|
||||
title="选择结算单"
|
||||
@click="openSettlementDialog" /></template></el-input></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="认领人"
|
||||
><el-input v-model="form.claimerName" disabled /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="认领日期"
|
||||
><el-input v-model="form.claimDate" disabled /></el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="认领人部门"
|
||||
><el-input v-model="form.claimerDeptName" disabled /></el-form-item
|
||||
></el-col>
|
||||
</el-row>
|
||||
</section>
|
||||
|
||||
<section class="receipt-claim-form-page__section">
|
||||
<div class="receipt-claim-form-page__section-title">结算信息</div>
|
||||
<el-table :data="form.settlements" border>
|
||||
<el-table-column type="index" label="序号" width="64" align="center" />
|
||||
<el-table-column label="结算单号" min-width="180" align="center"
|
||||
><template #default="{ row }"
|
||||
><el-link type="primary" @click="openSettlementDetail(row)">{{
|
||||
row.formalSettlementNo
|
||||
}}</el-link></template
|
||||
></el-table-column
|
||||
>
|
||||
<el-table-column label="结算总金额" min-width="150" align="right"
|
||||
><template #default="{ row }">{{
|
||||
formatMoney(row.settlementAmount)
|
||||
}}</template></el-table-column
|
||||
>
|
||||
<el-table-column label="已认领收款金额" min-width="160" align="right"
|
||||
><template #default="{ row }">{{
|
||||
formatMoney(row.claimedReceiptAmount)
|
||||
}}</template></el-table-column
|
||||
>
|
||||
<el-table-column label="分摊收款金额" min-width="180"
|
||||
><template #default="{ row }"
|
||||
><el-input-number
|
||||
v-model="row.allocatedReceiptAmount"
|
||||
:min="0"
|
||||
:max="remainingAmount(row)"
|
||||
:precision="2"
|
||||
:controls="false" /></template
|
||||
></el-table-column>
|
||||
</el-table>
|
||||
</section>
|
||||
|
||||
<section class="receipt-claim-form-page__section">
|
||||
<div class="receipt-claim-form-page__section-heading">
|
||||
<div class="receipt-claim-form-page__section-title">附件信息</div>
|
||||
<el-button
|
||||
v-if="form.attachments.length"
|
||||
type="primary"
|
||||
plain
|
||||
:icon="Download"
|
||||
@click="downloadAttachments"
|
||||
>批量下载</el-button
|
||||
>
|
||||
</div>
|
||||
<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" 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-claim-form-page__links">
|
||||
<el-link type="primary" :href="row.url || row.link" target="_blank">查看</el-link
|
||||
><el-link type="danger" @click="form.attachments.splice($index, 1)">删除</el-link>
|
||||
</div></template
|
||||
></el-table-column
|
||||
>
|
||||
</el-table>
|
||||
<vehicle-attachment-upload
|
||||
v-model="form.attachments"
|
||||
:multiple="true"
|
||||
:limit="20"
|
||||
:max-size="500"
|
||||
:file-types="attachmentFileTypes"
|
||||
:show-file-list="false"
|
||||
button-text="上传附件"
|
||||
class="receipt-claim-form-page__uploader"
|
||||
@change="normalizeAttachments"
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section class="receipt-claim-form-page__section">
|
||||
<div class="receipt-claim-form-page__section-title">备注</div>
|
||||
<el-form-item class="receipt-claim-form-page__remark"
|
||||
><el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/></el-form-item>
|
||||
</section>
|
||||
<div class="receipt-claim-form-page__actions">
|
||||
<el-button type="primary" :loading="submitting" @click="submitClaim">确认</el-button
|
||||
><el-button :disabled="submitting" @click="goBack">取消</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<el-dialog
|
||||
v-model="settlementDialog.visible"
|
||||
title="选择应收正式结算单"
|
||||
width="86%"
|
||||
append-to-body
|
||||
>
|
||||
<div class="receipt-claim-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
|
||||
@selection-change="settlementDialog.selection = $event"
|
||||
>
|
||||
<el-table-column type="selection" width="52" align="center" /><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>
|
||||
<template #footer
|
||||
><el-button @click="settlementDialog.visible = false">取消</el-button
|
||||
><el-button type="primary" @click="confirmSettlements">确定</el-button></template
|
||||
>
|
||||
</el-dialog>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Download, Search } from '@element-plus/icons-vue';
|
||||
import * as api from '@/api/payment/receiptFlow';
|
||||
|
||||
const emptyForm = () => ({
|
||||
id: null,
|
||||
receiptNoticeNo: '',
|
||||
payerName: '',
|
||||
receiptAmount: 0,
|
||||
counterpartyName: '',
|
||||
counterpartyAccount: '',
|
||||
counterpartyBank: '',
|
||||
summary: '',
|
||||
transactionTime: '',
|
||||
detailSerialNo: '',
|
||||
claimedAmount: 0,
|
||||
claimerName: '',
|
||||
claimerDeptName: '',
|
||||
claimDate: '',
|
||||
settlementIds: [],
|
||||
settlements: [],
|
||||
attachments: [],
|
||||
remark: '',
|
||||
});
|
||||
|
||||
export default {
|
||||
name: 'ReceiptFlowForm',
|
||||
data() {
|
||||
return {
|
||||
Download,
|
||||
Search,
|
||||
form: emptyForm(),
|
||||
submitting: false,
|
||||
attachmentFileTypes: [
|
||||
'pdf',
|
||||
'bmp',
|
||||
'jpeg',
|
||||
'png',
|
||||
'jpg',
|
||||
'doc',
|
||||
'docx',
|
||||
'ppt',
|
||||
'pptx',
|
||||
'xlsx',
|
||||
'xls',
|
||||
'eml',
|
||||
'msg',
|
||||
'zip',
|
||||
],
|
||||
settlementDialog: { visible: false, loading: false, keyword: '', rows: [], selection: [] },
|
||||
rules: {
|
||||
settlementIds: [
|
||||
{ required: true, message: '请选择应收正式结算单', trigger: 'change' },
|
||||
{ validator: this.validateSettlements, trigger: 'change' },
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
flowId() {
|
||||
return this.$route.query.id || '';
|
||||
},
|
||||
settlementLabel() {
|
||||
return this.form.settlements
|
||||
.map(item => item.formalSettlementNo)
|
||||
.filter(Boolean)
|
||||
.join(',');
|
||||
},
|
||||
allocatedTotal() {
|
||||
return this.form.settlements.reduce(
|
||||
(total, item) => total + Number(item.allocatedReceiptAmount || 0),
|
||||
0
|
||||
);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.initialize();
|
||||
},
|
||||
methods: {
|
||||
unwrapData(response) {
|
||||
const body = response?.data || response || {};
|
||||
return body?.data || body;
|
||||
},
|
||||
async initialize() {
|
||||
if (!this.flowId) {
|
||||
this.$message.error('缺少收款流水');
|
||||
this.goBack();
|
||||
return;
|
||||
}
|
||||
const data = this.unwrapData(await api.getDetail(this.flowId));
|
||||
const userInfo = this.$store.getters.userInfo || {};
|
||||
this.form = {
|
||||
...emptyForm(),
|
||||
...data,
|
||||
claimerName: userInfo.realName || userInfo.userName || data.claimerName || '',
|
||||
claimerDeptName: userInfo.deptName || userInfo.dept_name || data.claimerDeptName || '',
|
||||
claimDate: this.$dayjs().format('YYYY-MM-DD'),
|
||||
settlementIds: [],
|
||||
settlements: [],
|
||||
attachments: [],
|
||||
};
|
||||
},
|
||||
validateSettlements(rule, value, callback) {
|
||||
this.form.settlements.length ? callback() : callback(new Error('请选择应收正式结算单'));
|
||||
},
|
||||
async openSettlementDialog() {
|
||||
this.settlementDialog.visible = true;
|
||||
await this.loadSettlementCandidates();
|
||||
},
|
||||
async loadSettlementCandidates() {
|
||||
this.settlementDialog.loading = true;
|
||||
try {
|
||||
this.settlementDialog.rows =
|
||||
this.unwrapData(
|
||||
await api.getSettlementCandidates(this.settlementDialog.keyword, this.flowId)
|
||||
) || [];
|
||||
} finally {
|
||||
this.settlementDialog.loading = false;
|
||||
}
|
||||
},
|
||||
confirmSettlements() {
|
||||
const rows = this.settlementDialog.selection;
|
||||
if (!rows.length) {
|
||||
this.$message.warning('请至少选择一张应收正式结算单');
|
||||
return;
|
||||
}
|
||||
const first = rows[0];
|
||||
if (
|
||||
rows.some(
|
||||
item =>
|
||||
String(item.projectId) !== String(first.projectId) ||
|
||||
String(item.deptId) !== String(first.deptId) ||
|
||||
item.payerName !== first.payerName ||
|
||||
item.payeeName !== first.payeeName
|
||||
)
|
||||
) {
|
||||
this.$message.warning('关联结算单必须属于同一项目、组织及收付款方');
|
||||
return;
|
||||
}
|
||||
if (
|
||||
this.form.counterpartyName &&
|
||||
rows.some(item => item.payerName && item.payerName !== this.form.counterpartyName)
|
||||
) {
|
||||
this.$message.warning('对方户名与结算单付款方不一致');
|
||||
return;
|
||||
}
|
||||
this.form.settlements = rows.map(item => ({
|
||||
...item,
|
||||
formalSettlementId: item.id,
|
||||
settlementId: item.id,
|
||||
allocatedReceiptAmount: 0,
|
||||
}));
|
||||
this.form.settlementIds = this.form.settlements.map(item => item.formalSettlementId);
|
||||
this.settlementDialog.visible = false;
|
||||
this.$nextTick(() => this.$refs.formRef?.validateField('settlementIds'));
|
||||
},
|
||||
remainingAmount(row) {
|
||||
return Math.max(Number(row.settlementAmount || 0) - Number(row.claimedReceiptAmount || 0), 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();
|
||||
});
|
||||
},
|
||||
async submitClaim() {
|
||||
await this.$refs.formRef.validate();
|
||||
const amount = Number(this.form.receiptAmount || 0);
|
||||
if (amount <= 0 || this.allocatedTotal <= 0) {
|
||||
this.$message.warning('分摊收款金额必须大于0');
|
||||
return;
|
||||
}
|
||||
if (this.allocatedTotal > amount - Number(this.form.claimedAmount || 0) + 0.001) {
|
||||
this.$message.warning('本次分摊金额不能超过流水剩余可认领金额');
|
||||
return;
|
||||
}
|
||||
for (const row of this.form.settlements)
|
||||
if (Number(row.allocatedReceiptAmount || 0) > this.remainingAmount(row) + 0.001) {
|
||||
this.$message.warning(`结算单${row.formalSettlementNo}的累计认领金额不能超过结算总金额`);
|
||||
return;
|
||||
}
|
||||
this.submitting = true;
|
||||
try {
|
||||
await api.claim({
|
||||
flowId: this.flowId,
|
||||
attachmentsJson: JSON.stringify(this.form.attachments || []),
|
||||
remark: this.form.remark,
|
||||
settlements: this.form.settlements.map(item => ({
|
||||
settlementId: item.formalSettlementId || item.settlementId,
|
||||
allocatedReceiptAmount: item.allocatedReceiptAmount,
|
||||
})),
|
||||
});
|
||||
this.$message.success('认领成功');
|
||||
this.goBack();
|
||||
} finally {
|
||||
this.submitting = false;
|
||||
}
|
||||
},
|
||||
openSettlementDetail(row) {
|
||||
const id = row.formalSettlementId || row.settlementId || row.id;
|
||||
if (id)
|
||||
this.$router.push({
|
||||
path: '/settlement/formal-settlement/form',
|
||||
query: { mode: 'view', id, name: '查看正式结算' },
|
||||
});
|
||||
},
|
||||
goBack() {
|
||||
this.$router.push('/payment/receipt-flow');
|
||||
},
|
||||
formatMoney(value) {
|
||||
return Number(value || 0).toFixed(2);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.receipt-claim-form-page__section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.receipt-claim-form-page__section-title::before {
|
||||
width: 4px;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
background: #409eff;
|
||||
content: '';
|
||||
}
|
||||
.receipt-claim-form-page__section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.receipt-claim-form-page__section-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
.receipt-claim-form-page__section-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.receipt-claim-form-page__section-heading .receipt-claim-form-page__section-title {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.receipt-claim-form-page__form :deep(.el-form-item) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.receipt-claim-form-page__form :deep(.el-select),
|
||||
.receipt-claim-form-page__form :deep(.el-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
.receipt-claim-form-page__links {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.receipt-claim-form-page__remark :deep(.el-form-item__content) {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
.receipt-claim-form-page__uploader {
|
||||
margin-top: 12px;
|
||||
}
|
||||
.receipt-claim-form-page__actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 16px 0 8px;
|
||||
}
|
||||
.receipt-claim-form-page__dialog-search {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.receipt-claim-form-page__dialog-search .el-input {
|
||||
width: 360px;
|
||||
}
|
||||
.receipt-claim-form-page :deep(.el-table) {
|
||||
--el-table-border-color: #eff1f7;
|
||||
}
|
||||
.receipt-claim-form-page :deep(.el-table__row:nth-child(even) > td.el-table__cell) {
|
||||
background: #fafafa;
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.receipt-claim-form-page__form :deep(.el-col-12) {
|
||||
max-width: 100%;
|
||||
flex: 0 0 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user