Просмотр исходного кода

fix(T01): 修复 G3 事后绑定成员不补时序 + confirm 链路补写

- HealthReportService.bindReportToMember: 报告此前无归属时绑定后补跑 NormalizeIndicatorPipeline
- HealthReportController.confirmDraft: createReport 后补写统一指标层时序
- 两处均 try/catch,失败不阻断主流程;底层 upsert 幂等
Sisyphus 2 недель назад
Родитель
Сommit
eff28f10d8

+ 11 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/HealthReportController.java

@@ -39,6 +39,7 @@ import com.etotem.cfc.service.HealthReportService;
 import com.etotem.cfc.service.MemberIndicatorCurrentService;
 import com.etotem.cfc.service.BasicQuotaService;
 import com.etotem.cfc.service.NutritionDeficiencyService;
+import com.etotem.cfc.service.NormalizeIndicatorPipeline;
 import com.etotem.cfc.service.PdfParseService;
 import com.etotem.cfc.service.ReportCollectService;
 import com.etotem.cfc.service.ReportTransferService;
@@ -181,6 +182,9 @@ public class HealthReportController {
     @Resource
     private com.etotem.cfc.service.PurchaseService purchaseService;
 
+    @Resource
+    private NormalizeIndicatorPipeline normalizeIndicatorPipeline;
+
     @Resource
     private MemberIndicatorCurrentService memberIndicatorCurrentService;
 
@@ -1433,6 +1437,13 @@ public class HealthReportController {
 
             HealthReport created = healthReportService.createReport(report, indicators, gutFlora, diseaseRisks);
 
+            // G2(DS-2026-10-25-01):confirm 链路补写统一指标层时序(失败不阻断确认)
+            try {
+                normalizeIndicatorPipeline.processReport(created, payload);
+            } catch (Exception e) {
+                log.warn("confirm 归一化管道写入失败 reportId={}: {}", created.getId(), e.getMessage());
+            }
+
             // 落库 payload 快照 + 创建日志
             healthReportService.savePayloadSnapshot(created.getId(), userId, "create", null, payloadJson);
 

+ 21 - 2
cfc-backend/src/main/java/com/etotem/cfc/service/HealthReportService.java

@@ -1282,10 +1282,12 @@ public class HealthReportService {
     public void bindReportToMember(Long reportId, Long subjectId) {
         // 使用 JdbcTemplate 直接 UPDATE,避免 MyBatis-Plus NOT_NULL 策略导致 NULL 值不更新
         String sql = "UPDATE health_reports SET subject_id = ? WHERE id = ?";
+        Long previousSubjectId = null;
         // A方案:写库前归一化为 family_members.id 口径
         if (subjectId != null && subjectId > 0) {
             HealthReport rep = healthReportMapper.selectById(reportId);
             if (rep != null) {
+                previousSubjectId = rep.getSubjectId();
                 Long resolved = resolveSubjectToMemberId(subjectId, rep.getFamilyId());
                 if (resolved != null && !resolved.equals(subjectId)) {
                     log.info("subjectId归一化 reportId={}, {} -> {}", reportId, subjectId, resolved);
@@ -1296,8 +1298,25 @@ public class HealthReportService {
         int updatedRows = jdbcTemplate.update(sql, subjectId, reportId);
         if (updatedRows == 0) {
             log.warn("reportId={}, subjectId={} 更新失败 - 报告不存在", reportId, subjectId);
-        } else {
-            log.info("已绑定报告 {} 到被检测人 {}", reportId, subjectId);
+            return;
+        }
+        log.info("已绑定报告 {} 到被检测人 {}", reportId, subjectId);
+
+        // G3(DS-2026-10-25-01):上传时未选成员 → NormalizeIndicatorPipeline 因 subjectId==null 静默跳过,
+        // 仅 UPDATE subject_id 不会补写时序,用户会看到「绑了成员却没有历史」。
+        // 只在「此前无归属」时补跑(即 G3 缺口),失败不阻断绑定;processReport 底层 upsert 幂等。
+        if (previousSubjectId == null && subjectId != null) {
+            try {
+                HealthReport rep = healthReportMapper.selectById(reportId);
+                if (rep != null && rep.getSubjectId() != null && rep.getPayloadJson() != null) {
+                    ParsedReportPayload.Payload payload =
+                            objectMapper.readValue(rep.getPayloadJson(), ParsedReportPayload.Payload.class);
+                    normalizeIndicatorPipeline.processReport(rep, payload);
+                    log.info("绑定成员后补写时序 reportId={}, subjectId={}", reportId, subjectId);
+                }
+            } catch (Exception e) {
+                log.warn("绑定成员后补写时序失败 reportId={}: {}", reportId, e.getMessage());
+            }
         }
     }