jiapu 2 недель назад
Родитель
Сommit
49106d4cc0

+ 16 - 0
cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java

@@ -8495,6 +8495,13 @@ public class DatabaseInitializer implements CommandLineRunner {
 
         // 迁移181: health_report_drafts 添加备注字段(代上传说明文字)
         ensureColumn("health_report_drafts", "remark", "VARCHAR(500) DEFAULT NULL COMMENT '备注(如代上传时的说明文字)'");
+        // 迁移181b: 异步采集状态列(实体已映射,必须在查询前存在;放在草稿表迁移旁避免后面 ensureColumn 抛错导致漏执行)
+        ensureColumn("health_report_drafts", "parse_status",
+                "VARCHAR(20) DEFAULT NULL COMMENT '异步解析状态: collecting/completed/failed(NULL=未触发异步采集)'");
+        ensureColumn("health_report_drafts", "parse_method",
+                "VARCHAR(32) DEFAULT NULL COMMENT '解析方式: fingerprint_script/opencode/langgraph'");
+        ensureColumn("health_report_drafts", "parse_error",
+                "VARCHAR(2000) DEFAULT NULL COMMENT '异步解析失败原因'");
 
         // 迁移182: 创建 family_challenge_participant 表(挑战参与成员,任意成员发起/可选参与)
         try {
@@ -10264,5 +10271,14 @@ public class DatabaseInitializer implements CommandLineRunner {
         ensureColumn("health_report_drafts", "parse_error",
                 "VARCHAR(2000) DEFAULT NULL COMMENT '异步解析失败原因'");
         log.info("已添加 health_report_drafts 异步采集状态列 (parse_status/parse_method/parse_error)");
+
+        // 迁移289: health_report_drafts.expire_at 去掉 ON UPDATE CURRENT_TIMESTAMP
+        // 解析更新 payload 时会把过期时间重置为当前时刻,导致确认入库被误判过期
+        try {
+            jdbcTemplate.execute("ALTER TABLE health_report_drafts MODIFY COLUMN expire_at DATETIME COMMENT '草稿过期时间'");
+            log.info("已修正 health_report_drafts.expire_at 列定义");
+        } catch (Exception e) {
+            log.warn("修正 health_report_drafts.expire_at 失败: {}", e.getMessage());
+        }
     }
 }

+ 1 - 1
cfc-backend/src/main/java/com/etotem/cfc/entity/HealthReportDraft.java

@@ -59,7 +59,7 @@ public class HealthReportDraft implements Serializable {
     /** 异步解析失败原因 */
     private String parseError;
 
-    /** 草稿过期时间(创建时间+24h) */
+    /** 草稿过期时间(创建时间+72h) */
     private Date expireAt;
 
     /** 确认后对应的真实报告ID */

+ 11 - 2
cfc-backend/src/main/java/com/etotem/cfc/service/HealthReportDraftService.java

@@ -65,7 +65,14 @@ public class HealthReportDraftService {
             return null;
         }
         if (draft.getExpireAt() != null && draft.getExpireAt().before(new Date())) {
-            return null;
+            // expire_at 可能被 ON UPDATE CURRENT_TIMESTAMP 在解析写回时重置;
+            // 仍以 created_at + TTL 为准,避免刚解析完的草稿被误判过期。
+            Date created = draft.getCreatedAt();
+            if (created == null || System.currentTimeMillis() - created.getTime() > DRAFT_TTL_MS) {
+                return null;
+            }
+            log.warn("草稿 expire_at 已过期但 created_at 仍在 TTL 内,放行: draftId={}, expireAt={}, createdAt={}",
+                    draftId, draft.getExpireAt(), created);
         }
         return draft;
     }
@@ -112,10 +119,12 @@ public class HealthReportDraftService {
      * 更新草稿载荷 JSON(解析完成后写入)
      */
     public void updatePayload(Long draftId, String payloadJson) {
+        Date now = new Date();
         LambdaUpdateWrapper<HealthReportDraft> uw = new LambdaUpdateWrapper<>();
         uw.eq(HealthReportDraft::getId, draftId)
           .set(HealthReportDraft::getPayloadJson, payloadJson)
-          .set(HealthReportDraft::getUpdatedAt, new Date());
+          .set(HealthReportDraft::getExpireAt, new Date(now.getTime() + DRAFT_TTL_MS))
+          .set(HealthReportDraft::getUpdatedAt, now);
         draftMapper.update(null, uw);
     }
     public void updateNote(Long draftId, String note) {