# 开发风险明细涉疑交易明细前端 Implementation Plan > **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. > > **Repo note:** 本仓库 `AGENTS.md` 明确禁止开启 subagent,执行本计划时请在当前会话使用 `superpowers:executing-plans`。 **Goal:** 在结果总览页的“风险明细”区块内实现真实“涉疑交易明细”表格,支持来源切换、导出和查看详情,并保持表格与流水详情样式和“流水明细查询”页面一致。 **Architecture:** 前端继续以 `PreliminaryCheck.vue` 作为结果总览入口,通过 `projectOverview.js` 新增结果总览涉疑交易接口封装,在父组件加载后将数据注入 `RiskDetailSection.vue`。`RiskDetailSection.vue` 负责呈现筛选下拉、真实业务列、详情弹窗与导出按钮;详情接口直接复用 `ccdiProjectBankStatement.js` 中已有的 `getBankStatementDetail`。 **Tech Stack:** Vue 2, Element UI, RuoYi 全局 `download`, Node `assert` 单测, axios request 封装 --- ### Task 1: 新增结果总览涉疑交易前端 API 契约 **Files:** - Modify: `ruoyi-ui/src/api/ccdi/projectOverview.js` - Test: `ruoyi-ui/tests/unit/project-overview-api.test.js` - [ ] **Step 1: 先补 API 契约测试,锁定新接口名和参数透传** ```js [ "getOverviewSuspiciousTransactions", "/ccdi/project/overview/suspicious-transactions", "projectId: params.projectId", "suspiciousType: params.suspiciousType", "pageNum: params.pageNum", "pageSize: params.pageSize", ].forEach((token) => assert(source.includes(token), token)); ``` - [ ] **Step 2: 运行测试,确认新接口尚未接入** Run: ```bash node ruoyi-ui/tests/unit/project-overview-api.test.js ``` Expected: FAIL,提示缺少 `getOverviewSuspiciousTransactions` - [ ] **Step 3: 写最小 API 封装** ```js export function getOverviewSuspiciousTransactions(params) { return request({ url: "/ccdi/project/overview/suspicious-transactions", method: "get", params: { projectId: params.projectId, suspiciousType: params.suspiciousType, pageNum: params.pageNum, pageSize: params.pageSize, }, }); } ``` - [ ] **Step 4: 回跑 API 契约测试** Run: ```bash node ruoyi-ui/tests/unit/project-overview-api.test.js ``` Expected: PASS - [ ] **Step 5: 提交本任务** ```bash git add ruoyi-ui/src/api/ccdi/projectOverview.js \ ruoyi-ui/tests/unit/project-overview-api.test.js git commit -m "新增结果总览涉疑交易前端接口" ``` ### Task 2: 把结果总览父组件接到真实涉疑交易数据 **Files:** - Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue` - Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/preliminaryCheck.mock.js` - Test: `ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js` - Create: `ruoyi-ui/tests/unit/preliminary-check-suspicious-transaction-load.test.js` - [ ] **Step 1: 先写失败测试,锁定父组件加载新接口和风险明细数据结构** ```js assert(source.includes("getOverviewSuspiciousTransactions"), "结果总览应加载涉疑交易接口"); assert(source.includes("riskDetails"), "结果总览应继续向 RiskDetailSection 注入 riskDetails"); assert(source.includes("suspiciousTransactionList"), "mock 归一化应保留涉疑交易列表"); ``` - [ ] **Step 2: 运行测试,确认当前仍是 mock 空数组** Run: ```bash node ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js node ruoyi-ui/tests/unit/preliminary-check-suspicious-transaction-load.test.js ``` Expected: - 旧测试仍只认“涉险交易明细” - 新测试提示未加载涉疑交易接口 - [ ] **Step 3: 在父组件中并行加载涉疑交易接口,并改造 mock 归一化函数** ```js const [dashboardRes, riskPeopleRes, riskModelCardsRes, suspiciousRes] = await Promise.all([ getOverviewDashboard(this.projectId), getOverviewRiskPeople(this.projectId), getOverviewRiskModelCards(this.projectId), getOverviewSuspiciousTransactions({ projectId: this.projectId, suspiciousType: "ALL", pageNum: 1, pageSize: 10, }), ]); ``` ```js riskDetails: { suspiciousTransactionList: normalizeSuspiciousTransactions(suspiciousData && suspiciousData.rows), suspiciousType: "ALL", total: suspiciousData && suspiciousData.total ? suspiciousData.total : 0, abnormalAccountList: [], } ``` - [ ] **Step 4: 回跑父组件相关测试** Run: ```bash node ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js node ruoyi-ui/tests/unit/preliminary-check-suspicious-transaction-load.test.js ``` Expected: PASS - [ ] **Step 5: 提交本任务** ```bash git add ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue \ ruoyi-ui/src/views/ccdiProject/components/detail/preliminaryCheck.mock.js \ ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js \ ruoyi-ui/tests/unit/preliminary-check-suspicious-transaction-load.test.js git commit -m "接通结果总览涉疑交易数据加载" ``` ### Task 3: 重写 RiskDetailSection 的涉疑交易表格列和筛选交互 **Files:** - Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue` - Test: `ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js` - Create: `ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-layout.test.js` - [ ] **Step 1: 先写失败测试,锁定下拉项、业务列和新标题** ```js [ "涉疑交易明细", "全部可疑人员类型", "名单库命中", "模型规则命中", "可疑人员", "关联人", "关联员工", "关系", "摘要/交易类型", ].forEach((token) => assert(source.includes(token), token)); ``` - [ ] **Step 2: 运行测试,确认当前仍是旧占位表格** Run: ```bash node ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js node ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-layout.test.js ``` Expected: FAIL,提示仍存在“涉险交易明细 / 对手方 / 方向 / 账号” - [ ] **Step 3: 写最小 UI 改造** ```vue {{ currentSuspiciousTypeLabel }} ``` - [ ] **Step 4: 回跑布局测试** Run: ```bash node ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js node ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-layout.test.js ``` Expected: PASS - [ ] **Step 5: 提交本任务** ```bash git add ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue \ ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js \ ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-layout.test.js git commit -m "改造结果总览涉疑交易表格结构" ``` ### Task 4: 复用流水详情弹窗与导出能力,并做前端回归 **Files:** - Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue` - Modify: `ruoyi-ui/src/api/ccdi/projectOverview.js` - Reuse: `ruoyi-ui/src/api/ccdiProjectBankStatement.js` - Test: `ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-layout.test.js` - Create: `ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-detail-dialog.test.js` - [ ] **Step 1: 先写失败测试,锁定详情复用与导出路径** ```js [ "getBankStatementDetail", "detailVisible", "handleViewDetail", "this.download(", "ccdi/project/overview/suspicious-transactions/export", ].forEach((token) => assert(source.includes(token), token)); ``` - [ ] **Step 2: 运行测试,确认详情与导出还未接通** Run: ```bash node ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-layout.test.js node ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-detail-dialog.test.js ``` Expected: FAIL,提示未复用 `getBankStatementDetail` 或未指向新导出路径 - [ ] **Step 3: 在 RiskDetailSection 中复用 DetailQuery 的详情弹窗结构和金额/标签格式化** ```js import { getBankStatementDetail } from "@/api/ccdiProjectBankStatement"; async handleViewDetail(row) { const response = await getBankStatementDetail(row.bankStatementId); this.detailData = normalizeDetailData(response.data); this.detailVisible = true; } handleExport() { this.download( "ccdi/project/overview/suspicious-transactions/export", { projectId: this.projectId, suspiciousType: this.currentSuspiciousType }, `涉疑交易明细_${new Date().getTime()}.xlsx` ); } ``` - [ ] **Step 4: 跑前端回归检查** Run: ```bash node ruoyi-ui/tests/unit/project-overview-api.test.js node ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js node ruoyi-ui/tests/unit/preliminary-check-suspicious-transaction-load.test.js node ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-layout.test.js node ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-detail-dialog.test.js cd ruoyi-ui && npm run build:prod ``` Expected: - 所有 Node 断言测试 PASS - `npm run build:prod` 成功产出构建结果 - [ ] **Step 5: 提交本任务** ```bash git add ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue \ ruoyi-ui/src/api/ccdi/projectOverview.js \ ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-layout.test.js \ ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-detail-dialog.test.js git commit -m "接通结果总览涉疑交易详情与导出" ```