Files
ccdi/docs/plans/backend/2026-03-25-results-overview-project-analysis-dialog-real-detail-backend-implementation.md

18 KiB
Raw Blame History

Results Overview Project Analysis Dialog Real Detail Backend Implementation Plan

For agentic workers: REQUIRED: Use superpowers:executing-plans to implement this plan. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 为结果总览“项目分析”弹窗新增真实详情后端接口,统一返回员工基础信息与按类型分组的异常明细,支撑前端弹窗脱离本地 mock 展示真实数据。

Architecture: 延续 CcdiProjectOverviewController + ICcdiProjectOverviewService + CcdiProjectOverviewServiceImpl + CcdiProjectOverviewMapper.xml 的结果总览域链路,不新建平行控制器。详情接口内部统一完成项目存在性校验、员工主数据查询、风险等级补齐、流水型异常归并和 OBJECT 型摘要组装;流水字段尽量复用现有 CcdiBankStatement*VO 口径,避免再造一套详情专用字段体系。

Tech Stack: Java 21, Spring Boot 3, MyBatis XML, Maven, JUnit 5


Task 1: 补齐详情接口契约与服务结构测试

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

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectPersonAnalysisDetailQueryDTO.java

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisDetailVO.java

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisBasicInfoVO.java

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisAbnormalDetailVO.java

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisAbnormalGroupVO.java

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisObjectRecordVO.java

  • Test: ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerContractTest.java

  • Test: ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectOverviewServiceStructureTest.java

  • Step 1: Write the failing contract assertions

CcdiProjectOverviewControllerContractTest.javaCcdiProjectOverviewServiceStructureTest.java 追加静态或反射断言,锁定以下边界:

  • 控制器新增 GET /ccdi/project/overview/person-analysis/detail
  • 入参 DTO 只包含 projectIdstaffIdCard
  • 服务接口新增 getPersonAnalysisDetail(CcdiProjectPersonAnalysisDetailQueryDTO queryDTO)
  • 详情返回 VO 至少包含:
    • basicInfo
    • abnormalDetail.groups
  • abnormalDetail.groups[*].groupType 只按本轮设计承载 BANK_STATEMENTOBJECT

示例断言片段:

assertTrue(source.contains("@GetMapping(\"/person-analysis/detail\")"));
assertTrue(source.contains("CcdiProjectPersonAnalysisDetailVO getPersonAnalysisDetail"));
assertTrue(source.contains("private Long projectId;"));
assertTrue(source.contains("private String staffIdCard;"));
  • Step 2: Run test to verify it fails

Run:

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

Expected:

  • FAIL

  • 原因是详情接口、DTO、VO 和服务签名尚未存在

  • Step 3: Write the minimal contract code

补齐 DTO、VO 和服务方法签名,控制器新增接口但先只接线到服务,不在此步写完整查询逻辑。

DTO 结构示例:

@Data
public class CcdiProjectPersonAnalysisDetailQueryDTO implements Serializable {
    private Long projectId;
    private String staffIdCard;
}

服务接口签名示例:

CcdiProjectPersonAnalysisDetailVO getPersonAnalysisDetail(CcdiProjectPersonAnalysisDetailQueryDTO queryDTO);
  • Step 4: Run test to verify it passes

Run:

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

Expected:

  • PASS

  • Step 5: Commit

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/domain/dto/CcdiProjectPersonAnalysisDetailQueryDTO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisDetailVO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisBasicInfoVO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisAbnormalDetailVO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisAbnormalGroupVO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisObjectRecordVO.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerContractTest.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectOverviewServiceStructureTest.java
git commit -m "补充结果总览详情接口契约"

Task 2: 先写服务层失败测试,锁定基础信息与分组口径

Files:

  • Modify: ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java

  • Modify: ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerTest.java

  • Step 1: Write the failing service test

CcdiProjectOverviewServiceImplTest.java 新增测试,锁定:

  • 项目不存在时抛出 ServiceException("项目不存在")
  • 员工基础信息优先从员工信息表读取
  • 风险等级来自结果总览员工结果口径
  • 返回结果中同时存在 BANK_STATEMENTOBJECT 分组时,顺序保持稳定
  • 从模型人员入口进入与否不影响“返回全部异常明细”的后端查询口径,因为接口不接收当前模型参数

