Sisyphus Agent 4 ay önce
ebeveyn
işleme
28ec126c4c

+ 256 - 459
cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java

@@ -8,7 +8,6 @@ import org.springframework.core.io.ResourceLoader;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Component;
 import org.springframework.util.StreamUtils;
-import org.springframework.context.annotation.Lazy;
 
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
@@ -18,7 +17,6 @@ import java.util.regex.Pattern;
 
 @Slf4j
 @Component
-@Lazy  // defer init so app starts fast; migrations run once via version gate
 public class DatabaseInitializer implements CommandLineRunner {
 
     @Resource
@@ -34,102 +32,19 @@ public class DatabaseInitializer implements CommandLineRunner {
         // 1. 检查并创建数据库
         initializeDatabase();
 
-        // 2. 检查并创建表(始终运行,表结构幂等)
+        // 2. 检查并创建表
         initializeTables();
 
-        // 3. 迁移版本门控:只在新版本或首次运行时执行
-        if (!isSchemaInitialized()) {
-            runMigrations();
-            initializeDefaultData();
-            initFoodTables();
-            runIndexMigrations();
-            runShopMigrations();
-            recordSchemaVersion(6);
-            log.info("数据库初始化完成!");
-        } else {
-            log.info("数据库初始化已执行,检查增量迁移...");
-            runShopMigrations(); // 增量迁移独立检查,不受主版本门控限制
-        }
-    }
-
-    /** 检查 schema_version 表是否已记录初始化 */
-    private boolean isSchemaInitialized() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS schema_version (version INT PRIMARY KEY, applied_at DATETIME DEFAULT CURRENT_TIMESTAMP)");
-            Integer v = jdbcTemplate.queryForObject("SELECT version FROM schema_version ORDER BY version DESC LIMIT 1", Integer.class);
-            return v != null && v >= 6;
-        } catch (Exception e) {
-            return false;
-        }
-    }
-
-    private void recordSchemaVersion(int version) {
-        jdbcTemplate.update("INSERT INTO schema_version (version) VALUES (?)", version);
-    }
+        // 3. 执行数据库迁移(添加新列)
+        runMigrations();
 
-    private void runIndexMigrations() {
-        String[] ddl = {
-            "CREATE INDEX idx_tasks_family_category ON tasks(family_id, category)",
-            "CREATE INDEX idx_tasks_family_status ON tasks(family_id, status)",
-            "CREATE INDEX idx_points_log_family_created ON points_log(family_id, created_at)",
-            "CREATE INDEX idx_products_category_status ON products(category, status)",
-            "CREATE INDEX idx_game_records_user_date ON game_records(user_id, created_at)",
-            "CREATE INDEX idx_articles_status_published ON articles(status, published_at)",
-            "CREATE INDEX idx_users_phone ON users(phone)",
-            "CREATE INDEX idx_growth_records_child_date ON growth_records(child_id, record_date)",
-            "CREATE INDEX idx_product_orders_buyer ON product_orders(buyer_id, status)"
-        };
-        for (String sql : ddl) {
-            try {
-                jdbcTemplate.execute(sql);
-                log.info("Index created: {}", sql.split(" ON ")[0].replace("CREATE INDEX ", ""));
-            } catch (Exception e) {
-                log.debug("Index skipped (may already exist): {}", sql);
-            }
-        }
-    }
+        // 4. 初始化默认数据
+        initializeDefaultData();
 
