diff --git a/app/Enums/CurrencySource.php b/app/Enums/CurrencySource.php index 04d7d59..4a6a239 100644 --- a/app/Enums/CurrencySource.php +++ b/app/Enums/CurrencySource.php @@ -46,6 +46,29 @@ enum CurrencySource: string // case TASK_REWARD = 'task_reward'; // 任务奖励 // case PVP_WIN = 'pvp_win'; // PVP 胜利奖励 + // ─── 婚姻系统 ──────────────────────────────────────────────── + + /** 结婚魅力加成(双方各获得,由戒指档次决定) */ + case MARRY_CHARM = 'marry_charm'; + + /** 离婚魅力惩罚(协议/强制/超时自动)*/ + case DIVORCE_CHARM = 'divorce_charm'; + + /** 购买戒指(gold 消耗,由 ShopService 代理) */ + case RING_BUY = 'ring_buy'; + + /** 戒指消失记录(求婚被拒/超时,金额=0,仅存档) */ + case RING_LOST = 'ring_lost'; + + /** 发送婚礼红包(扣除金币) */ + case WEDDING_ENV_SEND = 'wedding_env_send'; + + /** 领取婚礼红包(收入金币) */ + case WEDDING_ENV_RECV = 'wedding_env_recv'; + + /** 强制离婚财产转移(付出方为负,接收方为正) */ + case FORCED_DIVORCE_TRANSFER = 'forced_divorce_transfer'; + /** * 返回该来源的中文名称,用于后台统计展示。 */ @@ -61,6 +84,13 @@ enum CurrencySource: string self::SHOP_BUY => '商城购买', self::ADMIN_ADJUST => '管理员调整', self::POSITION_REWARD => '职务奖励', + self::MARRY_CHARM => '结婚魅力加成', + self::DIVORCE_CHARM => '离婚魅力惩罚', + self::RING_BUY => '购买戒指', + self::RING_LOST => '戒指消失', + self::WEDDING_ENV_SEND => '发送婚礼红包', + self::WEDDING_ENV_RECV => '领取婚礼红包', + self::FORCED_DIVORCE_TRANSFER => '强制离婚财产转移', }; } } diff --git a/app/Enums/IntimacySource.php b/app/Enums/IntimacySource.php new file mode 100644 index 0000000..4f46094 --- /dev/null +++ b/app/Enums/IntimacySource.php @@ -0,0 +1,54 @@ + '每日时间奖励', + self::ONLINE_TOGETHER => '双方同时在线', + self::RECV_FLOWER => '收到伴侣送花', + self::SEND_FLOWER => '向伴侣送花', + self::PRIVATE_CHAT => '私聊消息', + self::WEDDING_BONUS => '结婚戒指加成', + self::ADMIN_ADJUST => '管理员调整', + }; + } +} diff --git a/database/migrations/2026_03_01_145033_create_marriage_configs_table.php b/database/migrations/2026_03_01_145033_create_marriage_configs_table.php new file mode 100644 index 0000000..5da31e0 --- /dev/null +++ b/database/migrations/2026_03_01_145033_create_marriage_configs_table.php @@ -0,0 +1,41 @@ +id(); + $table->string('group', 30)->index()->comment('配置分组(用于后台分组展示)'); + $table->string('key', 60)->unique()->comment('配置键名(系统内部使用)'); + $table->integer('value')->comment('配置值(均为整数)'); + $table->string('label', 60)->comment('中文名称(后台显示)'); + $table->string('description', 120)->nullable()->comment('说明(提示管理员含义)'); + $table->integer('min')->nullable()->comment('允许最小值'); + $table->integer('max')->nullable()->comment('允许最大值'); + $table->timestamps(); + }); + } + + /** + * 回滚:删除 marriage_configs 表。 + */ + public function down(): void + { + Schema::dropIfExists('marriage_configs'); + } +}; diff --git a/database/migrations/2026_03_01_145033_create_marriage_intimacy_logs_table.php b/database/migrations/2026_03_01_145033_create_marriage_intimacy_logs_table.php new file mode 100644 index 0000000..8c3c211 --- /dev/null +++ b/database/migrations/2026_03_01_145033_create_marriage_intimacy_logs_table.php @@ -0,0 +1,41 @@ +id(); + $table->unsignedBigInteger('marriage_id')->index()->comment('所属婚姻记录 ID'); + $table->integer('amount')->comment('变更量(正数增加,负数减少)'); + $table->integer('balance_after')->comment('变更后亲密度总值'); + $table->string('source', 50)->comment('来源(对应 IntimacySource 枚举值)'); + $table->string('remark', 100)->nullable()->comment('备注说明'); + $table->timestamp('created_at')->nullable()->comment('记录时间'); + + $table->foreign('marriage_id')->references('id')->on('marriages')->onDelete('cascade'); + }); + } + + /** + * 回滚:删除亲密度日志表。 + */ + public function down(): void + { + Schema::dropIfExists('marriage_intimacy_logs'); + } +}; diff --git a/database/migrations/2026_03_01_145034_add_frozen_jjb_and_marriage_fields_to_marriages_table.php b/database/migrations/2026_03_01_145034_add_frozen_jjb_and_marriage_fields_to_marriages_table.php new file mode 100644 index 0000000..58b6552 --- /dev/null +++ b/database/migrations/2026_03_01_145034_add_frozen_jjb_and_marriage_fields_to_marriages_table.php @@ -0,0 +1,83 @@ +unsignedBigInteger('user_id')->nullable()->after('id')->index()->comment('求婚发起方 user.id'); + $table->unsignedBigInteger('partner_id')->nullable()->after('user_id')->index()->comment('被求婚方 user.id'); + + // 使用的戒指 + $table->unsignedBigInteger('ring_item_id')->nullable()->after('partner_id')->comment('使用的戒指 shop_items.id'); + $table->unsignedBigInteger('ring_purchase_id')->nullable()->after('ring_item_id')->comment('消耗的购买记录 user_purchases.id'); + + // 婚姻状态 + $table->enum('status', ['pending', 'married', 'divorced', 'rejected', 'expired']) + ->default('pending')->after('ring_purchase_id')->comment('婚姻状态'); + + // 关键时间节点 + $table->timestamp('proposed_at')->nullable()->after('status')->comment('求婚时间'); + $table->timestamp('expires_at')->nullable()->after('proposed_at')->comment('求婚48h后过期时间'); + $table->timestamp('married_at')->nullable()->after('expires_at')->comment('结婚时间'); + $table->timestamp('divorced_at')->nullable()->after('married_at')->comment('离婚时间'); + + // 离婚相关 + $table->enum('divorce_type', ['mutual', 'forced', 'auto', 'admin']) + ->nullable()->after('divorced_at')->comment('离婚类型'); + $table->unsignedBigInteger('divorcer_id')->nullable()->after('divorce_type')->comment('强制离婚发起方 user.id'); + $table->timestamp('divorce_requested_at')->nullable()->after('divorcer_id')->comment('协议离婚申请时间(用于72h超时检测)'); + + // 亲密度 + $table->integer('intimacy')->default(0)->after('divorce_requested_at')->comment('当前亲密度积分'); + $table->tinyInteger('level')->unsigned()->default(1)->after('intimacy')->comment('婚姻等级(1-4)'); + + // 统计字段 + $table->integer('online_minutes')->default(0)->after('level')->comment('双方同时在线累计分钟数'); + $table->integer('flower_count')->default(0)->after('online_minutes')->comment('相互送花累计次数'); + $table->integer('chat_count')->default(0)->after('flower_count')->comment('私聊消息累计条数'); + + // 管理员备注 + $table->string('admin_note', 200)->nullable()->after('chat_count')->comment('管理员操作备注'); + }); + + // ── users 表:新增定时婚礼冻结金币字段 ────────────────────── + Schema::table('users', function (Blueprint $table) { + $table->integer('frozen_jjb')->default(0)->after('jjb')->comment('定时婚礼预冻结金币(待婚礼触发后正式扣除)'); + }); + } + + /** + * 回滚:移除新增字段。 + */ + public function down(): void + { + Schema::table('marriages', function (Blueprint $table) { + $table->dropColumn([ + 'user_id', 'partner_id', 'ring_item_id', 'ring_purchase_id', + 'status', 'proposed_at', 'expires_at', 'married_at', 'divorced_at', + 'divorce_type', 'divorcer_id', 'divorce_requested_at', + 'intimacy', 'level', 'online_minutes', 'flower_count', 'chat_count', + 'admin_note', + ]); + }); + + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('frozen_jjb'); + }); + } +}; diff --git a/database/migrations/2026_03_01_145034_create_wedding_tiers_table.php b/database/migrations/2026_03_01_145034_create_wedding_tiers_table.php new file mode 100644 index 0000000..5941d05 --- /dev/null +++ b/database/migrations/2026_03_01_145034_create_wedding_tiers_table.php @@ -0,0 +1,40 @@ +id(); + $table->tinyInteger('tier')->unsigned()->unique()->comment('档位编号(1-5,固定)'); + $table->string('name', 30)->comment('档位名称(可改,如:小小祝福)'); + $table->string('icon', 20)->comment('档位图标(如:⭐⭐⭐)'); + $table->integer('amount')->comment('该档位总金币数'); + $table->string('description', 100)->nullable()->comment('前台展示描述'); + $table->boolean('is_active')->default(true)->comment('是否启用(关闭则前台不显示该档位)'); + $table->timestamps(); + }); + } + + /** + * 回滚:删除婚礼档位表。 + */ + public function down(): void + { + Schema::dropIfExists('wedding_tiers'); + } +}; diff --git a/database/migrations/2026_03_01_145036_create_wedding_ceremonies_table.php b/database/migrations/2026_03_01_145036_create_wedding_ceremonies_table.php new file mode 100644 index 0000000..92c4b92 --- /dev/null +++ b/database/migrations/2026_03_01_145036_create_wedding_ceremonies_table.php @@ -0,0 +1,51 @@ +id(); + $table->unsignedBigInteger('marriage_id')->index()->comment('关联婚姻 ID'); + $table->unsignedBigInteger('tier_id')->nullable()->index()->comment('关联婚礼档位 ID(NULL=不举办红包)'); + // 快照金额:防止档位金额被修改后影响历史记录 + $table->integer('total_amount')->default(0)->comment('婚礼红包总金额(快照值)'); + $table->enum('payer_type', ['groom', 'joint'])->comment('支付方式:groom=男方全付,joint=双方各半'); + $table->integer('groom_amount')->default(0)->comment('男方实际扣除金额'); + $table->integer('partner_amount')->default(0)->comment('女方实际扣除金额(joint时各半)'); + $table->enum('ceremony_type', ['immediate', 'scheduled'])->comment('婚礼类型:immediate=立即,scheduled=定时'); + $table->timestamp('ceremony_at')->nullable()->comment('实际或计划举办时间'); + $table->enum('status', ['pending', 'active', 'completed', 'cancelled', 'expired']) + ->default('pending')->comment('婚礼状态'); + $table->integer('online_count')->nullable()->comment('触发时在线用户数(分发后记录)'); + $table->integer('claimed_count')->default(0)->comment('已领取人数'); + $table->integer('claimed_amount')->default(0)->comment('已领取金额合计'); + $table->timestamp('expires_at')->nullable()->comment('红包领取截止时间(24h后过期)'); + $table->timestamps(); + + $table->foreign('marriage_id')->references('id')->on('marriages')->onDelete('cascade'); + }); + } + + /** + * 回滚:删除婚礼仪式表。 + */ + public function down(): void + { + Schema::dropIfExists('wedding_ceremonies'); + } +}; diff --git a/database/migrations/2026_03_01_145037_create_wedding_envelope_claims_table.php b/database/migrations/2026_03_01_145037_create_wedding_envelope_claims_table.php new file mode 100644 index 0000000..ef7e2c5 --- /dev/null +++ b/database/migrations/2026_03_01_145037_create_wedding_envelope_claims_table.php @@ -0,0 +1,43 @@ +id(); + $table->unsignedBigInteger('ceremony_id')->index()->comment('关联婚礼仪式 ID'); + $table->unsignedBigInteger('user_id')->index()->comment('领取用户 ID'); + $table->integer('amount')->comment('预分配金额(随机红包算法计算)'); + $table->boolean('claimed')->default(false)->index()->comment('是否已领取'); + $table->timestamp('claimed_at')->nullable()->comment('领取时间'); + $table->timestamp('created_at')->nullable()->comment('分配时间'); + + $table->unique(['ceremony_id', 'user_id'], 'unique_ceremony_user'); + $table->foreign('ceremony_id')->references('id')->on('wedding_ceremonies')->onDelete('cascade'); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + }); + } + + /** + * 回滚:删除红包领取记录表。 + */ + public function down(): void + { + Schema::dropIfExists('wedding_envelope_claims'); + } +}; diff --git a/database/migrations/2026_03_01_145620_add_ring_type_to_shop_items_table.php b/database/migrations/2026_03_01_145620_add_ring_type_to_shop_items_table.php new file mode 100644 index 0000000..64b3c3e --- /dev/null +++ b/database/migrations/2026_03_01_145620_add_ring_type_to_shop_items_table.php @@ -0,0 +1,31 @@ + '亲密度加分', 'key' => 'intimacy_daily_time', 'value' => 10, 'label' => '每日时间奖励', 'description' => '每天00:00给所有婚姻对各加的亲密度', 'min' => 1, 'max' => 100], + ['group' => '亲密度加分', 'key' => 'intimacy_online_per_min', 'value' => 1, 'label' => '同时在线(每分钟)', 'description' => '双方同时在线每分钟增加的亲密度', 'min' => 0, 'max' => 10], + ['group' => '亲密度加分', 'key' => 'intimacy_online_daily_cap', 'value' => 120, 'label' => '同时在线每日上限', 'description' => '每日因同时在线最多可得亲密度(约2小时)', 'min' => 0, 'max' => 1440], + ['group' => '亲密度加分', 'key' => 'intimacy_recv_flower', 'value' => 2, 'label' => '收到伴侣送花(每朵)', 'description' => '收到伴侣送花时每朵花增加的亲密度', 'min' => 0, 'max' => 20], + ['group' => '亲密度加分', 'key' => 'intimacy_recv_flower_cap', 'value' => 40, 'label' => '收花每日上限', 'description' => '每日因收花最多可得亲密度', 'min' => 0, 'max' => 500], + ['group' => '亲密度加分', 'key' => 'intimacy_send_flower', 'value' => 1, 'label' => '向伴侣送花(每朵)', 'description' => '向伴侣送花时每朵花增加的亲密度(送方)', 'min' => 0, 'max' => 10], + ['group' => '亲密度加分', 'key' => 'intimacy_send_flower_cap', 'value' => 20, 'label' => '送花每日上限', 'description' => '每日因送花最多可得亲密度', 'min' => 0, 'max' => 200], + ['group' => '亲密度加分', 'key' => 'intimacy_private_chat', 'value' => 1, 'label' => '私聊加分', 'description' => '每2条私信获得1亲密度', 'min' => 0, 'max' => 10], + ['group' => '亲密度加分', 'key' => 'intimacy_private_chat_cap', 'value' => 10, 'label' => '私聊每日上限', 'description' => '每日因私聊最多可得亲密度', 'min' => 0, 'max' => 100], + + // 【戒指魅力加成与初始亲密度】 + ['group' => '戒指参数', 'key' => 'ring_silver_charm', 'value' => 50, 'label' => '银戒指魅力加成', 'description' => '双方各获得的魅力值(结婚时一次性)', 'min' => 0, 'max' => 9999], + ['group' => '戒指参数', 'key' => 'ring_gold_charm', 'value' => 150, 'label' => '金戒指魅力加成', 'description' => '双方各获得的魅力值(结婚时一次性)', 'min' => 0, 'max' => 9999], + ['group' => '戒指参数', 'key' => 'ring_diamond_charm', 'value' => 500, 'label' => '钻戒魅力加成', 'description' => '双方各获得的魅力值(结婚时一次性)', 'min' => 0, 'max' => 99999], + ['group' => '戒指参数', 'key' => 'ring_silver_intimacy', 'value' => 10, 'label' => '银戒指初始亲密度', 'description' => '结婚时一次性赠予的亲密度(银戒)', 'min' => 0, 'max' => 500], + ['group' => '戒指参数', 'key' => 'ring_gold_intimacy', 'value' => 30, 'label' => '金戒指初始亲密度', 'description' => '结婚时一次性赠予的亲密度(金戒)', 'min' => 0, 'max' => 500], + ['group' => '戒指参数', 'key' => 'ring_diamond_intimacy', 'value' => 80, 'label' => '钻戒初始亲密度', 'description' => '结婚时一次性赠予的亲密度(钻戒)', 'min' => 0, 'max' => 1000], + + // 【婚姻等级阈值】 + ['group' => '婚姻等级', 'key' => 'level2_threshold', 'value' => 200, 'label' => '等级2(恩爱夫妻)阈值', 'description' => '达到此亲密度后升至等级2', 'min' => 1, 'max' => 9999], + ['group' => '婚姻等级', 'key' => 'level3_threshold', 'value' => 600, 'label' => '等级3(情深意重)阈值', 'description' => '达到此亲密度后升至等级3', 'min' => 1, 'max' => 9999], + ['group' => '婚姻等级', 'key' => 'level4_threshold', 'value' => 1500, 'label' => '等级4(白头偕老)阈值', 'description' => '达到此亲密度后升至等级4', 'min' => 1, 'max' => 99999], + + // 【离婚惩罚】 + ['group' => '离婚惩罚', 'key' => 'divorce_mutual_charm', 'value' => 100, 'label' => '协议离婚魅力惩罚', 'description' => '双方各扣减魅力(填正数,系统取负)', 'min' => 0, 'max' => 9999], + ['group' => '离婚惩罚', 'key' => 'divorce_forced_charm', 'value' => 300, 'label' => '强制离婚魅力惩罚', 'description' => '强制方扣减魅力', 'min' => 0, 'max' => 9999], + ['group' => '离婚惩罚', 'key' => 'divorce_auto_charm', 'value' => 150, 'label' => '超时自动离婚惩罚', 'description' => '发起方扣减魅力(72h无响应自动解除)', 'min' => 0, 'max' => 9999], + ['group' => '离婚惩罚', 'key' => 'divorce_mutual_cooldown', 'value' => 70, 'label' => '协议离婚冷静期(天)', 'description' => '协议离婚后多少天内不可再次结婚', 'min' => 0, 'max' => 365], + ['group' => '离婚惩罚', 'key' => 'divorce_forced_cooldown', 'value' => 90, 'label' => '强制离婚冷静期(天)', 'description' => '强制方多少天内不可再次结婚', 'min' => 0, 'max' => 365], + ['group' => '离婚惩罚', 'key' => 'divorce_auto_cooldown', 'value' => 30, 'label' => '超时自动离婚冷静期', 'description' => '发起方多少天内不可再次结婚', 'min' => 0, 'max' => 365], + ['group' => '离婚惩罚', 'key' => 'forced_divorce_limit_days', 'value' => 60, 'label' => '强制离婚间隔(天)', 'description' => '多少天内只能使用强制离婚1次', 'min' => 1, 'max' => 365], + + // 【时间规则】 + ['group' => '时间规则', 'key' => 'proposal_expire_hours', 'value' => 48, 'label' => '求婚有效期(小时)', 'description' => '超时后戒指消失、求婚作废', 'min' => 1, 'max' => 168], + ['group' => '时间规则', 'key' => 'divorce_request_timeout', 'value' => 72, 'label' => '离婚申请等待时长(小时)', 'description' => '协议离婚后对方多久不响应则自动升级为强制', 'min' => 1, 'max' => 168], + ['group' => '时间规则', 'key' => 'envelope_expire_hours', 'value' => 24, 'label' => '婚礼红包有效期(小时)', 'description' => '超时未领取的红包自动消失(不退还)', 'min' => 1, 'max' => 72], + ]; + + foreach ($configs as &$row) { + $row['created_at'] = $now; + $row['updated_at'] = $now; + } + unset($row); + + DB::table('marriage_configs')->upsert($configs, ['key'], ['value', 'label', 'description', 'min', 'max', 'updated_at']); + + // ── 2. wedding_tiers ───────────────────────────────────────── + $tiers = [ + ['tier' => 1, 'name' => '小小祝福', 'icon' => '⭐', 'amount' => 5888, 'description' => '小小心意,愿新人幸福美满!', 'is_active' => true], + ['tier' => 2, 'name' => '甜蜜相拥', 'icon' => '⭐⭐', 'amount' => 28888, 'description' => '诚意满满,共享甜蜜时光!', 'is_active' => true], + ['tier' => 3, 'name' => '盛世婚礼', 'icon' => '⭐⭐⭐', 'amount' => 68888, 'description' => '盛世婚宴,全场同贺!', 'is_active' => true], + ['tier' => 4, 'name' => '豪华盛典', 'icon' => '⭐⭐⭐⭐', 'amount' => 128888, 'description' => '贵族婚礼,普天同庆,豪气冲天!', 'is_active' => true], + ['tier' => 5, 'name' => '传世佳话', 'icon' => '⭐⭐⭐⭐⭐', 'amount' => 288888, 'description' => '传说级婚礼,流芳百世,共见证!', 'is_active' => true], + ]; + + foreach ($tiers as &$t) { + $t['created_at'] = $now; + $t['updated_at'] = $now; + } + unset($t); + + DB::table('wedding_tiers')->upsert($tiers, ['tier'], ['name', 'icon', 'amount', 'description', 'is_active', 'updated_at']); + + // ── 3. shop_items — 三种戒指 ───────────────────────────────── + // 先查询 shop_items 的当前最大 sort_order + $maxSort = DB::table('shop_items')->max('sort_order') ?? 0; + + $rings = [ + [ + 'name' => '银戒指', + 'slug' => 'ring_silver', + 'icon' => '💍', + 'description' => '用银戒指求婚,表达心意。结婚时双方各获 +50 魅力,初始亲密度 +10。', + 'price' => 3888, + 'type' => 'ring', + 'duration_days' => null, + 'is_active' => true, + 'sort_order' => $maxSort + 1, + ], + [ + 'name' => '金戒指', + 'slug' => 'ring_gold', + 'icon' => '💎', + 'description' => '用金戒指求婚,彰显诚意。结婚时双方各获 +150 魅力,初始亲密度 +30。', + 'price' => 12888, + 'type' => 'ring', + 'duration_days' => null, + 'is_active' => true, + 'sort_order' => $maxSort + 2, + ], + [ + 'name' => '钻戒', + 'slug' => 'ring_diamond', + 'icon' => '👑', + 'description' => '顶级钻戒,永结同心!结婚时双方各获 +500 魅力,初始亲密度 +80。', + 'price' => 38888, + 'type' => 'ring', + 'duration_days' => null, + 'is_active' => true, + 'sort_order' => $maxSort + 3, + ], + ]; + + foreach ($rings as &$r) { + $r['created_at'] = $now; + $r['updated_at'] = $now; + } + unset($r); + + DB::table('shop_items')->upsert($rings, ['slug'], [ + 'name', 'icon', 'description', 'price', 'type', 'duration_days', 'is_active', 'sort_order', 'updated_at', + ]); + + $this->command->info('✅ 婚姻系统初始数据写入完成:'.count($configs).' 条配置 + 5 个婚礼档位 + 3 种戒指'); + } +}