Files
ccdi/ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue

467 lines
14 KiB
Vue

<template>
<div class="preliminary-check-container">
<div v-if="pageState === 'loading'" class="preliminary-check-state">
<div class="state-card">
<el-skeleton animated :rows="6" />
</div>
</div>
<div v-else-if="pageState === 'empty'" class="preliminary-check-state">
<div class="state-card">
<el-empty description="暂无结果总览数据" />
</div>
</div>
<div v-else class="preliminary-check-page">
<section class="section-card risk-overview-card">
<div class="section-header">
<div>
<div class="section-title">风险总览</div>
<div class="section-subtitle">集中展示项目风险统计与命中人员总览</div>
</div>
<el-button
size="mini"
type="primary"
plain
icon="el-icon-download"
:disabled="!projectId"
@click="handleOverviewReportExport"
>
导出报告
</el-button>
</div>
<overview-stats :summary="visibleSummary" />
<risk-people-section
:project-id="projectId"
:section-data="currentData.riskPeople"
:selected-model-codes="selectedModelCodes"
@view-project-analysis="handleRiskPeopleProjectAnalysis"
@view-external-detail="handleExternalDetail"
@scope-summary-change="handleRiskPeopleScopeSummaryChange"
/>
</section>
<risk-model-section
:section-data="currentData.riskModels"
@selection-change="handleRiskModelSelectionChange"
@view-project-analysis="handleRiskModelProjectAnalysis"
@view-external-detail="handleExternalDetail"
/>
<risk-detail-section
:section-data="currentData.riskDetails"
@evidence-confirm="$emit('evidence-confirm', $event)"
/>
</div>
<project-analysis-dialog
:visible.sync="projectAnalysisDialogVisible"
:project-id="projectId"
:person="currentProjectAnalysisPerson"
:source="projectAnalysisSource"
:model-summary="projectAnalysisModelSummary"
:project-name="projectInfo.projectName"
@close="handleProjectAnalysisDialogClose"
@evidence-confirm="$emit('evidence-confirm', $event)"
/>
<external-person-detail-dialog
:visible.sync="externalDetailVisible"
:person="currentExternalPerson"
:project-id="projectId"
:project-name="projectInfo.projectName"
@evidence-confirm="$emit('evidence-confirm', $event)"
/>
</div>
</template>
<script>
import {
createOverviewLoadedData,
mockOverviewData,
mockOverviewStateData,
} from "./preliminaryCheck.mock";
import {
getOverviewDashboard,
getOverviewEmployeeCreditNegative,
getOverviewExternalRiskSummary,
getOverviewRiskPeople,
getOverviewRiskModelCards,
getOverviewSuspiciousTransactions,
} from "@/api/ccdi/projectOverview";
import OverviewStats from "./OverviewStats";
import RiskPeopleSection from "./RiskPeopleSection";
import RiskModelSection from "./RiskModelSection";
import RiskDetailSection from "./RiskDetailSection";
import ProjectAnalysisDialog from "./ProjectAnalysisDialog";
import ExternalPersonDetailDialog from "./ExternalPersonDetailDialog";
export default {
name: "PreliminaryCheck",
components: {
OverviewStats,
RiskPeopleSection,
RiskModelSection,
RiskDetailSection,
ProjectAnalysisDialog,
ExternalPersonDetailDialog,
},
props: {
projectId: {
type: [String, Number],
default: null,
},
projectInfo: {
type: Object,
default: () => ({
projectName: "",
updateTime: "",
projectStatus: "0",
}),
},
},
data() {
return {
pageState: "loading",
selectedModelCodes: [],
mockData: mockOverviewData,
stateDataMap: mockOverviewStateData,
realData: mockOverviewData,
projectAnalysisDialogVisible: false,
currentProjectAnalysisPerson: null,
projectAnalysisSource: "riskPeople",
projectAnalysisModelSummary: {
modelCount: 0,
currentModel: "-",
riskTags: [],
},
riskPeopleScopeSummary: {
activeTab: "employee",
external: {
total: 0,
rows: [],
},
},
currentExternalPerson: null,
externalDetailVisible: false,
};
},
computed: {
currentData() {
if (this.pageState === "loaded") {
return this.realData;
}
return this.stateDataMap[this.pageState] || this.realData;
},
visibleSummary() {
return {
...this.currentData.summary,
stats: this.buildCombinedSummaryStats(),
};
},
},
watch: {
projectId(newVal) {
if (newVal) {
this.loadOverviewData();
return;
}
this.realData = this.stateDataMap.empty;
this.pageState = "empty";
this.selectedModelCodes = [];
this.resetProjectAnalysisDialog();
this.resetExternalDetailDialog();
},
},
created() {
if (this.projectId) {
this.loadOverviewData();
return;
}
this.realData = this.stateDataMap.empty;
this.pageState = "empty";
this.resetProjectAnalysisDialog();
this.resetExternalDetailDialog();
},
methods: {
handleRiskModelSelectionChange(modelCodes) {
this.selectedModelCodes = Array.isArray(modelCodes) ? [...modelCodes] : [];
},
handleRiskPeopleScopeSummaryChange(summary) {
this.riskPeopleScopeSummary = {
activeTab: summary && summary.activeTab ? summary.activeTab : "employee",
external: {
total: summary && summary.external ? summary.external.total || 0 : 0,
rows: summary && summary.external && Array.isArray(summary.external.rows)
? summary.external.rows
: [],
},
};
},
buildCombinedSummaryStats() {
const external = (this.currentData.summary && this.currentData.summary.externalRiskSummary) || {};
const employeeStats = ((this.currentData.summary && this.currentData.summary.stats) || []);
const statMap = employeeStats.reduce((result, item) => {
result[item.key] = item;
return result;
}, {});
const high = Number((statMap.riskPeople && statMap.riskPeople.value) || 0);
const medium = Number((statMap.medium && statMap.medium.value) || 0);
const low = Number((statMap.low && statMap.low.value) || 0);
const noRisk = Number((statMap.count && statMap.count.value) || 0);
const externalTotal = Number(external.total || 0);
const externalHigh = Number(external.high || 0);
const externalMedium = Number(external.medium || 0);
const externalLow = Number(external.low || 0);
const externalNoRisk = Number(external.noRisk || 0);
const buildSplit = (employeeValue, externalValue) => (externalTotal > 0
? `员工 ${employeeValue} / 外部 ${externalValue}`
: "");
return [
{
...(statMap.people || {}),
key: "people",
label: "总人数",
value: Number((statMap.people && statMap.people.value) || 0) + externalTotal,
desc: buildSplit(Number((statMap.people && statMap.people.value) || 0), externalTotal),
},
{
...(statMap.riskPeople || {}),
key: "riskPeople",
label: "高风险",
value: high + externalHigh,
desc: buildSplit(high, externalHigh),
},
{
...(statMap.medium || {}),
key: "medium",
label: "中风险",
value: medium + externalMedium,
desc: buildSplit(medium, externalMedium),
},
{
...(statMap.low || {}),
key: "low",
label: "低风险",
value: low + externalLow,
desc: buildSplit(low, externalLow),
},
{
...(statMap.count || {}),
key: "count",
label: "无风险",
value: noRisk + externalNoRisk,
desc: buildSplit(noRisk, externalNoRisk),
},
];
},
handleRiskPeopleProjectAnalysis(row) {
this.openProjectAnalysisDialog("riskPeople", row);
},
handleRiskModelProjectAnalysis(row) {
this.openProjectAnalysisDialog("riskModelPeople", row);
},
handleExternalDetail(row) {
this.currentExternalPerson = row || null;
this.externalDetailVisible = true;
},
openProjectAnalysisDialog(source, person) {
this.projectAnalysisSource = source || "riskPeople";
this.currentProjectAnalysisPerson = person || null;
this.projectAnalysisModelSummary = this.buildProjectAnalysisModelSummary(
this.projectAnalysisSource,
this.currentProjectAnalysisPerson
);
this.projectAnalysisDialogVisible = true;
},
handleProjectAnalysisDialogClose() {
this.projectAnalysisDialogVisible = false;
this.resetProjectAnalysisDialog();
},
resetProjectAnalysisDialog() {
this.projectAnalysisDialogVisible = false;
this.currentProjectAnalysisPerson = null;
this.projectAnalysisSource = "riskPeople";
this.projectAnalysisModelSummary = {
modelCount: 0,
currentModel: "-",
riskTags: [],
};
},
buildProjectAnalysisModelSummary(source, person) {
const safePerson = person || {};
const riskTags = Array.isArray(safePerson.riskPointTagList)
? safePerson.riskPointTagList
: Array.isArray(safePerson.hitTagList)
? safePerson.hitTagList
: [];
return {
staffIdCard: safePerson.idNo || safePerson.staffIdCard || "",
modelCount: safePerson.modelCount || (Array.isArray(safePerson.modelNames) ? safePerson.modelNames.length : 0),
currentModel: source === "riskModelPeople"
? (Array.isArray(safePerson.modelNames) && safePerson.modelNames.length
? safePerson.modelNames.join("、")
: safePerson.modelName || "-")
: ((riskTags[0] && riskTags[0].modelName) || "-"),
riskTags,
};
},
resetExternalDetailDialog() {
this.externalDetailVisible = false;
this.currentExternalPerson = null;
},
handleOverviewReportExport() {
if (!this.projectId) {
return;
}
this.download(
"ccdi/project/overview/report/export",
{
projectId: this.projectId,
},
`初核结果报告_${this.projectId}_${new Date().getTime()}.pdf`
);
},
async loadOverviewData() {
if (!this.projectId) {
this.realData = this.stateDataMap.empty;
this.pageState = "empty";
this.selectedModelCodes = [];
this.resetProjectAnalysisDialog();
this.resetExternalDetailDialog();
return;
}
this.pageState = "loading";
this.selectedModelCodes = [];
this.riskPeopleScopeSummary = {
activeTab: "employee",
external: {
total: 0,
rows: [],
},
};
this.resetProjectAnalysisDialog();
this.resetExternalDetailDialog();
try {
const [
dashboardRes,
riskPeopleRes,
riskModelCardsRes,
suspiciousRes,
creditNegativeRes,
externalSummaryRes,
] = await Promise.all([
getOverviewDashboard(this.projectId),
getOverviewRiskPeople({
projectId: this.projectId,
pageNum: 1,
pageSize: 5,
}),
getOverviewRiskModelCards(this.projectId),
getOverviewSuspiciousTransactions({
projectId: this.projectId,
suspiciousType: "ALL",
pageNum: 1,
pageSize: 5,
}),
getOverviewEmployeeCreditNegative({
projectId: this.projectId,
pageNum: 1,
pageSize: 5,
}),
getOverviewExternalRiskSummary(this.projectId),
]);
const dashboardData = (dashboardRes && dashboardRes.data) || {};
const riskPeopleData = (riskPeopleRes && riskPeopleRes.data) || {};
const riskModelCardsData = (riskModelCardsRes && riskModelCardsRes.data) || {};
const suspiciousData = (suspiciousRes && suspiciousRes.data) || {};
const creditNegativeData = (creditNegativeRes && creditNegativeRes.data) || {};
const externalRiskSummary = (externalSummaryRes && externalSummaryRes.data) || {};
this.realData = createOverviewLoadedData({
projectId: this.projectId,
dashboardData,
riskPeopleData,
riskModelCardsData,
suspiciousData,
creditNegativeData,
externalRiskSummary,
});
const hasOverviewData = Boolean(
(Array.isArray(dashboardData.stats) && dashboardData.stats.length) ||
(Array.isArray(riskPeopleData.rows) && riskPeopleData.rows.length) ||
(Array.isArray(riskModelCardsData.cardList) && riskModelCardsData.cardList.length)
);
this.pageState = hasOverviewData ? "loaded" : "empty";
} catch (error) {
this.realData = this.stateDataMap.empty;
this.pageState = "empty";
this.selectedModelCodes = [];
this.resetProjectAnalysisDialog();
this.resetExternalDetailDialog();
console.error("加载结果总览失败", error);
}
},
},
};
</script>
<style lang="scss" scoped>
.preliminary-check-container {
min-height: 400px;
padding: 0 0 24px;
}
.preliminary-check-state {
min-height: 400px;
}
.state-card {
padding: 32px 24px;
border-radius: 14px;
background: #fff;
border: 1px solid var(--ccdi-border);
box-shadow: var(--ccdi-shadow);
}
.preliminary-check-page {
min-height: 400px;
}
.section-card {
padding: 20px;
border-radius: 14px;
background: #fff;
border: 1px solid var(--ccdi-border);
box-shadow: var(--ccdi-shadow);
}
.risk-overview-card {
margin-bottom: 16px;
padding: 24px 20px 20px;
}
.section-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
margin-bottom: 18px;
padding-left: 12px;
border-left: 4px solid var(--ccdi-primary);
}
.section-title {
font-size: 20px;
line-height: 28px;
font-weight: 700;
color: var(--ccdi-text-primary);
}
.section-subtitle {
margin-top: 6px;
font-size: 12px;
color: var(--ccdi-text-muted);
}
</style>