|
|
@@ -10869,6 +10869,177 @@ log.info("迁移298: 已为无 openid 的 child 账号补齐 family_members 记
|
|
|
// 迁移312: 为 gut_flora 补默认指纹规则(空表会导致指纹引擎永远 unknown)
|
|
|
seedGutFloraFingerprints();
|
|
|
|
|
|
+ // 迁移316-329: 原误置于 seedGutFloraFingerprints 早返回(return)之后,gut_flora 指纹存在时永不执行;
|
|
|
+ // 现移至 runSystemMigrations 无条件执行(recommendation_rules / task_orchestration / onboarding_guide_config / 打卡表照片语音字段)
|
|
|
+ // 迁移316: 创建 recommendation_rules 表(统一推荐规则配置)
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS recommendation_rules (" +
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
+ "rule_type TINYINT NOT NULL COMMENT '1-5', " +
|
|
|
+ "rule_name VARCHAR(100) COMMENT '运营名称', " +
|
|
|
+ "trigger_product_id BIGINT COMMENT '触发商品ID', " +
|
|
|
+ "trigger_product_ids VARCHAR(1000) COMMENT '触发商品ID JSON 数组', " +
|
|
|
+ "target_product_id BIGINT COMMENT '目标商品ID', " +
|
|
|
+ "priority INT DEFAULT 10 COMMENT '优先级,越大越优', " +
|
|
|
+ "enabled TINYINT DEFAULT 1 COMMENT '启用 1/0', " +
|
|
|
+ "time_window_days INT COMMENT '回溯窗口(天)', " +
|
|
|
+ "delay_days INT COMMENT '复购延迟天数', " +
|
|
|
+ "scope VARCHAR(20) COMMENT 'family/individual', " +
|
|
|
+ "scene_codes VARCHAR(500) COMMENT '生效场景 JSON 数组', " +
|
|
|
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
+ "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品推荐规则配置'");
|
|
|
+ log.info("迁移316: 已创建recommendation_rules表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 表已存在,忽略错误
|
|
|
+ }
|
|
|
+
|
|
|
+ // 迁移317: recommendation_rules 表索引
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute("CREATE INDEX idx_rules_enabled ON recommendation_rules(enabled)");
|
|
|
+ log.info("迁移317: 已创建idx_rules_enabled索引");
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 索引已存在,忽略错误
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute("CREATE INDEX idx_rules_scene ON recommendation_rules(scene_codes)");
|
|
|
+ log.info("迁移317: 已创建idx_rules_scene索引");
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 索引已存在,忽略错误
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute("CREATE INDEX idx_rules_priority ON recommendation_rules(priority)");
|
|
|
+ log.info("迁移317: 已创建idx_rules_priority索引");
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 索引已存在,忽略错误
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `task_orchestration_flows` (" +
|
|
|
+ "`id` bigint NOT NULL AUTO_INCREMENT," +
|
|
|
+ "`name` varchar(100) NOT NULL," +
|
|
|
+ "`description` text," +
|
|
|
+ "`creator_id` bigint NOT NULL," +
|
|
|
+ "`family_id` bigint DEFAULT NULL," +
|
|
|
+ "`version` int NOT NULL DEFAULT 1," +
|
|
|
+ "`status` varchar(20) NOT NULL DEFAULT 'draft'," +
|
|
|
+ "`schedule_cron` varchar(64) DEFAULT NULL," +
|
|
|
+ "`config_json` json DEFAULT NULL," +
|
|
|
+ "`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP," +
|
|
|
+ "`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
|
|
|
+ "PRIMARY KEY (`id`)," +
|
|
|
+ "KEY `idx_family_id` (`family_id`)," +
|
|
|
+ "KEY `idx_status` (`status`)" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流定义'");
|
|
|
+ log.info("迁移329: 已创建task_orchestration_flows表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("迁移329: task_orchestration_flows 已存在或创建失败: {}", e.getMessage());
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `task_orchestration_edges` (" +
|
|
|
+ "`id` bigint NOT NULL AUTO_INCREMENT," +
|
|
|
+ "`flow_id` bigint NOT NULL," +
|
|
|
+ "`from_node_id` varchar(64) NOT NULL," +
|
|
|
+ "`to_node_id` varchar(64) NOT NULL," +
|
|
|
+ "`edge_type` varchar(20) NOT NULL," +
|
|
|
+ "`operator` varchar(10) NOT NULL DEFAULT 'AND'," +
|
|
|
+ "`sort_order` int NOT NULL DEFAULT 0," +
|
|
|
+ "`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP," +
|
|
|
+ "PRIMARY KEY (`id`)," +
|
|
|
+ "KEY `idx_flow_id` (`flow_id`)," +
|
|
|
+ "UNIQUE KEY `uk_flow_edge` (`flow_id`, `from_node_id`, `to_node_id`)" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流边定义'");
|
|
|
+ log.info("迁移329: 已创建task_orchestration_edges表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("迁移329: task_orchestration_edges 已存在或创建失败: {}", e.getMessage());
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `task_orchestration_executions` (" +
|
|
|
+ "`id` bigint NOT NULL AUTO_INCREMENT," +
|
|
|
+ "`flow_id` bigint NOT NULL," +
|
|
|
+ "`flow_version` int NOT NULL DEFAULT 1," +
|
|
|
+ "`family_id` bigint NOT NULL," +
|
|
|
+ "`family_member_id` bigint NOT NULL," +
|
|
|
+ "`trigger_source` varchar(20) NOT NULL DEFAULT 'manual'," +
|
|
|
+ "`status` varchar(20) NOT NULL DEFAULT 'running'," +
|
|
|
+ "`started_at` datetime NOT NULL," +
|
|
|
+ "`finished_at` datetime DEFAULT NULL," +
|
|
|
+ "`error_reason` varchar(255) DEFAULT NULL," +
|
|
|
+ "`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP," +
|
|
|
+ "`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
|
|
|
+ "PRIMARY KEY (`id`)," +
|
|
|
+ "KEY `idx_execution_flow` (`flow_id`)," +
|
|
|
+ "KEY `idx_execution_status` (`status`)" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流执行记录'");
|
|
|
+ log.info("迁移329: 已创建task_orchestration_executions表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("迁移329: task_orchestration_executions 已存在或创建失败: {}", e.getMessage());
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `task_orchestration_node_instances` (" +
|
|
|
+ "`id` bigint NOT NULL AUTO_INCREMENT," +
|
|
|
+ "`execution_id` bigint NOT NULL," +
|
|
|
+ "`node_id` varchar(64) NOT NULL," +
|
|
|
+ "`task_id` bigint DEFAULT NULL," +
|
|
|
+ "`status` varchar(20) NOT NULL DEFAULT 'pending'," +
|
|
|
+ "`generation` int NOT NULL DEFAULT 0," +
|
|
|
+ "`condition_met_at` datetime DEFAULT NULL COMMENT '条件终止:外部API通知条件达成时间'," +
|
|
|
+ "`loop_termination_reason` varchar(50) DEFAULT NULL," +
|
|
|
+ "`started_at` datetime DEFAULT NULL," +
|
|
|
+ "`completed_at` datetime DEFAULT NULL," +
|
|
|
+ "`error_reason` varchar(255) DEFAULT NULL," +
|
|
|
+ "`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP," +
|
|
|
+ "`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
|
|
|
+ "PRIMARY KEY (`id`)," +
|
|
|
+ "UNIQUE KEY `uk_node_instance` (`execution_id`, `node_id`, `generation`)," +
|
|
|
+ "KEY `idx_execution_id` (`execution_id`)," +
|
|
|
+ "KEY `idx_task_id` (`task_id`)" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流节点实例'");
|
|
|
+ log.info("迁移329: 已创建task_orchestration_node_instances表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("迁移329: task_orchestration_node_instances 已存在或创建失败: {}", e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 迁移318: sys_config 预置首页引导浮层默认配置(onboarding_guide_config key)
|
|
|
+ try {
|
|
|
+ String defaultConfig = "{"
|
|
|
+ + "\"enabled\":true,"
|
|
|
+ + "\"version\":\"1.0\","
|
|
|
+ + "\"positions\":[\"home\",\"child\"],"
|
|
|
+ + "\"parent\":["
|
|
|
+ + "{\"icon\":\"🔍\",\"title\":\"你真的了解孩子的状态吗?\",\"desc\":\"情绪低落没察觉、习惯变化没注意、能力短板没发现——很多问题等爆发了才看见。浠艾福帮你在问题发生前,看清孩子真实的身心状态。\",\"isIntro\":true},"
|
|
|
+ + "{\"icon\":\"🌏\",\"title\":\"五维沙盘,看见全家\",\"desc\":\"身·心·智·行·富,一张全景图看清每个维度。孩子身体好不好、情绪怎么样、能力到哪了——不用猜,看得见.\"},"
|
|
|
+ + "{\"icon\":\"📋\",\"title\":\"小任务,大改变\",\"desc\":\"布置每日小任务,完成就能攒星星。每天一点点积累,好习惯自然养成.\"},"
|
|
|
+ + "{\"icon\":\"🎁\",\"title\":\"心愿墙,看得见努力\",\"desc\":\"孩子攒够星星就能兑换心愿。努力有回报,目标感和坚持力一起培养.\"}"
|
|
|
+ + "],"
|
|
|
+ + "\"child\":["
|
|
|
+ + "{\"icon\":\"🔍\",\"title\":\"你的每一点成长,都被看见\",\"desc\":\"今天完成了几个任务?比昨天进步了多少?浠艾福帮你记录每一点努力,让成长看得见。\",\"isIntro\":true},"
|
|
|
+ + "{\"icon\":\"🌟\",\"title\":\"赚星星\",\"desc\":\"完成爸爸妈妈布置的任务,就能获得星星积分,越努力越多!\"},"
|
|
|
+ + "{\"icon\":\"🎮\",\"title\":\"玩中学\",\"desc\":\"完成任务后可以玩小游戏、兑换心愿,学习和快乐两不误!\"},"
|
|
|
+ + "{\"icon\":\"🏆\",\"title\":\"升级挑战\",\"desc\":\"从星星宝宝到宇宙小英雄,一步步升级,看看你能走多远!\"}"
|
|
|
+ + "]"
|
|
|
+ + "}";
|
|
|
+ jdbcTemplate.update(
|
|
|
+ "INSERT IGNORE INTO sys_config (config_key, config_value, description) VALUES ('onboarding_guide_config', ?, '首页引导浮层配置')",
|
|
|
+ defaultConfig
|
|
|
+ );
|
|
|
+ log.info("迁移318: 已预置onboarding_guide_config默认配置");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("预置onboarding_guide_config可能已存在: {}", e.getMessage());
|
|
|
+ }
|
|
|
+ // 迁移328: 饮食/运动打卡表补充照片与语音字段(前端已上传 media URL,补上持久化列)
|
|
|
+ try {
|
|
|
+ ensureColumn("health_meal_record", "photo_urls", "TEXT COMMENT '照片URL列表(逗号分隔)'");
|
|
|
+ ensureColumn("health_meal_record", "voice_url", "VARCHAR(500) COMMENT '语音URL'");
|
|
|
+ ensureColumn("health_meal_record", "voice_text", "TEXT COMMENT '语音转写文字'");
|
|
|
+ ensureColumn("exercise_record", "photo_urls", "TEXT COMMENT '照片URL列表(逗号分隔)'");
|
|
|
+ ensureColumn("exercise_record", "voice_url", "VARCHAR(500) COMMENT '语音URL'");
|
|
|
+ ensureColumn("exercise_record", "voice_text", "TEXT COMMENT '语音转写文字'");
|
|
|
+ log.info("迁移328: 已为health_meal_record/exercise_record补充照片语音字段");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("迁移328: 补充照片语音字段失败: {}", e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
// 迁移323: 注册素质测评A2报告类型(dan家族)+ 默认指纹规则
|
|
|
// 统一上传后指纹识别为 dan_a2 → ReportCollectService 按 report_type_registry.family=dan 分流走 DAN 采集管道
|
|
|
try {
|
|
|
@@ -11278,254 +11449,6 @@ log.info("迁移298: 已为无 openid 的 child 账号补齐 family_members 记
|
|
|
} catch (Exception e) {
|
|
|
log.warn("迁移312: 写入 gut_flora 指纹规则失败: {}", e.getMessage());
|
|
|
}
|
|
|
-
|
|
|
- // 迁移316: 创建 recommendation_rules 表(统一推荐规则配置)
|
|
|
- try {
|
|
|
- jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS recommendation_rules (" +
|
|
|
- "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
- "rule_type TINYINT NOT NULL COMMENT '1-5', " +
|
|
|
- "rule_name VARCHAR(100) COMMENT '运营名称', " +
|
|
|
- "trigger_product_id BIGINT COMMENT '触发商品ID', " +
|
|
|
- "trigger_product_ids VARCHAR(1000) COMMENT '触发商品ID JSON 数组', " +
|
|
|
- "target_product_id BIGINT COMMENT '目标商品ID', " +
|
|
|
- "priority INT DEFAULT 10 COMMENT '优先级,越大越优', " +
|
|
|
- "enabled TINYINT DEFAULT 1 COMMENT '启用 1/0', " +
|
|
|
- "time_window_days INT COMMENT '回溯窗口(天)', " +
|
|
|
- "delay_days INT COMMENT '复购延迟天数', " +
|
|
|
- "scope VARCHAR(20) COMMENT 'family/individual', " +
|
|
|
- "scene_codes VARCHAR(500) COMMENT '生效场景 JSON 数组', " +
|
|
|
- "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
- "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
|
|
|
- ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品推荐规则配置'");
|
|
|
- log.info("迁移316: 已创建recommendation_rules表");
|
|
|
- } catch (Exception e) {
|
|
|
- // 表已存在,忽略错误
|
|
|
- }
|
|
|
-
|
|
|
- // 迁移317: recommendation_rules 表索引
|
|
|
- try {
|
|
|
- jdbcTemplate.execute("CREATE INDEX idx_rules_enabled ON recommendation_rules(enabled)");
|
|
|
- log.info("迁移317: 已创建idx_rules_enabled索引");
|
|
|
- } catch (Exception e) {
|
|
|
- // 索引已存在,忽略错误
|
|
|
- }
|
|
|
- try {
|
|
|
- jdbcTemplate.execute("CREATE INDEX idx_rules_scene ON recommendation_rules(scene_codes)");
|
|
|
- log.info("迁移317: 已创建idx_rules_scene索引");
|
|
|
- } catch (Exception e) {
|
|
|
- // 索引已存在,忽略错误
|
|
|
- }
|
|
|
- try {
|
|
|
- jdbcTemplate.execute("CREATE INDEX idx_rules_priority ON recommendation_rules(priority)");
|
|
|
- log.info("迁移317: 已创建idx_rules_priority索引");
|
|
|
- } catch (Exception e) {
|
|
|
- // 索引已存在,忽略错误
|
|
|
- }
|
|
|
- try {
|
|
|
- jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `task_orchestration_flows` (" +
|
|
|
- "`id` bigint NOT NULL AUTO_INCREMENT," +
|
|
|
- "`name` varchar(100) NOT NULL," +
|
|
|
- "`description` text," +
|
|
|
- "`creator_id` bigint NOT NULL," +
|
|
|
- "`family_id` bigint DEFAULT NULL," +
|
|
|
- "`version` int NOT NULL DEFAULT 1," +
|
|
|
- "`status` varchar(20) NOT NULL DEFAULT 'draft'," +
|
|
|
- "`schedule_cron` varchar(64) DEFAULT NULL," +
|
|
|
- "`config_json` json DEFAULT NULL," +
|
|
|
- "`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP," +
|
|
|
- "`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
|
|
|
- "PRIMARY KEY (`id`)," +
|
|
|
- "KEY `idx_family_id` (`family_id`)," +
|
|
|
- "KEY `idx_status` (`status`)" +
|
|
|
- ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流定义'");
|
|
|
- log.info("迁移329: 已创建task_orchestration_flows表");
|
|
|
- } catch (Exception e) {
|
|
|
- log.warn("迁移329: task_orchestration_flows 已存在或创建失败: {}", e.getMessage());
|
|
|
- }
|
|
|
- try {
|
|
|
- jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `task_orchestration_edges` (" +
|
|
|
- "`id` bigint NOT NULL AUTO_INCREMENT," +
|
|
|
- "`flow_id` bigint NOT NULL," +
|
|
|
- "`from_node_id` varchar(64) NOT NULL," +
|
|
|
- "`to_node_id` varchar(64) NOT NULL," +
|
|
|
- "`edge_type` varchar(20) NOT NULL," +
|
|
|
- "`operator` varchar(10) NOT NULL DEFAULT 'AND'," +
|
|
|
- "`sort_order` int NOT NULL DEFAULT 0," +
|
|
|
- "`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP," +
|
|
|
- "PRIMARY KEY (`id`)," +
|
|
|
- "KEY `idx_flow_id` (`flow_id`)," +
|
|
|
- "UNIQUE KEY `uk_flow_edge` (`flow_id`, `from_node_id`, `to_node_id`)" +
|
|
|
- ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流边定义'");
|
|
|
- log.info("迁移329: 已创建task_orchestration_edges表");
|
|
|
- } catch (Exception e) {
|
|
|
- log.warn("迁移329: task_orchestration_edges 已存在或创建失败: {}", e.getMessage());
|
|
|
- }
|
|
|
- try {
|
|
|
- jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `task_orchestration_executions` (" +
|
|
|
- "`id` bigint NOT NULL AUTO_INCREMENT," +
|
|
|
- "`flow_id` bigint NOT NULL," +
|
|
|
- "`flow_version` int NOT NULL DEFAULT 1," +
|
|
|
- "`family_id` bigint NOT NULL," +
|
|
|
- "`family_member_id` bigint NOT NULL," +
|
|
|
- "`trigger_source` varchar(20) NOT NULL DEFAULT 'manual'," +
|
|
|
- "`status` varchar(20) NOT NULL DEFAULT 'running'," +
|
|
|
- "`started_at` datetime NOT NULL," +
|
|
|
- "`finished_at` datetime DEFAULT NULL," +
|
|
|
- "`error_reason` varchar(255) DEFAULT NULL," +
|
|
|
- "`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP," +
|
|
|
- "`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
|
|
|
- "PRIMARY KEY (`id`)," +
|
|
|
- "KEY `idx_execution_flow` (`flow_id`)," +
|
|
|
- "KEY `idx_execution_status` (`status`)" +
|
|
|
- ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流执行记录'");
|
|
|
- log.info("迁移329: 已创建task_orchestration_executions表");
|
|
|
- } catch (Exception e) {
|
|
|
- log.warn("迁移329: task_orchestration_executions 已存在或创建失败: {}", e.getMessage());
|
|
|
- }
|
|
|
- try {
|
|
|
- jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `task_orchestration_node_instances` (" +
|
|
|
- "`id` bigint NOT NULL AUTO_INCREMENT," +
|
|
|
- "`execution_id` bigint NOT NULL," +
|
|
|
- "`node_id` varchar(64) NOT NULL," +
|
|
|
- "`task_id` bigint DEFAULT NULL," +
|
|
|
- "`status` varchar(20) NOT NULL DEFAULT 'pending'," +
|
|
|
- "`generation` int NOT NULL DEFAULT 0," +
|
|
|
- "`condition_met_at` datetime DEFAULT NULL COMMENT '条件终止:外部API通知条件达成时间'," +
|
|
|
- "`loop_termination_reason` varchar(50) DEFAULT NULL," +
|
|
|
- "`started_at` datetime DEFAULT NULL," +
|
|
|
- "`completed_at` datetime DEFAULT NULL," +
|
|
|
- "`error_reason` varchar(255) DEFAULT NULL," +
|
|
|
- "`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP," +
|
|
|
- "`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
|
|
|
- "PRIMARY KEY (`id`)," +
|
|
|
- "UNIQUE KEY `uk_node_instance` (`execution_id`, `node_id`, `generation`)," +
|
|
|
- "KEY `idx_execution_id` (`execution_id`)," +
|
|
|
- "KEY `idx_task_id` (`task_id`)" +
|
|
|
- ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流节点实例'");
|
|
|
- log.info("迁移329: 已创建task_orchestration_node_instances表");
|
|
|
- } catch (Exception e) {
|
|
|
- log.warn("迁移329: task_orchestration_node_instances 已存在或创建失败: {}", e.getMessage());
|
|
|
- }
|
|
|
-
|
|
|
- // 迁移318: sys_config 预置首页引导浮层默认配置(onboarding_guide_config key)
|
|
|
- try {
|
|
|
- String defaultConfig = "{"
|
|
|
- + "\"enabled\":true,"
|
|
|
- + "\"version\":\"1.0\","
|
|
|
- + "\"positions\":[\"home\",\"child\"],"
|
|
|
- + "\"parent\":["
|
|
|
- + "{\"icon\":\"🔍\",\"title\":\"你真的了解孩子的状态吗?\",\"desc\":\"情绪低落没察觉、习惯变化没注意、能力短板没发现——很多问题等爆发了才看见。浠艾福帮你在问题发生前,看清孩子真实的身心状态。\",\"isIntro\":true},"
|
|
|
- + "{\"icon\":\"🌏\",\"title\":\"五维沙盘,看见全家\",\"desc\":\"身·心·智·行·富,一张全景图看清每个维度。孩子身体好不好、情绪怎么样、能力到哪了——不用猜,看得见.\"},"
|
|
|
- + "{\"icon\":\"📋\",\"title\":\"小任务,大改变\",\"desc\":\"布置每日小任务,完成就能攒星星。每天一点点积累,好习惯自然养成.\"},"
|
|
|
- + "{\"icon\":\"🎁\",\"title\":\"心愿墙,看得见努力\",\"desc\":\"孩子攒够星星就能兑换心愿。努力有回报,目标感和坚持力一起培养.\"}"
|
|
|
- + "],"
|
|
|
- + "\"child\":["
|
|
|
- + "{\"icon\":\"🔍\",\"title\":\"你的每一点成长,都被看见\",\"desc\":\"今天完成了几个任务?比昨天进步了多少?浠艾福帮你记录每一点努力,让成长看得见。\",\"isIntro\":true},"
|
|
|
- + "{\"icon\":\"🌟\",\"title\":\"赚星星\",\"desc\":\"完成爸爸妈妈布置的任务,就能获得星星积分,越努力越多!\"},"
|
|
|
- + "{\"icon\":\"🎮\",\"title\":\"玩中学\",\"desc\":\"完成任务后可以玩小游戏、兑换心愿,学习和快乐两不误!\"},"
|
|
|
- + "{\"icon\":\"🏆\",\"title\":\"升级挑战\",\"desc\":\"从星星宝宝到宇宙小英雄,一步步升级,看看你能走多远!\"}"
|
|
|
- + "]"
|
|
|
- + "}";
|
|
|
- jdbcTemplate.update(
|
|
|
- "INSERT IGNORE INTO sys_config (config_key, config_value, description) VALUES ('onboarding_guide_config', ?, '首页引导浮层配置')",
|
|
|
- defaultConfig
|
|
|
- );
|
|
|
- log.info("迁移318: 已预置onboarding_guide_config默认配置");
|
|
|
- } catch (Exception e) {
|
|
|
- log.warn("预置onboarding_guide_config可能已存在: {}", e.getMessage());
|
|
|
- }
|
|
|
- // 迁移328: 饮食/运动打卡表补充照片与语音字段(前端已上传 media URL,补上持久化列)
|
|
|
- try {
|
|
|
- ensureColumn("health_meal_record", "photo_urls", "TEXT COMMENT '照片URL列表(逗号分隔)'");
|
|
|
- ensureColumn("health_meal_record", "voice_url", "VARCHAR(500) COMMENT '语音URL'");
|
|
|
- ensureColumn("health_meal_record", "voice_text", "TEXT COMMENT '语音转写文字'");
|
|
|
- ensureColumn("exercise_record", "photo_urls", "TEXT COMMENT '照片URL列表(逗号分隔)'");
|
|
|
- ensureColumn("exercise_record", "voice_url", "VARCHAR(500) COMMENT '语音URL'");
|
|
|
- ensureColumn("exercise_record", "voice_text", "TEXT COMMENT '语音转写文字'");
|
|
|
- log.info("迁移328: 已为health_meal_record/exercise_record补充照片语音字段");
|
|
|
- } catch (Exception e) {
|
|
|
- log.warn("迁移328: 补充照片语音字段失败: {}", e.getMessage());
|
|
|
- }
|
|
|
-
|
|
|
- // 迁移329: 创建 guide_popup 表(弹窗引导页配置化管理)
|
|
|
- try {
|
|
|
- jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_popup (" +
|
|
|
- "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', " +
|
|
|
- "slug VARCHAR(64) NOT NULL UNIQUE COMMENT '唯一标识', " +
|
|
|
- "title VARCHAR(128) NOT NULL DEFAULT '' COMMENT '弹窗标题', " +
|
|
|
- "description TEXT COMMENT '主描述文案', " +
|
|
|
- "icon VARCHAR(256) NOT NULL DEFAULT '' COMMENT '图标:emoji或图片URL', " +
|
|
|
- "icon_type TINYINT NOT NULL DEFAULT 0 COMMENT '图标类型:0=emoji 1=图片', " +
|
|
|
- "theme_color VARCHAR(20) NOT NULL DEFAULT '#F97316' COMMENT '主题色', " +
|
|
|
- "btn_text VARCHAR(64) NOT NULL DEFAULT '知道了' COMMENT '按钮文案', " +
|
|
|
- "btn_action VARCHAR(256) NOT NULL DEFAULT '' COMMENT '点击跳转路径,空=关闭', " +
|
|
|
- "status TINYINT NOT NULL DEFAULT 1 COMMENT '状态:0=禁用 1=启用', " +
|
|
|
- "sort_order INT NOT NULL DEFAULT 0 COMMENT '排序优先级', " +
|
|
|
- "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
|
|
|
- "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', " +
|
|
|
- "INDEX idx_status_sort (status, sort_order)" +
|
|
|
- ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引导弹窗配置表'");
|
|
|
- log.info("迁移329: 已创建 guide_popup 表");
|
|
|
- } catch (Exception e) {
|
|
|
- log.warn("guide_popup 表可能已存在: {}", e.getMessage());
|
|
|
- }
|
|
|
-
|
|
|
- // 迁移330: 创建 guide_popup_step 表(引导弹窗步骤)
|
|
|
- try {
|
|
|
- jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_popup_step (" +
|
|
|
- "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', " +
|
|
|
- "popup_id BIGINT NOT NULL COMMENT '关联 guide_popup.id', " +
|
|
|
- "step_order INT NOT NULL DEFAULT 0 COMMENT '步骤顺序', " +
|
|
|
- "title VARCHAR(128) NOT NULL DEFAULT '' COMMENT '步骤标题', " +
|
|
|
- "desc TEXT COMMENT '步骤描述', " +
|
|
|
- "icon VARCHAR(256) NOT NULL DEFAULT '' COMMENT '步骤图标', " +
|
|
|
- "icon_type TINYINT NOT NULL DEFAULT 0 COMMENT '图标类型:0=emoji 1=图片', " +
|
|
|
- "is_intro TINYINT NOT NULL DEFAULT 0 COMMENT '是否为开场身份定义页', " +
|
|
|
- "btn_text VARCHAR(64) NOT NULL DEFAULT '下一步' COMMENT '本步骤按钮文案', " +
|
|
|
- "btn_action VARCHAR(256) NOT NULL DEFAULT '' COMMENT '最后一步跳转链接', " +
|
|
|
- "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
|
|
|
- "INDEX idx_popup_order (popup_id, step_order)" +
|
|
|
- ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引导弹窗步骤表'");
|
|
|
- log.info("迁移330: 已创建 guide_popup_step 表");
|
|
|
- } catch (Exception e) {
|
|
|
- log.warn("guide_popup_step 表可能已存在: {}", e.getMessage());
|
|
|
- }
|
|
|
-
|
|
|
- // 迁移331: 创建 guide_popup_trigger 表(引导弹窗触发条件)
|
|
|
- try {
|
|
|
- jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_popup_trigger (" +
|
|
|
- "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', " +
|
|
|
- "popup_id BIGINT NOT NULL COMMENT '关联 guide_popup.id', " +
|
|
|
- "trigger_type VARCHAR(32) NOT NULL COMMENT '触发类型:page_enter/task_complete/assessment_done/first_login/daily_active/role_change', " +
|
|
|
- "target_page VARCHAR(128) DEFAULT '' COMMENT '目标页面路径', " +
|
|
|
- "target_action VARCHAR(128) DEFAULT '' COMMENT '触发行为标识', " +
|
|
|
- "min_role VARCHAR(32) DEFAULT 'parent' COMMENT '最低角色要求', " +
|
|
|
- "extra_config JSON DEFAULT NULL COMMENT '扩展条件', " +
|
|
|
- "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
|
|
|
- "INDEX idx_popup_trigger (popup_id)" +
|
|
|
- ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引导弹窗触发条件表'");
|
|
|
- log.info("迁移331: 已创建 guide_popup_trigger 表");
|
|
|
- } catch (Exception e) {
|
|
|
- log.warn("guide_popup_trigger 表可能已存在: {}", e.getMessage());
|
|
|
- }
|
|
|
-
|
|
|
- // 迁移332: 创建 guide_popup_log 表(引导弹窗用户消费记录)
|
|
|
- try {
|
|
|
- jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_popup_log (" +
|
|
|
- "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', " +
|
|
|
- "popup_id BIGINT NOT NULL COMMENT '关联 guide_popup.id', " +
|
|
|
- "user_id BIGINT NOT NULL COMMENT '用户ID users.id', " +
|
|
|
- "member_id BIGINT DEFAULT NULL COMMENT '家庭成员ID family_members.id', " +
|
|
|
- "role VARCHAR(32) NOT NULL COMMENT '弹出时所在角色', " +
|
|
|
- "consumed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '消费时间', " +
|
|
|
- "button_clicked TINYINT NOT NULL DEFAULT 0 COMMENT '是否点击按钮', " +
|
|
|
- "INDEX idx_user_popup (user_id, popup_id), " +
|
|
|
- "INDEX idx_consume_time (consumed_at)" +
|
|
|
- ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引导弹窗用户消费记录表'");
|
|
|
- log.info("迁移332: 已创建 guide_popup_log 表");
|
|
|
- } catch (Exception e) {
|
|
|
- log.warn("guide_popup_log 表可能已存在: {}", e.getMessage());
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
/**
|