Explorar o código

feat: add growth record DB schema, entity fields, and PDFBox dependency

Add 8 new columns + unique dedup_hash index to growth_records. Add sourceType, sourceFileUrl, orderId, reportDate, parentRecordId, isLatest, dedupHash, parsedData fields to GrowthRecord entity. Add DuplicateGrowthRecordException and ParsedReport DTO. Add PDFBox 2.0.31 for report parsing.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
liaoxg hai 4 meses
pai
achega
8c52d97651

+ 7 - 0
cfc-backend/pom.xml

@@ -112,6 +112,13 @@
             <version>3.5.3</version>
         </dependency>
 
+        <!-- Apache PDFBox -->
+        <dependency>
+            <groupId>org.apache.pdfbox</groupId>
+            <artifactId>pdfbox</artifactId>
+            <version>2.0.31</version>
+        </dependency>
+
         <!-- SpringDoc OpenAPI (Swagger) -->
         <dependency>
             <groupId>org.springdoc</groupId>

+ 16 - 0
cfc-backend/src/main/java/com/etotem/cfc/common/DuplicateGrowthRecordException.java

@@ -0,0 +1,16 @@
+package com.etotem.cfc.common;
+
+/**
+ * Thrown when attempting to create a growth record whose dedup_hash
+ * already exists (unique index violation on growth_records.dedup_hash).
+ */
+public class DuplicateGrowthRecordException extends RuntimeException {
+
+    public DuplicateGrowthRecordException(String message) {
+        super(message);
+    }
+
+    public DuplicateGrowthRecordException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

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

@@ -3271,6 +3271,59 @@ try {
             log.warn("创建dan_knowledge_base_tag表可能已存在: {}", e.getMessage());
         }
 
+        // 迁移: growth_records表添加来源类型/去重/补充字段
+        try {
+            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN source_type VARCHAR(20) DEFAULT 'manual' COMMENT '来源类型: manual/platform_purchase/self_upload/supplement'");
+            log.info("已添加source_type列到growth_records表");
+        } catch (Exception e) {}
+
+        try {
+            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN source_file_url VARCHAR(500) COMMENT '原始报告文件URL'");
+            log.info("已添加source_file_url列到growth_records表");
+        } catch (Exception e) {}
+
+        try {
+            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN order_id BIGINT COMMENT '关联订单ID'");
+            log.info("已添加order_id列到growth_records表");
+        } catch (Exception e) {}
+
+        try {
+            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN report_date DATETIME COMMENT '测评/报告日期'");
+            log.info("已添加report_date列到growth_records表");
+        } catch (Exception e) {}
+
+        try {
+            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN parent_record_id BIGINT COMMENT '关联的原始档案ID(补充档案专用)'");
+            log.info("已添加parent_record_id列到growth_records表");
+        } catch (Exception e) {}
+
+        try {
+            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN is_latest TINYINT(1) DEFAULT 1 COMMENT '是否同组最新记录'");
+            log.info("已添加is_latest列到growth_records表");
+        } catch (Exception e) {}
+
+        try {
+            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN dedup_hash VARCHAR(64) COMMENT '去重哈希值(SHA256)'");
+            log.info("已添加dedup_hash列到growth_records表");
+        } catch (Exception e) {}
+
+        try {
+            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN parsed_data TEXT COMMENT '上传报告的解析结果(JSON)'");
+            log.info("已添加parsed_data列到growth_records表");
+        } catch (Exception e) {}
+
+        try {
+            jdbcTemplate.execute("CREATE UNIQUE INDEX IF NOT EXISTS uk_growth_dedup_hash ON growth_records(dedup_hash)");
+            log.info("已添加uk_growth_dedup_hash唯一索引到growth_records表");
+        } catch (Exception e) {
+            try {
+                jdbcTemplate.execute("ALTER TABLE growth_records ADD UNIQUE INDEX uk_growth_dedup_hash (dedup_hash)");
+                log.info("已通过ALTER TABLE添加uk_growth_dedup_hash唯一索引");
+            } catch (Exception e2) {
+                log.warn("添加uk_growth_dedup_hash索引可能已存在: {}", e2.getMessage());
+            }
+        }
+
         // 迁移: foods表添加营养字段
         ensureColumn("foods", "energy_kj", "DECIMAL(8,2) COMMENT '能量(kJ/100g)'");
         ensureColumn("foods", "starch", "DECIMAL(8,2) COMMENT '淀粉(g/100g)'");

+ 37 - 0
cfc-backend/src/main/java/com/etotem/cfc/dto/ParsedReport.java

@@ -0,0 +1,37 @@
+package com.etotem.cfc.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ParsedReport implements Serializable {
+
+    private Date reportDate;
+    private String danLevel;
+    private Integer overallScore;
+    private Integer attentionScore;
+    private Integer focusScore;
+    private Integer memoryScore;
+    private Integer logicScore;
+    private Integer perceptionScore;
+    private Integer spatialScore;
+    private Integer processingSpeedScore;
+    private Integer emotionScore;
+    private Integer resilienceScore;
+    private String assessmentSummary;
+    private String growthSuggestions;
+    private String rawText;
+    private String sourceFileUrl;
+
+    public static ParsedReport empty() {
+        return ParsedReport.builder().build();
+    }
+}

+ 17 - 0
cfc-backend/src/main/java/com/etotem/cfc/entity/GrowthRecord.java

@@ -62,4 +62,21 @@ public class GrowthRecord implements Serializable {
     private Date createdAt;
 
     private Date updatedAt;
+
+    // ===== Growth Record Rebuild fields =====
+    private String sourceType;
+
+    private String sourceFileUrl;
+
+    private Long orderId;
+
+    private Date reportDate;
+
+    private Long parentRecordId;
+
+    private Boolean isLatest;
+
+    private String dedupHash;
+
+    private String parsedData;
 }