-    /**
-     * 增量迁移:添加商品订单相关字段(来自 migration_add_shop_tables.sql)
-     * 幂等执行,列已存在时忽略错误
-     */
-    private void runShopMigrations() {
-        log.info("开始执行商品订单增量迁移...");
-        String[] alterStatements = {
-            "ALTER TABLE `product_orders` ADD COLUMN `delivery_method` tinyint(1) DEFAULT 1 COMMENT '配送方式:1快递 2自提'",
-            "ALTER TABLE `product_orders` ADD COLUMN `address_snapshot` json DEFAULT NULL COMMENT '收货地址快照'",
-            "ALTER TABLE `product_orders` ADD COLUMN `coupon_id` int(11) DEFAULT NULL COMMENT '使用的优惠券ID'",
-            "ALTER TABLE `product_orders` ADD COLUMN `discount_amount` decimal(10,2) DEFAULT 0 COMMENT '优惠金额'",
-            "ALTER TABLE `product_orders` ADD COLUMN `delivery_fee` decimal(10,2) DEFAULT 0 COMMENT '运费'",
-            "ALTER TABLE `product_orders` ADD COLUMN `tracking_number` varchar(128) DEFAULT NULL COMMENT '快递单号'",
-            "ALTER TABLE `product_orders` ADD COLUMN `express_company` varchar(64) DEFAULT NULL COMMENT '快递公司'",
-            "ALTER TABLE `product_orders` ADD COLUMN `refund_status` tinyint(1) DEFAULT 0 COMMENT '退款状态:0无 1申请中 2已退款 3拒绝'",
-            "ALTER TABLE `product_orders` ADD COLUMN `refund_reason` varchar(512) DEFAULT NULL COMMENT '退款原因'",
-            "ALTER TABLE `product_orders` ADD COLUMN `refund_amount` decimal(10,2) DEFAULT NULL COMMENT '退款金额'",
-            "ALTER TABLE `product_orders` ADD COLUMN `refund_time` datetime DEFAULT NULL COMMENT '退款时间'",
-            "ALTER TABLE `product_orders` ADD COLUMN `pickup_code` varchar(16) DEFAULT NULL COMMENT '自提码'",
-            "ALTER TABLE `product_orders` ADD COLUMN `remark` varchar(512) DEFAULT NULL COMMENT '买家备注'"
-        };
-        for (String sql : alterStatements) {
-            try {
-                jdbcTemplate.execute(sql);
-                String colName = sql.replaceFirst(".*ADD COLUMN `?\\w+`?\\s+.*", "$1");
-                log.info("商品订单迁移成功: ADD COLUMN {}", colName);
-            } catch (Exception e) {
-                log.debug("商品订单字段已存在,跳过: {}", e.getMessage());
-            }
-        }
-        log.info("商品订单增量迁移完成");
+        // 5. 初始化食品相关表
+        initFoodTables();
 
-        // 修复 relationship_types 表中 enabled 为 NULL 的种子数据(schema.sql 早期版本未设置 enabled)
-        try {
-            int patched = jdbcTemplate.update("UPDATE relationship_types SET enabled = 1 WHERE enabled IS NULL");
-            if (patched > 0) {
-                log.info("已修复 relationship_types NULL enabled 数据,affected={}", patched);
-            }
-        } catch (Exception e) {
-            log.debug("relationship_types enabled 修复跳过: {}", e.getMessage());
-        }
+        log.info("数据库初始化完成!");
     }
 
     private void initializeDatabase() {
@@ -1113,146 +1028,12 @@ log.info("已添加template_id列到tasks表");
                 "  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
                 ")"
             );
+            log.info("content_sections 表已创建");
         } catch (Exception e) {
-            log.warn("创建content_sections表失败: {}", e.getMessage());
+            log.warn("创建 content_sections 表失败: {}", e.getMessage());
         }
 
