# HealthLink-HIS 代码库优化实施计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use compose:subagent (recommended) or compose:execute to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 修复健康检查发现的 Critical/High 级别问题,提升代码质量和可维护性 **Architecture:** 保持现有分层架构(Controller → AppService → Service → Mapper → Entity),重点解决 God Classes、重复代码、测试覆盖等结构性问题 **Tech Stack:** Java 25, Spring Boot 4.0.6, MyBatis-Plus 3.5.16, JUnit 5, Mockito --- ## 任务概览 | 优先级 | 任务 | 预计时间 | 影响范围 | |:------:|------|:--------:|----------| | P0 | 删除重复文件 | 30分钟 | 2个文件 | | P0 | 修复脆弱断言 | 1小时 | 8个测试文件 | | P1 | 提取测试基类 | 2小时 | 新建1个基类 | | P1 | 清理过期TODO | 1小时 | ~20个文件 | | P2 | 拆分IChargeBillServiceImpl | 8小时 | 1个God Class | | P2 | 添加单元测试框架 | 4小时 | 新建测试结构 | --- ## Task 1: 删除重复文件(消除classpath冲突风险) **Covers:** 架构维度 Finding 2 **Files:** - Delete: `healthlink-his-yb/src/main/java/com/healthlink/his/yb/util/YbParamBuilderUtil.java` - Delete: `healthlink-his-yb/src/main/java/com/healthlink/his/yb/dto/Yb4401InputBaseInfoDto.java` - Modify: `healthlink-his-yb/pom.xml` (确认依赖) - [ ] **Step 1: 确认重复文件存在** ```bash # 验证两个文件内容相同 diff healthlink-his-domain/src/main/java/com/healthlink/his/yb/util/YbParamBuilderUtil.java healthlink-his-yb/src/main/java/com/healthlink/his/yb/util/YbParamBuilderUtil.java ``` - [ ] **Step 2: 检查yb模块是否直接使用这些文件** ```bash # 搜索yb模块中的引用 rg "YbParamBuilderUtil" healthlink-his-yb/src --include="*.java" | grep -v "^.*YbParamBuilderUtil.java:" rg "Yb4401InputBaseInfoDto" healthlink-his-yb/src --include="*.java" | grep -v "^.*Yb4401InputBaseInfoDto.java:" ``` - [ ] **Step 3: 删除重复文件** ```bash rm healthlink-his-yb/src/main/java/com/healthlink/his/yb/util/YbParamBuilderUtil.java rm healthlink-his-yb/src/main/java/com/healthlink/his/yb/dto/Yb4401InputBaseInfoDto.java ``` - [ ] **Step 4: 验证编译通过** ```bash mvn clean compile -DskipTests ``` - [ ] **Step 5: Commit** ```bash git add -A git commit -m "fix: remove duplicate files to prevent classpath conflicts" ``` --- ## Task 2: 修复脆弱断言(提高测试可信度) **Covers:** 测试维度 Finding 5A **Files:** - Modify: `healthlink-his-application/src/test/java/com/healthlink/his/web/doctorstation/DoctorWorkstationTest.java` - Modify: `healthlink-his-application/src/test/java/com/healthlink/his/web/registration/RegistrationApiTest.java` - Modify: `healthlink-his-application/src/test/java/com/healthlink/his/web/report/ReportApiTest.java` - [ ] **Step 1: 修复DoctorWorkstationTest中的脆弱断言** ```java // 修改前 (line 221-226): assertTrue("未授权应返回401/403", code == 401 || code == 403 || code == 200); // 修改后: assertTrue("未授权应返回401或403", code == 401 || code == 403); assertFalse("未授权不应返回200", code == 200); ``` - [ ] **Step 2: 修复RegistrationApiTest中的空断言** ```java // 修改前 (line 221-229): if (result.path("code").asInt() == 200) { // If 200, check msg } // 修改后: int code = result.path("code").asInt(); assertTrue("退号失败应返回错误码", code != 200 || result.path("msg").asText().contains("失败")); ``` - [ ] **Step 3: 修复ReportApiTest中的永真断言** ```java // 修改前 (line 126-129): assertTrue("...", result.path("code").asInt() != 500 || result.path("code").asInt() == 500); // 修改后: int code = result.path("code").asInt(); assertTrue("应返回成功或业务错误", code == 200 || code == 500 || (code >= 400 && code < 500)); ``` - [ ] **Step 4: 运行测试验证** ```bash cd healthlink-his-application && mvn test -Dtest="DoctorWorkstationTest,RegistrationApiTest,ReportApiTest" ``` - [ ] **Step 5: Commit** ```bash git add -A git commit -m "fix(test): replace fragile assertions with meaningful validations" ``` --- ## Task 3: 提取测试基类(消除重复代码) **Covers:** 测试维度 Finding 5D **Files:** - Create: `healthlink-his-application/src/test/java/com/healthlink/his/web/BaseApiTest.java` - Modify: 8个测试文件(继承基类) - [ ] **Step 1: 创建BaseApiTest基类** ```java package com.healthlink.his.web; import io.restassured.RestAssured; import io.restassured.response.Response; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.TestInstance; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public abstract class BaseApiTest { protected static String token; @BeforeAll void setUp() { // 登录获取token Response loginResponse = RestAssured.given() .contentType("application/json") .body("{\"username\":\"admin\",\"password\":\"admin123\"}") .post("/auth/login"); token = loginResponse.jsonPath().getString("token"); } protected Response get(String path) { return RestAssured.given() .header("Authorization", "Bearer " + token) .get(path); } protected Response post(String path, Object body) { return RestAssured.given() .header("Authorization", "Bearer " + token) .contentType("application/json") .body(body) .post(path); } } ``` - [ ] **Step 2: 修改DoctorWorkstationTest继承基类** ```java // 修改前: public class DoctorWorkstationTest { // ... 重复的登录代码 // 修改后: public class DoctorWorkstationTest extends BaseApiTest { // 删除重复的登录代码 ``` - [ ] **Step 3: 对其他7个测试文件执行相同修改** ```bash # 批量替换(示例) sed -i 's/public class RegistrationApiTest {/public class RegistrationApiTest extends BaseApiTest {/' RegistrationApiTest.java ``` - [ ] **Step 4: 运行所有测试验证** ```bash mvn test -pl healthlink-his-application ``` - [ ] **Step 5: Commit** ```bash git add -A git commit -m "refactor(test): extract BaseApiTest to eliminate login duplication" ``` --- ## Task 4: 清理过期TODO(消除技术债务标记) **Covers:** 技术债务维度 Finding 3 **Files:** - Modify: `healthlink-his-domain/src/main/java/com/healthlink/his/yb/util/TenantOptionUtil.java` - Modify: 其他过期TODO文件 - [ ] **Step 1: 搜索所有过期TODO** ```bash rg "TODO.*2025|FIXME|HACK" healthlink-his-domain/src healthlink-his-application/src --include="*.java" -l ``` - [ ] **Step 2: 修复TenantOptionUtil中的过期TODO** ```java // 修改前 (line 36): // TODO:2025/10/17 李永兴提出的sys_option切换TenantOption临时防止报错方案,最晚2025年11月底删除 // 修改后: 直接删除这行注释(代码逻辑已正确) ``` - [ ] **Step 3: 评估其他TODO并分类** ```bash # 统计TODO数量 rg "TODO" healthlink-his-domain/src healthlink-his-application/src --include="*.java" -c | awk -F: '{sum+=$2} END {print sum}' ``` - [ ] **Step 4: 为高风险TODO创建issue跟踪** ```bash # 示例:为YbServiceImpl中的TODO创建备忘 echo "TODO:YbServiceImpl:274-后续处理需等待门诊住院开发完全后" >> docs/TODO_TRACKING.md ``` - [ ] **Step 5: Commit** ```bash git add -A git commit -m "chore: clean up expired TODOs and create tracking document" ``` --- ## Task 5: 拆分IChargeBillServiceImpl(解决God Class问题) **Covers:** 架构维度 Finding 1, 技术债务维度 Finding 1 **Files:** - Split: `IChargeBillServiceImpl.java` (2764行) → 多个服务类 - Create: `ChargeBillQueryService.java` - Create: `ChargeBillCalculationService.java` - Create: `ChargeBillStatisticsService.java` - [ ] **Step 1: 分析IChargeBillServiceImpl的方法职责** ```bash # 列出所有public方法 rg "public .* \w+\(" healthlink-his-application/src/main/java/com/healthlink/his/web/paymentmanage/appservice/impl/IChargeBillServiceImpl.java | head -20 ``` - [ ] **Step 2: 创建ChargeBillQueryService(查询相关)** ```java package com.healthlink.his.web.paymentmanage.appservice; import org.springframework.stereotype.Service; @Service public class ChargeBillQueryService { public Page getChargeBills(ChargeBillQueryDto query) { // 从IChargeBillServiceImpl迁移查询逻辑 } public ChargeBillDetailDto getChargeBillDetail(Long billId) { // 从getDetail()方法迁移 } } ``` - [ ] **Step 3: 创建ChargeBillCalculationService(计算相关)** ```java @Service public class ChargeBillCalculationService { public ChargeBillSummary calculateSummary(List items) { // 从getTotal()方法迁移 } public BigDecimal calculateInsurance(ChargeBillSummary summary, Contract contract) { // 从getTotalCommen()方法迁移 } } ``` - [ ] **Step 4: 创建ChargeBillStatisticsService(统计相关)** ```java @Service public class ChargeBillStatisticsService { public StatisticsDto getStatistics(DateRange range) { // 从getTotalCcu()方法迁移 } } ``` - [ ] **Step 5: 重构IChargeBillServiceImpl使用新服务** ```java @Service public class ChargeBillAppServiceImpl implements IChargeBillAppService { @Autowired private ChargeBillQueryService queryService; @Autowired private ChargeBillCalculationService calculationService; @Autowired private ChargeBillStatisticsService statisticsService; @Override public Page getChargeBills(ChargeBillQueryDto query) { return queryService.getChargeBills(query); } } ``` - [ ] **Step 6: 运行测试验证功能不变** ```bash mvn test -pl healthlink-his-application -Dtest="BillingApiTest,PaymentApiTest" ``` - [ ] **Step 7: Commit** ```bash git add -A git commit -m "refactor: split IChargeBillServiceImpl into query/calculation/statistics services" ``` --- ## Task 6: 添加单元测试框架(建立测试基础设施) **Covers:** 测试维度 Finding 4 **Files:** - Create: `healthlink-his-domain/src/test/java/com/healthlink/his/BaseUnitTest.java` - Create: `healthlink-his-domain/src/test/java/com/healthlink/his/payment/ChargeBillCalculationServiceTest.java` - [ ] **Step 1: 创建BaseUnitTest基类** ```java package com.healthlink.his; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) public abstract class BaseUnitTest { // Mockito配置 } ``` - [ ] **Step 2: 创建ChargeBillCalculationService的单元测试** ```java package com.healthlink.his.payment; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; class ChargeBillCalculationServiceTest extends BaseUnitTest { @InjectMocks private ChargeBillCalculationService service; @Test void calculateSummary_withValidItems_returnsCorrectTotal() { // Given List items = Arrays.asList( new ChargeItem("药品A", new BigDecimal("100.00")), new ChargeItem("药品B", new BigDecimal("200.00")) ); // When ChargeBillSummary summary = service.calculateSummary(items); // Then assertEquals(new BigDecimal("300.00"), summary.getTotalAmount()); } @Test void calculateSummary_withEmptyItems_returnsZero() { // Given List items = Collections.emptyList(); // When ChargeBillSummary summary = service.calculateSummary(items); // Then assertEquals(BigDecimal.ZERO, summary.getTotalAmount()); } } ``` - [ ] **Step 3: 运行单元测试** ```bash mvn test -pl healthlink-his-domain -Dtest="ChargeBillCalculationServiceTest" ``` - [ ] **Step 4: Commit** ```bash git add -A git commit -m "test: add unit test framework and calculation service tests" ``` --- ## 执行顺序 1. Task 1(删除重复文件)- 立即执行,风险最低 2. Task 2(修复脆弱断言)- 立即执行,提高测试可信度 3. Task 3(提取测试基类)- 短期执行,消除重复 4. Task 4(清理过期TODO)- 短期执行,减少噪音 5. Task 5(拆分God Class)- 中期执行,需要仔细设计 6. Task 6(添加单元测试)- 长期执行,建立测试文化 --- ## 验证标准 每个Task完成后必须验证: - [ ] `mvn clean compile -DskipTests` 编译通过 - [ ] `mvn test` 测试通过 - [ ] 无新增编译警告 - [ ] git commit 包含清晰的变更说明