新增开发风险明细涉疑交易明细实施计划
This commit is contained in:
@@ -0,0 +1,347 @@
|
||||
# 开发风险明细涉疑交易明细后端 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:** 以后端结果总览专用接口承载本功能,不污染现有通用流水明细查询接口。查询以 `ccdi_bank_statement` 为基表,分别聚合“规则名称包含可疑”的命中结果和“交易对手方命中中介库”的命中结果,再按 `bank_statement_id` 去重输出展示所需业务字段。由于数据库当前缺少交易对手方证件号与统一社会信用代码字段,先补齐表结构、LSFX 响应映射和本地入库链路,再落查询聚合。
|
||||
|
||||
**Tech Stack:** Java 21, Spring Boot 3, MyBatis XML, MyBatis Plus `Page`, Maven, JUnit 5, Mockito, MySQL 8, ExcelUtil
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 补齐交易对手方身份字段入库链路
|
||||
|
||||
**Files:**
|
||||
- Create: `sql/migration/2026-03-27-ccdi-bank-statement-counterparty-identity-columns.sql`
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/entity/CcdiBankStatement.java`
|
||||
- Modify: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankStatementMapper.xml`
|
||||
- Modify: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/response/GetBankStatementResponse.java`
|
||||
- Modify: `lsfx-mock-server/models/response.py`
|
||||
- Modify: `lsfx-mock-server/services/statement_service.py`
|
||||
- Modify: `lsfx-mock-server/services/statement_rule_samples.py`
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/domain/entity/CcdiBankStatementTest.java`
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankStatementMapperXmlTest.java`
|
||||
- Test: `lsfx-mock-server/tests/test_statement_service.py`
|
||||
|
||||
- [ ] **Step 1: 先写失败测试,锁定新增字段名和映射行为**
|
||||
|
||||
```java
|
||||
@Test
|
||||
void testFromResponse_ShouldMapCounterpartyIdentityFields() {
|
||||
BankStatementItem item = new BankStatementItem();
|
||||
item.setCustomerCertNo("330101199001011234");
|
||||
item.setCustomerSocialCreditCode("91330100123456789X");
|
||||
|
||||
CcdiBankStatement entity = CcdiBankStatement.fromResponse(item);
|
||||
|
||||
assertEquals("330101199001011234", entity.getCustomerCertNo());
|
||||
assertEquals("91330100123456789X", entity.getCustomerSocialCreditCode());
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行测试,确认当前实现确实缺字段**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiBankStatementTest,CcdiBankStatementMapperXmlTest test
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `CcdiBankStatementTest` 编译失败或断言失败,提示缺少 `customerCertNo` / `customerSocialCreditCode`
|
||||
- `CcdiBankStatementMapperXmlTest` 尚未覆盖新列
|
||||
|
||||
- [ ] **Step 3: 实现最小字段补齐**
|
||||
|
||||
```sql
|
||||
ALTER TABLE `ccdi_bank_statement`
|
||||
ADD COLUMN `customer_cert_no` varchar(50) NULL COMMENT '交易对手方证件号' AFTER `customer_reference`,
|
||||
ADD COLUMN `customer_social_credit_code` varchar(50) NULL COMMENT '交易对手方统一社会信用代码' AFTER `customer_cert_no`;
|
||||
```
|
||||
|
||||
```java
|
||||
private String customerCertNo;
|
||||
private String customerSocialCreditCode;
|
||||
|
||||
entity.setCustomerCertNo(item.getCustomerCertNo());
|
||||
entity.setCustomerSocialCreditCode(item.getCustomerSocialCreditCode());
|
||||
```
|
||||
|
||||
```xml
|
||||
<result property="customerCertNo" column="customer_cert_no" />
|
||||
<result property="customerSocialCreditCode" column="customer_social_credit_code" />
|
||||
...
|
||||
customer_bank, customer_reference, customer_cert_no, customer_social_credit_code,
|
||||
...
|
||||
#{item.customerBank}, #{item.customerReference}, #{item.customerCertNo}, #{item.customerSocialCreditCode},
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 同步本地 LSFX mock 契约,保证联调可生成这两个字段**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
pytest lsfx-mock-server/tests/test_statement_service.py -v
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- mock 返回结构包含 `customerCertNo`
|
||||
- mock 返回结构包含 `customerSocialCreditCode`
|
||||
|
||||
- [ ] **Step 5: 提交本任务**
|
||||
|
||||
```bash
|
||||
git add sql/migration/2026-03-27-ccdi-bank-statement-counterparty-identity-columns.sql \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/entity/CcdiBankStatement.java \
|
||||
ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankStatementMapper.xml \
|
||||
ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/response/GetBankStatementResponse.java \
|
||||
lsfx-mock-server/models/response.py \
|
||||
lsfx-mock-server/services/statement_service.py \
|
||||
lsfx-mock-server/services/statement_rule_samples.py \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/domain/entity/CcdiBankStatementTest.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankStatementMapperXmlTest.java \
|
||||
lsfx-mock-server/tests/test_statement_service.py
|
||||
git commit -m "补齐涉疑交易明细对手方身份字段"
|
||||
```
|
||||
|
||||
### Task 2: 建立结果总览涉疑交易接口契约
|
||||
|
||||
**Files:**
|
||||
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectSuspiciousTransactionQueryDTO.java`
|
||||
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectSuspiciousTransactionItemVO.java`
|
||||
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectSuspiciousTransactionPageVO.java`
|
||||
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiProjectSuspiciousTransactionExcel.java`
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java`
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java`
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectOverviewServiceStructureTest.java`
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerContractTest.java`
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: 先加结构测试,锁定新 DTO、接口方法和控制器路由**
|
||||
|
||||
```java
|
||||
assertNotNull(clazz.getMethod(
|
||||
"getSuspiciousTransactions",
|
||||
Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectSuspiciousTransactionQueryDTO")
|
||||
));
|
||||
```
|
||||
|
||||
```java
|
||||
assertEquals("/suspicious-transactions", getMapping.value()[0]);
|
||||
assertEquals(List.of("projectId", "suspiciousType", "pageNum", "pageSize"), fieldNames);
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行控制器与结构测试,确认当前缺少接口**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceStructureTest,CcdiProjectOverviewControllerContractTest,CcdiProjectOverviewControllerTest test
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- 结构测试报 `NoSuchMethodException`
|
||||
- 控制器契约测试提示缺少 `/suspicious-transactions`
|
||||
|
||||
- [ ] **Step 3: 写最小 DTO / VO / Controller / Service 签名**
|
||||
|
||||
```java
|
||||
public class CcdiProjectSuspiciousTransactionQueryDTO {
|
||||
private Long projectId;
|
||||
private String suspiciousType;
|
||||
private Integer pageNum;
|
||||
private Integer pageSize;
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
@GetMapping("/suspicious-transactions")
|
||||
public AjaxResult getSuspiciousTransactions(CcdiProjectSuspiciousTransactionQueryDTO queryDTO) {
|
||||
return AjaxResult.success(overviewService.getSuspiciousTransactions(queryDTO));
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 增加导出接口契约**
|
||||
|
||||
```java
|
||||
@PostMapping("/suspicious-transactions/export")
|
||||
public void exportSuspiciousTransactions(HttpServletResponse response,
|
||||
CcdiProjectSuspiciousTransactionQueryDTO queryDTO) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceStructureTest,CcdiProjectOverviewControllerContractTest,CcdiProjectOverviewControllerTest test
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: 提交本任务**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectSuspiciousTransactionQueryDTO.java \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectSuspiciousTransactionItemVO.java \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectSuspiciousTransactionPageVO.java \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiProjectSuspiciousTransactionExcel.java \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectOverviewServiceStructureTest.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerContractTest.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerTest.java
|
||||
git commit -m "新增结果总览涉疑交易接口契约"
|
||||
```
|
||||
|
||||
### Task 3: 落地涉疑交易聚合 SQL 与服务逻辑
|
||||
|
||||
**Files:**
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java`
|
||||
- Modify: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml`
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java`
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java`
|
||||
- Create: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceSuspiciousTransactionTest.java`
|
||||
|
||||
- [ ] **Step 1: 先写 SQL 结构测试和服务测试,锁定去重与筛选口径**
|
||||
|
||||
```java
|
||||
assertTrue(suspiciousSql.contains("rule_name like '%可疑%'"));
|
||||
assertTrue(suspiciousSql.contains("ccdi_biz_intermediary"));
|
||||
assertTrue(suspiciousSql.contains("ccdi_enterprise_base_info"));
|
||||
assertTrue(suspiciousSql.contains("group by merged.bankStatementId"));
|
||||
```
|
||||
|
||||
```java
|
||||
assertEquals(1, result.getRows().size());
|
||||
assertTrue(result.getRows().getFirst().getHasModelRuleHit());
|
||||
assertTrue(result.getRows().getFirst().getHasNameListHit());
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行测试,确认当前尚无聚合查询实现**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewServiceSuspiciousTransactionTest test
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- SQL 测试找不到 `selectSuspiciousTransactionPage`
|
||||
- 服务测试编译失败或返回空实现
|
||||
|
||||
- [ ] **Step 3: 在 Mapper XML 中实现“三层聚合 + 按流水去重”**
|
||||
|
||||
```xml
|
||||
<select id="selectSuspiciousTransactionPage" resultType="com.ruoyi.ccdi.project.domain.vo.CcdiProjectSuspiciousTransactionItemVO">
|
||||
SELECT merged.bankStatementId,
|
||||
MAX(merged.trxDate) AS trxDate,
|
||||
MAX(merged.suspiciousPersonName) AS suspiciousPersonName,
|
||||
MAX(merged.relatedPersonName) AS relatedPersonName,
|
||||
MAX(merged.relatedStaffName) AS relatedStaffName,
|
||||
MAX(merged.relatedStaffCode) AS relatedStaffCode,
|
||||
MAX(merged.relationType) AS relationType,
|
||||
MAX(merged.userMemo) AS userMemo,
|
||||
MAX(merged.cashType) AS cashType,
|
||||
MAX(merged.displayAmount) AS displayAmount,
|
||||
MAX(merged.hasModelRuleHit) AS hasModelRuleHit,
|
||||
MAX(merged.hasNameListHit) AS hasNameListHit
|
||||
FROM (...)
|
||||
GROUP BY merged.bankStatementId
|
||||
</select>
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 在 Service 中补查询类型标准化、项目存在性校验和分页返回**
|
||||
|
||||
```java
|
||||
if (queryDTO.getSuspiciousType() == null || queryDTO.getSuspiciousType().isBlank()) {
|
||||
queryDTO.setSuspiciousType("ALL");
|
||||
}
|
||||
queryDTO.setSuspiciousType(queryDTO.getSuspiciousType().trim().toUpperCase());
|
||||
```
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewServiceSuspiciousTransactionTest,CcdiProjectOverviewServiceImplTest test
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: 提交本任务**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java \
|
||||
ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceSuspiciousTransactionTest.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java
|
||||
git commit -m "实现结果总览涉疑交易聚合查询"
|
||||
```
|
||||
|
||||
### Task 4: 接通导出与回归验证
|
||||
|
||||
**Files:**
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java`
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java`
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java`
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerTest.java`
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerContractTest.java`
|
||||
|
||||
- [ ] **Step 1: 先补导出控制器测试**
|
||||
|
||||
```java
|
||||
Method method = CcdiProjectOverviewController.class.getMethod(
|
||||
"exportSuspiciousTransactions",
|
||||
HttpServletResponse.class,
|
||||
CcdiProjectSuspiciousTransactionQueryDTO.class
|
||||
);
|
||||
assertEquals("/suspicious-transactions/export", postMapping.value()[0]);
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行导出相关测试,确认导出接口尚未闭环**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiProjectOverviewControllerTest,CcdiProjectOverviewControllerContractTest test
|
||||
```
|
||||
|
||||
Expected: FAIL,提示导出接口缺失或未调用服务
|
||||
|
||||
- [ ] **Step 3: 实现导出列表查询与 Excel 输出**
|
||||
|
||||
```java
|
||||
List<CcdiProjectSuspiciousTransactionExcel> rows = overviewService.exportSuspiciousTransactions(queryDTO);
|
||||
ExcelUtil<CcdiProjectSuspiciousTransactionExcel> util = new ExcelUtil<>(CcdiProjectSuspiciousTransactionExcel.class);
|
||||
util.exportExcel(response, rows, "涉疑交易明细");
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 运行后端回归测试**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiBankStatementTest,CcdiBankStatementMapperXmlTest,CcdiProjectOverviewServiceStructureTest,CcdiProjectOverviewControllerContractTest,CcdiProjectOverviewControllerTest,CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewServiceImplTest,CcdiProjectOverviewServiceSuspiciousTransactionTest test
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: 提交本任务**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerTest.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerContractTest.java
|
||||
git commit -m "接通结果总览涉疑交易导出能力"
|
||||
```
|
||||
@@ -0,0 +1,302 @@
|
||||
# 开发风险明细涉疑交易明细前端 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 "接通结果总览涉疑交易详情与导出"
|
||||
```
|
||||
@@ -0,0 +1,31 @@
|
||||
# 开发风险明细涉疑交易明细实施计划记录
|
||||
|
||||
## 本次改动
|
||||
|
||||
- 新增后端实施计划:
|
||||
- `docs/plans/backend/2026-03-27-development-risk-suspicious-transaction-detail-backend-implementation.md`
|
||||
- 新增前端实施计划:
|
||||
- `docs/plans/frontend/2026-03-27-development-risk-suspicious-transaction-detail-frontend-implementation.md`
|
||||
|
||||
## 计划拆分结果
|
||||
|
||||
- 后端计划聚焦三件事:
|
||||
- 补齐交易对手方证件号与统一社会信用代码的入库链路
|
||||
- 新增结果总览涉疑交易列表与导出接口
|
||||
- 实现“规则命中 + 名单库命中”聚合 SQL 与回归测试
|
||||
|
||||
- 前端计划聚焦三件事:
|
||||
- 新增结果总览涉疑交易接口封装
|
||||
- 将 `PreliminaryCheck.vue` 从 mock 风险明细切换到真实加载
|
||||
- 改造 `RiskDetailSection.vue`,复用流水详情弹窗并接通导出
|
||||
|
||||
## 文档落点检查
|
||||
|
||||
- 后端计划已放入:`docs/plans/backend/`
|
||||
- 前端计划已放入:`docs/plans/frontend/`
|
||||
- 本次计划记录已放入:`docs/reports/implementation/`
|
||||
|
||||
## 说明
|
||||
|
||||
- 依据仓库 `AGENTS.md` 约束,本轮未启用 subagent 审核流程
|
||||
- 下一步可直接按计划在当前会话使用执行型流程落地
|
||||
Reference in New Issue
Block a user