|
|
@@ -8611,5 +8611,214 @@ private void runMigration100() {
|
|
|
} catch (Exception e) {
|
|
|
log.warn("迁移213: 微行动维度映射更新失败: " + e.getMessage());
|
|
|
}
|
|
|
+
|
|
|
+ // 迁移214: 创建 nutrition_category 表(营养产品分类)
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute(
|
|
|
+ "CREATE TABLE IF NOT EXISTS nutrition_category (" +
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
+ "name VARCHAR(50) NOT NULL COMMENT '分类名', " +
|
|
|
+ "parent_id BIGINT DEFAULT NULL COMMENT '父分类ID', " +
|
|
|
+ "sort_order INT DEFAULT 0 COMMENT '排序', " +
|
|
|
+ "create_time DATETIME DEFAULT CURRENT_TIMESTAMP" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养产品分类'"
|
|
|
+ );
|
|
|
+ log.info("已创建nutrition_category表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("创建nutrition_category表失败(可能已存在): " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 迁移215: 创建 nutrition_brand 表(品牌)
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute(
|
|
|
+ "CREATE TABLE IF NOT EXISTS nutrition_brand (" +
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
+ "name VARCHAR(100) NOT NULL COMMENT '品牌名', " +
|
|
|
+ "logo_url VARCHAR(500) DEFAULT NULL COMMENT '品牌Logo', " +
|
|
|
+ "description TEXT COMMENT '品牌简介', " +
|
|
|
+ "country VARCHAR(50) DEFAULT NULL COMMENT '产地国', " +
|
|
|
+ "create_time DATETIME DEFAULT CURRENT_TIMESTAMP" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养产品品牌'"
|
|
|
+ );
|
|
|
+ log.info("已创建nutrition_brand表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("创建nutrition_brand表失败(可能已存在): " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 迁移216: 创建 nutrition_product 表(营养产品主表)
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute(
|
|
|
+ "CREATE TABLE IF NOT EXISTS nutrition_product (" +
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
+ "name VARCHAR(200) NOT NULL COMMENT '产品名称', " +
|
|
|
+ "brand_id BIGINT DEFAULT NULL COMMENT '品牌ID', " +
|
|
|
+ "category_id BIGINT DEFAULT NULL COMMENT '分类ID', " +
|
|
|
+ "sub_category VARCHAR(50) DEFAULT NULL COMMENT '子分类', " +
|
|
|
+ "form VARCHAR(30) DEFAULT NULL COMMENT '剂型', " +
|
|
|
+ "net_content VARCHAR(50) DEFAULT NULL COMMENT '净含量', " +
|
|
|
+ "shelf_life VARCHAR(50) DEFAULT NULL COMMENT '保质期', " +
|
|
|
+ "suitable_for VARCHAR(200) DEFAULT NULL COMMENT '适用人群', " +
|
|
|
+ "image_url VARCHAR(500) DEFAULT NULL COMMENT '产品图', " +
|
|
|
+ "description TEXT COMMENT '产品描述', " +
|
|
|
+ "status TINYINT DEFAULT 1 COMMENT '状态 0下架/1上架', " +
|
|
|
+ "create_time DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
+ "update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
|
|
|
+ "INDEX idx_brand (brand_id), " +
|
|
|
+ "INDEX idx_category (category_id)" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养产品'"
|
|
|
+ );
|
|
|
+ log.info("已创建nutrition_product表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("创建nutrition_product表失败(可能已存在): " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 迁移217: 创建 nutrition_ingredient 表(成分明细)
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute(
|
|
|
+ "CREATE TABLE IF NOT EXISTS nutrition_ingredient (" +
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
+ "product_id BIGINT NOT NULL COMMENT '产品ID', " +
|
|
|
+ "ingredient_type VARCHAR(20) COMMENT '成分类型', " +
|
|
|
+ "name VARCHAR(100) NOT NULL COMMENT '成分名', " +
|
|
|
+ "strain VARCHAR(100) DEFAULT NULL COMMENT '菌株号', " +
|
|
|
+ "amount_per_serving DECIMAL(10,2) DEFAULT NULL COMMENT '每份含量', " +
|
|
|
+ "unit VARCHAR(20) DEFAULT NULL COMMENT '单位', " +
|
|
|
+ "daily_value VARCHAR(50) DEFAULT NULL COMMENT '每日参考值%', " +
|
|
|
+ "purpose VARCHAR(200) DEFAULT NULL COMMENT '功效说明', " +
|
|
|
+ "create_time DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
+ "INDEX idx_product (product_id)" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养产品成分明细'"
|
|
|
+ );
|
|
|
+ log.info("已创建nutrition_ingredient表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("创建nutrition_ingredient表失败(可能已存在): " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 迁移218: 创建 nutrition_platform_listing 表(平台在售信息)
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute(
|
|
|
+ "CREATE TABLE IF NOT EXISTS nutrition_platform_listing (" +
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
+ "product_id BIGINT NOT NULL COMMENT '产品ID', " +
|
|
|
+ "platform VARCHAR(30) COMMENT '平台', " +
|
|
|
+ "platform_url VARCHAR(500) DEFAULT NULL COMMENT '商品链接', " +
|
|
|
+ "current_price DECIMAL(10,2) DEFAULT NULL COMMENT '当前价格', " +
|
|
|
+ "original_price DECIMAL(10,2) DEFAULT NULL COMMENT '原价/划线价', " +
|
|
|
+ "price_unit VARCHAR(30) DEFAULT NULL COMMENT '价格单位', " +
|
|
|
+ "price_per_unit DECIMAL(10,2) DEFAULT NULL COMMENT '每单位价格', " +
|
|
|
+ "sales_count INT DEFAULT NULL COMMENT '销量', " +
|
|
|
+ "stock_status VARCHAR(20) DEFAULT NULL COMMENT '库存状态', " +
|
|
|
+ "last_checked DATETIME DEFAULT NULL COMMENT '最后爬取时间', " +
|
|
|
+ "create_time DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
+ "update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
|
|
|
+ "INDEX idx_product (product_id), " +
|
|
|
+ "INDEX idx_platform (platform)" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养产品平台在售信息'"
|
|
|
+ );
|
|
|
+ log.info("已创建nutrition_platform_listing表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("创建nutrition_platform_listing表失败(可能已存在): " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 迁移219: 创建 nutrition_product_review 表(评价)
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute(
|
|
|
+ "CREATE TABLE IF NOT EXISTS nutrition_product_review (" +
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
+ "platform_listing_id BIGINT NOT NULL COMMENT '平台在售ID', " +
|
|
|
+ "source VARCHAR(30) DEFAULT NULL COMMENT '来源平台', " +
|
|
|
+ "rating DECIMAL(2,1) DEFAULT NULL COMMENT '评分', " +
|
|
|
+ "review_count INT DEFAULT NULL COMMENT '评价数', " +
|
|
|
+ "good_rate VARCHAR(10) DEFAULT NULL COMMENT '好评率', " +
|
|
|
+ "last_updated DATETIME DEFAULT NULL COMMENT '最后更新时间', " +
|
|
|
+ "INDEX idx_listing (platform_listing_id)" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养产品评价'"
|
|
|
+ );
|
|
|
+ log.info("已创建nutrition_product_review表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("创建nutrition_product_review表失败(可能已存在): " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 迁移220: 创建 file_record 表(文件去重+维护)
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute(
|
|
|
+ "CREATE TABLE IF NOT EXISTS file_record (" +
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
+ "hash VARCHAR(64) NOT NULL COMMENT 'SHA-256 文件哈希', " +
|
|
|
+ "url VARCHAR(500) NOT NULL COMMENT '文件访问URL', " +
|
|
|
+ "file_size BIGINT NOT NULL COMMENT '文件大小(字节)', " +
|
|
|
+ "content_type VARCHAR(100) DEFAULT NULL COMMENT 'MIME类型', " +
|
|
|
+ "original_filename VARCHAR(255) DEFAULT NULL COMMENT '原始文件名', " +
|
|
|
+ "category VARCHAR(50) DEFAULT 'general' COMMENT '分类', " +
|
|
|
+ "description VARCHAR(500) DEFAULT NULL COMMENT '描述', " +
|
|
|
+ "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
+ "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
|
|
|
+ "UNIQUE KEY uk_hash (hash), " +
|
|
|
+ "INDEX idx_category (category), " +
|
|
|
+ "INDEX idx_created_at (created_at)" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件记录表(去重&维护)'"
|
|
|
+ );
|
|
|
+ log.info("已创建file_record表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("创建file_record表失败(可能已存在): " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 迁移221: nutrition_product 添加 local_product_id 字段(关联本平台商品)
|
|
|
+ ensureColumn("nutrition_product", "local_product_id", "BIGINT DEFAULT NULL COMMENT '本平台商品ID,关联products.id'");
|
|
|
+
|
|
|
+ // 迁移222: 创建 unlock_gates 表(通关关卡定义)
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS unlock_gates (" +
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
+ "gate_type VARCHAR(32) NOT NULL COMMENT 'SELF_CHECK/INVITE_FAMILY/CREATE_FAMILY_MEMBER/PURCHASE/MEMBERSHIP/REPORT_UPLOAD/MICRO_ACTION/STREAK_DAYS', " +
|
|
|
+ "name VARCHAR(50) NOT NULL COMMENT '关卡名称', " +
|
|
|
+ "description VARCHAR(200) COMMENT '关卡说明', " +
|
|
|
+ "icon VARCHAR(10) COMMENT '图标emoji', " +
|
|
|
+ "sort_order INT DEFAULT 0 COMMENT '排序号', " +
|
|
|
+ "enabled TINYINT DEFAULT 1 COMMENT '启用:1 禁用:0', " +
|
|
|
+ "is_required TINYINT DEFAULT 1 COMMENT '主线:1 增值:0', " +
|
|
|
+ "is_soft TINYINT DEFAULT 0 COMMENT '硬门禁:0 软引导:1', " +
|
|
|
+ "unlock_target VARCHAR(32) COMMENT 'PERSONAL_SANDBOX/FAMILY_SANDBOX/CHILD_MICRO_ACTION/...', " +
|
|
|
+ "condition_params VARCHAR(500) COMMENT '条件参数JSON', " +
|
|
|
+ "reward_points INT DEFAULT 0 COMMENT '通关奖励积分', " +
|
|
|
+ "reward_energy INT DEFAULT 0 COMMENT '通关奖励能量', " +
|
|
|
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
+ "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
|
|
|
+ "INDEX idx_sort (enabled, is_required, is_soft, sort_order)" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通关解锁关卡定义'");
|
|
|
+ log.info("已创建unlock_gates表");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("创建unlock_gates表失败(可能已存在): " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 迁移223: 创建 family_gate_progress 表(家庭通关进度)
|
|
|
+ try {
|
|
|
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_gate_progress (" +
|
|
|
+ "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
+ "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
|
|
|
+ "gate_id BIGINT NOT NULL COMMENT '关卡ID', " +
|
|
|
+ "status VARCHAR(16) DEFAULT 'LOCKED' COMMENT 'LOCKED/UNLOCKED', " +
|
|
|
+ "unlocked_by BIGINT COMMENT '解锁人user_id', " +
|
|
|
+ "unlocked_at DATETIME COMMENT '解锁时间', " +
|
|
|
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
+ "UNIQUE KEY uk_family_gate (family_id, gate_id)" +
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭关卡通关进度'");
|
|
|
+ log.info("已创建family_gate_progress表");
|
|
|
+
|
|
|
+ // 默认关卡种子数据(幂等:INSERT IGNORE)
|
|
|
+ jdbcTemplate.execute("INSERT IGNORE INTO unlock_gates (gate_type, name, description, icon, sort_order, enabled, is_required, is_soft, unlock_target, condition_params, reward_points, reward_energy) VALUES " +
|
|
|
+ "('SELF_CHECK', '五维自检', '完成15题五维自检,看见自己的能量状态', '📝', 1, 1, 1, 0, 'PERSONAL_SANDBOX', '{\"minCount\":1}', 60, 10), " +
|
|
|
+ "('INVITE_FAMILY', '邀请家人', '邀请家人加入,共同创建家庭数据', '👨👩👧👦', 2, 1, 1, 0, 'FAMILY_SANDBOX', '{}', 80, 15), " +
|
|
|
+ "('CREATE_FAMILY_MEMBER', '创建家人', '为孩子创建账号,开启家庭互动', '👶', 3, 1, 1, 0, 'CHILD_MICRO_ACTION', '{}', 50, 10), " +
|
|
|
+ "('MICRO_ACTION', '首次微行动', '完成一次微行动,养成每日小习惯', '🎯', 4, 1, 1, 1, 'MICRO_ACTION_DAILY', '{\"count\":1}', 50, 5), " +
|
|
|
+ "('STREAK_DAYS', '连续打卡3天', '连续打卡3天,获得里程碑奖励', '🔥', 5, 1, 1, 1, 'BADGE_MILESTONE', '{\"days\":3}', 30, 5), " +
|
|
|
+ "('SELF_CHECK', '复测对比', '完成第二次自检,看见前后变化', '📊', 6, 1, 1, 1, 'TREND_COMPARE', '{\"minCount\":2}', 60, 10), " +
|
|
|
+ "('PURCHASE', '首次购物', '在商城完成首次购物,解锁深度分析', '🛒', 7, 0, 0, 0, 'PREMIUM_MODULES', '{}', 150, 30), " +
|
|
|
+ "('MEMBERSHIP', '加入会员', '加入家庭会员,享受专属权益', '👑', 8, 0, 0, 0, 'PREMIUM_MODULES', '{}', 200, 50), " +
|
|
|
+ "('REPORT_UPLOAD', '健康报告上传', '上传健康报告,获取AI解读与洞察', '📋', 9, 0, 0, 0, 'HEALTH_INSIGHTS', '{\"minCount\":1}', 100, 20)");
|
|
|
+ log.info("已插入默认关卡种子数据");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("创建family_gate_progress表或插入种子数据失败: " + e.getMessage());
|
|
|
+ }
|
|
|
}
|
|
|
}
|