-        // ==================== T5: 内容裂变 ====================
-        // 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'," +
-                "  event_type VARCHAR(32) NOT NULL COMMENT '事件类型: article/product/activity'," +
-                "  target_id BIGINT COMMENT '分享对象ID'," +
-                "  share_code VARCHAR(64) COMMENT '分享码'," +
-                "  click_count INT DEFAULT 0 COMMENT '点击次数'," +
-                "  created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                "  INDEX idx_user (user_id)," +
-                "  INDEX idx_share_code (share_code)" +
-                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分享事件表'"
-            );
-        } catch (Exception e) { /* ignore */ }
-
-        // 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(64) COMMENT '阅读者IP'," +
-                "  duration_seconds INT DEFAULT 0 COMMENT '阅读时长(秒)'," +
-                "  rewarded TINYINT DEFAULT 0 COMMENT '是否已奖励: 0=否,1=是'," +
-                "  created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                "  INDEX idx_share_event (share_event_id)," +
-                "  INDEX idx_reader (reader_id)," +
-                "  INDEX idx_rewarded (rewarded)" +
-                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分享阅读记录表'"
-            );
-        } catch (Exception e) { /* ignore */ }
-
-        // T5 SysConfig seeds
-        try {
-            insertSysConfigSeed("share_article_points", "10", "分享文章奖励积分");
-            insertSysConfigSeed("share_read_min_duration", "60", "阅读奖励最少秒数");
-            insertSysConfigSeed("share_read_reward_points", "5", "有效阅读奖励积分");
-            insertSysConfigSeed("share_daily_limit", "20", "每日分享奖励上限(次)");
-        } catch (Exception e) { /* ignore */ }
-
-        // ==================== T6: 推广素材中心 ====================
-        // promotion_materials 表
-        try {
-            jdbcTemplate.execute(
-                "CREATE TABLE IF NOT EXISTS promotion_materials (" +
-                "  id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                "  title VARCHAR(200) NOT NULL COMMENT '素材标题'," +
-                "  description TEXT COMMENT '素材描述'," +
-                "  material_type VARCHAR(32) NOT NULL COMMENT '类型: image/video/article/link'," +
-                "  material_url VARCHAR(500) NOT NULL COMMENT '素材URL'," +
-                "  thumbnail_url VARCHAR(500) COMMENT '缩略图URL'," +
-                "  scenario VARCHAR(32) COMMENT '使用场景: friend/moments/publication'," +
-                "  tags VARCHAR(500) COMMENT '标签,逗号分隔'," +
-                "  status VARCHAR(20) DEFAULT 'enabled' COMMENT '状态: enabled/disabled'," +
-                "  sort_order INT DEFAULT 0 COMMENT '排序'," +
-                "  created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                "  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                "  INDEX idx_scenario (scenario)," +
-                "  INDEX idx_status (status)" +
-                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推广素材表'"
-            );
-        } catch (Exception e) { /* ignore */ }
-
-        // T6 SysConfig seeds
-        try {
-            insertSysConfigSeed("promotion_materials_page_size", "20", "推广素材每页数量");
-        } catch (Exception e) { /* ignore */ }
-
-        // ==================== T7: 积分商城 ====================
-        // 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 '库存(-1表示无限)'," +
-                "  product_type VARCHAR(32) NOT NULL COMMENT '商品类型: virtual/coupon/entity'," +
-                "  category VARCHAR(32) COMMENT '分类: vip/redeem/flow/gift'," +
-                "  expiry_days INT DEFAULT 0 COMMENT '有效期(天,0=永久)'," +
-                "  sort_order INT DEFAULT 0 COMMENT '排序'," +
-                "  status VARCHAR(20) DEFAULT 'enabled' COMMENT '状态: enabled/disabled'," +
-                "  created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                "  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                "  INDEX idx_category (category)," +
-                "  INDEX idx_status (status)" +
-                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分兑换商品表'"
-            );
-        } catch (Exception e) { /* ignore */ }
-
-        // points_exchange_records 表
-        try {
-            jdbcTemplate.execute(
-                "CREATE TABLE IF NOT EXISTS points_exchange_records (" +
-                "  id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                "  user_id BIGINT NOT NULL COMMENT '兑换用户ID'," +
-                "  child_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 'completed' COMMENT '状态: completed/refunded/expired'," +
-                "  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_id (user_id)," +
-                "  INDEX idx_child_id (child_id)," +
-                "  INDEX idx_product_id (product_id)," +
-                "  INDEX idx_created_at (created_at)" +
-                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分兑换记录表'"
-            );
-        } catch (Exception e) { /* ignore */ }
-
-        // T7 SysConfig seeds
-        try {
-            insertSysConfigSeed("exchange_daily_limit", "5", "每日兑换次数上限");
-            insertSysConfigSeed("exchange_points_min", "100", "最低兑换积分");
-        } catch (Exception e) { /* ignore */ }
-
-// ==================== T8: 社交关系链 ====================
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS contact_match_requests (id BIGINT AUTO_INCREMENT PRIMARY KEY, requester_id BIGINT NOT NULL COMMENT '发起人用户ID', target_user_id BIGINT NOT NULL COMMENT '目标用户ID', contact_id BIGINT COMMENT '关联联系人ID', status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/accepted/rejected', message VARCHAR(500) COMMENT '申请留言', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE INDEX idx_requester_target (requester_id, target_user_id), INDEX idx_target (target_user_id), INDEX idx_status (status)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='联系人匹配请求表');");
-        } catch (Exception e) {}
-
-        // ==================== T9: 用户分层运营 ====================
-        try { jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS user_rfm_tags (id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL UNIQUE COMMENT '用户ID', r_score INT DEFAULT 0 COMMENT 'R评分(最近消费)', f_score INT DEFAULT 0 COMMENT 'F评分(消费频次)', m_score INT DEFAULT 0 COMMENT 'M评分(消费金额)', rfm_tier VARCHAR(10) DEFAULT 'C' COMMENT 'RFM等级: S/A/B/C/D', total_orders INT DEFAULT 0 COMMENT '总订单数', total_amount DECIMAL(12,2) DEFAULT 0 COMMENT '总消费金额', last_order_at DATETIME COMMENT '最近下单时间', updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_user (user_id), INDEX idx_rfm_tier (rfm_tier)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户RFM标签表'"); } catch (Exception e) {}
-        try { jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS user_trigger_rules (id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL COMMENT '用户ID', trigger_type VARCHAR(50) NOT NULL COMMENT '触发类型: rfm_upgrade/rfm_downgrade/inactive_warning/high_value_retention', trigger_action VARCHAR(50) NOT NULL COMMENT '触发动作: sms/notice/push/points_bonus', action_config VARCHAR(500) COMMENT '动作配置JSON', status VARCHAR(20) DEFAULT 'active' COMMENT '状态', last_triggered_at DATETIME COMMENT '最后触发时间', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_user (user_id), INDEX idx_trigger_type (trigger_type)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户触发规则表'"); } catch (Exception e) {}
-
-        // ContentSection 种子数据
+        // ContentSection 种子数据
         try {
             insertContentSectionSeed("mind", "func_entries", "功能入口", "[\"anonymous\"]", 1);
             insertContentSectionSeed("mind", "daily_tip", "每日心理", "[\"anonymous\"]", 2);
@@ -2156,6 +1937,249 @@ log.info("已添加template_id列到tasks表");
             log.warn("检查/添加 users 表 show_to_family 列失败: {}", e.getMessage());
         }
 
+        // ==================== DanShop 电商模块建表 ====================
+        // 1. danshop_categories (商品分类表)
+        try {
+            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS danshop_categories (" +
+                "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+                "parent_id BIGINT DEFAULT NULL COMMENT '父分类ID(null=一级)', " +
+                "name VARCHAR(64) NOT NULL COMMENT '分类名称', " +
+                "image VARCHAR(512) DEFAULT NULL COMMENT '分类图标URL', " +
+                "sort_order INT DEFAULT 0 COMMENT '排序(越小越靠前)', " +
+                "energy_dimension_id BIGINT DEFAULT NULL COMMENT '关联五维维度ID', " +
+                "status INT DEFAULT 1 COMMENT '1启用/0禁用', " +
+                "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
+                "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
+                "INDEX idx_parent (parent_id), " +
+                "INDEX idx_status (status)" +
+                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品分类表'");
+            log.info("已创建 danshop_categories 表");
+        } catch (Exception e) {
+            log.warn("创建 danshop_categories 表失败: {}", e.getMessage());
+        }
+
+        // 2. danshop_products (商品表)
+        try {
+            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS danshop_products (" +
+                "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+                "category_id BIGINT NOT NULL COMMENT '所属分类ID', " +
+                "name VARCHAR(128) NOT NULL COMMENT '商品名称', " +
+                "description TEXT COMMENT '商品详细描述', " +
+                "cover_image VARCHAR(512) COMMENT '封面图URL', " +
+                "images TEXT COMMENT '多图(JSON数组)', " +
+                "price INT NOT NULL COMMENT '售价(分)', " +
+                "member_price INT DEFAULT NULL COMMENT '会员价(分)', " +
+                "cost_price INT DEFAULT NULL COMMENT '成本价(分)', " +
+                "stock INT DEFAULT 0 COMMENT '库存数量', " +
+                "sales_count INT DEFAULT 0 COMMENT '销量', " +
+                "product_type VARCHAR(32) NOT NULL COMMENT '类型: physical/virtual/coupon/course', " +
+                "vendor_id BIGINT DEFAULT NULL COMMENT '供应商ID', " +
+                "vendor_name VARCHAR(64) COMMENT '供应商名称', " +
+                "status VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT 'pending/approved/rejected/on_shelf/off_shelf', " +
+                "reject_reason VARCHAR(255) DEFAULT NULL COMMENT '审核拒绝原因', " +
+                "profit_rate INT DEFAULT 0 COMMENT '平台利润率(bps,100=1%)', " +
+                "external_source VARCHAR(32) COMMENT '外部商品来源', " +
+                "external_id VARCHAR(64) COMMENT '外部商品ID', " +
+                "external_data TEXT COMMENT '外部商品完整数据(JSON)', " +
+                "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
+                "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
+                "INDEX idx_category (category_id), " +
+                "INDEX idx_vendor (vendor_id), " +
+                "INDEX idx_status (status)" +
+                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表'");
+            log.info("已创建 danshop_products 表");
+        } catch (Exception e) {
+            log.warn("创建 danshop_products 表失败: {}", e.getMessage());
+        }
+
+        // 3. danshop_orders (主订单表)
+        try {
+            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS danshop_orders (" +
+                "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+                "order_no VARCHAR(32) NOT NULL UNIQUE COMMENT '订单号(DS+时间戳+6位随机)', " +
+                "buyer_id BIGINT NOT NULL COMMENT '买家ID', " +
+                "family_id BIGINT DEFAULT NULL COMMENT '家庭ID', " +
+                "total_amount INT NOT NULL COMMENT '订单总金额(分)', " +
+                "discount_amount INT DEFAULT 0 COMMENT '优惠金额(分)', " +
+                "actual_amount INT NOT NULL COMMENT '实付金额(分)', " +
+                "status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT 'pending/paid/shipped/completed/refunding/refunded/cancelled', " +
+                "payment_method VARCHAR(16) DEFAULT 'wechat' COMMENT 'wechat/alipay', " +
+                "transaction_id VARCHAR(64) DEFAULT NULL COMMENT '微信/支付宝交易号', " +
+                "paid_at DATETIME DEFAULT NULL COMMENT '支付时间', " +
+                "shipped_at DATETIME DEFAULT NULL COMMENT '发货时间', " +
+                "completed_at DATETIME DEFAULT NULL COMMENT '完成时间', " +
+                "remark VARCHAR(255) DEFAULT NULL COMMENT '买家备注', " +
+                "cancel_reason VARCHAR(255) DEFAULT NULL COMMENT '取消原因', " +
+                "receiver_name VARCHAR(32) DEFAULT NULL COMMENT '收件人姓名', " +
+                "receiver_phone VARCHAR(16) DEFAULT NULL COMMENT '收件人电话', " +
+                "receiver_address VARCHAR(256) DEFAULT NULL COMMENT '收件人地址', " +
+                "freight INT DEFAULT 0 COMMENT '运费(分)', " +
+                "profit_amount INT DEFAULT 0 COMMENT '分润金额(分)', " +
+                "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
+                "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
+                "INDEX idx_buyer (buyer_id), " +
+                "INDEX idx_family (family_id), " +
+                "INDEX idx_status (status), " +
+                "INDEX idx_order_no (order_no)" +
+                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='主订单表'");
+            log.info("已创建 danshop_orders 表");
+        } catch (Exception e) {
+            log.warn("创建 danshop_orders 表失败: {}", e.getMessage());
+        }
+
+        // 4. danshop_order_items (订单明细表)
+        try {
+            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS danshop_order_items (" +
+                "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+                "order_id BIGINT NOT NULL COMMENT '所属订单ID', " +
+                "product_id BIGINT NOT NULL COMMENT '商品ID', " +
+                "product_name VARCHAR(128) NOT NULL COMMENT '商品名称(快照)', " +
+                "cover_image VARCHAR(512) COMMENT '封面图(快照)', " +
+                "unit_price INT NOT NULL COMMENT '单价(分,快照)', " +
+                "price INT NOT NULL COMMENT '单价(分,别名兼容)', " +
+                "quantity INT NOT NULL DEFAULT 1 COMMENT '购买数量', " +
+                "subtotal INT NOT NULL COMMENT '小计(分)', " +
+                "product_type VARCHAR(32) COMMENT '商品类型(快照)', " +
+                "vendor_id BIGINT COMMENT '供应商ID(快照)', " +
+                "vendor_name VARCHAR(64) COMMENT '供应商名称(快照)', " +
+                "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
+                "INDEX idx_order (order_id), " +
+                "INDEX idx_product (product_id)" +
+                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单明细表'");
+            log.info("已创建 danshop_order_items 表");
+        } catch (Exception e) {
+            log.warn("创建 danshop_order_items 表失败: {}", e.getMessage());
+        }
+
+        // 5. danshop_order_logs (订单操作日志表)
+        try {
+            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS danshop_order_logs (" +
+                "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+                "order_id BIGINT NOT NULL COMMENT '订单ID', " +
+                "action VARCHAR(32) NOT NULL COMMENT '操作: create/pay/ship/confirm/refund/cancel', " +
+                "operator_id BIGINT DEFAULT NULL COMMENT '操作人ID', " +
+                "operator_type VARCHAR(16) DEFAULT NULL COMMENT 'buyer/vendor/admin/system', " +
+                "detail TEXT DEFAULT NULL COMMENT '操作详情(JSON)', " +
+                "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
+                "INDEX idx_order (order_id)" +
+                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单操作日志表'");
+            log.info("已创建 danshop_order_logs 表");
+        } catch (Exception e) {
+            log.warn("创建 danshop_order_logs 表失败: {}", e.getMessage());
+        }
+
+        // 6. danshop_logistics (物流信息表)
+        try {
+            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS danshop_logistics (" +
+                "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+                "order_id BIGINT NOT NULL COMMENT '订单ID', " +
+                "order_item_id BIGINT DEFAULT NULL COMMENT '订单明细ID', " +
+                "logistics_no VARCHAR(64) NOT NULL COMMENT '物流单号', " +
+                "logistics_company VARCHAR(32) NOT NULL COMMENT '物流公司编码: sf/yto/zt/sto/yd/ttkd', " +
+                "logistics_name VARCHAR(32) DEFAULT NULL COMMENT '物流公司名称', " +
+                "sender_name VARCHAR(32) DEFAULT NULL COMMENT '发货人姓名', " +
+                "sender_phone VARCHAR(16) DEFAULT NULL COMMENT '发货人电话', " +
+                "sender_address VARCHAR(256) DEFAULT NULL COMMENT '发货人地址', " +
+                "receiver_name VARCHAR(32) NOT NULL COMMENT '收件人姓名', " +
+                "receiver_phone VARCHAR(16) NOT NULL COMMENT '收件人电话', " +
+                "receiver_address VARCHAR(256) NOT NULL COMMENT '收件人地址', " +
+                "status VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT 'pending/shipped/signing/completed', " +
+                "tracking_data TEXT DEFAULT NULL COMMENT '物流轨迹(JSON数组)', " +
+                "shipped_at DATETIME DEFAULT NULL COMMENT '发货时间', " +
+                "signed_at DATETIME DEFAULT NULL COMMENT '签收时间', " +
+                "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
+                "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
+                "INDEX idx_order (order_id), " +
+                "INDEX idx_logistics_no (logistics_no), " +
+                "INDEX idx_status (status)" +
+                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物流信息表'");
+            log.info("已创建 danshop_logistics 表");
+        } catch (Exception e) {
+            log.warn("创建 danshop_logistics 表失败: {}", e.getMessage());
+        }
+
+        // 7. danshop_profit_rules (分润规则配置表)
+        try {
+            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS danshop_profit_rules (" +
+                "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+                "rule_name VARCHAR(64) NOT NULL COMMENT '规则名称', " +
+                "rule_type VARCHAR(32) NOT NULL COMMENT '规则类型: product_category/vendor_level/global', " +
+                "target_id BIGINT DEFAULT NULL COMMENT '关联目标ID', " +
+                "platform_profit_rate INT NOT NULL COMMENT '平台利润率(bps,100=1%)', " +
+                "referrer_l1_rate INT DEFAULT 0 COMMENT '直接推荐人分润比例(bps,占利润%)', " +
+                "referrer_l2_rate INT DEFAULT 0 COMMENT '间接推荐人分润比例(bps,占利润%)', " +
+                "platform_service_rate INT DEFAULT 0 COMMENT '平台服务费率(bps,占订单金额%)', " +
+                "is_active INT DEFAULT 1 COMMENT '1启用/0禁用', " +
+                "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
+                "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
+                "INDEX idx_type (rule_type, target_id), " +
+                "INDEX idx_active (is_active)" +
+                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分润规则配置表'");
+            log.info("已创建 danshop_profit_rules 表");
+        } catch (Exception e) {
+            log.warn("创建 danshop_profit_rules 表失败: {}", e.getMessage());
+        }
+
+        // 8. danshop_profit_logs (分润流水表)
+        try {
+            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS danshop_profit_logs (" +
+                "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+                "order_id BIGINT NOT NULL COMMENT '订单ID', " +
+                "order_no VARCHAR(32) NOT NULL COMMENT '订单号', " +
+                "order_amount INT NOT NULL COMMENT '订单实付金额(分)', " +
+                "cost_amount INT DEFAULT 0 COMMENT '成本金额(分)', " +
+                "profit_amount INT NOT NULL COMMENT '利润金额(分)', " +
+                "platform_retained INT NOT NULL COMMENT '平台留存金额(分)', " +
+                "vendor_income INT NOT NULL COMMENT '供应商实收金额(分)', " +
+                "commission_l1 INT DEFAULT 0 COMMENT 'L1推荐人佣金(分)', " +
+                "commission_l2 INT DEFAULT 0 COMMENT 'L2推荐人佣金(分)', " +
+                "rule_id BIGINT DEFAULT NULL COMMENT '使用的分润规则ID', " +
+                "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
+                "INDEX idx_order (order_id), " +
+                "INDEX idx_order_no (order_no)" +
+                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分润流水表'");
+            log.info("已创建 danshop_profit_logs 表");
+        } catch (Exception e) {
+            log.warn("创建 danshop_profit_logs 表失败: {}", e.getMessage());
+        }
+
+        // 9. danshop_favorites (商品收藏表)
+        try {
+            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS danshop_favorites (" +
+                "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+                "user_id BIGINT NOT NULL COMMENT '用户ID', " +
+                "product_id BIGINT NOT NULL COMMENT '商品ID', " +
+                "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
+                "UNIQUE INDEX idx_user_product (user_id, product_id), " +
+                "INDEX idx_user (user_id)" +
+                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品收藏表'");
+            log.info("已创建 danshop_favorites 表");
+        } catch (Exception e) {
+            log.warn("创建 danshop_favorites 表失败: {}", e.getMessage());
+        }
+
+        // 10. danshop_addresses (收货地址表)
+        try {
+            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS danshop_addresses (" +
+                "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+                "user_id BIGINT NOT NULL COMMENT '用户ID', " +
+                "receiver_name VARCHAR(32) NOT NULL COMMENT '收货人姓名', " +
+                "phone VARCHAR(16) NOT NULL COMMENT '收货人电话', " +
+                "province VARCHAR(32) NOT NULL COMMENT '省份', " +
+                "city VARCHAR(32) NOT NULL COMMENT '城市', " +
+                "district VARCHAR(32) NOT NULL COMMENT '区县', " +
+                "street VARCHAR(256) NOT NULL COMMENT '详细地址', " +
+                "is_default INT DEFAULT 0 COMMENT '是否默认地址 1=是 0=否', " +
+                "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
+                "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
+                "INDEX idx_user (user_id), " +
+                "INDEX idx_user_default (user_id, is_default)" +
+                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='收货地址表'");
+            log.info("已创建 danshop_addresses 表");
+        } catch (Exception e) {
+            log.warn("创建 danshop_addresses 表失败: {}", e.getMessage());
+        }
+
         // ==================== 迁移: activities表添加visible_scope列 ====================
         try {
             Integer colExists = jdbcTemplate.queryForObject(
@@ -2261,49 +2285,6 @@ log.info("已添加template_id列到tasks表");
             log.warn("检查/添加activities表checkin_points列失败: {}", e.getMessage());
         }
 
-        // ==================== 迁移: activities表添加报名相关列 ====================
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activities' AND COLUMN_NAME = 'require_registration'",
-                Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE activities ADD COLUMN require_registration TINYINT DEFAULT 1 COMMENT '是否需要报名: 1=需要, 0=直接参与'");
-                log.info("已添加require_registration列到activities表");
-            } else {
-                log.info("activities表require_registration列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加activities表require_registration列失败: {}", e.getMessage());
-        }
-
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activities' AND COLUMN_NAME = 'require_checkin_review'",
-                Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE activities ADD COLUMN require_checkin_review TINYINT DEFAULT 1 COMMENT '打卡是否需要审核: 1=需要, 0=直接通过'");
-                log.info("已添加require_checkin_review列到activities表");
-            } else {
-                log.info("activities表require_checkin_review列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加activities表require_checkin_review列失败: {}", e.getMessage());
-        }
-
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activities' AND COLUMN_NAME = 'energy_penalty_unregistered'",
-                Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE activities ADD COLUMN energy_penalty_unregistered INT DEFAULT 5 COMMENT '未报名打卡的行能量扣减值'");
-                log.info("已添加energy_penalty_unregistered列到activities表");
-            } else {
-                log.info("activities表energy_penalty_unregistered列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加activities表energy_penalty_unregistered列失败: {}", e.getMessage());
-        }
-
         // 迁移: 创建family_invitations表(家庭邀请令牌)
         try {
             jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_invitations (" +
@@ -2566,6 +2547,7 @@ log.info("已添加template_id列到tasks表");
             log.warn("numsoul_config 种子数据初始化失败: {}", e.getMessage());
         }
 
+
         try {
             jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS user_address (" +
                     "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
@@ -2692,14 +2674,6 @@ log.info("已添加template_id列到tasks表");
         } catch (Exception e) {
             log.warn("旧维度评分数据迁移跳过: {}", e.getMessage());
         }
-
-        // 迁移: users表添加mascot字段(AI助手形象)
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN mascot VARCHAR(20) COMMENT 'AI助手形象: xibao(浠宝-女孩)/fubao(福宝-男孩)'");
-            log.info("已添加mascot列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
     }
 
     private void seedHealthNorms() {
@@ -3877,186 +3851,9 @@ try {
         ensureColumn("user_nutrition_profile", "cooking_ability", "VARCHAR(20) DEFAULT 'simple' COMMENT '烹饪能力: simple/medium/advanced'");
 
         log.info("食品相关表初始化完成");
-
-        // 迁移: family_members 表添加关系质量字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN trust_score DECIMAL(5,2) DEFAULT 0 COMMENT '信任度 0-100'");
-            log.info("已添加trust_score列到family_members表");
-        } catch (Exception e) {}
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN intimacy_score DECIMAL(5,2) DEFAULT 0 COMMENT '亲密度 0-100'");
-            log.info("已添加intimacy_score列到family_members表");
-        } catch (Exception e) {}
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN communication_score DECIMAL(5,2) DEFAULT 0 COMMENT '沟通质量 0-100'");
-            log.info("已添加communication_score列到family_members表");
-        } catch (Exception e) {}
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN last_interaction_at DATETIME DEFAULT NULL COMMENT '最近互动时间'");
-            log.info("已添加last_interaction_at列到family_members表");
-        } catch (Exception e) {}
-
-        // 迁移: 创建互动记录表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS interaction_logs (id BIGINT AUTO_INCREMENT PRIMARY KEY, family_id BIGINT NOT NULL, from_member_id BIGINT NOT NULL, to_member_id BIGINT NOT NULL, interaction_type VARCHAR(32) NOT NULL COMMENT 'dining/outgoing/call/video/chat/play/gift', description VARCHAR(256), happened_at DATETIME NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_family (family_id), INDEX idx_member (from_member_id), INDEX idx_happened (happened_at)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '家庭成员互动记录'");
-            log.info("已创建interaction_logs表");
-        } catch (Exception e) {}
-
-        // 迁移: 创建问卷快照表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS relationship_questionnaire_snapshots (id BIGINT AUTO_INCREMENT PRIMARY KEY, family_member_id BIGINT NOT NULL, respondent_id BIGINT NOT NULL, member_name VARCHAR(64), relationship_type VARCHAR(32), ai_generated_json LONGTEXT NOT NULL COMMENT 'AI生成的题目JSON', version VARCHAR(32), created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_member (family_member_id)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '关系问卷快照'");
-            log.info("已创建relationship_questionnaire_snapshots表");
-        } catch (Exception e) {}
-
-        // 迁移: 创建问卷回答结果表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS relationship_questionnaire_responses (id BIGINT AUTO_INCREMENT PRIMARY KEY, snapshot_id BIGINT NOT NULL, respondent_id BIGINT NOT NULL, answers_json LONGTEXT NOT NULL COMMENT '用户回答JSON', trust_score DECIMAL(5,2), intimacy_score DECIMAL(5,2), communication_score DECIMAL(5,2), interaction_bonus DECIMAL(5,2) DEFAULT 0, total_score DECIMAL(5,2), calculated_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_snapshot (snapshot_id), INDEX idx_respondent (respondent_id)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='关系问卷回答结果'");
-            log.info("已创建relationship_questionnaire_responses表");
-        } catch (Exception e) {}
-
-        // 迁移: 创建分销体系表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS distribution_systems (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "name VARCHAR(100) NOT NULL COMMENT '团队名称', " +
-                    "description VARCHAR(500) COMMENT '团队描述', " +
-                    "owner_id BIGINT COMMENT '创建人(服务商用户ID)', " +
-                    "profit_rate INT DEFAULT 0 COMMENT '利润分成比例(bps, 如2000=20%)', " +
-                    "enabled TINYINT(1) DEFAULT 1 COMMENT '是否启用', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='虚拟服务商团队(分销体系)'");
-            log.info("已创建distribution_systems表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移: 创建分销体系成员关系表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS distribution_relations (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "system_id BIGINT NOT NULL COMMENT '所属团队ID', " +
-                    "user_id BIGINT NOT NULL COMMENT '服务商用户ID', " +
-                    "parent_id BIGINT COMMENT '上级服务商用户ID', " +
-                    "depth INT DEFAULT 0 COMMENT '层级深度(0=root)', " +
-                    "invite_code VARCHAR(32) COMMENT '分销邀请码', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_system (system_id), " +
-                    "INDEX idx_user (user_id), " +
-                    "INDEX idx_parent (parent_id), " +
-                    "INDEX idx_invite_code (invite_code)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='团队-服务商关系'");
-            log.info("已创建distribution_relations表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移: distribution_relations表添加invite_code字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE distribution_relations ADD COLUMN invite_code VARCHAR(32) COMMENT '分销邀请码'");
-            log.info("已添加invite_code列到distribution_relations表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE distribution_relations ADD INDEX idx_invite_code (invite_code)");
-            log.info("已添加idx_invite_code索引到distribution_relations表");
-        } catch (Exception e) {
-            // 索引已存在,忽略错误
-        }
-
-        // 迁移: 创建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) COMMENT '告警类型', " +
-                    "severity VARCHAR(20) COMMENT '严重程度', " +
-                    "title VARCHAR(200) COMMENT '告警标题', " +
-                    "message TEXT COMMENT '告警详情', " +
-                    "related_checkin_id BIGINT DEFAULT NULL COMMENT '关联打卡ID', " +
-                    "resolved TINYINT(1) DEFAULT 0 COMMENT '是否已处理: 0否1是', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "resolved_at DATETIME DEFAULT NULL COMMENT '处理时间', " +
-                    "INDEX idx_child_id (child_id), " +
-                    "INDEX idx_severity (severity), " +
-                    "INDEX idx_resolved (resolved)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='情绪风险告警表'");
-            log.info("已创建emotion_alert表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移: 创建mental_health_screen表(心理健康筛查)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS mental_health_screen (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "child_id BIGINT NOT NULL COMMENT '孩子ID', " +
-                    "screen_type VARCHAR(50) COMMENT '筛查类型: phq9/gad7', " +
-                    "answers TEXT COMMENT '答案JSON', " +
-                    "total_score INT COMMENT '总分', " +
-                    "severity_level VARCHAR(20) COMMENT '严重程度', " +
-                    "risk_flags TEXT COMMENT '风险标记JSON', " +
-                    "suggestions TEXT COMMENT '建议', " +
-                    "completed_at DATETIME COMMENT '完成时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_child_id (child_id), " +
-                    "INDEX idx_screen_type (screen_type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='心理健康筛查表'");
-            log.info("已创建mental_health_screen表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移: emotion_checkin表添加缺失列
-        try {
-            jdbcTemplate.execute("ALTER TABLE emotion_checkin ADD COLUMN moodScore INT COMMENT '情绪评分(1-10)'");
-            log.info("已添加moodScore列到emotion_checkin表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE emotion_checkin ADD COLUMN stressLevel INT COMMENT '压力水平(1-10)'");
-            log.info("已添加stressLevel列到emotion_checkin表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE emotion_checkin ADD COLUMN arousalLevel INT COMMENT '激活水平(1-10)'");
-            log.info("已添加arousalLevel列到emotion_checkin表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE emotion_checkin ADD COLUMN sleepHours FLOAT COMMENT '睡眠时长(小时)'");
-            log.info("已添加sleepHours列到emotion_checkin表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE emotion_checkin ADD COLUMN sleepQuality INT COMMENT '睡眠质量(1-5)'");
-            log.info("已添加sleepQuality列到emotion_checkin表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE emotion_checkin ADD COLUMN energyLevel INT COMMENT '精力水平(1-10)'");
-            log.info("已添加energyLevel列到emotion_checkin表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
     }
 
-    private void ensureColumn(String table, String column, String definition) {
+    private void ensureColumn(String table, String column, String definition) {
         try {
             jdbcTemplate.execute("ALTER TABLE " + table + " ADD COLUMN " + column + " " + definition);
             log.info("已添加列 {}.{}", table, column);

+ 2 - 8
cfc-backend/src/main/java/com/etotem/cfc/service/TaskService.java

@@ -578,14 +578,8 @@ return result;
         Map<String, Object> result = new HashMap<>();
         result.put("pointsEarned", pointsEarned);
 
-        // 触发首次任务成长事件(如果有关联的孩子)
-        if (task.getChildId() != null) {
-            Child taskChild = childMapper.selectById(task.getChildId());
-            if (taskChild != null) {
-                try { onboardingService.completeTask(taskChild.getUserId(), "FIRST_TASK"); } catch (Exception e) { /* onboarding trigger failure should not block task completion */ }
-            }
-        }
-    result.put("newBalance", user.getTotalPoints());
+        try { Child child = childMapper.selectById(task.getChildId()); if (child != null) { onboardingService.completeTask(child.getUserId(), "FIRST_TASK"); } } catch (Exception e) { /* onboarding trigger failure should not block task completion */ }
+    result.put("newBalance", user.getTotalPoints());
     result.put("needReview", task.getNeedReview() == 1);
 
     return result;