示例测试骨架:

@Test
void getPersonAnalysisDetail_shouldReturnBasicInfoAndGroupedAbnormalDetail() {
    CcdiProjectPersonAnalysisDetailQueryDTO queryDTO = new CcdiProjectPersonAnalysisDetailQueryDTO();
    queryDTO.setProjectId(1L);
    queryDTO.setStaffIdCard("330101199001010011");

    CcdiProjectPersonAnalysisDetailVO result = service.getPersonAnalysisDetail(queryDTO);

    assertEquals("张三", result.getBasicInfo().getName());
    assertEquals("高风险", result.getBasicInfo().getRiskLevel());
    assertEquals("BANK_STATEMENT", result.getAbnormalDetail().getGroups().get(0).getGroupType());
}
  • Step 2: Write the failing controller test

CcdiProjectOverviewControllerTest.java 新增控制器单测,锁定:

  • 控制器能接收 projectIdstaffIdCard

  • AjaxResult.success(data) 返回值里包含 basicInfoabnormalDetail

  • Step 3: Run test to verify it fails

Run:

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

Expected:

  • FAIL

  • 原因是服务实现和控制器查询逻辑尚未完成

  • Step 4: Add the minimal service/controller scaffolding

CcdiProjectOverviewServiceImpl.java 中先新增空实现骨架与必要的私有辅助方法声明,例如:

@Override
public CcdiProjectPersonAnalysisDetailVO getPersonAnalysisDetail(CcdiProjectPersonAnalysisDetailQueryDTO queryDTO) {
    ensureProjectExists(queryDTO.getProjectId());
    return new CcdiProjectPersonAnalysisDetailVO();
}

控制器中完成调用接线。

  • Step 5: Re-run the same tests

Run:

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

Expected:

  • 仍可能 FAIL,但失败点应收敛到“数据查询为空/字段未组装”,不再是找不到方法或类

  • Step 6: Commit

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 ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerTest.java
git commit -m "搭建结果总览详情服务骨架"

Task 3: 补齐 Mapper 查询与 XML 结构测试

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

  • Test: ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java

  • Test: ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankStatementMapperXmlTest.java

  • Step 1: Write the failing mapper SQL assertions

CcdiProjectOverviewMapperSqlTest.java 追加断言,锁定 mapper XML 必须新增以下查询:

  • 查询员工基础信息及部门名
  • 查询人员在项目下的流水型异常明细
  • 查询人员在项目下的 OBJECT 型异常摘要原始行

静态断言可直接检查 XML 中存在的 SQL id例如

assertTrue(source.contains("selectPersonAnalysisBasicInfo"));
assertTrue(source.contains("selectPersonAnalysisStatementRows"));
assertTrue(source.contains("selectPersonAnalysisObjectRows"));
  • Step 2: Run test to verify it fails

Run:

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

Expected:

  • FAIL

  • Step 3: Implement mapper methods and XML

在 mapper 接口与 XML 中新增最小查询:

  • selectPersonAnalysisBasicInfo(projectId, staffIdCard)
  • selectPersonAnalysisStatementRows(projectId, staffIdCard)
  • selectPersonAnalysisObjectRows(projectId, staffIdCard)

要求:

  • 基础信息查询关联 ccdi_project_overview_employee_result 获取风险等级
  • 流水查询字段与 CcdiBankStatementListVO 口径对齐
  • OBJECT 查询只取前端摘要卡需要的最小字段,不做整对象平铺

SQL 方向示例:

<select id="selectPersonAnalysisStatementRows" resultType="com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementListVO">
  SELECT DISTINCT
    s.bank_statement_id,
    s.trx_date,
    s.le_account_no,
    s.le_account_name,
    s.customer_account_name,
    s.customer_account_no,
    s.user_memo,
    s.cash_type,
    s.display_amount
  FROM ccdi_bank_statement s
  ...
</select>
  • Step 4: Re-run the same tests

Run:

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

Expected:

  • PASS

  • Step 5: Commit

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/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankStatementMapperXmlTest.java
git commit -m "补充结果总览详情查询SQL"

