Files
ccdi/docs/plans/backend/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-implementation.md

13 KiB
Raw Blame History

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 新签名

assertNotNull(clazz.getMethod(
    "getRiskPeopleOverview",
    Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectRiskPeopleQueryDTO")
));
Method method = CcdiProjectOverviewController.class.getMethod(
    "getRiskPeople",
    CcdiProjectRiskPeopleQueryDTO.class
);
assertEquals("/risk-people", method.getAnnotation(GetMapping.class).value()[0]);
CcdiProjectRiskPeopleOverviewVO overview = new CcdiProjectRiskPeopleOverviewVO();
overview.setRows(List.of(item));
overview.setTotal(1L);
overview.setPageNum(1L);
overview.setPageSize(5L);
  • Step 2: 运行结构测试与控制器测试,确认当前仓库仍是旧全量契约

Run:

mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceStructureTest,CcdiProjectOverviewControllerTest test

Expected:

  • CcdiProjectOverviewServiceStructureTest 因缺少 DTO 签名而失败

  • CcdiProjectOverviewControllerTest 仍断言 getRiskPeople(Long projectId),与新契约不匹配

  • Step 3: 写最小 DTO / VO / Controller / Service 契约

@Data
public class CcdiProjectRiskPeopleQueryDTO {
    private Long projectId;
    private Integer pageNum;
    private Integer pageSize;
}
@GetMapping("/risk-people")
public AjaxResult getRiskPeople(CcdiProjectRiskPeopleQueryDTO queryDTO) {
    CcdiProjectRiskPeopleOverviewVO overview = overviewService.getRiskPeopleOverview(queryDTO);
    return AjaxResult.success(overview);
}
@Data
public class CcdiProjectRiskPeopleOverviewVO {
    private List<CcdiProjectRiskPeopleOverviewItemVO> rows;
    private Long total;
    private Long pageNum;
    private Long pageSize;
}
  • Step 4: 回跑契约测试,确认分页接口外壳已建立

Run:

mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceStructureTest,CcdiProjectOverviewControllerTest test

Expected:

  • PASS

  • 控制器测试明确返回 rows + total + pageNum + pageSize

  • Step 5: 提交本任务

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: 先写失败测试,锁定分页查询方法名、排序和分页参数默认值

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);
verify(overviewMapper).selectRiskPeopleOverviewPage(
    argThat(page -> page.getCurrent() == 1L && page.getSize() == 5L),
    argThat(query -> query.getProjectId().equals(40L))
);
  • Step 2: 运行 SQL 与 Service 测试,确认当前实现仍是全量查询

Run:

mvn -pl ccdi-project -Dtest=CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewServiceImplTest test

Expected:

  • SQL 测试提示缺少 selectRiskPeopleOverviewPage

  • Service 测试因仍调用 selectRiskPeopleOverviewByProjectId 而失败

  • Step 3: 写最小分页 SQL 与服务实现

Page<CcdiProjectEmployeeRiskAggregateVO> page = new Page<>(
    defaultPageNum(queryDTO.getPageNum()),
    defaultPageSize(queryDTO.getPageSize())
);
Page<CcdiProjectEmployeeRiskAggregateVO> resultPage =
    overviewMapper.selectRiskPeopleOverviewPage(page, queryDTO);
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());
<select id="selectRiskPeopleOverviewPage" resultMap="EmployeeRiskAggregateResultMap">
    select
        result.staff_id_card,
        result.staff_name,
        result.dept_id,
        result.dept_name,
        result.rule_count,
        result.model_count,
        result.hit_count,
        null as top_rule_code,
        null as top_rule_name,
        result.risk_point,
        result.risk_level_code,
        case
            when result.risk_level_code = 'HIGH' then '高风险'
            when result.risk_level_code = 'MEDIUM' then '中风险'
            else '低风险'
        end as risk_level_name,
        case
            when result.risk_level_code = 'HIGH' then 1
            when result.risk_level_code = 'MEDIUM' then 2
            else 3
        end as risk_level_sort
    from ccdi_project_overview_employee_result result
    where result.project_id = #{query.projectId}
    order by risk_level_sort asc, result.model_count desc, result.rule_count desc, result.staff_id_card asc
</select>
  • Step 4: 回跑分页相关测试,确认改成真分页且字段映射不变

Run:

mvn -pl ccdi-project -Dtest=CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewServiceImplTest test

Expected:

  • PASS

  • shouldMapRiskPeopleOverviewRows 改为断言 rows

  • 新增断言 total/pageNum/pageSize

  • riskLevel/riskLevelType/modelCount/riskPointTagList 保持原语义

  • Step 5: 提交本任务

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

CcdiProjectRiskPeopleQueryDTO queryDTO = new CcdiProjectRiskPeopleQueryDTO();
queryDTO.setProjectId(40L);

service.getRiskPeopleOverview(queryDTO);

verify(overviewMapper).selectRiskPeopleOverviewPage(
    argThat(page -> page.getCurrent() == 1L && page.getSize() == 5L),
    any(CcdiProjectRiskPeopleQueryDTO.class)
);
CcdiProjectRiskPeopleQueryDTO invalidQuery = new CcdiProjectRiskPeopleQueryDTO();
invalidQuery.setProjectId(40L);
invalidQuery.setPageNum(0);
invalidQuery.setPageSize(-1);
  • Step 2: 运行 Service 测试,确认当前没有锁死默认值

Run:

mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceImplTest test

Expected:

  • 新增默认值断言失败

  • Step 3: 在 Service 中复用现有默认分页工具方法或补充最小默认值逻辑

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:

mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceImplTest test

Expected:

  • PASS

  • 项目不存在 的旧异常断言仍通过

  • Step 5: 提交本任务

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:

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:

git status --short
git diff --cached --name-only

Expected:

  • 暂存区只出现本任务相关后端源码、测试和文档

  • Step 5: 提交本任务

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
  • 后端验证记录与实施记录已补齐