新增未提交账户风险明细
This commit is contained in:
@@ -152,6 +152,18 @@ export function getOverviewUnsubmittedAccounts(projectId) {
|
||||
})
|
||||
}
|
||||
|
||||
export function getOverviewUnsubmittedAccountFlows(params) {
|
||||
return request({
|
||||
url: '/ccdi/project/overview/unsubmitted-accounts/flows',
|
||||
method: 'get',
|
||||
params: {
|
||||
projectId: params.projectId,
|
||||
subjectName: params.subjectName,
|
||||
accountNo: params.accountNo
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function exportOverviewReport(projectId) {
|
||||
return request({
|
||||
url: '/ccdi/project/overview/report/export',
|
||||
|
||||
@@ -6,31 +6,31 @@
|
||||
<div class="section-title">风险明细</div>
|
||||
<div class="section-subtitle">展示涉疑交易与异常账户关联人员信息</div>
|
||||
</div>
|
||||
<el-button size="mini" type="text" :disabled="!projectId" @click="handleRiskDetailExport">
|
||||
导出
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
<div class="block-header">
|
||||
<div>
|
||||
<div class="block-title">未提交账户</div>
|
||||
<div class="block-subtitle">被调查主体未提交分析的同名账户,已排除银行贷款类账号</div>
|
||||
<div class="block-subtitle">被调查主体未提交分析的同名账户</div>
|
||||
</div>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-download"
|
||||
:disabled="!projectId || unsubmittedAccountTotal <= 0"
|
||||
@click="handleUnsubmittedAccountExport"
|
||||
>
|
||||
导出流水
|
||||
导出
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div v-loading="unsubmittedAccountLoading" class="unsubmitted-panel">
|
||||
<template v-if="unsubmittedAccountTotal > 0">
|
||||
<div class="unsubmitted-metrics">
|
||||
<div class="unsubmitted-metric">
|
||||
<div class="metric-label">涉及主体数</div>
|
||||
<div class="metric-value">{{ unsubmittedSubjectTotal }}</div>
|
||||
</div>
|
||||
<div class="unsubmitted-metric">
|
||||
<div class="metric-label">未提交账户数</div>
|
||||
<div class="metric-value">{{ unsubmittedAccountTotal }}</div>
|
||||
@@ -65,6 +65,10 @@
|
||||
v-for="account in subject.accounts"
|
||||
:key="`${subject.subjectName}-${account.accountNo}`"
|
||||
class="unsubmitted-account-card"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@click="handleUnsubmittedAccountCardClick(subject, account)"
|
||||
@keyup.enter="handleUnsubmittedAccountCardClick(subject, account)"
|
||||
>
|
||||
<div class="unsubmitted-account-head">
|
||||
<div class="unsubmitted-account-no">
|
||||
@@ -143,6 +147,11 @@
|
||||
查询
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item class="suspicious-export-action">
|
||||
<el-button size="mini" type="text" :disabled="!projectId" @click="handleSuspiciousTransactionExport">
|
||||
导出
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table
|
||||
@@ -329,6 +338,96 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
:visible.sync="unsubmittedFlowVisible"
|
||||
append-to-body
|
||||
custom-class="unsubmitted-flow-dialog"
|
||||
width="88%"
|
||||
top="4vh"
|
||||
@close="closeUnsubmittedFlowDialog"
|
||||
>
|
||||
<template slot="title">
|
||||
<div class="unsubmitted-flow-title">
|
||||
<span>流水明细</span>
|
||||
<div v-if="selectedUnsubmittedAccount" class="unsubmitted-flow-title-tags">
|
||||
<span>{{ formatUnsubmittedFlowPeriod }}</span>
|
||||
<span>{{ formatField(selectedUnsubmittedAccount.subjectName) }}</span>
|
||||
<span>{{ formatField(selectedUnsubmittedAccount.accountNo) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="unsubmitted-flow-toolbar">
|
||||
<el-radio-group v-model="unsubmittedFlowType" size="small">
|
||||
<el-radio-button label="ALL">全部 · {{ unsubmittedFlowAllCount }}</el-radio-button>
|
||||
<el-radio-button label="INFLOW">流入 · {{ unsubmittedFlowInCount }}</el-radio-button>
|
||||
<el-radio-button label="OUTFLOW">流出 · {{ unsubmittedFlowOutCount }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-button
|
||||
size="small"
|
||||
type="text"
|
||||
icon="el-icon-download"
|
||||
:disabled="!selectedUnsubmittedAccount || unsubmittedFlowAllCount <= 0"
|
||||
@click="handleUnsubmittedFlowExport"
|
||||
>
|
||||
导出流水
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
v-loading="unsubmittedFlowLoading"
|
||||
:data="unsubmittedFlowFilteredList"
|
||||
class="result-table unsubmitted-flow-table"
|
||||
height="640"
|
||||
>
|
||||
<template slot="empty">
|
||||
<el-empty :image-size="96" description="当前账号暂无流水明细" />
|
||||
</template>
|
||||
<el-table-column label="交易时间" min-width="150">
|
||||
<template slot-scope="scope">
|
||||
<div class="multi-line-cell">
|
||||
<div class="primary-text">{{ formatDatePart(scope.row.trxDate) }}</div>
|
||||
<div class="secondary-text">{{ formatTimePart(scope.row.trxDate) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="本方账户/主体" min-width="240">
|
||||
<template slot-scope="scope">
|
||||
<div class="multi-line-cell">
|
||||
<div class="primary-text">{{ formatField(scope.row.leAccountNo) }}</div>
|
||||
<div class="secondary-text">{{ formatField(scope.row.leAccountName) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="对方名称/账户" min-width="260">
|
||||
<template slot-scope="scope">
|
||||
<div class="multi-line-cell">
|
||||
<div class="primary-text link-text">{{ formatField(scope.row.customerAccountName) }}</div>
|
||||
<div class="secondary-text">{{ formatField(scope.row.customerAccountNo) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="摘要/交易类型" min-width="260" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<div class="multi-line-cell">
|
||||
<div class="primary-text">{{ formatField(scope.row.userMemo) }}</div>
|
||||
<div class="secondary-text">{{ formatField(scope.row.cashType) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="交易金额" min-width="170" align="right">
|
||||
<template slot-scope="scope">
|
||||
<span class="flow-amount" :class="getUnsubmittedFlowAmountClass(scope.row)">
|
||||
{{ formatUnsubmittedFlowAmount(scope.row) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="分类" min-width="130">
|
||||
<template>
|
||||
<span>未提交账户</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
:visible.sync="detailVisible"
|
||||
append-to-body
|
||||
@@ -456,6 +555,7 @@ import {
|
||||
getOverviewAbnormalAccountPeople,
|
||||
getOverviewEmployeeCreditNegative,
|
||||
getOverviewSuspiciousTransactions,
|
||||
getOverviewUnsubmittedAccountFlows,
|
||||
getOverviewUnsubmittedAccounts,
|
||||
} from "@/api/ccdi/projectOverview";
|
||||
import { getBankStatementDetail } from "@/api/ccdiProjectBankStatement";
|
||||
@@ -655,6 +755,11 @@ export default {
|
||||
},
|
||||
unsubmittedAccountTotal: 0,
|
||||
unsubmittedAccountSubjects: [],
|
||||
unsubmittedFlowVisible: false,
|
||||
unsubmittedFlowLoading: false,
|
||||
unsubmittedFlowType: "ALL",
|
||||
selectedUnsubmittedAccount: null,
|
||||
unsubmittedFlowList: [],
|
||||
projectId: null,
|
||||
statementDetailCache: {},
|
||||
suspiciousRequestSeq: 0,
|
||||
@@ -683,6 +788,33 @@ export default {
|
||||
allModelOptionLabel() {
|
||||
return this.isExternalSuspiciousType ? "全部外部模型" : "全部模型";
|
||||
},
|
||||
unsubmittedFlowFilteredList() {
|
||||
if (this.unsubmittedFlowType === "INFLOW") {
|
||||
return this.unsubmittedFlowList.filter((row) => this.isUnsubmittedFlowIn(row));
|
||||
}
|
||||
if (this.unsubmittedFlowType === "OUTFLOW") {
|
||||
return this.unsubmittedFlowList.filter((row) => this.isUnsubmittedFlowOut(row));
|
||||
}
|
||||
return this.unsubmittedFlowList;
|
||||
},
|
||||
unsubmittedFlowAllCount() {
|
||||
return this.unsubmittedFlowList.length;
|
||||
},
|
||||
unsubmittedSubjectTotal() {
|
||||
return this.unsubmittedAccountSubjects.length;
|
||||
},
|
||||
unsubmittedFlowInCount() {
|
||||
return this.unsubmittedFlowList.filter((row) => this.isUnsubmittedFlowIn(row)).length;
|
||||
},
|
||||
unsubmittedFlowOutCount() {
|
||||
return this.unsubmittedFlowList.filter((row) => this.isUnsubmittedFlowOut(row)).length;
|
||||
},
|
||||
formatUnsubmittedFlowPeriod() {
|
||||
if (!this.selectedUnsubmittedAccount) {
|
||||
return "-";
|
||||
}
|
||||
return `${this.formatDatePart(this.selectedUnsubmittedAccount.startDate)} ~ ${this.formatDatePart(this.selectedUnsubmittedAccount.endDate)}`;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
sectionData: {
|
||||
@@ -718,6 +850,7 @@ export default {
|
||||
this.suspiciousLoading = false;
|
||||
this.statementDetailCache = {};
|
||||
this.closeDetailDialog();
|
||||
this.closeUnsubmittedFlowDialog();
|
||||
}
|
||||
this.loadAbnormalAccountPeople();
|
||||
this.loadUnsubmittedAccounts();
|
||||
@@ -928,6 +1061,42 @@ export default {
|
||||
this.unsubmittedAccountLoading = false;
|
||||
}
|
||||
},
|
||||
async handleUnsubmittedAccountCardClick(subject, account) {
|
||||
if (!this.projectId || !subject || !account || !account.accountNo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedAccount = {
|
||||
...account,
|
||||
subjectName: subject.subjectName,
|
||||
};
|
||||
this.selectedUnsubmittedAccount = selectedAccount;
|
||||
this.unsubmittedFlowType = "ALL";
|
||||
this.unsubmittedFlowList = [];
|
||||
this.unsubmittedFlowVisible = true;
|
||||
this.unsubmittedFlowLoading = true;
|
||||
try {
|
||||
const response = await getOverviewUnsubmittedAccountFlows({
|
||||
projectId: this.projectId,
|
||||
subjectName: selectedAccount.subjectName,
|
||||
accountNo: selectedAccount.accountNo,
|
||||
});
|
||||
this.unsubmittedFlowList = Array.isArray(response && response.data) ? response.data : [];
|
||||
} catch (error) {
|
||||
this.unsubmittedFlowList = [];
|
||||
this.$message.error("加载未提交账户流水失败");
|
||||
console.error("加载未提交账户流水失败", error);
|
||||
} finally {
|
||||
this.unsubmittedFlowLoading = false;
|
||||
}
|
||||
},
|
||||
closeUnsubmittedFlowDialog() {
|
||||
this.unsubmittedFlowVisible = false;
|
||||
this.unsubmittedFlowLoading = false;
|
||||
this.unsubmittedFlowType = "ALL";
|
||||
this.selectedUnsubmittedAccount = null;
|
||||
this.unsubmittedFlowList = [];
|
||||
},
|
||||
async fetchStatementDetail(bankStatementId, silent, scope = {}) {
|
||||
if (!bankStatementId) {
|
||||
return createEmptyDetailData();
|
||||
@@ -1022,18 +1191,18 @@ export default {
|
||||
const value = this.formatField(detail.leAccountName);
|
||||
return value === "-" ? "关联人员" : value;
|
||||
},
|
||||
handleRiskDetailExport() {
|
||||
handleSuspiciousTransactionExport() {
|
||||
if (!this.projectId) {
|
||||
return;
|
||||
}
|
||||
this.download(
|
||||
"ccdi/project/overview/risk-details/export",
|
||||
"ccdi/project/overview/suspicious-transactions/export",
|
||||
{
|
||||
projectId: this.projectId,
|
||||
modelCode: this.selectedModelCode,
|
||||
suspiciousType: this.currentSuspiciousType,
|
||||
},
|
||||
`风险明细_${this.projectId}_${new Date().getTime()}.xlsx`
|
||||
`涉疑交易明细_${this.projectId}_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
},
|
||||
handleUnsubmittedAccountExport() {
|
||||
@@ -1046,6 +1215,20 @@ export default {
|
||||
`未提交账户流水_${this.projectId}_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
},
|
||||
handleUnsubmittedFlowExport() {
|
||||
if (!this.projectId || !this.selectedUnsubmittedAccount) {
|
||||
return;
|
||||
}
|
||||
this.download(
|
||||
"ccdi/project/overview/unsubmitted-accounts/export",
|
||||
{
|
||||
projectId: this.projectId,
|
||||
subjectName: this.selectedUnsubmittedAccount.subjectName,
|
||||
accountNo: this.selectedUnsubmittedAccount.accountNo,
|
||||
},
|
||||
`未提交账户流水_${this.projectId}_${this.selectedUnsubmittedAccount.accountNo}_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
},
|
||||
formatRelatedStaff(row) {
|
||||
if (!row || !row.relatedStaffName) {
|
||||
return "-";
|
||||
@@ -1113,6 +1296,42 @@ export default {
|
||||
}
|
||||
return `${text.slice(0, 8)} ... ${text.slice(-6)}`;
|
||||
},
|
||||
formatDatePart(value) {
|
||||
if (value === null || value === undefined || value === "") {
|
||||
return "-";
|
||||
}
|
||||
return String(value).split(" ")[0] || "-";
|
||||
},
|
||||
formatTimePart(value) {
|
||||
if (value === null || value === undefined || value === "") {
|
||||
return "-";
|
||||
}
|
||||
const parts = String(value).split(" ");
|
||||
return parts.length > 1 && parts[1] ? parts[1] : "-";
|
||||
},
|
||||
isUnsubmittedFlowIn(row) {
|
||||
return Number(row && row.amountCr) > 0;
|
||||
},
|
||||
isUnsubmittedFlowOut(row) {
|
||||
return Number(row && row.amountDr) > 0;
|
||||
},
|
||||
getUnsubmittedFlowAmountValue(row) {
|
||||
if (this.isUnsubmittedFlowIn(row)) {
|
||||
return Number(row.amountCr) || 0;
|
||||
}
|
||||
if (this.isUnsubmittedFlowOut(row)) {
|
||||
return -Number(row.amountDr || 0);
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
formatUnsubmittedFlowAmount(row) {
|
||||
const amount = this.getUnsubmittedFlowAmountValue(row);
|
||||
const prefix = amount < 0 ? "-¥" : "¥";
|
||||
return `${prefix}${this.formatAmount(Math.abs(amount))}`;
|
||||
},
|
||||
getUnsubmittedFlowAmountClass(row) {
|
||||
return this.getUnsubmittedFlowAmountValue(row) >= 0 ? "amount-in" : "amount-out";
|
||||
},
|
||||
formatSignedAmount(value) {
|
||||
if (value === null || value === undefined || value === "") {
|
||||
return "-";
|
||||
@@ -1283,6 +1502,10 @@ export default {
|
||||
min-width: 88px;
|
||||
}
|
||||
|
||||
.suspicious-export-action {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.suspicious-filter-select {
|
||||
width: 240px;
|
||||
}
|
||||
@@ -1297,7 +1520,7 @@ export default {
|
||||
|
||||
.unsubmitted-metrics {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
gap: 18px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
@@ -1345,6 +1568,16 @@ export default {
|
||||
padding: 18px 20px;
|
||||
border: 1px solid #e5e7eb;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
|
||||
}
|
||||
|
||||
.unsubmitted-account-card:hover,
|
||||
.unsubmitted-account-card:focus {
|
||||
border-color: #93c5fd;
|
||||
box-shadow: 0 10px 24px rgba(37, 99, 235, 0.1);
|
||||
outline: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.unsubmitted-account-head {
|
||||
@@ -1397,6 +1630,60 @@ export default {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.unsubmitted-flow-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.unsubmitted-flow-title > span {
|
||||
flex: 0 0 auto;
|
||||
color: #111827;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.unsubmitted-flow-title-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.unsubmitted-flow-title-tags span {
|
||||
max-width: 260px;
|
||||
padding: 4px 10px;
|
||||
color: #409eff;
|
||||
background: #ecf5ff;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.unsubmitted-flow-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.unsubmitted-flow-table :deep(.el-table__header th) {
|
||||
background: #fff;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.flow-amount {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.link-text {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.result-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user