|
@@ -2982,6 +2982,7 @@ insertSysConfigSeed("gift_membership_pay_price", "198000", "送会员商品达
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
runSystemMigrations();
|
|
runSystemMigrations();
|
|
|
|
|
+ registerCollectExpectedIndicators();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private void migrateHealthDimensionsTable() {
|
|
private void migrateHealthDimensionsTable() {
|
|
@@ -11851,7 +11852,7 @@ log.info("迁移298: 已为无 openid 的 child 账号补齐 family_members 记
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 迁移354: product_recommendation_log 补齐缺失列
|
|
|
|
|
|
|
+ // 迁移355: product_recommendation_log 补齐缺失列
|
|
|
// 旧库该表由更早版本的建表语句创建(CREATE TABLE IF NOT EXISTS 不会补列),
|
|
// 旧库该表由更早版本的建表语句创建(CREATE TABLE IF NOT EXISTS 不会补列),
|
|
|
// 缺 family_id/was_clicked/was_purchased/clicked_at/purchased_at/updated_at,
|
|
// 缺 family_id/was_clicked/was_purchased/clicked_at/purchased_at/updated_at,
|
|
|
// 导致 stats/ab-summary、stats/by-type 查询报 Unknown column 返回 500
|
|
// 导致 stats/ab-summary、stats/by-type 查询报 Unknown column 返回 500
|
|
@@ -11868,6 +11869,155 @@ log.info("迁移298: 已为无 openid 的 child 账号补齐 family_members 记
|
|
|
"DATETIME DEFAULT NULL COMMENT '购买时间'");
|
|
"DATETIME DEFAULT NULL COMMENT '购买时间'");
|
|
|
ensureColumn("product_recommendation_log", "updated_at",
|
|
ensureColumn("product_recommendation_log", "updated_at",
|
|
|
"DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'");
|
|
"DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'");
|
|
|
- log.info("迁移354: product_recommendation_log 已补齐缺失列");
|
|
|
|
|
|
|
+ log.info("迁移355: product_recommendation_log 已补齐缺失列");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移354: 报告采集指标项定义(report_type_registry.expected_indicators)+ 草稿采集校验结果列(health_report_drafts.collect_validation)
|
|
|
|
|
+ // 每个报告类型定义「应采集指标项」清单(JSON 数组),ReportCollectService 采集完成后按此校验完整性,结果写入草稿 collect_validation。
|
|
|
|
|
+ // DAN 指标项按 测评数据_优化提取.csv 各报告类型列(填充率>=30%)总结;菌群指标项按 docs/参考资料 已解析报告的指标/区块总结。
|
|
|
|
|
+ private void registerCollectExpectedIndicators() {
|
|
|
|
|
+ ensureColumn("report_type_registry", "expected_indicators",
|
|
|
|
|
+ "TEXT NULL COMMENT '该报告类型应采集的指标项定义(JSON数组),用于数据采集完整性校验'");
|
|
|
|
|
+ ensureColumn("health_report_drafts", "collect_validation",
|
|
|
|
|
+ "TEXT NULL COMMENT '采集指标校验结果(JSON: typeId/expected/matched/pass/missing)'");
|
|
|
|
|
+
|
|
|
|
|
+ // 确保注册表存在各 DAN 类型 + 北京菌群类型的行(parser_path 空 = 保持走 LangGraph 检测,不影响既有路由)
|
|
|
|
|
+ ensureReportTypeRow("dan_a1", "dan", "素质测评A1", "核心认知发展评估报告:感知觉/注意力/记忆力/推理能力/空间能力/加工速度");
|
|
|
|
|
+ ensureReportTypeRow("dan_b2", "dan", "素质测评B2", "儿童行为评估报告:自我概念/行为问题");
|
|
|
|
|
+ ensureReportTypeRow("dan_b3", "dan", "素质测评B3", "学习能力评估报告:执行功能/学习动机/学习策略/自我效能感");
|
|
|
|
|
+ ensureReportTypeRow("dan_b4", "dan", "素质测评B4", "核心素养评估报告:认知能力/成长型思维/自我概念");
|
|
|
|
|
+ ensureReportTypeRow("dan_b5", "dan", "素质测评B5", "青春期发展评估报告:情绪调节/人际关系/睡眠/运动/网络依赖/学业压力");
|
|
|
|
|
+ ensureReportTypeRow("dan_b6", "dan", "素质测评B6", "职业发展评估报告:霍兰德兴趣/多元智能/职业价值观");
|
|
|
|
|
+ ensureReportTypeRow("dan_c1", "dan", "素质测评C1", "校园版核心素养评估报告:认知能力/大五人格/自我概念/学习动机");
|
|
|
|
|
+ ensureReportTypeRow("gut_flora_beijing", "gut_flora", "北京菌群检测", "北京肠道菌群检测报告(FMT移植前/后评估)");
|
|
|
|
|
+
|
|
|
|
|
+ // 种子各类型「应采集指标项」定义(每次启动覆盖,保证与代码一致)
|
|
|
|
|
+ seedExpectedIndicator("dan_a1", jsonArray(
|
|
|
|
|
+ "感知觉_pct", "感知觉_score", "注意力_pct", "注意力_score",
|
|
|
|
|
+ "记忆力_pct", "记忆力_score", "推理能力_pct", "推理能力_score",
|
|
|
|
|
+ "空间能力_pct", "空间能力_score", "加工速度_pct", "加工速度_score",
|
|
|
|
|
+ "总分", "百分位"));
|
|
|
|
|
+ seedExpectedIndicator("dan_a2", jsonArray(
|
|
|
|
|
+ "BMI", "感知觉_pct", "记忆力_pct", "注意力_pct",
|
|
|
|
|
+ "外倾性", "宜人性", "开放性", "责任心", "神经质",
|
|
|
|
|
+ "情绪总分", "焦虑-安详", "抑郁-愉快", "无力感-掌控感", "自卑-自尊",
|
|
|
|
|
+ "与同伴亲近", "与同伴信任", "与同伴沟通",
|
|
|
|
|
+ "与母亲亲近", "与母亲信任", "与母亲沟通",
|
|
|
|
|
+ "与父亲亲近", "与父亲信任", "与父亲沟通",
|
|
|
|
|
+ "身高", "体重", "睡眠_小时", "运动_小时", "饮食_小时",
|
|
|
|
|
+ "总分", "百分位"));
|
|
|
|
|
+ seedExpectedIndicator("dan_b2", jsonArray(
|
|
|
|
|
+ "自我概念_合群", "自我概念_幸福与满足", "自我概念_情绪状态", "自我概念_能力与学校",
|
|
|
|
|
+ "自我概念_行为表现", "自我概念_躯体外貌",
|
|
|
|
|
+ "行为_品行问题", "行为_学习问题", "行为_情绪问题", "行为_生活习惯", "行为_社交问题"));
|
|
|
|
|
+ seedExpectedIndicator("dan_b3", jsonArray(
|
|
|
|
|
+ "工作记忆_pct", "认知灵活性_pct", "抑制控制_pct",
|
|
|
|
|
+ "表面动机", "深层动机", "学习自我调节", "表面方法与策略", "深层方法与策略",
|
|
|
|
|
+ "自我效能感", "总分"));
|
|
|
|
|
+ seedExpectedIndicator("dan_b4", jsonArray(
|
|
|
|
|
+ "感知觉_pct", "感知觉_score", "注意力_pct", "注意力_score",
|
|
|
|
|
+ "记忆力_pct", "记忆力_score", "推理能力_pct", "推理能力_score",
|
|
|
|
|
+ "空间能力_pct", "空间能力_score", "加工速度_pct", "加工速度_score",
|
|
|
|
|
+ "成长型思维",
|
|
|
|
|
+ "自我概念_合群", "自我概念_幸福与满足", "自我概念_情绪状态", "自我概念_能力与学校",
|
|
|
|
|
+ "自我概念_行为表现", "自我概念_躯体外貌",
|
|
|
|
|
+ "自主性", "胜任感", "归属感",
|
|
|
|
|
+ "总分", "百分位"));
|
|
|
|
|
+ seedExpectedIndicator("dan_b5", jsonArray(
|
|
|
|
|
+ "表达抑制", "认知重评",
|
|
|
|
|
+ "人际_父亲关系", "人际_父亲关系_过度期待", "人际_父亲关系_价值冲突",
|
|
|
|
|
+ "人际_父亲关系_控制压迫", "人际_父亲关系_情感疏离", "人际_父亲关系_双重标准",
|
|
|
|
|
+ "人际_母亲关系", "人际_母亲关系_过度期待", "人际_母亲关系_价值冲突",
|
|
|
|
|
+ "人际_母亲关系_控制压迫", "人际_母亲关系_情感疏离", "人际_母亲关系_双重标准",
|
|
|
|
|
+ "人际_师生关系", "人际_师生关系_敌对型", "人际_师生关系_高控制型",
|
|
|
|
|
+ "人际_师生关系_关系疏离型", "人际_师生关系_回避型",
|
|
|
|
|
+ "人际_同伴关系", "人际_同伴关系_被排斥型", "人际_同伴关系_边缘型",
|
|
|
|
|
+ "人际_同伴关系_攻击型", "人际_同伴关系_回避型", "人际_同伴关系_特殊因素型",
|
|
|
|
|
+ "社交_表达影响", "社交_冲突解决", "社交_情感表达", "社交_情感支持", "社交_主动交往",
|
|
|
|
|
+ "入睡时间_min", "睡眠_催眠药物", "睡眠_日间功能", "睡眠_时长", "睡眠_效率",
|
|
|
|
|
+ "睡眠_障碍", "睡眠_主观质量",
|
|
|
|
|
+ "网络依赖_戒断反应", "网络依赖_强迫使用", "网络依赖_时间管理", "网络依赖_总分",
|
|
|
|
|
+ "学业压力_家庭期望", "学业压力_师生关系", "学业压力_同伴竞争", "学业压力_学业负担", "学业压力_自我期望",
|
|
|
|
|
+ "运动_步行_频率", "运动_步行_时长", "运动_高强度_频率", "运动_高强度_时长",
|
|
|
|
|
+ "运动_久坐_频率", "运动_久坐_时长", "运动_中等强度_频率", "运动_中等强度_时长",
|
|
|
|
|
+ "总分", "百分位"));
|
|
|
|
|
+ seedExpectedIndicator("dan_b6", jsonArray(
|
|
|
|
|
+ "能力_内省", "能力_人际关系", "能力_音乐", "能力_自然",
|
|
|
|
|
+ "兴趣_常规型", "兴趣_社会型", "兴趣_事业型", "兴趣_现实型", "兴趣_研究型", "兴趣_艺术型",
|
|
|
|
|
+ "职业价值观"));
|
|
|
|
|
+ seedExpectedIndicator("dan_c1", jsonArray(
|
|
|
|
|
+ "BMI",
|
|
|
|
|
+ "感知觉_pct", "感知觉_score", "注意力_pct", "注意力_score",
|
|
|
|
|
+ "记忆力_pct", "记忆力_score", "推理能力_pct", "推理能力_score",
|
|
|
|
|
+ "空间能力_pct", "空间能力_score", "加工速度_pct", "加工速度_score",
|
|
|
|
|
+ "外倾性", "宜人性", "开放性", "责任心", "神经质", "情绪总分",
|
|
|
|
|
+ "自我概念_合群", "自我概念_幸福与满足", "自我概念_情绪状态", "自我概念_能力与学校",
|
|
|
|
|
+ "自我概念_行为表现", "自我概念_躯体外貌",
|
|
|
|
|
+ "表面动机", "深层动机", "学习自我调节", "表面方法与策略", "深层方法与策略", "自我效能感",
|
|
|
|
|
+ "自主性", "胜任感", "归属感",
|
|
|
|
|
+ "与同伴亲近", "与同伴信任", "与同伴沟通",
|
|
|
|
|
+ "与母亲亲近", "与母亲信任", "与母亲沟通",
|
|
|
|
|
+ "与父亲亲近", "与父亲信任", "与父亲沟通",
|
|
|
|
|
+ "身高", "体重", "睡眠时长", "运动时间",
|
|
|
|
|
+ "总分", "百分位"));
|
|
|
|
|
+ seedExpectedIndicator("gut_flora", jsonArray(
|
|
|
|
|
+ "肠道预测年龄", "肠型", "肠道菌群平衡", "菌群多样性", "有益菌", "有害菌", "核心菌属",
|
|
|
|
|
+ "健康总分", "菌群健康", "慢病控制", "营养均衡",
|
|
|
|
|
+ "疾病风险评估", "主要营养评估", "氨基酸评估", "维生素评估", "微量元素评估",
|
|
|
|
|
+ "主要消化道致病菌", "抗生素风险评估", "肠道屏障及代谢物", "短链脂肪酸",
|
|
|
|
|
+ "神经递质及激素", "菌群检出详细列表", "个体化食物推荐表"));
|
|
|
|
|
+ seedExpectedIndicator("gut_flora_beijing", jsonArray(
|
|
|
|
|
+ "肠型", "肠道微生物健康指数", "肠道菌群平衡评估", "肠道黏膜屏障", "肠道菌群多样性",
|
|
|
|
|
+ "肠道菌群表型评估", "肠道抗炎能力", "肠道免疫力", "肠道膳食纤维需求", "短链脂肪酸合成能力",
|
|
|
|
|
+ "核心菌属综合评分", "有益菌综合评分", "有害菌综合评分",
|
|
|
|
|
+ "疾病风险评估", "营养物质及营养素代谢评估", "抗生素风险评估",
|
|
|
|
|
+ "毒性物质清除能力评估", "胃肠道感染病原体评估", "趣味肠菌评估",
|
|
|
|
|
+ "菌群检出详细列表", "个体化食物推荐表"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 注册报告类型行(INSERT IF 不存在,幂等;parser_path=null 保持走 LangGraph 检测) */
|
|
|
|
|
+ private void ensureReportTypeRow(String typeId, String family, String displayName, String description) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Integer count = jdbcTemplate.queryForObject(
|
|
|
|
|
+ "SELECT COUNT(*) FROM report_type_registry WHERE type_id = ?", Integer.class, typeId);
|
|
|
|
|
+ if (count == null || count == 0) {
|
|
|
|
|
+ jdbcTemplate.update(
|
|
|
|
|
+ "INSERT INTO report_type_registry (type_id, family, display_name, description, parser_path, " +
|
|
|
|
|
+ "min_confidence, is_active, source, review_status, version, created_at, updated_at) " +
|
|
|
|
|
+ "VALUES (?, ?, ?, ?, NULL, 30, 1, 'prebuilt', 'approved', '1.0', NOW(), NOW())",
|
|
|
|
|
+ typeId, family, displayName, description);
|
|
|
|
|
+ log.info("迁移354: 已注册报告类型 {}", typeId);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("迁移354: 注册报告类型 {} 失败: {}", typeId, e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 写入类型「应采集指标项」定义(每次启动覆盖,保证与代码一致) */
|
|
|
|
|
+ private void seedExpectedIndicator(String typeId, String expectedJson) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ int updated = jdbcTemplate.update(
|
|
|
|
|
+ "UPDATE report_type_registry SET expected_indicators = ?, updated_at = NOW() WHERE type_id = ?",
|
|
|
|
|
+ expectedJson, typeId);
|
|
|
|
|
+ if (updated == 0) {
|
|
|
|
|
+ log.warn("迁移354: 类型 {} 不存在,跳过指标项定义", typeId);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.info("迁移354: 已为类型 {} 写入指标项定义", typeId);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("迁移354: 为类型 {} 写入指标项定义失败: {}", typeId, e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 简易 JSON 字符串数组序列化(指标项均为中文/ASCII,无转义风险) */
|
|
|
|
|
+ private String jsonArray(String... items) {
|
|
|
|
|
+ StringBuilder sb = new StringBuilder("[");
|
|
|
|
|
+ for (int i = 0; i < items.length; i++) {
|
|
|
|
|
+ if (i > 0) {
|
|
|
|
|
+ sb.append(',');
|
|
|
|
|
+ }
|
|
|
|
|
+ sb.append('"').append(items[i]).append('"');
|
|
|
|
|
+ }
|
|
|
|
|
+ return sb.append(']').toString();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|