|
@@ -202,26 +202,10 @@ public class DatabaseInitializer implements CommandLineRunner {
|
|
|
try {
|
|
try {
|
|
|
jdbcTemplate.execute("ALTER TABLE users ADD INDEX idx_phone (phone)");
|
|
jdbcTemplate.execute("ALTER TABLE users ADD INDEX idx_phone (phone)");
|
|
|
log.info("已添加idx_phone索引到users表");
|
|
log.info("已添加idx_phone索引到users表");
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- // 索引已存在,忽略错误
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 迁移4: children表添加新字段
|
|
|
|
|
- try {
|
|
|
|
|
- jdbcTemplate.execute("ALTER TABLE children ADD COLUMN birthday DATE COMMENT '生日'");
|
|
|
|
|
- log.info("已添加birthday列到children表");
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- // 列已存在,忽略错误
|
|
|
|
|
- }
|
|
|
|
|
|
|
+} catch (Exception e) {
|
|
|
|
|
|
|
|
- try {
|
|
|
|
|
- jdbcTemplate.execute("ALTER TABLE children ADD COLUMN gender ENUM('male', 'female') COMMENT '性别'");
|
|
|
|
|
- log.info("已添加gender列到children表");
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- // 列已存在,忽略错误
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 迁移5: 修改users.role为支持teacher
|
|
|
|
|
try {
|
|
try {
|
|
|
jdbcTemplate.execute("ALTER TABLE users MODIFY COLUMN role ENUM('parent', 'child', 'teacher') NOT NULL");
|
|
jdbcTemplate.execute("ALTER TABLE users MODIFY COLUMN role ENUM('parent', 'child', 'teacher') NOT NULL");
|
|
|
log.info("已更新users.role字段支持teacher角色");
|
|
log.info("已更新users.role字段支持teacher角色");
|
|
@@ -782,26 +766,11 @@ public class DatabaseInitializer implements CommandLineRunner {
|
|
|
"INDEX idx_action (action)" +
|
|
"INDEX idx_action (action)" +
|
|
|
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长规划师申请过程记录表'");
|
|
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长规划师申请过程记录表'");
|
|
|
log.info("已创建guide_application_records表");
|
|
log.info("已创建guide_application_records表");
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- // 表已存在,忽略错误
|
|
|
|
|
- }
|
|
|
|
|
|
|
+} catch (Exception e) {
|
|
|
|
|
|
|
|
- // 迁移20: children表添加system_points字段
|
|
|
|
|
- try {
|
|
|
|
|
- Integer exists = jdbcTemplate.queryForObject(
|
|
|
|
|
- "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'children' AND COLUMN_NAME = 'system_points'",
|
|
|
|
|
- Integer.class);
|
|
|
|
|
- if (exists == null || exists == 0) {
|
|
|
|
|
- jdbcTemplate.execute("ALTER TABLE children ADD COLUMN system_points INT DEFAULT 0 COMMENT '系统积分'");
|
|
|
|
|
- log.info("已添加system_points列到children表");
|
|
|
|
|
- } else {
|
|
|
|
|
- log.info("system_points列已存在,跳过");
|
|
|
|
|
- }
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.warn("检查/添加system_points列失败: {}", e.getMessage());
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 迁移21: points_log表添加category字段
|
|
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
Integer exists = jdbcTemplate.queryForObject(
|
|
Integer exists = jdbcTemplate.queryForObject(
|
|
|
"SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'points_log' AND COLUMN_NAME = 'category'",
|
|
"SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'points_log' AND COLUMN_NAME = 'category'",
|
|
@@ -2108,26 +2077,11 @@ public class DatabaseInitializer implements CommandLineRunner {
|
|
|
} else {
|
|
} else {
|
|
|
log.info("family_member_attributes 表已为 v1.2 结构,跳过");
|
|
log.info("family_member_attributes 表已为 v1.2 结构,跳过");
|
|
|
}
|
|
}
|
|
|
- } catch (Exception e) {
|
|
|
|
|
|
|
+} catch (Exception e) {
|
|
|
log.warn("重建 family_member_attributes 表失败: {}", e.getMessage());
|
|
log.warn("重建 family_member_attributes 表失败: {}", e.getMessage());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 迁移: children 表添加 show_to_family 列(v1.3 家庭成员卡)
|
|
|
|
|
- try {
|
|
|
|
|
- Integer colExists = jdbcTemplate.queryForObject(
|
|
|
|
|
- "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'children' AND COLUMN_NAME = 'show_to_family'",
|
|
|
|
|
- Integer.class);
|
|
|
|
|
- if (colExists == null || colExists == 0) {
|
|
|
|
|
- jdbcTemplate.execute("ALTER TABLE children ADD COLUMN show_to_family TINYINT DEFAULT 1 COMMENT '是否对家庭成员可见: 1=是, 0=否'");
|
|
|
|
|
- log.info("已为 children 表添加 show_to_family 列");
|
|
|
|
|
- } else {
|
|
|
|
|
- log.info("children 表 show_to_family 列已存在,跳过");
|
|
|
|
|
- }
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.warn("检查/添加 children 表 show_to_family 列失败: {}", e.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- // 迁移: users 表添加 show_to_family 列(v1.3 家庭成员卡)
|
|
|
|
|
try {
|
|
try {
|
|
|
Integer colExists = jdbcTemplate.queryForObject(
|
|
Integer colExists = jdbcTemplate.queryForObject(
|
|
|
"SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'show_to_family'",
|
|
"SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'show_to_family'",
|
|
@@ -6496,14 +6450,10 @@ sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min,
|
|
|
try {
|
|
try {
|
|
|
jdbcTemplate.execute("ALTER TABLE emotion_checkin MODIFY COLUMN emotion_type VARCHAR(50) DEFAULT 'custom' COMMENT '情绪类型'");
|
|
jdbcTemplate.execute("ALTER TABLE emotion_checkin MODIFY COLUMN emotion_type VARCHAR(50) DEFAULT 'custom' COMMENT '情绪类型'");
|
|
|
log.info("已修改emotion_checkin.emotion_type为VARCHAR");
|
|
log.info("已修改emotion_checkin.emotion_type为VARCHAR");
|
|
|
- } catch (Exception e) {
|
|
|
|
|
|
|
+} catch (Exception e) {
|
|
|
log.warn("修改emotion_checkin.emotion_type可能已处理: {}", e.getMessage());
|
|
log.warn("修改emotion_checkin.emotion_type可能已处理: {}", e.getMessage());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 迁移127: children表添加name列(兼容旧SQL查询如游戏排行榜LEFT JOIN)
|
|
|
|
|
- ensureColumn("children", "name", "VARCHAR(50) DEFAULT NULL COMMENT '姓名(兼容旧查询)'");
|
|
|
|
|
-
|
|
|
|
|
- // 迁移128: family_fortune表添加缺失列
|
|
|
|
|
ensureColumn("family_fortune", "fortune_level_text", "VARCHAR(50) DEFAULT NULL COMMENT '运势等级文字'");
|
|
ensureColumn("family_fortune", "fortune_level_text", "VARCHAR(50) DEFAULT NULL COMMENT '运势等级文字'");
|
|
|
ensureColumn("family_fortune", "fortune_description", "VARCHAR(500) DEFAULT NULL COMMENT '运势描述'");
|
|
ensureColumn("family_fortune", "fortune_description", "VARCHAR(500) DEFAULT NULL COMMENT '运势描述'");
|
|
|
ensureColumn("family_fortune", "mood_emoji", "VARCHAR(20) DEFAULT NULL COMMENT '心情表情'");
|
|
ensureColumn("family_fortune", "mood_emoji", "VARCHAR(20) DEFAULT NULL COMMENT '心情表情'");
|
|
@@ -10552,12 +10502,56 @@ sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min,
|
|
|
"WHERE u.role='child' AND (u.openid IS NULL OR u.openid='') " +
|
|
"WHERE u.role='child' AND (u.openid IS NULL OR u.openid='') " +
|
|
|
"AND u.family_id IS NOT NULL " +
|
|
"AND u.family_id IS NOT NULL " +
|
|
|
"AND NOT EXISTS (SELECT 1 FROM family_members fm WHERE fm.user_id = u.id)");
|
|
"AND NOT EXISTS (SELECT 1 FROM family_members fm WHERE fm.user_id = u.id)");
|
|
|
- log.info("迁移298: 已为无 openid 的 child 账号补齐 family_members 记录");
|
|
|
|
|
|
|
+log.info("迁移298: 已为无 openid 的 child 账号补齐 family_members 记录");
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.warn("迁移298第二步失败", e);
|
|
log.warn("迁移298第二步失败", e);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 迁移299: promotion_tier 表添加 rate_percent 列(实体新模型返佣比例;修复 PromotionTierCheckScheduledTask 每天01:00 Unknown column 崩溃,2026-09-06)
|
|
|
|
|
|
|
+
|
|
|
|
|
+// 迁移322: 废弃 children 表 —— 数据迁移到 family_members 后删除表(幂等,表不存在时跳过)
|
|
|
|
|
+ try {
|
|
|
|
|
+ Integer childrenTableCnt = jdbcTemplate.queryForObject(
|
|
|
|
|
+ "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'children'",
|
|
|
|
|
+ Integer.class);
|
|
|
|
|
+ if (childrenTableCnt == null || childrenTableCnt == 0) {
|
|
|
|
|
+ log.info("迁移322: children 表不存在,跳过(已废弃)");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 1. 匹配更新:family_members 已存在该成员记录时补全字段
|
|
|
|
|
+ jdbcTemplate.execute(
|
|
|
|
|
+ "UPDATE family_members fm INNER JOIN children c " +
|
|
|
|
|
+ "ON fm.family_id = c.family_id AND fm.nickname = c.nickname AND fm.user_id = c.user_id " +
|
|
|
|
|
+ "SET fm.id_card = c.id_card, fm.penalty_enabled = c.penalty_enabled, fm.theme = c.theme, " +
|
|
|
|
|
+ "fm.system_points = c.system_points, fm.streak_days = c.streak_days, fm.last_task_date = c.last_task_date, " +
|
|
|
|
|
+ "fm.focus_max_daily = c.focus_max_daily, fm.focus_remaining = c.focus_remaining, " +
|
|
|
|
|
+ "fm.focus_reset_date = c.focus_reset_date, fm.total_points = c.total_points, " +
|
|
|
|
|
+ "fm.show_to_family = c.show_to_family, fm.birthday = c.birthday, fm.gender = c.gender, " +
|
|
|
|
|
+ "fm.phone = c.phone, fm.role_override = 'child'");
|
|
|
|
|
+ log.info("迁移322: 已更新 family_members 中已存在的 children 匹配记录字段");
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 不匹配则插入新记录
|
|
|
|
|
+ jdbcTemplate.execute(
|
|
|
|
|
+ "INSERT INTO family_members (family_id, user_id, nickname, birthday, gender, phone, " +
|
|
|
|
|
+ "id_card, penalty_enabled, theme, system_points, streak_days, last_task_date, " +
|
|
|
|
|
+ "focus_max_daily, focus_remaining, focus_reset_date, show_to_family, total_points, " +
|
|
|
|
|
+ "role_override, created_at, updated_at) " +
|
|
|
|
|
+ "SELECT family_id, user_id, nickname, birthday, gender, phone, " +
|
|
|
|
|
+ "id_card, penalty_enabled, theme, system_points, streak_days, last_task_date, " +
|
|
|
|
|
+ "focus_max_daily, focus_remaining, focus_reset_date, show_to_family, total_points, " +
|
|
|
|
|
+ "'child', created_at, updated_at " +
|
|
|
|
|
+ "FROM children " +
|
|
|
|
|
+ "WHERE NOT EXISTS (SELECT 1 FROM family_members fm2 WHERE fm2.family_id = children.family_id " +
|
|
|
|
|
+ "AND fm2.nickname = children.nickname AND fm2.user_id = children.user_id)");
|
|
|
|
|
+ log.info("迁移322: 已从 children 插入不匹配记录到 family_members");
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 删除 children 表
|
|
|
|
|
+ jdbcTemplate.execute("DROP TABLE IF EXISTS children");
|
|
|
|
|
+ log.info("迁移322: 已删除 children 表(数据已迁移到 family_members)");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("迁移322执行失败(children 表可能不存在或迁移范围内字段缺失): {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
ensureColumn("promotion_tier", "rate_percent", "INT DEFAULT 0 COMMENT '当前返佣比例(%)'");
|
|
ensureColumn("promotion_tier", "rate_percent", "INT DEFAULT 0 COMMENT '当前返佣比例(%)'");
|
|
|
|
|
|
|
|
// 迁移300: family_members 添加 status 列(成员状态: active/recycled,非微信用户被移出进回收箱)
|
|
// 迁移300: family_members 添加 status 列(成员状态: active/recycled,非微信用户被移出进回收箱)
|
|
@@ -10565,14 +10559,14 @@ sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min,
|
|
|
|
|
|
|
|
// ===== 生产库对账候选风险记录(已核对生产库,2026-09,按用户决定不迁移/暂不动,仅记录)=====
|
|
// ===== 生产库对账候选风险记录(已核对生产库,2026-09,按用户决定不迁移/暂不动,仅记录)=====
|
|
|
// 注:以下为 entity 期望但生产库未对齐.项目,用户已决定保持现状或记为候选,勿重复迁移。
|
|
// 注:以下为 entity 期望但生产库未对齐.项目,用户已决定保持现状或记为候选,勿重复迁移。
|
|
|
- // 1. children 表缺 phone、id_card(Child 实体+ChildMapper 仍活跃,AccountCleanupService
|
|
|
|
|
|
|
+
|
|
|
// exportUserData 全字段 SELECT 会报 Unknown column 'phone')。schema.sql 已将 children 标为
|
|
// exportUserData 全字段 SELECT 会报 Unknown column 'phone')。schema.sql 已将 children 标为
|
|
|
// 已废除/并入 family_members,用户决定不迁移。
|
|
// 已废除/并入 family_members,用户决定不迁移。
|
|
|
// 2. user_trigger_rules:生产表仅剩 user_id(PK,auto_increment)/action_config/last_triggered_at,
|
|
// 2. user_trigger_rules:生产表仅剩 user_id(PK,auto_increment)/action_config/last_triggered_at,
|
|
|
// 实体期望 id/trigger_type/trigger_action/status/created_at 共 8 列,表 0 行且不在 schema.sql。
|
|
// 实体期望 id/trigger_type/trigger_action/status/created_at 共 8 列,表 0 行且不在 schema.sql。
|
|
|
// UserSegmentationService.getTriggerRules 会查 status,命中时会报 Unknown column 'status'。候选。
|
|
// UserSegmentationService.getTriggerRules 会查 status,命中时会报 Unknown column 'status'。候选。
|
|
|
// 3. promotion_tier.rate_percent:生产用旧模型(tier/team_size_1st/2nd/3rd/total_*),实体期望新模型,
|
|
// 3. promotion_tier.rate_percent:生产用旧模型(tier/team_size_1st/2nd/3rd/total_*),实体期望新模型,
|
|
|
- // 表 0 行。已由迁移299补充 rate_percent 列(2026-09-06 定时任务崩溃修复,生产库已手动 ALTER 补列)。
|
|
|
|
|
|
|
+
|
|
|
// 4. promotion_tier_config:实体已废弃,改用 cf_rate_tier(迁移279),保持现状。
|
|
// 4. promotion_tier_config:实体已废弃,改用 cf_rate_tier(迁移279),保持现状。
|
|
|
// 5. family_members.member_type:实体为 VO 计算值已加 @TableField(exist=false)(不落库),schema.sql
|
|
// 5. family_members.member_type:实体为 VO 计算值已加 @TableField(exist=false)(不落库),schema.sql
|
|
|
// 无此列;2026-09-06 生产已手动 ALTER 补列(JwtInterceptor/SurveyServiceImpl 查询报 Unknown column
|
|
// 无此列;2026-09-06 生产已手动 ALTER 补列(JwtInterceptor/SurveyServiceImpl 查询报 Unknown column
|
|
@@ -10956,7 +10950,6 @@ sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min,
|
|
|
// 表已存在,忽略
|
|
// 表已存在,忽略
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 迁移318: 创建 DOA 个人目标-周计划-周复盘三表(家庭打卡个人目标模块,2026-09-12)
|
|
|
|
|
try {
|
|
try {
|
|
|
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS doa_stage (" +
|
|
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS doa_stage (" +
|
|
|
"id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
"id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
@@ -11071,9 +11064,8 @@ sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min,
|
|
|
}
|
|
}
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.warn("迁移319: 插入 health_plan 提示词种子数据失败: {}", e.getMessage());
|
|
log.warn("迁移319: 插入 health_plan 提示词种子数据失败: {}", e.getMessage());
|
|
|
- }
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 迁移320: exercise_record 表添加 step_count 列(微信运动步数同步)
|
|
|
|
|
try {
|
|
try {
|
|
|
jdbcTemplate.execute("ALTER TABLE exercise_record ADD COLUMN step_count INT COMMENT '微信运动步数'");
|
|
jdbcTemplate.execute("ALTER TABLE exercise_record ADD COLUMN step_count INT COMMENT '微信运动步数'");
|
|
|
log.info("迁移320: exercise_record.step_count 列已添加");
|
|
log.info("迁移320: exercise_record.step_count 列已添加");
|