Task 4: 实现服务组装逻辑并打通真实详情返回

Files:

  • Modify: ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisObjectFieldVO.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/controller/CcdiProjectOverviewControllerTest.java

  • Step 1: Implement basic info assembly

在服务层把基础信息统一组装为:

  • name
  • idNo
  • staffCode
  • department
  • phone
  • riskLevel
  • projectName

若员工主数据查不到:

  • 不抛异常

  • 返回空 basicInfo 字段并继续组装异常明细

  • Step 2: Implement grouped abnormal detail assembly

在服务层把异常明细统一收敛为 groups

  • 流水型异常组:
    • groupCode = BANK_STATEMENT
    • groupType = BANK_STATEMENT
  • 对象型异常组:
    • groupType = OBJECT
    • 记录内只保留 title/subtitle/riskTags/summary/extraFields

推荐新增私有方法:

private CcdiProjectPersonAnalysisAbnormalGroupVO buildBankStatementGroup(...);
private CcdiProjectPersonAnalysisAbnormalGroupVO buildObjectGroup(...);
private List<CcdiProjectPersonAnalysisObjectFieldVO> buildObjectExtraFields(...);
  • Step 3: Reuse statement hit tags

流水组装时不要重新发明标签结构,直接复用现有流水标签查询方式:

  • 可复用 CcdiBankTagResultMapper
  • 或复用 CcdiBankStatementServiceImpl 当前的标签附着逻辑思路

但不要在服务层直接复制整段重复代码;若出现重复,抽一个结果总览域内部私有辅助方法即可。

  • Step 4: Run focused tests

Run:

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

Expected:

  • PASS

  • Step 5: Commit

git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisObjectFieldVO.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerTest.java
git commit -m "实现结果总览详情数据组装"

Task 5: 做后端回归、写验证记录和实施记录

Files:

  • 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

  • Test: ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java

  • Test: ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java

  • Test: ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperRiskModelPeopleTest.java

  • Test: ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperRiskModelCardsTest.java

  • Create: docs/tests/records/2026-03-25-results-overview-project-analysis-dialog-real-detail-backend-verification.md

  • Create: docs/reports/implementation/2026-03-25-results-overview-project-analysis-dialog-real-detail-backend-implementation.md

  • Verify: docs/design/2026-03-25-results-overview-project-analysis-dialog-real-detail-design.md

  • Step 1: Run full focused regression

Run:

mvn test -pl ccdi-project -Dtest=CcdiProjectOverviewControllerContractTest,CcdiProjectOverviewControllerTest,CcdiProjectOverviewServiceImplTest,CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewMapperRiskModelPeopleTest,CcdiProjectOverviewMapperRiskModelCardsTest

Expected:

  • 全部 PASS

  • Step 2: Write verification record

docs/tests/records/2026-03-25-results-overview-project-analysis-dialog-real-detail-backend-verification.md 记录:

  • 执行命令

  • 执行时间

  • 关键通过项

  • 结论:详情接口已返回真实基础信息和分组异常明细

  • Step 3: Write implementation record

docs/reports/implementation/2026-03-25-results-overview-project-analysis-dialog-real-detail-backend-implementation.md 记录:

  • 新增接口、DTO、VO、Mapper 查询

  • 服务层如何组装 BANK_STATEMENT / OBJECT

  • 验证结果

  • Step 4: Review changed files

Run:

git diff --name-only

Expected:

  • 只包含本次后端实现、测试和文档文件

  • Step 5: Commit

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/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/domain/dto/CcdiProjectPersonAnalysisDetailQueryDTO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisDetailVO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisBasicInfoVO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisAbnormalDetailVO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisAbnormalGroupVO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisObjectRecordVO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectPersonAnalysisObjectFieldVO.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 ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectOverviewServiceStructureTest.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankStatementMapperXmlTest.java docs/tests/records/2026-03-25-results-overview-project-analysis-dialog-real-detail-backend-verification.md docs/reports/implementation/2026-03-25-results-overview-project-analysis-dialog-real-detail-backend-implementation.md
git commit -m "实现结果总览详情弹窗后端接口"