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

fix: 处理生产日志错误(foods.report_id/score + 知识库JSON + DBI迁移112)

- 修复 Unknown column 'report_id' 错误:
  - 迁移191: foods 添加 report_id/score 列
  - 直连生产 DB ALTER 已执行
- 修复 菌属-食材映射 JSON 解析失败:
  - DB 顶层为 JSON Array 但代码期望 Map,加载时包装为 {_list: [...]}
  - 消费端兼容两种形态
- 修复 迁移112 日志等级:
  - Duplicate column 已存在是幂等预期,log.error → log.warn
  - 避免误报
Xiaogang Liao 1 месяц назад
Родитель
Сommit
6ee3047736

+ 6 - 1
cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java

@@ -7220,7 +7220,8 @@ private void runMigration100() {
 			jdbcTemplate.execute("ALTER TABLE users ADD COLUMN article_admin_status VARCHAR(20) DEFAULT NULL COMMENT '文章管理员状态: pending/approved/rejected'");
 			log.info("迁移112: 已添加article_admin_status列到users表");
 		} catch (Exception e) {
-			log.error("迁移112: 添加article_admin_status列失败: {}", e.getMessage());
+			// 列已存在,幂等忽略(用warn而非error避免日志噪声)
+			log.warn("迁移112: 添加article_admin_status列失败(可能已存在): {}", e.getMessage());
 		}
 
 		// 迁移113: users表添加activity_provider_status字段(活动提供商状态)
@@ -8283,5 +8284,9 @@ private void runMigration100() {
 		} catch (Exception e) {
 			log.warn("创建 report_parser_import 表失败(可能已存在): " + e.getMessage());
 		}
+
+		// 迁移191: foods 添加 report_id/score 列(Food 实体已含字段,生产库缺列导致 Unknown column 'report_id' 错误)
+		ensureColumn("foods", "report_id", "BIGINT DEFAULT NULL COMMENT '关联报告ID(从PDF解析的食物推荐)'");
+		ensureColumn("foods", "score", "INT DEFAULT NULL COMMENT '食物评分'");
 	}
 }

+ 23 - 3
cfc-backend/src/main/java/com/etotem/cfc/service/UnifiedKnowledgeBaseService.java

@@ -127,8 +127,18 @@ public class UnifiedKnowledgeBaseService {
                     continue;
                 }
                 try {
-                    Map<String, Object> content = objectMapper.readValue(row.getContent(),
-                            new TypeReference<Map<String, Object>>() {});
+                    Object parsed = objectMapper.readValue(row.getContent(), Object.class);
+                    Map<String, Object> content;
+                    if (parsed instanceof Map) {
+                        content = (Map<String, Object>) parsed;
+                    } else if (parsed instanceof List) {
+                        // 兼容菌属-食材映射等顶层为数组的模块(包装为 {"_list": list})
+                        content = new java.util.LinkedHashMap<>();
+                        content.put("_list", parsed);
+                    } else {
+                        content = new java.util.LinkedHashMap<>();
+                        content.put("_value", parsed);
+                    }
                     sectionMap.put(row.getModuleKey(), content);
                 } catch (Exception e) {
                     log.warn("解析模块[{}]内容失败: {}", row.getModuleKey(), e.getMessage());
@@ -345,9 +355,19 @@ public class UnifiedKnowledgeBaseService {
 
         // --- 菌属-食材映射: [{拉丁名, 中文名, 分组, 功能分类, 功能说明, ...}] ---
         Object mapping = sectionMap.get("菌属-食材映射");
+        List<Object> mappingList = null;
         if (mapping instanceof List) {
+            mappingList = (List<Object>) mapping;
+        } else if (mapping instanceof Map) {
+            // 兼容 DB 顶层为 Map 但实际数据在 _list 键下的情况
+            Object inner = ((Map<String, Object>) mapping).get("_list");
+            if (inner instanceof List) {
+                mappingList = (List<Object>) inner;
+            }
+        }
+        if (mappingList != null) {
             List<Map<String, Object>> list = new ArrayList<>();
-            for (Object item : (List<Object>) mapping) {
+            for (Object item : mappingList) {
                 if (item instanceof Map) {
                     list.add((Map<String, Object>) item);
                 }