# 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.java` 和 `CcdiProjectOverviewServiceStructureTest.java` 追加静态或反射断言,锁定以下边界: - 控制器新增 `GET /ccdi/project/overview/person-analysis/detail` - 入参 DTO 只包含 `projectId` 和 `staffIdCard` - 服务接口新增 `getPersonAnalysisDetail(CcdiProjectPersonAnalysisDetailQueryDTO queryDTO)` - 详情返回 VO 至少包含: - `basicInfo` - `abnormalDetail.groups` - `abnormalDetail.groups[*].groupType` 只按本轮设计承载 `BANK_STATEMENT` 和 `OBJECT` 示例断言片段: ```java 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: ```bash mvn test -pl ccdi-project -Dtest=CcdiProjectOverviewControllerContractTest,CcdiProjectOverviewServiceStructureTest ``` Expected: - `FAIL` - 原因是详情接口、DTO、VO 和服务签名尚未存在 - [ ] **Step 3: Write the minimal contract code** 补齐 DTO、VO 和服务方法签名,控制器新增接口但先只接线到服务,不在此步写完整查询逻辑。 DTO 结构示例: ```java @Data public class CcdiProjectPersonAnalysisDetailQueryDTO implements Serializable { private Long projectId; private String staffIdCard; } ``` 服务接口签名示例: ```java CcdiProjectPersonAnalysisDetailVO getPersonAnalysisDetail(CcdiProjectPersonAnalysisDetailQueryDTO queryDTO); ``` - [ ] **Step 4: Run test to verify it passes** Run: ```bash mvn test -pl ccdi-project -Dtest=CcdiProjectOverviewControllerContractTest,CcdiProjectOverviewServiceStructureTest ``` Expected: - `PASS` - [ ] **Step 5: Commit** ```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/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_STATEMENT` 和 `OBJECT` 分组时,顺序保持稳定 - 从模型人员入口进入与否不影响“返回全部异常明细”的后端查询口径,因为接口不接收当前模型参数 示例测试骨架: ```java @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` 新增控制器单测,锁定: - 控制器能接收 `projectId` 和 `staffIdCard` - `AjaxResult.success(data)` 返回值里包含 `basicInfo` 和 `abnormalDetail` - [ ] **Step 3: Run test to verify it fails** Run: ```bash mvn test -pl ccdi-project -Dtest=CcdiProjectOverviewServiceImplTest,CcdiProjectOverviewControllerTest ``` Expected: - `FAIL` - 原因是服务实现和控制器查询逻辑尚未完成 - [ ] **Step 4: Add the minimal service/controller scaffolding** 在 `CcdiProjectOverviewServiceImpl.java` 中先新增空实现骨架与必要的私有辅助方法声明,例如: ```java @Override public CcdiProjectPersonAnalysisDetailVO getPersonAnalysisDetail(CcdiProjectPersonAnalysisDetailQueryDTO queryDTO) { ensureProjectExists(queryDTO.getProjectId()); return new CcdiProjectPersonAnalysisDetailVO(); } ``` 控制器中完成调用接线。 - [ ] **Step 5: Re-run the same tests** Run: ```bash mvn test -pl ccdi-project -Dtest=CcdiProjectOverviewServiceImplTest,CcdiProjectOverviewControllerTest ``` Expected: - 仍可能 `FAIL`,但失败点应收敛到“数据查询为空/字段未组装”,不再是找不到方法或类 - [ ] **Step 6: Commit** ```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 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,例如: ```java assertTrue(source.contains("selectPersonAnalysisBasicInfo")); assertTrue(source.contains("selectPersonAnalysisStatementRows")); assertTrue(source.contains("selectPersonAnalysisObjectRows")); ``` - [ ] **Step 2: Run test to verify it fails** Run: ```bash 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 方向示例: ```xml ``` - [ ] **Step 4: Re-run the same tests** Run: ```bash mvn test -pl ccdi-project -Dtest=CcdiProjectOverviewMapperSqlTest,CcdiBankStatementMapperXmlTest ``` Expected: - `PASS` - [ ] **Step 5: Commit** ```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/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` 推荐新增私有方法: ```java private CcdiProjectPersonAnalysisAbnormalGroupVO buildBankStatementGroup(...); private CcdiProjectPersonAnalysisAbnormalGroupVO buildObjectGroup(...); private List buildObjectExtraFields(...); ``` - [ ] **Step 3: Reuse statement hit tags** 流水组装时不要重新发明标签结构,直接复用现有流水标签查询方式: - 可复用 `CcdiBankTagResultMapper` - 或复用 `CcdiBankStatementServiceImpl` 当前的标签附着逻辑思路 但不要在服务层直接复制整段重复代码;若出现重复,抽一个结果总览域内部私有辅助方法即可。 - [ ] **Step 4: Run focused tests** Run: ```bash mvn test -pl ccdi-project -Dtest=CcdiProjectOverviewServiceImplTest,CcdiProjectOverviewControllerTest,CcdiProjectOverviewMapperSqlTest ``` Expected: - `PASS` - [ ] **Step 5: Commit** ```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/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: ```bash 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: ```bash git diff --name-only ``` Expected: - 只包含本次后端实现、测试和文档文件 - [ ] **Step 5: Commit** ```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/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 "实现结果总览详情弹窗后端接口" ```