diff --git a/docs/plans/backend/2026-03-31-project-detail-risk-details-abnormal-account-backend-implementation-plan.md b/docs/plans/backend/2026-03-31-project-detail-risk-details-abnormal-account-backend-implementation-plan.md new file mode 100644 index 00000000..dbb25ee6 --- /dev/null +++ b/docs/plans/backend/2026-03-31-project-detail-risk-details-abnormal-account-backend-implementation-plan.md @@ -0,0 +1,523 @@ +# 项目详情风险明细异常账户人员信息后端 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. +> +> 仓库约束:当前仓库明确禁止开启 subagent,执行时统一使用 `superpowers:executing-plans`。 + +**Goal:** 为项目详情风险明细补齐“异常账户人员信息”的真实后端查询与统一导出能力,让页面展示和第 3 个 Excel sheet 共用同一套异常账户明细口径。 + +**Architecture:** 在结果总览域内新增异常账户分页查询接口和非分页导出查询,数据源直接使用 `ccdi_bank_statement_tag_result + ccdi_account_info`,按“一条命中结果一行”返回。统一导出继续复用 `POST /ccdi/project/overview/risk-details/export`,仅将第 3 个 sheet 从空表头改为真实数据写出,不新增平行导出接口。 + +**Tech Stack:** Java 21, Spring Boot 3, MyBatis Plus Page, MyBatis XML, Apache POI, JUnit 5, Mockito + +--- + +## File Map + +**Create:** + +- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectAbnormalAccountQueryDTO.java` + - 结果总览异常账户分页查询入参,仅承载 `projectId/pageNum/pageSize` +- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectAbnormalAccountItemVO.java` + - 异常账户单行展示对象,字段与页面列一致 +- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectAbnormalAccountPageVO.java` + - 异常账户分页返回对象,统一承载 `rows/total` +- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiProjectAbnormalAccountExcel.java` + - `异常账户人员信息` sheet 行对象 +- `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceAbnormalAccountTest.java` + - 单独覆盖异常账户分页与导出映射 + +**Modify:** + +- `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/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java` + - 新增异常账户分页与导出查询声明 +- `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml` + - 新增异常账户基础 SQL、分页 SQL、导出 SQL +- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporter.java` + - 第 3 个 sheet 改为写出真实异常账户数据 +- `ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerTest.java` + - 覆盖新分页接口委托行为 +- `ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerContractTest.java` + - 覆盖新接口路径、注解与参数签名 +- `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java` + - 更新统一导出测试,断言第 3 个 sheet 已传入真实数据 +- `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporterTest.java` + - 更新工作簿导出断言,校验异常账户真实数据行 +- `ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java` + - 覆盖异常账户分页与导出 SQL 口径 +- `docs/reports/implementation/2026-03-31-project-detail-risk-details-abnormal-account-backend-implementation.md` + - 记录后端实施细节与验证结果 + +## Task 1: 锁定结果总览异常账户分页接口契约 + +**Files:** + +- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectAbnormalAccountQueryDTO.java` +- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectAbnormalAccountPageVO.java` +- 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/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerTest.java` +- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerContractTest.java` + +- [ ] **Step 1: 先写控制器契约测试** + +在 `CcdiProjectOverviewControllerContractTest` 中新增对新方法的反射断言: + +```java +Method method = controllerClass.getMethod( + "getAbnormalAccountPeople", + CcdiProjectAbnormalAccountQueryDTO.class +); +GetMapping getMapping = method.getAnnotation(GetMapping.class); +assertEquals("/abnormal-account-people", getMapping.value()[0]); +``` + +同时断言: + +- 存在 `@Operation(summary = "查询异常账户人员信息")` +- 存在 `@PreAuthorize("@ss.hasPermi('ccdi:project:query')")` + +- [ ] **Step 2: 再写控制器委托单测,先让它失败** + +在 `CcdiProjectOverviewControllerTest` 中新增测试: + +```java +CcdiProjectAbnormalAccountQueryDTO queryDTO = new CcdiProjectAbnormalAccountQueryDTO(); +queryDTO.setProjectId(40L); +when(overviewService.getAbnormalAccountPeople(queryDTO)).thenReturn(pageVO); + +AjaxResult result = controller.getAbnormalAccountPeople(queryDTO); + +verify(overviewService).getAbnormalAccountPeople(same(queryDTO)); +assertSame(pageVO, result.get("data")); +``` + +- [ ] **Step 3: 运行控制器定向测试确认失败点正确** + +Run: + +```bash +mvn -pl ccdi-project -am \ + -Dsurefire.failIfNoSpecifiedTests=false \ + -Dtest=CcdiProjectOverviewControllerContractTest,CcdiProjectOverviewControllerTest \ + test +``` + +Expected: + +- FAIL,提示缺少 `getAbnormalAccountPeople` 方法、DTO 或服务接口方法 + +- [ ] **Step 4: 最小化补齐控制器与接口骨架** + +1. 创建 `CcdiProjectAbnormalAccountQueryDTO` +2. 创建 `CcdiProjectAbnormalAccountPageVO` +3. 在 `ICcdiProjectOverviewService` 增加: + +```java +default CcdiProjectAbnormalAccountPageVO getAbnormalAccountPeople( + CcdiProjectAbnormalAccountQueryDTO queryDTO +) { + return new CcdiProjectAbnormalAccountPageVO(); +} +``` + +4. 在控制器中增加: + +```java +@GetMapping("/abnormal-account-people") +@Operation(summary = "查询异常账户人员信息") +@PreAuthorize("@ss.hasPermi('ccdi:project:query')") +public AjaxResult getAbnormalAccountPeople(CcdiProjectAbnormalAccountQueryDTO queryDTO) { + CcdiProjectAbnormalAccountPageVO pageVO = overviewService.getAbnormalAccountPeople(queryDTO); + return AjaxResult.success(pageVO); +} +``` + +- [ ] **Step 5: 重新运行控制器测试** + +Run: + +```bash +mvn -pl ccdi-project -am \ + -Dsurefire.failIfNoSpecifiedTests=false \ + -Dtest=CcdiProjectOverviewControllerContractTest,CcdiProjectOverviewControllerTest \ + test +``` + +Expected: + +- PASS + +- [ ] **Step 6: 提交本任务** + +```bash +git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectAbnormalAccountQueryDTO.java \ + ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectAbnormalAccountPageVO.java \ + 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/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 2: 补齐异常账户分页与导出 SQL 口径 + +**Files:** + +- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectAbnormalAccountItemVO.java` +- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiProjectAbnormalAccountExcel.java` +- 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/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java` + +- [ ] **Step 1: 先写 Mapper SQL 测试** + +在 `CcdiProjectOverviewMapperSqlTest` 中新增两个 select 断言: + +```java +String abnormalPageSql = extractSelect(xml, "selectAbnormalAccountPage"); +String abnormalExportSql = extractSelect(xml, "selectAbnormalAccountList"); + +assertTrue(abnormalPageSql.contains("tr.model_code = 'ABNORMAL_ACCOUNT'"), abnormalPageSql); +assertTrue(abnormalPageSql.contains("tr.bank_statement_id is null"), abnormalPageSql); +assertTrue(abnormalPageSql.contains("account.owner_type = 'EMPLOYEE'"), abnormalPageSql); +assertTrue(abnormalPageSql.contains("tr.reason_detail"), abnormalPageSql); +assertTrue(abnormalExportSql.contains("order by abnormal_time desc"), abnormalExportSql); +``` + +同时补充对状态映射和规则时间字段的静态断言: + +- `when account.status = 1 then '正常'` +- `when account.status = 2 then '已销户'` +- `when tr.rule_code = 'SUDDEN_ACCOUNT_CLOSURE'` +- `when tr.rule_code = 'DORMANT_ACCOUNT_LARGE_ACTIVATION'` + +- [ ] **Step 2: 运行 SQL 测试确认失败** + +Run: + +```bash +mvn -pl ccdi-project -am \ + -Dsurefire.failIfNoSpecifiedTests=false \ + -Dtest=CcdiProjectOverviewMapperSqlTest \ + test +``` + +Expected: + +- FAIL,提示缺少 `selectAbnormalAccountPage` 或 `selectAbnormalAccountList` + +- [ ] **Step 3: 设计基础 SQL 片段,再补 Mapper 方法签名** + +在 `CcdiProjectOverviewMapper.java` 中新增: + +```java +Page selectAbnormalAccountPage( + Page page, + @Param("query") CcdiProjectAbnormalAccountQueryDTO query +); + +List selectAbnormalAccountList(@Param("projectId") Long projectId); +``` + +在 XML 中先抽出基础 SQL 片段: + +- `abnormalAccountBaseSql` +- 统一负责: + - 项目过滤 + - `ABNORMAL_ACCOUNT` 模型过滤 + - 对象型结果过滤 + - `owner_type = 'EMPLOYEE'` + - 账号唯一关联 + - `账号 / 开户人 / 银行 / 异常类型 / 异常发生时间 / 状态` 映射 + +- [ ] **Step 4: 实现分页 SQL 与导出 SQL** + +分页 SQL: + +- 使用 `#{query.projectId}` +- 按 `abnormal_time desc, account.account_no asc, tr.rule_code asc` + +导出 SQL: + +- 使用 `#{projectId}` +- 与分页 SQL 保持同一列集合与同一排序规则 + +账号唯一关联要求: + +- 优先通过 `tr.reason_detail` 中包含的账号匹配 `account.account_no` +- 没有账号匹配条件时不要把员工名下全部账户笛卡尔展开 + +- [ ] **Step 5: 重新运行 SQL 测试** + +Run: + +```bash +mvn -pl ccdi-project -am \ + -Dsurefire.failIfNoSpecifiedTests=false \ + -Dtest=CcdiProjectOverviewMapperSqlTest \ + test +``` + +Expected: + +- PASS + +- [ ] **Step 6: 提交本任务** + +```bash +git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectAbnormalAccountItemVO.java \ + ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiProjectAbnormalAccountExcel.java \ + 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/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java +git commit -m "补充异常账户人员查询SQL" +``` + +## Task 3: 完成服务层分页映射与项目校验 + +**Files:** + +- 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` +- Create: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceAbnormalAccountTest.java` + +- [ ] **Step 1: 先写服务层失败测试** + +在 `CcdiProjectOverviewServiceAbnormalAccountTest` 中新增 4 个测试: + +1. 分页查询返回 `rows/total` +2. 分页查询默认页码为 `1`、分页大小为 `5` +3. 导出查询返回 `List` +4. 项目不存在时,分页与导出都抛 `ServiceException` + +核心断言示例: + +```java +CcdiProjectAbnormalAccountPageVO result = service.getAbnormalAccountPeople(queryDTO); +assertEquals(1, result.getRows().size()); +assertEquals("突然销户", result.getRows().getFirst().getAbnormalType()); +verify(overviewMapper).selectAbnormalAccountPage(any(Page.class), any(CcdiProjectAbnormalAccountQueryDTO.class)); +``` + +- [ ] **Step 2: 跑服务层测试确认失败** + +Run: + +```bash +mvn -pl ccdi-project -am \ + -Dsurefire.failIfNoSpecifiedTests=false \ + -Dtest=CcdiProjectOverviewServiceAbnormalAccountTest \ + test +``` + +Expected: + +- FAIL,提示缺少服务方法、Mapper 调用或 Excel 映射 + +- [ ] **Step 3: 实现最小服务层逻辑** + +在 `ICcdiProjectOverviewService` 中新增: + +```java +default List exportAbnormalAccountPeople(Long projectId) { + return List.of(); +} +``` + +在 `CcdiProjectOverviewServiceImpl` 中实现: + +1. `getAbnormalAccountPeople(queryDTO)` +2. `exportAbnormalAccountPeople(projectId)` +3. `buildAbnormalAccountExcelRow(...)` + +实现要求: + +- 先 `ensureProjectExists(...)` +- 分页默认值沿用现有结果总览风格 +- 页面 VO 和 Excel 行对象字段完全同构 + +- [ ] **Step 4: 重新运行服务层测试** + +Run: + +```bash +mvn -pl ccdi-project -am \ + -Dsurefire.failIfNoSpecifiedTests=false \ + -Dtest=CcdiProjectOverviewServiceAbnormalAccountTest \ + test +``` + +Expected: + +- PASS + +- [ ] **Step 5: 提交本任务** + +```bash +git add 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/service/impl/CcdiProjectOverviewServiceAbnormalAccountTest.java +git commit -m "补充异常账户人员服务映射" +``` + +## Task 4: 将异常账户真实数据接入统一导出工作簿 + +**Files:** + +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java` +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporter.java` +- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java` +- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporterTest.java` + +- [ ] **Step 1: 先改统一导出测试,让它要求第 3 个 sheet 有真实数据** + +在 `CcdiProjectRiskDetailWorkbookExporterTest` 中把原先“只有表头”改成: + +```java +CcdiProjectAbnormalAccountExcel abnormalRow = new CcdiProjectAbnormalAccountExcel(); +abnormalRow.setAccountNo("6222000000000001"); +abnormalRow.setAccountName("李四"); +abnormalRow.setBankName("中国农业银行"); +abnormalRow.setAbnormalType("突然销户"); +abnormalRow.setAbnormalTime("2026-03-20"); +abnormalRow.setStatus("已销户"); +``` + +断言: + +- sheet 名仍为 `异常账户人员信息` +- 第 1 行写出真实数据 +- 列顺序依次为: + - `账号` + - `开户人` + - `银行` + - `异常类型` + - `异常发生时间` + - `状态` + +- [ ] **Step 2: 再改服务层统一导出测试** + +在 `CcdiProjectOverviewServiceImplTest.shouldExportRiskDetailsWorkbook` 中增加异常账户 stub: + +```java +when(overviewMapper.selectAbnormalAccountList(40L)).thenReturn(List.of(abnormalItem)); +``` + +并把 `verify(workbookExporter).export(...)` 扩展为包含第 3 个参数列表断言。 + +- [ ] **Step 3: 运行导出相关测试确认失败** + +Run: + +```bash +mvn -pl ccdi-project -am \ + -Dsurefire.failIfNoSpecifiedTests=false \ + -Dtest=CcdiProjectOverviewServiceImplTest,CcdiProjectRiskDetailWorkbookExporterTest \ + test +``` + +Expected: + +- FAIL,提示导出器方法签名或第 3 个 sheet 断言不匹配 + +- [ ] **Step 4: 最小化修改导出器与服务** + +1. 将 `CcdiProjectRiskDetailWorkbookExporter.export(...)` 方法签名扩为接收异常账户列表 +2. `writeAbnormalAccountSheet(...)` 从“只写表头”改成“表头 + 数据行” +3. `CcdiProjectOverviewServiceImpl.exportRiskDetails(...)` 中查询 `exportAbnormalAccountPeople(projectId)` +4. 调用导出器时一并传入异常账户列表 + +- [ ] **Step 5: 重新运行导出相关测试** + +Run: + +```bash +mvn -pl ccdi-project -am \ + -Dsurefire.failIfNoSpecifiedTests=false \ + -Dtest=CcdiProjectOverviewServiceImplTest,CcdiProjectRiskDetailWorkbookExporterTest \ + test +``` + +Expected: + +- PASS + +- [ ] **Step 6: 提交本任务** + +```bash +git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java \ + ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporter.java \ + ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java \ + ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporterTest.java +git commit -m "补充风险明细异常账户统一导出" +``` + +## Task 5: 记录实施结果并做最终回归 + +**Files:** + +- Modify: `docs/reports/implementation/2026-03-31-project-detail-risk-details-abnormal-account-backend-implementation.md` + +- [ ] **Step 1: 运行后端最终回归测试** + +Run: + +```bash +mvn -pl ccdi-project -am \ + -Dsurefire.failIfNoSpecifiedTests=false \ + -Dtest=CcdiProjectOverviewControllerContractTest,CcdiProjectOverviewControllerTest,CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewServiceAbnormalAccountTest,CcdiProjectOverviewServiceImplTest,CcdiProjectRiskDetailWorkbookExporterTest \ + test +``` + +Expected: + +- PASS + +- [ ] **Step 2: 如需手工联调,启动后端并验证后立即关闭** + +Run: + +```bash +mvn -pl ruoyi-admin -am package -DskipTests +cd ruoyi-admin/target && java -jar ruoyi-admin.jar +``` + +至少验证: + +1. `GET /ccdi/project/overview/abnormal-account-people` 可返回 `rows/total` +2. `POST /ccdi/project/overview/risk-details/export` 第 3 个 sheet 含真实异常账户数据 + +验证结束后必须关闭 `java -jar ruoyi-admin.jar` 进程。 + +- [ ] **Step 3: 编写后端实施记录** + +在实施记录中写清: + +- 新增接口路径 +- 新增 DTO/VO/Excel 对象 +- Mapper SQL 口径 +- 统一导出第 3 个 sheet 的真实化改动 +- 自动化测试命令与结果 +- 如有手工联调,记录启动与关闭进程情况 + +- [ ] **Step 4: 提交本任务** + +```bash +git add docs/reports/implementation/2026-03-31-project-detail-risk-details-abnormal-account-backend-implementation.md +git commit -m "记录异常账户人员信息后端实施" +``` + +## Final Verification + +- [ ] `GET /ccdi/project/overview/abnormal-account-people` 返回字段完整:`accountNo/accountName/bankName/abnormalType/abnormalTime/status` +- [ ] 页面查询与导出查询都只取 `ABNORMAL_ACCOUNT` 对象型结果 +- [ ] 第 3 个 sheet 不再是空白模板 +- [ ] 同一账号命中多条规则时保留多行 +- [ ] 如启动了后端进程,验证结束后已手动关闭 diff --git a/docs/plans/frontend/2026-03-31-project-detail-risk-details-abnormal-account-frontend-implementation-plan.md b/docs/plans/frontend/2026-03-31-project-detail-risk-details-abnormal-account-frontend-implementation-plan.md new file mode 100644 index 00000000..64c408be --- /dev/null +++ b/docs/plans/frontend/2026-03-31-project-detail-risk-details-abnormal-account-frontend-implementation-plan.md @@ -0,0 +1,350 @@ +# 项目详情风险明细异常账户人员信息前端 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. +> +> 仓库约束:当前仓库明确禁止开启 subagent,执行时统一使用 `superpowers:executing-plans`。 + +**Goal:** 将 `RiskDetailSection.vue` 中的“异常账户人员信息”从占位表格改为真实接口驱动的列表,并与统一导出的 6 个字段保持一致。 + +**Architecture:** 前端保持最小改动,继续复用 `RiskDetailSection.vue` 内现有的独立分区加载模式,为异常账户区块补一套与员工负面征信相同风格的 `loading/pageNum/pageSize/total/list` 状态。数据请求通过 `@/api/ccdi/projectOverview` 新增一个轻量 GET 方法,不改 `PreliminaryCheck.vue` 的页面编排逻辑。 + +**Tech Stack:** Vue 2, Element UI, RuoYi request 封装, Node 静态单测, Vue CLI 构建 + +--- + +## File Map + +**Create:** + +- `ruoyi-ui/tests/unit/risk-detail-abnormal-account-layout.test.js` + - 覆盖异常账户区块的真实列结构和空态文案 +- `ruoyi-ui/tests/unit/risk-detail-abnormal-account-pagination.test.js` + - 覆盖异常账户独立分页状态与加载方法 + +**Modify:** + +- `ruoyi-ui/src/api/ccdi/projectOverview.js` + - 新增异常账户分页查询 API 封装 +- `ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue` + - 接入真实异常账户列表、独立分页、独立 loading、移除旧占位操作列 +- `ruoyi-ui/src/views/ccdiProject/components/detail/preliminaryCheck.mock.js` + - 对齐 mock 中异常账户字段名,避免静态预览口径落后于真实页面 +- `ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js` + - 更新旧断言,移除对“查看详情”的占位依赖 +- `docs/reports/implementation/2026-03-31-project-detail-risk-details-abnormal-account-frontend-implementation.md` + - 记录前端实施与验证结果 + +**No Change Expected:** + +- `ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue` + - 仍只负责把 `projectId` 传给 `RiskDetailSection` + +## Task 1: 锁定异常账户区块的静态结构与测试期望 + +**Files:** + +- Create: `ruoyi-ui/tests/unit/risk-detail-abnormal-account-layout.test.js` +- Modify: `ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js` + +- [ ] **Step 1: 先写新的静态布局测试** + +创建 `risk-detail-abnormal-account-layout.test.js`,直接读取 `RiskDetailSection.vue` 源码并断言以下 token: + +```js +[ + "异常账户人员信息", + "账号", + "开户人", + "银行", + "异常类型", + "异常发生时间", + "状态", + "当前项目暂无异常账户人员信息", +] +``` + +- [ ] **Step 2: 更新旧测试,先让它失败** + +在 `preliminary-check-model-and-detail.test.js` 中把这一段: + +```js +["风险明细", "涉疑交易明细", "异常账户人员信息", "查看详情"] +``` + +改成断言新的异常账户列名,不再要求旧占位的“查看详情”。 + +- [ ] **Step 3: 运行静态单测确认失败** + +Run: + +```bash +cd ruoyi-ui +node tests/unit/risk-detail-abnormal-account-layout.test.js +node tests/unit/preliminary-check-model-and-detail.test.js +``` + +Expected: + +- FAIL,提示 `RiskDetailSection.vue` 仍包含旧列结构或缺少新字段 + +- [ ] **Step 4: 提交本任务** + +本任务先不提交,等待真实模板改完后与 Task 2 一起提交。 + +## Task 2: 接入异常账户真实 API 与独立分页状态 + +**Files:** + +- Modify: `ruoyi-ui/src/api/ccdi/projectOverview.js` +- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue` +- Create: `ruoyi-ui/tests/unit/risk-detail-abnormal-account-pagination.test.js` + +- [ ] **Step 1: 先写分页/加载相关静态测试** + +创建 `risk-detail-abnormal-account-pagination.test.js`,断言源码已包含: + +- `getOverviewAbnormalAccountPeople` +- `abnormalAccountLoading` +- `abnormalAccountPageNum` +- `abnormalAccountPageSize` +- `abnormalAccountTotal` +- `abnormalAccountList` +- `handleAbnormalAccountPageChange` +- `loadAbnormalAccountPeople` + +- [ ] **Step 2: 跑静态测试确认失败** + +Run: + +```bash +cd ruoyi-ui +node tests/unit/risk-detail-abnormal-account-pagination.test.js +``` + +Expected: + +- FAIL,提示 API 方法或分页状态尚未接入 + +- [ ] **Step 3: 在 API 文件中增加轻量请求封装** + +在 `projectOverview.js` 中新增: + +```js +export function getOverviewAbnormalAccountPeople(params) { + return request({ + url: "/ccdi/project/overview/abnormal-account-people", + method: "get", + params: { + projectId: params.projectId, + pageNum: params.pageNum, + pageSize: params.pageSize + } + }) +} +``` + +- [ ] **Step 4: 在 `RiskDetailSection.vue` 中补齐独立状态与加载函数** + +按员工负面征信区块的模式补充: + +1. `data()` 中新增: + - `abnormalAccountLoading` + - `abnormalAccountPageNum` + - `abnormalAccountPageSize` + - `abnormalAccountTotal` + - `abnormalAccountList` +2. `watch.sectionData` 中初始化: + - `projectId` + - 默认页码 1 + - 页大小 5 + - 初始列表为空 +3. 新增: + - `loadAbnormalAccountPeople()` + - `handleAbnormalAccountPageChange(pageInfo)` + +加载规则: + +- 无 `projectId` 时直接清空列表并结束 +- 请求失败时仅清空异常账户区块并提示 `加载异常账户人员信息失败` +- 不影响涉疑交易和员工负面征信区块 + +- [ ] **Step 5: 重新运行静态测试** + +Run: + +```bash +cd ruoyi-ui +node tests/unit/risk-detail-abnormal-account-pagination.test.js +``` + +Expected: + +- PASS + +- [ ] **Step 6: 提交本任务** + +```bash +git add ruoyi-ui/src/api/ccdi/projectOverview.js \ + ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue \ + ruoyi-ui/tests/unit/risk-detail-abnormal-account-pagination.test.js +git commit -m "补充异常账户人员前端查询状态" +``` + +## Task 3: 把异常账户表格从占位列改成真实 6 列 + +**Files:** + +- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue` +- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/preliminaryCheck.mock.js` +- Create: `ruoyi-ui/tests/unit/risk-detail-abnormal-account-layout.test.js` +- Modify: `ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js` + +- [ ] **Step 1: 修改异常账户表格模板** + +把旧占位表格: + +- `账户号` +- `账户人姓名` +- `开户银行` +- `异常发生时间` +- `状态` +- `操作` + +改为真实 6 列: + +- `账号` +- `开户人` +- `银行` +- `异常类型` +- `异常发生时间` +- `状态` + +并删除“操作 / 查看详情”列。 + +- [ ] **Step 2: 补独立空态与分页组件** + +将异常账户区块从纯 `el-table` 升级为与员工负面征信一致的结构: + +- `v-loading="abnormalAccountLoading"` +- `:data="abnormalAccountList"` +- `` +- 独立 `pagination` + +- [ ] **Step 3: 对齐 mock 字段命名** + +在 `preliminaryCheck.mock.js` 中把异常账户 mock 数据对齐成: + +- `accountNo` +- `accountName` +- `bankName` +- `abnormalType` +- `abnormalTime` +- `status` + +说明: + +- 这里不要求 mock 走真实接口 +- 只是避免静态数据结构继续停留在旧字段名 + +- [ ] **Step 4: 运行静态布局测试** + +Run: + +```bash +cd ruoyi-ui +node tests/unit/risk-detail-abnormal-account-layout.test.js +node tests/unit/preliminary-check-model-and-detail.test.js +``` + +Expected: + +- PASS + +- [ ] **Step 5: 提交本任务** + +```bash +git add ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue \ + ruoyi-ui/src/views/ccdiProject/components/detail/preliminaryCheck.mock.js \ + ruoyi-ui/tests/unit/risk-detail-abnormal-account-layout.test.js \ + ruoyi-ui/tests/unit/preliminary-check-model-and-detail.test.js +git commit -m "调整异常账户人员信息前端展示列" +``` + +## Task 4: 做前端联调与构建回归 + +**Files:** + +- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue` +- Modify: `docs/reports/implementation/2026-03-31-project-detail-risk-details-abnormal-account-frontend-implementation.md` + +- [ ] **Step 1: 本地执行静态单测** + +Run: + +```bash +cd ruoyi-ui +node tests/unit/risk-detail-abnormal-account-layout.test.js +node tests/unit/risk-detail-abnormal-account-pagination.test.js +node tests/unit/preliminary-check-model-and-detail.test.js +node tests/unit/risk-detail-employee-credit-negative-layout.test.js +``` + +Expected: + +- PASS + +- [ ] **Step 2: 跑前端生产构建** + +Run: + +```bash +cd ruoyi-ui +npm run build:prod +``` + +Expected: + +- PASS + +- [ ] **Step 3: 如需手工联调,启动前端并在验证后关闭** + +Run: + +```bash +cd ruoyi-ui +npm run dev +``` + +至少验证: + +1. `异常账户人员信息` 区块只显示 6 个目标字段 +2. 翻页只刷新异常账户区块 +3. 统一导出按钮仍请求 `ccdi/project/overview/risk-details/export` +4. 异常账户查询失败时只影响当前区块 + +验证结束后必须关闭 `npm run dev` 进程。 + +- [ ] **Step 4: 编写前端实施记录** + +在实施记录中写清: + +- 新增 API 方法 +- `RiskDetailSection.vue` 的状态与模板调整 +- mock 字段对齐 +- 静态单测与构建结果 +- 如有手工联调,记录启动与关闭前端进程情况 + +- [ ] **Step 5: 提交本任务** + +```bash +git add docs/reports/implementation/2026-03-31-project-detail-risk-details-abnormal-account-frontend-implementation.md +git commit -m "记录异常账户人员信息前端实施" +``` + +## Final Verification + +- [ ] 页面与导出统一使用 `账号 / 开户人 / 银行 / 异常类型 / 异常发生时间 / 状态` +- [ ] 页面已移除旧占位“查看详情”列 +- [ ] 异常账户分页状态与员工负面征信分页状态互不干扰 +- [ ] 构建命令 `npm run build:prod` 通过 +- [ ] 如启动了前端进程,验证结束后已手动关闭 diff --git a/docs/reports/implementation/2026-03-31-project-detail-risk-details-abnormal-account-plan-record.md b/docs/reports/implementation/2026-03-31-project-detail-risk-details-abnormal-account-plan-record.md new file mode 100644 index 00000000..f0d14952 --- /dev/null +++ b/docs/reports/implementation/2026-03-31-project-detail-risk-details-abnormal-account-plan-record.md @@ -0,0 +1,31 @@ +# 风险明细异常账户人员信息实施计划记录 + +**日期**: 2026-03-31 +**类型**: 实施计划记录 +**范围**: 项目详情 - 结果总览 - 风险明细 + +## 1. 本次新增计划文档 + +- `docs/plans/backend/2026-03-31-project-detail-risk-details-abnormal-account-backend-implementation-plan.md` +- `docs/plans/frontend/2026-03-31-project-detail-risk-details-abnormal-account-frontend-implementation-plan.md` + +## 2. 计划拆分原则 + +- 后端计划只覆盖异常账户结果总览查询接口、Mapper SQL、统一导出第 3 个 sheet 真实化、后端自动化验证 +- 前端计划只覆盖 `RiskDetailSection.vue` 的异常账户真实加载、独立分页、列结构调整、前端静态单测与构建验证 +- 页面展示与统一导出统一采用 `账号 / 开户人 / 银行 / 异常类型 / 异常发生时间 / 状态` 六个字段 +- 展示与导出均按“一条命中结果一行”执行,不做账号合并或员工合并 + +## 3. 执行约束 + +- 前端开发直接在当前分支执行,不使用 git worktree +- 仓库要求不开启 subagent,后续执行阶段统一使用当前会话串行推进 +- 若验证时启动前后端进程,结束后必须主动关闭 +- Git 提交前必须检查暂存区,仅纳入本次任务相关文件 + +## 4. 后续交付物 + +执行实施计划时需补齐以下记录: + +- `docs/reports/implementation/2026-03-31-project-detail-risk-details-abnormal-account-backend-implementation.md` +- `docs/reports/implementation/2026-03-31-project-detail-risk-details-abnormal-account-frontend-implementation.md`