# Project Detail Risk Overview Risk People Pagination Backend 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:** 将 `GET /ccdi/project/overview/risk-people` 改造成标准分页接口,固定默认每页 5 条,保证项目详情“风险总览”员工列表按数据库真分页返回 `rows + total + pageNum + pageSize`。 **Architecture:** 后端继续沿用 `CcdiProjectOverviewController -> ICcdiProjectOverviewService -> CcdiProjectOverviewServiceImpl -> CcdiProjectOverviewMapper.xml` 这一条结果总览链路,不新增补丁接口。接口路径保持不变,只引入独立分页查询 DTO、分页 VO 和 MyBatis Plus `Page` 查询;数据来源继续使用 `ccdi_project_overview_employee_result`,排序规则保持现状,不新增筛选口径。 **Tech Stack:** Java 21, Spring Boot 3, MyBatis Plus `Page`, MyBatis XML, Maven, JUnit 5, Mockito, Swagger/OpenAPI --- ### Task 1: 建立 `risk-people` 分页接口契约 **Files:** - Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectRiskPeopleQueryDTO.java` - Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectRiskPeopleOverviewVO.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/CcdiProjectOverviewControllerTest.java` - [ ] **Step 1: 先写失败测试,锁定 DTO、VO 字段和 Controller / Service 新签名** ```java assertNotNull(clazz.getMethod( "getRiskPeopleOverview", Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectRiskPeopleQueryDTO") )); ``` ```java Method method = CcdiProjectOverviewController.class.getMethod( "getRiskPeople", CcdiProjectRiskPeopleQueryDTO.class ); assertEquals("/risk-people", method.getAnnotation(GetMapping.class).value()[0]); ``` ```java CcdiProjectRiskPeopleOverviewVO overview = new CcdiProjectRiskPeopleOverviewVO(); overview.setRows(List.of(item)); overview.setTotal(1L); overview.setPageNum(1L); overview.setPageSize(5L); ``` - [ ] **Step 2: 运行结构测试与控制器测试,确认当前仓库仍是旧全量契约** Run: ```bash mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceStructureTest,CcdiProjectOverviewControllerTest test ``` Expected: - `CcdiProjectOverviewServiceStructureTest` 因缺少 DTO 签名而失败 - `CcdiProjectOverviewControllerTest` 仍断言 `getRiskPeople(Long projectId)`,与新契约不匹配 - [ ] **Step 3: 写最小 DTO / VO / Controller / Service 契约** ```java @Data public class CcdiProjectRiskPeopleQueryDTO { private Long projectId; private Integer pageNum; private Integer pageSize; } ``` ```java @GetMapping("/risk-people") public AjaxResult getRiskPeople(CcdiProjectRiskPeopleQueryDTO queryDTO) { CcdiProjectRiskPeopleOverviewVO overview = overviewService.getRiskPeopleOverview(queryDTO); return AjaxResult.success(overview); } ``` ```java @Data public class CcdiProjectRiskPeopleOverviewVO { private List rows; private Long total; private Long pageNum; private Long pageSize; } ``` - [ ] **Step 4: 回跑契约测试,确认分页接口外壳已建立** Run: ```bash mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceStructureTest,CcdiProjectOverviewControllerTest test ``` Expected: - `PASS` - 控制器测试明确返回 `rows + total + pageNum + pageSize` - [ ] **Step 5: 提交本任务** ```bash git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectRiskPeopleQueryDTO.java \ ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectRiskPeopleOverviewVO.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/CcdiProjectOverviewControllerTest.java git commit -m "改造风险总览员工列表分页接口契约" ``` ### Task 2: 将风险人员查询改为数据库分页 **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` - Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java` - [ ] **Step 1: 先写失败测试,锁定分页查询方法名、排序和分页参数默认值** ```java String riskPeopleSql = extractSelect(xml, "selectRiskPeopleOverviewPage"); assertTrue(riskPeopleSql.contains("from ccdi_project_overview_employee_result"), riskPeopleSql); assertTrue(riskPeopleSql.contains("result.project_id = #{query.projectId}"), riskPeopleSql); assertTrue( riskPeopleSql.contains("order by risk_level_sort asc, result.model_count desc, result.rule_count desc, result.staff_id_card asc"), riskPeopleSql ); assertFalse(riskPeopleSql.contains("limit 10"), riskPeopleSql); ``` ```java verify(overviewMapper).selectRiskPeopleOverviewPage( argThat(page -> page.getCurrent() == 1L && page.getSize() == 5L), argThat(query -> query.getProjectId().equals(40L)) ); ``` - [ ] **Step 2: 运行 SQL 与 Service 测试,确认当前实现仍是全量查询** Run: ```bash mvn -pl ccdi-project -Dtest=CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewServiceImplTest test ``` Expected: - SQL 测试提示缺少 `selectRiskPeopleOverviewPage` - Service 测试因仍调用 `selectRiskPeopleOverviewByProjectId` 而失败 - [ ] **Step 3: 写最小分页 SQL 与服务实现** ```java Page page = new Page<>( defaultPageNum(queryDTO.getPageNum()), defaultPageSize(queryDTO.getPageSize()) ); Page resultPage = overviewMapper.selectRiskPeopleOverviewPage(page, queryDTO); ``` ```java overview.setRows(defaultList(resultPage == null ? null : resultPage.getRecords()) .stream() .map(aggregate -> buildRiskPeopleItem(queryDTO.getProjectId(), aggregate)) .toList()); overview.setTotal(resultPage == null ? 0L : resultPage.getTotal()); overview.setPageNum(page.getCurrent()); overview.setPageSize(page.getSize()); ``` ```xml ``` - [ ] **Step 4: 回跑分页相关测试,确认改成真分页且字段映射不变** Run: ```bash mvn -pl ccdi-project -Dtest=CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewServiceImplTest test ``` Expected: - `PASS` - `shouldMapRiskPeopleOverviewRows` 改为断言 `rows` - 新增断言 `total/pageNum/pageSize` - `riskLevel/riskLevelType/modelCount/riskPointTagList` 保持原语义 - [ ] **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/CcdiProjectOverviewServiceImplTest.java git commit -m "实现风险总览员工列表后端分页查询" ``` ### Task 3: 补齐分页默认值与项目不存在回归 **Files:** - Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java` - Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java` - [ ] **Step 1: 先写失败测试,锁定 `pageNum/pageSize` 缺省回落为 `1/5`** ```java CcdiProjectRiskPeopleQueryDTO queryDTO = new CcdiProjectRiskPeopleQueryDTO(); queryDTO.setProjectId(40L); service.getRiskPeopleOverview(queryDTO); verify(overviewMapper).selectRiskPeopleOverviewPage( argThat(page -> page.getCurrent() == 1L && page.getSize() == 5L), any(CcdiProjectRiskPeopleQueryDTO.class) ); ``` ```java CcdiProjectRiskPeopleQueryDTO invalidQuery = new CcdiProjectRiskPeopleQueryDTO(); invalidQuery.setProjectId(40L); invalidQuery.setPageNum(0); invalidQuery.setPageSize(-1); ``` - [ ] **Step 2: 运行 Service 测试,确认当前没有锁死默认值** Run: ```bash mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceImplTest test ``` Expected: - 新增默认值断言失败 - [ ] **Step 3: 在 Service 中复用现有默认分页工具方法或补充最小默认值逻辑** ```java private long defaultRiskPeoplePageNum(Integer pageNum) { return pageNum == null || pageNum <= 0 ? 1L : pageNum.longValue(); } private long defaultRiskPeoplePageSize(Integer pageSize) { return pageSize == null || pageSize <= 0 ? 5L : pageSize.longValue(); } ``` - [ ] **Step 4: 回跑 Service 测试** Run: ```bash mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceImplTest test ``` Expected: - `PASS` - `项目不存在` 的旧异常断言仍通过 - [ ] **Step 5: 提交本任务** ```bash git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java \ ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java git commit -m "补齐风险总览员工列表分页默认值" ``` ### Task 4: 补齐后端验证记录与实施记录 **Files:** - Create: `docs/tests/records/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-verification.md` - Create: `docs/reports/implementation/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-implementation.md` - Verify: `docs/design/2026-03-29-project-detail-risk-overview-risk-people-pagination-design.md` - [ ] **Step 1: 运行本需求后端最小回归** Run: ```bash mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceStructureTest,CcdiProjectOverviewControllerTest,CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewServiceImplTest test ``` Expected: - `PASS` - `risk-people` 分页契约、SQL 和服务映射全部通过 - [ ] **Step 2: 写后端验证记录** 在 `docs/tests/records/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-verification.md` 记录: - 执行命令 - 执行日期 - 测试结果 - 结论:`risk-people` 已改为标准分页接口,默认每页 5 条 - [ ] **Step 3: 写后端实施记录** 在 `docs/reports/implementation/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-implementation.md` 记录: - 改造的 Controller / Service / Mapper / SQL / 测试文件 - 返回结构从 `overviewList` 迁移到 `rows` - 排序规则保持不变 - 本次未新增补丁接口 - [ ] **Step 4: 检查暂存区仅包含本任务文件** Run: ```bash git status --short git diff --cached --name-only ``` Expected: - 暂存区只出现本任务相关后端源码、测试和文档 - [ ] **Step 5: 提交本任务** ```bash git add docs/tests/records/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-verification.md \ docs/reports/implementation/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-implementation.md git commit -m "补充风险总览员工列表后端分页实施记录" ``` ## Done When - `GET /ccdi/project/overview/risk-people` 已改为接收 `projectId + pageNum + pageSize` - 接口返回 `rows + total + pageNum + pageSize` - SQL 基于 `ccdi_project_overview_employee_result` 实现真分页 - 默认分页固定回落为 `1 / 5` - 后端验证记录与实施记录已补齐