From a13c73f9a8c06874fe1a2225fca71e52c62b10c2 Mon Sep 17 00:00:00 2001 From: wkc <978997012@qq.com> Date: Wed, 25 Mar 2026 14:05:30 +0800 Subject: [PATCH] =?UTF-8?q?=E6=90=AD=E5=BB=BA=E7=BB=93=E6=9E=9C=E6=80=BB?= =?UTF-8?q?=E8=A7=88=E9=A1=B9=E7=9B=AE=E5=88=86=E6=9E=90=E5=BC=B9=E7=AA=97?= =?UTF-8?q?=E9=AA=A8=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/detail/PreliminaryCheck.vue | 1 + .../detail/ProjectAnalysisDialog.vue | 115 ++++++++++++-- .../detail/ProjectAnalysisSidebar.vue | 144 ++++++++++++++++++ .../detail/preliminaryCheck.mock.js | 87 +++++++++++ ...roject-analysis-dialog-default-tab.test.js | 20 +++ .../project-analysis-dialog-layout.test.js | 39 +++++ .../project-analysis-dialog-sidebar.test.js | 29 ++++ 7 files changed, 422 insertions(+), 13 deletions(-) create mode 100644 ruoyi-ui/src/views/ccdiProject/components/detail/ProjectAnalysisSidebar.vue create mode 100644 ruoyi-ui/tests/unit/project-analysis-dialog-default-tab.test.js create mode 100644 ruoyi-ui/tests/unit/project-analysis-dialog-layout.test.js create mode 100644 ruoyi-ui/tests/unit/project-analysis-dialog-sidebar.test.js diff --git a/ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue b/ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue index 2e083fa1..3978effa 100644 --- a/ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue +++ b/ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue @@ -30,6 +30,7 @@ :visible.sync="projectAnalysisDialogVisible" :person="currentProjectAnalysisPerson" :source="projectAnalysisSource" + :project-name="projectInfo.projectName" @close="handleProjectAnalysisDialogClose" /> diff --git a/ruoyi-ui/src/views/ccdiProject/components/detail/ProjectAnalysisDialog.vue b/ruoyi-ui/src/views/ccdiProject/components/detail/ProjectAnalysisDialog.vue index 8fd054e4..3de7de0f 100644 --- a/ruoyi-ui/src/views/ccdiProject/components/detail/ProjectAnalysisDialog.vue +++ b/ruoyi-ui/src/views/ccdiProject/components/detail/ProjectAnalysisDialog.vue @@ -4,20 +4,61 @@ :visible.sync="visibleProxy" width="1280px" append-to-body - @close="handleClose" + custom-class="project-analysis-dialog" + @close="handleDialogClosed" > -
-
{{ person && person.name ? person.name : "项目分析" }}
-
- 当前来源:{{ source === "riskModelPeople" ? "命中模型涉及人员" : "风险人员总览" }} +
+ +
+ + +
+
异常明细
+
{{ getTabDescription("abnormalDetail") }}
+
+
+ +
+
资产分析
+
{{ getTabDescription("assetAnalysis") }}
+
+
+ +
+
征信摘要
+
{{ getTabDescription("creditSummary") }}
+
+
+ +
+
关系图谱
+
{{ getTabDescription("relationshipGraph") }}
+
+
+ +
+
资金流向
+
{{ getTabDescription("fundFlow") }}
+
+
+
diff --git a/ruoyi-ui/src/views/ccdiProject/components/detail/ProjectAnalysisSidebar.vue b/ruoyi-ui/src/views/ccdiProject/components/detail/ProjectAnalysisSidebar.vue new file mode 100644 index 00000000..6564a1cb --- /dev/null +++ b/ruoyi-ui/src/views/ccdiProject/components/detail/ProjectAnalysisSidebar.vue @@ -0,0 +1,144 @@ + + + + + diff --git a/ruoyi-ui/src/views/ccdiProject/components/detail/preliminaryCheck.mock.js b/ruoyi-ui/src/views/ccdiProject/components/detail/preliminaryCheck.mock.js index 5392e058..5c5bebb8 100644 --- a/ruoyi-ui/src/views/ccdiProject/components/detail/preliminaryCheck.mock.js +++ b/ruoyi-ui/src/views/ccdiProject/components/detail/preliminaryCheck.mock.js @@ -128,6 +128,93 @@ export const mockOverviewData = { }, }; +export const projectAnalysisTabs = [ + { + key: "abnormalDetail", + label: "异常明细", + description: "展示异常交易、频繁转账账户与关联交易的分析摘要。", + }, + { + key: "assetAnalysis", + label: "资产分析", + description: "静态承载资产分析页签内容,本轮不接入新接口。", + }, + { + key: "creditSummary", + label: "征信摘要", + description: "静态承载征信摘要页签内容,本轮不接入新接口。", + }, + { + key: "relationshipGraph", + label: "关系图谱", + description: "静态承载关系图谱页签内容,本轮不接入新接口。", + }, + { + key: "fundFlow", + label: "资金流向", + description: "静态承载资金流向页签内容,本轮不接入新接口。", + }, +]; + +function normalizeProjectAnalysisTags(person) { + const sourceTags = Array.isArray(person && person.riskPointTagList) + ? person.riskPointTagList + : Array.isArray(person && person.hitTagList) + ? person.hitTagList + : []; + + return sourceTags + .map((item) => { + if (typeof item === "string") { + return item; + } + if (item && typeof item === "object") { + return item.ruleName || item.label || item.name || ""; + } + return ""; + }) + .filter(Boolean); +} + +function resolveCurrentModel(person, source) { + if (source === "riskModelPeople") { + if (Array.isArray(person && person.modelNames) && person.modelNames.length) { + return person.modelNames.join("、"); + } + return person && person.modelName ? person.modelName : "-"; + } + + const firstTag = Array.isArray(person && person.riskPointTagList) ? person.riskPointTagList[0] : null; + if (firstTag && firstTag.modelName) { + return firstTag.modelName; + } + return "-"; +} + +export function buildProjectAnalysisDialogData({ person, source = "riskPeople", projectName = "" } = {}) { + const safePerson = person || {}; + const riskTags = normalizeProjectAnalysisTags(safePerson); + + return { + tabs: projectAnalysisTabs, + sidebar: { + basicInfo: { + name: safePerson.name || safePerson.staffName || "-", + staffCode: safePerson.staffCode || "-", + department: safePerson.department || "-", + riskLevel: safePerson.riskLevel || safePerson.warningType || "-", + projectName: projectName || safePerson.projectName || "-", + }, + modelSummary: { + modelCount: safePerson.modelCount || (Array.isArray(safePerson.modelNames) ? safePerson.modelNames.length : "-"), + currentModel: resolveCurrentModel(safePerson, source), + riskTags, + }, + recordSummary: "排查记录摘要为静态承载内容,本轮用于展示统一工作台侧栏结构。", + }, + }; +} + const summaryStatMetaMap = mockOverviewData.summary.stats.reduce((acc, item) => { acc[item.key] = { icon: item.icon, diff --git a/ruoyi-ui/tests/unit/project-analysis-dialog-default-tab.test.js b/ruoyi-ui/tests/unit/project-analysis-dialog-default-tab.test.js new file mode 100644 index 00000000..94c93f70 --- /dev/null +++ b/ruoyi-ui/tests/unit/project-analysis-dialog-default-tab.test.js @@ -0,0 +1,20 @@ +const assert = require("assert"); +const fs = require("fs"); +const path = require("path"); + +const dialog = fs.readFileSync( + path.resolve( + __dirname, + "../../src/views/ccdiProject/components/detail/ProjectAnalysisDialog.vue" + ), + "utf8" +); + +[ + 'activeTab: "abnormalDetail"', + "resetDialogState()", + 'this.activeTab = "abnormalDetail"', + "handleDialogClosed()", + "if (value) {", + "this.resetDialogState()", +].forEach((token) => assert(dialog.includes(token), token)); diff --git a/ruoyi-ui/tests/unit/project-analysis-dialog-layout.test.js b/ruoyi-ui/tests/unit/project-analysis-dialog-layout.test.js new file mode 100644 index 00000000..28ceae1c --- /dev/null +++ b/ruoyi-ui/tests/unit/project-analysis-dialog-layout.test.js @@ -0,0 +1,39 @@ +const assert = require("assert"); +const fs = require("fs"); +const path = require("path"); + +const dialog = fs.readFileSync( + path.resolve( + __dirname, + "../../src/views/ccdiProject/components/detail/ProjectAnalysisDialog.vue" + ), + "utf8" +); +const mockSource = fs.readFileSync( + path.resolve( + __dirname, + "../../src/views/ccdiProject/components/detail/preliminaryCheck.mock.js" + ), + "utf8" +); + +[ + 'title="项目分析"', + " assert(dialog.includes(token), token)); + +[ + "projectAnalysisTabs", + 'key: "abnormalDetail"', + 'key: "assetAnalysis"', + 'key: "creditSummary"', + 'key: "relationshipGraph"', + 'key: "fundFlow"', +].forEach((token) => assert(mockSource.includes(token), token)); diff --git a/ruoyi-ui/tests/unit/project-analysis-dialog-sidebar.test.js b/ruoyi-ui/tests/unit/project-analysis-dialog-sidebar.test.js new file mode 100644 index 00000000..7324b8b9 --- /dev/null +++ b/ruoyi-ui/tests/unit/project-analysis-dialog-sidebar.test.js @@ -0,0 +1,29 @@ +const assert = require("assert"); +const fs = require("fs"); +const path = require("path"); + +const sidebar = fs.readFileSync( + path.resolve( + __dirname, + "../../src/views/ccdiProject/components/detail/ProjectAnalysisSidebar.vue" + ), + "utf8" +); + +[ + "人员基础信息", + "命中模型摘要", + "排查记录摘要", + "姓名", + "工号", + "部门", + "风险等级", + "所属项目", + "命中模型数", + "当前命中模型", + "核心异常标签", + "暂无异常标签", +].forEach((token) => assert(sidebar.includes(token), token)); + +assert(!sidebar.includes("关系人画像"), "侧栏不应扩展到额外区块"); +assert(!sidebar.includes("资产分布"), "侧栏不应扩展到额外区块");