|
@@ -5782,6 +5782,213 @@ try {
|
|
|
// 迁移116: growth_records表添加family_member_id和family_member_age列(修复/record/list 500错误)
|
|
// 迁移116: growth_records表添加family_member_id和family_member_age列(修复/record/list 500错误)
|
|
|
ensureColumn("growth_records", "family_member_id", "BIGINT COMMENT '关联家庭成员ID'");
|
|
ensureColumn("growth_records", "family_member_id", "BIGINT COMMENT '关联家庭成员ID'");
|
|
|
ensureColumn("growth_records", "family_member_age", "INT COMMENT '成员年龄快照'");
|
|
ensureColumn("growth_records", "family_member_age", "INT COMMENT '成员年龄快照'");
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移117: 创建 emotion_checkin 表情绪打卡表(Fix 心理与情绪模块 500 错误)
|
|
|
|
|
+ try {
|
|
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS emotion_checkin (" +
|
|
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
|
|
+ "child_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
|
|
|
|
|
+ "mood_weather VARCHAR(50) COMMENT '心情晴雨表: sunny/cloudy/rainy/stormy', " +
|
|
|
|
|
+ "emotion_tags VARCHAR(200) COMMENT '情绪标签(逗号分隔)', " +
|
|
|
|
|
+ "photo_url VARCHAR(500) COMMENT '配图URL', " +
|
|
|
|
|
+ "note TEXT COMMENT '文字备注', " +
|
|
|
|
|
+ "energy_awarded INT DEFAULT 0 COMMENT '奖励能量值', " +
|
|
|
|
|
+ "checkin_date DATE COMMENT '打卡日期', " +
|
|
|
|
|
+ "mood_score INT COMMENT '心情分数(1-10)', " +
|
|
|
|
|
+ "emotion_type VARCHAR(50) COMMENT '情绪类型', " +
|
|
|
|
|
+ "stress_level INT COMMENT '压力等级(1-10)', " +
|
|
|
|
|
+ "arousal_level INT COMMENT '激活水平(1-10)', " +
|
|
|
|
|
+ "energy_level INT COMMENT '精力水平(1-10)', " +
|
|
|
|
|
+ "sleep_hours DECIMAL(4,1) COMMENT '睡眠时长', " +
|
|
|
|
|
+ "sleep_quality INT COMMENT '睡眠质量(1-10)', " +
|
|
|
|
|
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "INDEX idx_child_date (child_id, checkin_date)" +
|
|
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='情绪打卡记录'");
|
|
|
|
|
+ log.info("已创建emotion_checkin表");
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("创建emotion_checkin表可能已存在: {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移118: 创建 emotion_alert 表情绪告警表
|
|
|
|
|
+ try {
|
|
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS emotion_alert (" +
|
|
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
|
|
+ "child_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
|
|
|
|
|
+ "alert_type VARCHAR(50) NOT NULL COMMENT '告警类型: consecutive_low_mood/crisis_keyword/sharp_decline', " +
|
|
|
|
|
+ "severity VARCHAR(20) NOT NULL DEFAULT 'low' COMMENT '严重级别: low/medium/high', " +
|
|
|
|
|
+ "title VARCHAR(200) COMMENT '告警标题', " +
|
|
|
|
|
+ "message TEXT COMMENT '告警具体描述', " +
|
|
|
|
|
+ "related_checkin_id BIGINT COMMENT '关联情绪打卡ID', " +
|
|
|
|
|
+ "resolved TINYINT(1) DEFAULT 0 COMMENT '是否已处理', " +
|
|
|
|
|
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "resolved_at DATETIME COMMENT '处理时间', " +
|
|
|
|
|
+ "INDEX idx_child (child_id), " +
|
|
|
|
|
+ "INDEX idx_alert_type (alert_type)" +
|
|
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='情绪告警'");
|
|
|
|
|
+ log.info("已创建emotion_alert表");
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("创建emotion_alert表可能已存在: {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移119: 创建 membership_levels 表(会员等级配置)
|
|
|
|
|
+ try {
|
|
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS membership_levels (" +
|
|
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
|
|
+ "level_code VARCHAR(50) NOT NULL COMMENT '等级编码: FREE/BASIC/PROFESSIONAL/ENTERPRISE', " +
|
|
|
|
|
+ "level_name VARCHAR(100) NOT NULL COMMENT '等级名称', " +
|
|
|
|
|
+ "level_desc TEXT COMMENT '等级描述', " +
|
|
|
|
|
+ "price_monthly INT COMMENT '月费(分)', " +
|
|
|
|
|
+ "price_quarterly INT COMMENT '季费(分)', " +
|
|
|
|
|
+ "price_yearly INT COMMENT '年费(分)', " +
|
|
|
|
|
+ "features TEXT COMMENT '功能权限列表(JSON)', " +
|
|
|
|
|
+ "max_children INT DEFAULT 0 COMMENT '可添加孩子数量', " +
|
|
|
|
|
+ "max_tasks_per_day INT DEFAULT 0 COMMENT '每日任务上限', " +
|
|
|
|
|
+ "ai_review_enabled TINYINT(1) DEFAULT 0 COMMENT 'AI审核功能', " +
|
|
|
|
|
+ "priority_support TINYINT(1) DEFAULT 0 COMMENT '优先客服', " +
|
|
|
|
|
+ "teacher_consultation TINYINT(1) DEFAULT 0 COMMENT '老师咨询', " +
|
|
|
|
|
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "UNIQUE KEY uk_level_code (level_code)" +
|
|
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员等级配置'");
|
|
|
|
|
+ log.info("已创建membership_levels表");
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("创建membership_levels表可能已存在: {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移120: 创建 family_memberships 表(家庭会员订阅记录)
|
|
|
|
|
+ try {
|
|
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_memberships (" +
|
|
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
|
|
+ "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
|
|
|
|
|
+ "level_code VARCHAR(50) NOT NULL DEFAULT 'FREE' COMMENT '会员等级编码', " +
|
|
|
|
|
+ "start_date DATETIME COMMENT '开始时间', " +
|
|
|
|
|
+ "end_date DATETIME COMMENT '结束时间', " +
|
|
|
|
|
+ "payment_method VARCHAR(50) COMMENT '支付方式: wechat/alipay/card', " +
|
|
|
|
|
+ "payment_status VARCHAR(20) DEFAULT 'pending' COMMENT '支付状态: pending/paid/expired/refunded', " +
|
|
|
|
|
+ "order_no VARCHAR(100) COMMENT '订单号', " +
|
|
|
|
|
+ "transaction_id VARCHAR(200) COMMENT '交易流水号', " +
|
|
|
|
|
+ "amount INT COMMENT '支付金额(分)', " +
|
|
|
|
|
+ "auto_renew TINYINT(1) DEFAULT 0 COMMENT '自动续费', " +
|
|
|
|
|
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "INDEX idx_family_id (family_id), " +
|
|
|
|
|
+ "INDEX idx_end_date (end_date)" +
|
|
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭会员订阅'");
|
|
|
|
|
+ log.info("已创建family_memberships表");
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("创建family_memberships表可能已存在: {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移121: 创建 share_events 表(分享事件记录)
|
|
|
|
|
+ try {
|
|
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS share_events (" +
|
|
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
|
|
+ "user_id BIGINT NOT NULL COMMENT '分享用户ID', " +
|
|
|
|
|
+ "target_type VARCHAR(50) NOT NULL COMMENT '分享目标类型: article/growth/product', " +
|
|
|
|
|
+ "target_id BIGINT NOT NULL COMMENT '分享目标ID', " +
|
|
|
|
|
+ "share_channel VARCHAR(50) COMMENT '分享渠道: wechat/timeline/qq/url', " +
|
|
|
|
|
+ "share_title VARCHAR(200) COMMENT '分享标题', " +
|
|
|
|
|
+ "share_url VARCHAR(500) COMMENT '分享URL', " +
|
|
|
|
|
+ "click_count INT DEFAULT 0 COMMENT '点击次数', " +
|
|
|
|
|
+ "read_count INT DEFAULT 0 COMMENT '阅读次数', " +
|
|
|
|
|
+ "reward_points INT DEFAULT 0 COMMENT '奖励积分', " +
|
|
|
|
|
+ "status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active/expired', " +
|
|
|
|
|
+ "expires_at DATETIME COMMENT '过期时间', " +
|
|
|
|
|
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "INDEX idx_user (user_id), " +
|
|
|
|
|
+ "INDEX idx_target (target_type, target_id)" +
|
|
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分享事件'");
|
|
|
|
|
+ log.info("已创建share_events表");
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("创建share_events表可能已存在: {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移122: 创建 share_reads 表(分享阅读记录)
|
|
|
|
|
+ try {
|
|
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS share_reads (" +
|
|
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
|
|
+ "share_event_id BIGINT NOT NULL COMMENT '分享事件ID', " +
|
|
|
|
|
+ "reader_id BIGINT COMMENT '阅读者用户ID', " +
|
|
|
|
|
+ "reader_ip VARCHAR(50) COMMENT '阅读者IP', " +
|
|
|
|
|
+ "read_duration INT COMMENT '阅读时长(秒)', " +
|
|
|
|
|
+ "read_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '阅读时间', " +
|
|
|
|
|
+ "INDEX idx_share_event (share_event_id), " +
|
|
|
|
|
+ "INDEX idx_reader (reader_id)" +
|
|
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分享阅读记录'");
|
|
|
|
|
+ log.info("已创建share_reads表");
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("创建share_reads表可能已存在: {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移123: 创建 food_recommend_idx 表(饮食推荐指数)
|
|
|
|
|
+ try {
|
|
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS food_recommend_idx (" +
|
|
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
|
|
+ "user_id BIGINT NOT NULL COMMENT '用户ID', " +
|
|
|
|
|
+ "food_id BIGINT NOT NULL COMMENT '食材ID', " +
|
|
|
|
|
+ "food_name VARCHAR(100) COMMENT '食材名称', " +
|
|
|
|
|
+ "index_score INT COMMENT '推荐指数(0-100)', " +
|
|
|
|
|
+ "health_report_id BIGINT COMMENT '关联健康报告ID', " +
|
|
|
|
|
+ "calculated_at DATETIME COMMENT '计算时间', " +
|
|
|
|
|
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "INDEX idx_user (user_id), " +
|
|
|
|
|
+ "INDEX idx_food (food_id), " +
|
|
|
|
|
+ "INDEX idx_report (health_report_id)" +
|
|
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食推荐指数'");
|
|
|
|
|
+ log.info("已创建food_recommend_idx表");
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("创建food_recommend_idx表可能已存在: {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移124: 创建 points_exchange_products 表(积分兑换商品)
|
|
|
|
|
+ try {
|
|
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS points_exchange_products (" +
|
|
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
|
|
+ "name VARCHAR(200) NOT NULL COMMENT '商品名称', " +
|
|
|
|
|
+ "description TEXT COMMENT '商品描述', " +
|
|
|
|
|
+ "cover_image VARCHAR(500) COMMENT '封面图片', " +
|
|
|
|
|
+ "points_price INT NOT NULL COMMENT '积分价格', " +
|
|
|
|
|
+ "stock INT DEFAULT 0 COMMENT '库存', " +
|
|
|
|
|
+ "product_type VARCHAR(50) COMMENT '商品类型', " +
|
|
|
|
|
+ "category VARCHAR(50) COMMENT '分类', " +
|
|
|
|
|
+ "expiry_days INT COMMENT '有效期(天)', " +
|
|
|
|
|
+ "sort_order INT DEFAULT 0 COMMENT '排序', " +
|
|
|
|
|
+ "status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active/disabled', " +
|
|
|
|
|
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "INDEX idx_status (status), " +
|
|
|
|
|
+ "INDEX idx_category (category)" +
|
|
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分兑换商品'");
|
|
|
|
|
+ log.info("已创建points_exchange_products表");
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("创建points_exchange_products表可能已存在: {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移125: 创建 points_exchange_records 表(积分兑换记录)
|
|
|
|
|
+ try {
|
|
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS points_exchange_records (" +
|
|
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
|
|
+ "user_id BIGINT COMMENT '用户ID', " +
|
|
|
|
|
+ "child_id BIGINT COMMENT '孩子ID', " +
|
|
|
|
|
+ "family_member_id BIGINT COMMENT '家庭成员ID', " +
|
|
|
|
|
+ "product_id BIGINT NOT NULL COMMENT '商品ID', " +
|
|
|
|
|
+ "product_name VARCHAR(200) COMMENT '商品名称快照', " +
|
|
|
|
|
+ "points_cost INT NOT NULL COMMENT '消耗积分', " +
|
|
|
|
|
+ "quantity INT DEFAULT 1 COMMENT '数量', " +
|
|
|
|
|
+ "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/completed/cancelled', " +
|
|
|
|
|
+ "redeem_code VARCHAR(100) COMMENT '兑换码', " +
|
|
|
|
|
+ "expired_at DATETIME COMMENT '过期时间', " +
|
|
|
|
|
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ "INDEX idx_user (user_id), " +
|
|
|
|
|
+ "INDEX idx_product (product_id), " +
|
|
|
|
|
+ "INDEX idx_status (status)" +
|
|
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分兑换记录'");
|
|
|
|
|
+ log.info("已创建points_exchange_records表");
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("创建points_exchange_records表可能已存在: {}", e.getMessage());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private void runMigration82() {
|
|
private void runMigration82() {
|