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

406 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
<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:
```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<CcdiProjectPersonAnalysisObjectFieldVO> 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 "实现结果总览详情弹窗后端接口"
```