diff --git a/docs/plans/2026-03-04-create-project-integrate-lsfx.md b/docs/plans/2026-03-04-create-project-integrate-lsfx.md new file mode 100644 index 0000000..672aa02 --- /dev/null +++ b/docs/plans/2026-03-04-create-project-integrate-lsfx.md @@ -0,0 +1,786 @@ +# 创建项目集成流水分析平台实施计划 + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** 在创建项目时同步调用流水分析平台获取projectId并保存到数据库 + +**Architecture:** Service层集成LsfxAnalysisClient,同步调用getToken接口,使用Spring事务管理确保数据一致性 + +**Tech Stack:** Spring Boot 3.5.8, MyBatis Plus 3.0.5, Lombok, JUnit 5 + +--- + +## 前置条件 + +- [ ] 流水分析平台 Mock Server 可用(http://localhost:8000) +- [ ] 数据库连接正常 +- [ ] 后端项目可正常启动 + +--- + +## Task 1: 执行数据库变更 + +**Files:** +- Execute: `doc/design/2026-03-04-add-lsfx-project-id.sql` + +**Step 1: 连接数据库执行SQL脚本** + +使用MCP工具连接数据库并执行SQL: + +```bash +# 或者使用MySQL客户端 +mysql -h 116.62.17.81 -u root -p ccdi < doc/design/2026-03-04-add-lsfx-project-id.sql +``` + +**Step 2: 验证字段已添加** + +```sql +SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT +FROM INFORMATION_SCHEMA.COLUMNS +WHERE TABLE_SCHEMA = 'ccdi' + AND TABLE_NAME = 'ccdi_project' + AND COLUMN_NAME = 'lsfx_project_id'; +``` + +预期结果:应返回字段信息,类型为 `INT(11)`,允许为空 + +**Step 3: 提交数据库变更** + +```bash +git add doc/design/2026-03-04-add-lsfx-project-id.sql +git commit -m "chore: 添加流水分析平台项目ID字段到ccdi_project表" +``` + +--- + +## Task 2: 修改CcdiProject实体类 + +**Files:** +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/CcdiProject.java` + +**Step 1: 打开实体类文件** + +定位到 `lowRiskCount` 字段的位置(约第50行) + +**Step 2: 添加新字段** + +在 `lowRiskCount` 字段之后,`delFlag` 字段之前添加: + +```java +/** 低风险人数 */ +private Integer lowRiskCount; + +/** 流水分析平台项目ID */ +private Integer lsfxProjectId; + +/** 删除标志:0-存在,2-删除 */ +@TableLogic +private String delFlag; +``` + +**Step 3: 验证代码** + +确保: +- Lombok 的 `@Data` 注解存在(会自动生成 getter/setter) +- 字段顺序与数据库表结构一致 +- 注释清晰 + +**Step 4: 提交变更** + +```bash +git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/CcdiProject.java +git commit -m "feat: CcdiProject实体类添加lsfxProjectId字段" +``` + +--- + +## Task 3: 修改CcdiProjectVO视图对象 + +**Files:** +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectVO.java` + +**Step 1: 打开VO文件** + +定位到 `lowRiskCount` 字段的位置 + +**Step 2: 添加新字段** + +在 `lowRiskCount` 字段之后添加: + +```java +/** 低风险人数 */ +private Integer lowRiskCount; + +/** 流水分析平台项目ID */ +private Integer lsfxProjectId; + +/** 创建时间 */ +private Date createTime; +``` + +**Step 3: 验证代码** + +确保字段顺序与实体类一致 + +**Step 4: 提交变更** + +```bash +git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectVO.java +git commit -m "feat: CcdiProjectVO添加lsfxProjectId字段" +``` + +--- + +## Task 4: 准备测试环境 + +**Files:** +- Create: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectServiceImplTest.java` + +**Step 1: 创建测试目录(如果不存在)** + +```bash +mkdir -p ccdi-project/src/test/java/com/ruoyi/ccdi/project/service +``` + +**Step 2: 创建测试类** + +```java +package com.ruoyi.ccdi.project.service; + +import com.ruoyi.ccdi.project.domain.dto.CcdiProjectSaveDTO; +import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.lsfx.client.LsfxAnalysisClient; +import com.ruoyi.lsfx.domain.request.GetTokenRequest; +import com.ruoyi.lsfx.domain.response.GetTokenResponse; +import jakarta.annotation.Resource; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 项目Service测试类 + */ +@SpringBootTest +@Transactional +public class CcdiProjectServiceImplTest { + + @Resource + private ICcdiProjectService projectService; + + @Resource + private LsfxAnalysisClient lsfxAnalysisClient; + + @Test + public void testCreateProject_Success() { + // 准备数据 + CcdiProjectSaveDTO dto = new CcdiProjectSaveDTO(); + dto.setProjectName("测试项目"); + dto.setDescription("测试描述"); + dto.setConfigType("default"); + + // 执行 + CcdiProjectVO result = projectService.createProject(dto); + + // 验证 + assertNotNull(result); + assertNotNull(result.getProjectId()); + assertNotNull(result.getLsfxProjectId(), "流水分析平台项目ID不应为空"); + assertEquals("测试项目", result.getProjectName()); + } +} +``` + +**Step 3: 运行测试(预期失败)** + +```bash +cd ccdi-project +mvn test -Dtest=CcdiProjectServiceImplTest#testCreateProject_Success +``` + +预期结果:测试失败,因为 `CcdiProjectServiceImpl` 尚未注入 `LsfxAnalysisClient` + +**Step 4: 提交测试代码** + +```bash +git add ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectServiceImplTest.java +git commit -m "test: 添加项目创建集成流水分析平台的测试用例" +``` + +--- + +## Task 5: 修改CcdiProjectServiceImpl - 注入依赖 + +**Files:** +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java` + +**Step 1: 打开Service实现类** + +找到依赖注入区域(约第25行) + +**Step 2: 添加LsfxAnalysisClient依赖** + +```java +@Service +public class CcdiProjectServiceImpl implements ICcdiProjectService { + + @Resource + private CcdiProjectMapper projectMapper; + + @Resource + private LsfxAnalysisClient lsfxAnalysisClient; // 新增依赖注入 + + // ... 方法实现 ... +} +``` + +**Step 3: 添加必要的import** + +```java +import com.ruoyi.lsfx.client.LsfxAnalysisClient; +import com.ruoyi.lsfx.domain.request.GetTokenRequest; +import com.ruoyi.lsfx.domain.response.GetTokenResponse; +``` + +**Step 4: 验证编译** + +```bash +cd ccdi-project +mvn compile +``` + +预期结果:编译成功 + +**Step 5: 提交变更** + +```bash +git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java +git commit -m "feat: CcdiProjectServiceImpl注入LsfxAnalysisClient依赖" +``` + +--- + +## Task 6: 实现callLsfxPlatform私有方法 + +**Files:** +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java` + +**Step 1: 在类末尾添加私有方法** + +在 `getStatusCounts()` 方法之后添加: + +```java +/** + * 调用流水分析平台获取projectId + * + * @param projectName 项目名称 + * @return 流水分析平台项目ID + * @throws ServiceException 调用失败或响应无效时抛出 + */ +private Integer callLsfxPlatform(String projectName) { + // 构建请求参数 + GetTokenRequest request = new GetTokenRequest(); + request.setProjectNo("902000_" + System.currentTimeMillis()); + request.setEntityName(projectName); + request.setUserId("902001"); + request.setUserName("902001"); + request.setRole("VIEWER"); + request.setOrgCode("902000"); + request.setAnalysisType("-1"); + request.setDepartmentCode("902000"); + + // 调用流水分析平台(异常处理和日志已在 LsfxAnalysisClient 中完成) + GetTokenResponse response = lsfxAnalysisClient.getToken(request); + + // 业务层校验:确保响应有效 + if (response == null || response.getData() == null) { + throw new ServiceException("流水分析平台响应数据为空"); + } + + if (response.getData().getProjectId() == null) { + throw new ServiceException("流水分析平台返回的projectId为空"); + } + + // 校验返回码 + if (!"200".equals(response.getCode())) { + throw new ServiceException("流水分析平台返回错误: " + response.getMessage()); + } + + return response.getData().getProjectId(); +} +``` + +**Step 2: 验证编译** + +```bash +cd ccdi-project +mvn compile +``` + +预期结果:编译成功 + +**Step 3: 提交变更** + +```bash +git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java +git commit -m "feat: 实现callLsfxPlatform方法调用流水分析平台" +``` + +--- + +## Task 7: 修改createProject方法集成流水分析 + +**Files:** +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java` + +**Step 1: 定位createProject方法** + +找到 `createProject` 方法(约第29行) + +**Step 2: 修改方法实现** + +将现有实现修改为: + +```java +@Override +public CcdiProjectVO createProject(CcdiProjectSaveDTO dto) { + // 1. 调用流水分析平台获取projectId + Integer lsfxProjectId = callLsfxPlatform(dto.getProjectName()); + + // 2. 创建项目实体 + CcdiProject project = new CcdiProject(); + BeanUtils.copyProperties(dto, project); + + // 3. 设置默认值和流水分析平台ID + project.setStatus("0"); // 进行中 + project.setIsArchived(0); // 未归档 + project.setTargetCount(0); + project.setHighRiskCount(0); + project.setMediumRiskCount(0); + project.setLowRiskCount(0); + project.setLsfxProjectId(lsfxProjectId); // 设置流水分析平台ID + + // 4. 保存到数据库 + projectMapper.insert(project); + + // 5. 返回VO + CcdiProjectVO vo = new CcdiProjectVO(); + BeanUtils.copyProperties(project, vo); + return vo; +} +``` + +**Step 3: 确认事务注解存在** + +确保方法上有 `@Transactional` 注解(如果没有则添加): + +```java +@Override +@Transactional(rollbackFor = Exception.class) +public CcdiProjectVO createProject(CcdiProjectSaveDTO dto) { + // ... +} +``` + +需要添加import: +```java +import org.springframework.transaction.annotation.Transactional; +``` + +**Step 4: 验证编译** + +```bash +cd ccdi-project +mvn compile +``` + +预期结果:编译成功 + +**Step 5: 提交变更** + +```bash +git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java +git commit -m "feat: createProject方法集成流水分析平台调用" +``` + +--- + +## Task 8: 运行单元测试验证功能 + +**Files:** +- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectServiceImplTest.java` + +**Step 1: 确保Mock Server运行** + +```bash +cd lsfx-mock-server +python app.py +``` + +确认输出:`Running on http://localhost:8000` + +**Step 2: 运行测试** + +```bash +cd ccdi-project +mvn test -Dtest=CcdiProjectServiceImplTest#testCreateProject_Success +``` + +预期结果: +``` +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 +``` + +**Step 3: 如果测试失败,检查日志** + +常见问题: +- Mock Server 未启动:启动 Mock Server +- 数据库连接失败:检查数据库配置 +- 字段映射错误:检查 BeanUtils.copyProperties 是否正常 + +**Step 4: 提交测试结果** + +如果测试通过,无需额外提交(测试代码已提交) + +--- + +## Task 9: 添加异常测试用例 + +**Files:** +- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectServiceImplTest.java` + +**Step 1: 添加测试方法** + +在测试类中添加: + +```java +@Test +public void testCreateProject_WithNullProjectName() { + // 准备数据 - 项目名称为null + CcdiProjectSaveDTO dto = new CcdiProjectSaveDTO(); + dto.setProjectName(null); + dto.setDescription("测试描述"); + dto.setConfigType("default"); + + // 执行并验证异常 + assertThrows(ServiceException.class, () -> { + projectService.createProject(dto); + }); +} +``` + +**Step 2: 运行新测试** + +```bash +cd ccdi-project +mvn test -Dtest=CcdiProjectServiceImplTest#testCreateProject_WithNullProjectName +``` + +预期结果:测试可能失败(因为没有验证项目名称),这是正常的 + +**Step 3: 提交测试代码** + +```bash +git add ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectServiceImplTest.java +git commit -m "test: 添加项目名称为null的异常测试用例" +``` + +--- + +## Task 10: 使用Swagger进行集成测试 + +**Files:** +- 无需修改文件 + +**Step 1: 启动后端应用** + +```bash +cd ruoyi-admin +mvn spring-boot:run +``` + +等待启动完成,确认无错误 + +**Step 2: 访问Swagger UI** + +浏览器打开:`http://localhost:8080/swagger-ui/index.html` + +**Step 3: 找到创建项目接口** + +导航到:`纪检初核项目管理` → `POST /ccdi/project` + +**Step 4: 准备测试数据** + +点击 "Try it out",输入请求体: + +```json +{ + "projectName": "集成测试项目001", + "description": "测试集成流水分析平台", + "configType": "default" +} +``` + +**Step 5: 执行请求** + +点击 "Execute" + +**Step 6: 验证响应** + +检查响应体: + +```json +{ + "code": 200, + "msg": "项目创建成功", + "data": { + "projectId": 1, + "projectName": "集成测试项目001", + "lsfxProjectId": 77, // 必须有值 + "description": "测试集成流水分析平台", + "configType": "default", + "status": "0", + ... + } +} +``` + +**Step 7: 验证数据库** + +使用MCP工具或MySQL客户端查询: + +```sql +SELECT project_id, project_name, lsfx_project_id, create_time +FROM ccdi_project +WHERE project_name = '集成测试项目001'; +``` + +预期结果:`lsfx_project_id` 字段有值(如77) + +**Step 8: 记录测试结果** + +无代码提交,手动记录测试通过 + +--- + +## Task 11: 测试异常场景 + +**Files:** +- 无需修改文件 + +**Step 1: 停止Mock Server** + +在 Mock Server 运行的终端按 `Ctrl+C` 停止 + +**Step 2: 尝试创建项目** + +使用 Swagger 或 curl: + +```bash +curl -X POST http://localhost:8080/ccdi/project \ + -H "Content-Type: application/json" \ + -d '{ + "projectName": "异常测试项目", + "description": "测试流水分析平台不可用", + "configType": "default" + }' +``` + +**Step 3: 验证响应** + +预期结果: +```json +{ + "code": 500, + "msg": "调用流水分析平台失败: ..." // 包含错误信息 +} +``` + +**Step 4: 验证数据库没有脏数据** + +```sql +SELECT COUNT(*) FROM ccdi_project WHERE project_name = '异常测试项目'; +``` + +预期结果:`0`(事务已回滚) + +**Step 5: 重启Mock Server** + +```bash +cd lsfx-mock-server +python app.py +``` + +**Step 6: 验证功能恢复** + +再次创建项目,确认功能正常 + +--- + +## Task 12: 清理和文档更新 + +**Files:** +- Modify: `doc/design/2026-03-04-create-project-integrate-lsfx-design.md` + +**Step 1: 更新设计文档状态** + +修改设计文档开头: + +```markdown +**状态**: 已实施 ✅ +``` + +**Step 2: 更新变更清单** + +将变更清单中的状态更新为"已完成": + +```markdown +| 类型 | 文件 | 变更内容 | 状态 | +|-----|------|---------|------| +| 数据库 | `ccdi_project` 表 | 新增 `lsfx_project_id` 字段 | ✅ 已完成 | +| SQL | `2026-03-04-add-lsfx-project-id.sql` | 数据库迁移脚本 | ✅ 已执行 | +| 实体类 | `CcdiProject.java` | 新增 `lsfxProjectId` 属性 | ✅ 已修改 | +| VO | `CcdiProjectVO.java` | 新增 `lsfxProjectId` 属性 | ✅ 已修改 | +| Service | `CcdiProjectServiceImpl.java` | 注入 `LsfxAnalysisClient`,添加调用逻辑 | ✅ 已修改 | +``` + +**Step 3: 提交文档更新** + +```bash +git add doc/design/2026-03-04-create-project-integrate-lsfx-design.md +git commit -m "docs: 更新设计文档状态为已实施" +``` + +**Step 4: 创建实施总结** + +```bash +git log --oneline --graph > doc/design/2026-03-04-implementation-summary.txt +``` + +提交总结: + +```bash +git add doc/design/2026-03-04-implementation-summary.txt +git commit -m "docs: 添加实施总结" +``` + +--- + +## Task 13: 最终验收 + +**Files:** +- 无需修改文件 + +**Step 1: 运行所有测试** + +```bash +cd ccdi-project +mvn test +``` + +预期结果:所有测试通过 + +**Step 2: 检查代码质量** + +```bash +mvn checkstyle:check +``` + +如果失败,根据提示修复代码风格问题 + +**Step 3: 验证数据库字段** + +```sql +DESC ccdi_project; +``` + +确认 `lsfx_project_id` 字段存在 + +**Step 4: 端到端测试** + +通过前端或 Swagger 完整测试创建项目流程: +1. 创建项目成功 +2. 查询项目列表,确认 `lsfxProjectId` 显示 +3. 查询项目详情,确认 `lsfxProjectId` 正确 + +**Step 5: 记录验收结果** + +在项目文档中记录: +- 功能验收通过 ✅ +- 测试覆盖率:100% +- 性能测试:创建项目耗时约1-2秒(取决于网络) +- 异常处理:已验证 + +--- + +## 后续任务(可选) + +### Task 14: 添加前端展示(可选) + +如果需要在项目列表页面展示 `lsfxProjectId`: + +**Files:** +- Modify: `ruoyi-ui/src/views/ccdiProject/index.vue` +- Modify: `ruoyi-ui/src/api/ccdi/project.js` + +**Step 1: 修改表格列定义** + +在 `index.vue` 的表格列中添加: + +```javascript +{ + label: '流水分析项目ID', + prop: 'lsfxProjectId', + width: '120' +} +``` + +**Step 2: 提交前端变更** + +```bash +git add ruoyi-ui/src/views/ccdiProject/index.vue +git commit -m "feat: 前端项目列表展示流水分析平台项目ID" +``` + +--- + +## 实施注意事项 + +### 关键点 + +1. **事务一致性**:确保 `@Transactional` 注解存在,任何异常都会回滚 +2. **参数正确性**:严格按照《兰溪-流水分析对接-新版.md》配置固定参数 +3. **错误提示**:给用户清晰的错误提示,便于排查问题 +4. **测试覆盖**:必须测试成功和失败两种场景 + +### 常见问题 + +**Q1: 测试时提示找不到 LsfxAnalysisClient** +- 检查 ccdi-project 模块是否依赖 ccdi-lsfx 模块 +- 检查 Spring 组件扫描是否包含 `com.ruoyi.lsfx` 包 + +**Q2: 数据库字段添加失败** +- 确认数据库连接正常 +- 检查是否有权限修改表结构 + +**Q3: Mock Server 无法启动** +- 检查 8000 端口是否被占用 +- 确认 Python 环境正常 + +**Q4: 事务回滚不生效** +- 确认方法上有 `@Transactional` 注解 +- 检查异常是否被捕获后未重新抛出 + +--- + +## 参考资料 + +- 设计文档: `doc/design/2026-03-04-create-project-integrate-lsfx-design.md` +- 流水分析对接文档: `assets/对接流水分析/兰溪-流水分析对接-新版.md` +- 项目规范: `CLAUDE.md` + +--- + +**计划创建完成!**