新增流水明细对手方汇总查询

This commit is contained in:
wjj
2026-07-20 14:29:23 +08:00
parent 7fec8e21be
commit 175a50bf96
13 changed files with 521 additions and 4 deletions

View File

@@ -152,8 +152,18 @@
<div class="shell-header">
<div class="shell-title-group">
<span class="shell-title">流水明细查询</span>
<el-radio-group
v-model="resultMode"
class="result-mode-switch"
size="small"
@change="handleResultModeChange"
>
<el-radio-button label="statement">流水明细</el-radio-button>
<el-radio-button label="counterparty">对手方</el-radio-button>
</el-radio-group>
</div>
<el-button
v-if="resultMode === 'statement'"
size="small"
type="primary"
plain
@@ -164,7 +174,7 @@
</el-button>
</div>
<el-alert
v-if="prefillTip"
v-if="resultMode === 'statement' && prefillTip"
:closable="false"
class="prefill-alert"
show-icon
@@ -180,15 +190,24 @@
<div class="result-card">
<el-alert
v-if="listError"
v-if="resultMode === 'statement' && listError"
:closable="false"
class="result-alert"
show-icon
title="流水明细加载失败,请稍后重试"
type="error"
/>
<el-alert
v-if="resultMode === 'counterparty' && counterpartyError"
:closable="false"
class="result-alert"
show-icon
title="对手方加载失败,请稍后重试"
type="error"
/>
<el-table
v-if="resultMode === 'statement'"
v-loading="loading"
:data="list"
class="result-table"
@@ -275,9 +294,82 @@
</el-table-column>
</el-table>
<el-table
v-else
v-loading="loading"
:data="counterpartyList"
class="result-table counterparty-table"
@sort-change="handleCounterpartySortChange"
>
<template slot="empty">
<el-empty
:image-size="96"
description="当前筛选条件下暂无对手方"
/>
</template>
<el-table-column
label="对手方名称"
prop="customerAccountName"
min-width="220"
:formatter="formatCounterpartyNameColumn"
/>
<el-table-column
label="流入合计"
prop="inAmount"
width="150"
align="right"
sortable="custom"
>
<template slot-scope="scope">
<div class="amount-stack">
<span class="amount-text amount-in">{{ formatAmount(scope.row.inAmount) }}</span>
<span class="secondary-text">{{ formatCount(scope.row.inCount) }} </span>
</div>
</template>
</el-table-column>
<el-table-column
label="流出合计"
prop="outAmount"
width="150"
align="right"
sortable="custom"
>
<template slot-scope="scope">
<div class="amount-stack">
<span class="amount-text amount-out">{{ formatAmount(scope.row.outAmount) }}</span>
<span class="secondary-text">{{ formatCount(scope.row.outCount) }} </span>
</div>
</template>
</el-table-column>
<el-table-column
label="总交易额"
prop="totalAmount"
width="150"
align="right"
sortable="custom"
>
<template slot-scope="scope">
<div class="amount-stack">
<span class="amount-text">{{ formatAmount(scope.row.totalAmount) }}</span>
<span class="secondary-text">{{ formatCount(scope.row.totalCount) }} </span>
</div>
</template>
</el-table-column>
<el-table-column
label="最近交易时间"
prop="latestTrxDate"
min-width="170"
sortable="custom"
>
<template slot-scope="scope">
{{ formatField(scope.row.latestTrxDate) }}
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-show="currentTotal > 0"
:total="currentTotal"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="handlePageChange"
@@ -411,6 +503,7 @@
import { parseTime } from "@/utils/ruoyi";
import {
listBankStatement,
listBankStatementCounterparties,
getBankStatementOptions,
getBankStatementDetail,
} from "@/api/ccdiProjectBankStatement";
@@ -427,6 +520,14 @@ const SORT_MAP = {
displayAmount: "amount",
};
const COUNTERPARTY_SORT_MAP = {
inAmount: "inAmount",
outAmount: "outAmount",
totalAmount: "totalAmount",
totalCount: "totalCount",
latestTrxDate: "latestTrxDate",
};
const createDefaultQueryParams = (projectId) => ({
projectId,
pageNum: 1,
@@ -517,10 +618,14 @@ export default {
optionsLoading: false,
detailLoading: false,
detailVisible: false,
resultMode: "statement",
activeTab: "all",
dateRange: [],
list: [],
total: 0,
counterpartyList: [],
counterpartyTotal: 0,
counterpartyError: "",
listError: "",
prefillTip: "",
detailData: createEmptyDetailData(),
@@ -532,6 +637,11 @@ export default {
this.getList();
this.getOptions();
},
computed: {
currentTotal() {
return this.resultMode === "counterparty" ? this.counterpartyTotal : this.total;
},
},
watch: {
dateRange(value) {
this.queryParams.transactionStartTime = value && value[0] ? value[0] : "";
@@ -557,12 +667,19 @@ export default {
if (!this.queryParams.projectId) {
this.list = [];
this.total = 0;
this.counterpartyList = [];
this.counterpartyTotal = 0;
this.listError = "";
this.counterpartyError = "";
return;
}
this.loading = true;
try {
if (this.resultMode === "counterparty") {
await this.getCounterpartyList();
return;
}
const res = await listBankStatement(this.queryParams);
this.list = (res.rows || []).map((item) => ({
...item,
@@ -579,6 +696,19 @@ export default {
this.loading = false;
}
},
async getCounterpartyList() {
try {
const res = await listBankStatementCounterparties(this.queryParams);
this.counterpartyList = res.rows || [];
this.counterpartyTotal = res.total || 0;
this.counterpartyError = "";
} catch (error) {
this.counterpartyList = [];
this.counterpartyTotal = 0;
this.counterpartyError = "加载对手方失败";
console.error("加载对手方失败", error);
}
},
async getOptions() {
this.syncProjectId();
if (!this.queryParams.projectId) {
@@ -624,6 +754,7 @@ export default {
if (!value || !Array.isArray(value.ourCertNos) || !value.ourCertNos.length) {
return;
}
this.resultMode = "statement";
this.activeTab = "all";
this.dateRange = [];
this.queryParams = {
@@ -634,6 +765,17 @@ export default {
this.syncProjectId();
this.getList();
},
handleResultModeChange(mode) {
this.queryParams.pageNum = 1;
if (mode === "counterparty") {
this.queryParams.orderBy = "totalAmount";
this.queryParams.orderDirection = "desc";
} else {
this.queryParams.orderBy = "trxDate";
this.queryParams.orderDirection = "desc";
}
this.getList();
},
handleTabChange(tab) {
const tabName = tab && tab.name ? tab.name : this.activeTab;
this.activeTab = tabName;
@@ -650,6 +792,15 @@ export default {
}
this.getList();
},
handleCounterpartySortChange({ prop, order }) {
this.queryParams.orderBy = COUNTERPARTY_SORT_MAP[prop] || "totalAmount";
this.queryParams.orderDirection = order === "ascending" ? "asc" : "desc";
if (!order) {
this.queryParams.orderBy = "totalAmount";
this.queryParams.orderDirection = "desc";
}
this.getList();
},
handlePageChange(pageInfo) {
if (typeof pageInfo === "number") {
this.queryParams.pageNum = pageInfo;
@@ -743,6 +894,13 @@ export default {
maximumFractionDigits: 2,
});
},
formatCount(value) {
if (value === null || value === undefined || value === "") {
return 0;
}
const count = Number(value);
return Number.isNaN(count) ? 0 : count;
},
formatSignedAmount(value) {
if (value === null || value === undefined || value === "") {
return "-";
@@ -766,6 +924,15 @@ export default {
}
return this.formatField(detail.customerAccountName);
},
formatCounterpartyRowName(row) {
if (!row || row.nameEmpty || !row.customerAccountName) {
return "为空";
}
return this.formatField(row.customerAccountName);
},
formatCounterpartyNameColumn(row) {
return this.formatCounterpartyRowName(row);
},
formatOriginalFileName(detail) {
if (!detail) {
return "暂无原始文件";
@@ -876,6 +1043,14 @@ export default {
color: #909399;
}
.result-mode-switch {
margin-top: 8px;
:deep(.el-radio-button__inner) {
min-width: 82px;
}
}
.shell-header {
display: flex;
align-items: flex-start;
@@ -1011,6 +1186,15 @@ export default {
font-weight: 600;
}
.amount-stack {
display: inline-flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
min-width: 0;
line-height: 20px;
}
.amount-in {
color: #67c23a;
}