303 lines
9.6 KiB
Markdown
303 lines
9.6 KiB
Markdown
# 开发风险明细涉疑交易明细前端 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
|
||
<el-dropdown @command="handleSuspiciousTypeChange">
|
||
<span class="el-dropdown-link">{{ currentSuspiciousTypeLabel }}</span>
|
||
</el-dropdown>
|
||
|
||
<el-table-column prop="trxDate" label="交易时间" />
|
||
<el-table-column prop="suspiciousPersonName" label="可疑人员" />
|
||
<el-table-column prop="relatedPersonName" label="关联人" />
|
||
<el-table-column label="关联员工">
|
||
<template slot-scope="scope">{{ formatRelatedStaff(scope.row) }}</template>
|
||
</el-table-column>
|
||
```
|
||
|
||
- [ ] **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 "接通结果总览涉疑交易详情与导出"
|
||
```
|