From 29e43507ac2627335dc3158f8b2addcd3113d1a9 Mon Sep 17 00:00:00 2001 From: lkddi Date: Sun, 1 Mar 2026 15:42:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9A=E5=95=86=E5=BA=97?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=88=92=E6=8C=87=E6=9D=BF=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 迁移: - 2026_03_01_153959:shop_items 增加 intimacy_bonus/charm_bonus 字段 Seeder(RingItemsSeeder): - 银质戒指 500金 亲密+10 魅力+30 - 黄金戒指 2000金 亲密+30 魅力+80 - 红宝石戒指 8000金 亲密+80 魅力+200 - 钻石戒指 30000金 亲密+200 魅力+500 - 传说神戒 100000金 亲密+500 魅力+1000 ShopService: - buyItem() 分支加 ring 类型 - buyRing():扣金币 + 写入 active UserPurchase(背包持有) ShopController::items(): - 返回 intimacy_bonus/charm_bonus - 统计 ring_counts(各戒指持有数量) shop-panel.blade.php: - 新增「💍 求婚戒指」分组(排在最后) - 图标右上角红色数字徽章(持有时) - 卡片下方显示亲密度/魅力加成 - 购买按钮与现有逻辑复用 --- app/Http/Controllers/ShopController.php | 13 +++ app/Services/ShopService.php | 26 ++++++ ...9_add_ring_bonuses_to_shop_items_table.php | 37 ++++++++ database/seeders/RingItemsSeeder.php | 92 +++++++++++++++++++ .../views/chat/partials/shop-panel.blade.php | 43 ++++++++- 5 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 database/migrations/2026_03_01_153959_add_ring_bonuses_to_shop_items_table.php create mode 100644 database/seeders/RingItemsSeeder.php diff --git a/app/Http/Controllers/ShopController.php b/app/Http/Controllers/ShopController.php index 4300a9e..f7c17fb 100644 --- a/app/Http/Controllers/ShopController.php +++ b/app/Http/Controllers/ShopController.php @@ -42,13 +42,26 @@ class ShopController extends Controller 'price' => $item->price, 'type' => $item->type, 'duration_days' => $item->duration_days, + 'intimacy_bonus' => $item->intimacy_bonus, + 'charm_bonus' => $item->charm_bonus, ]); + // 统计背包中各戒指持有数量 + $ringCounts = \App\Models\UserPurchase::query() + ->where('user_id', $user->id) + ->where('status', 'active') + ->whereHas('item', fn ($q) => $q->where('type', 'ring')) + ->selectRaw('shop_item_id, count(*) as qty') + ->groupBy('shop_item_id') + ->pluck('qty', 'shop_item_id') + ->toArray(); + return response()->json([ 'items' => $items, 'user_jjb' => $user->jjb ?? 0, 'active_week_effect' => $this->shopService->getActiveWeekEffect($user), 'has_rename_card' => $this->shopService->hasRenameCard($user), + 'ring_counts' => $ringCounts, // [item_id => qty] ]); } diff --git a/app/Services/ShopService.php b/app/Services/ShopService.php index cab49bc..5dbb74d 100644 --- a/app/Services/ShopService.php +++ b/app/Services/ShopService.php @@ -32,6 +32,7 @@ class ShopService 'instant' => $this->buyInstant($user, $item), 'duration' => $this->buyWeekCard($user, $item), 'one_time' => $this->buyRenameCard($user, $item), + 'ring' => $this->buyRing($user, $item), default => ['ok' => false, 'message' => '未知商品类型'], }; } @@ -209,6 +210,31 @@ class ShopService return $purchase->shopItem->effectKey(); } + /** + * 购买结婚戒指:扣金币、写入背包(active 状态,等待结婚时消耗)。 + * + * @return array{ok:bool, message:string} + */ + public function buyRing(User $user, ShopItem $item): array + { + DB::transaction(function () use ($user, $item): void { + // 扣除金币 + $user->decrement('jjb', $item->price); + // 写入背包(active = 未使用,求婚时变为 used_pending→used 或 lost) + UserPurchase::create([ + 'user_id' => $user->id, + 'shop_item_id' => $item->id, + 'status' => 'active', + 'price_paid' => $item->price, + ]); + }); + + return [ + 'ok' => true, + 'message' => "💍 {$item->name} 购买成功!已放入背包,可用于求婚。", + ]; + } + /** * 获取用户当前激活的改名卡(是否持有未用改名卡) */ diff --git a/database/migrations/2026_03_01_153959_add_ring_bonuses_to_shop_items_table.php b/database/migrations/2026_03_01_153959_add_ring_bonuses_to_shop_items_table.php new file mode 100644 index 0000000..ac802b2 --- /dev/null +++ b/database/migrations/2026_03_01_153959_add_ring_bonuses_to_shop_items_table.php @@ -0,0 +1,37 @@ +unsignedSmallInteger('intimacy_bonus')->default(0)->after('duration_days')->comment('结婚初始亲密度加成(戒指专用)'); + $table->unsignedSmallInteger('charm_bonus')->default(0)->after('intimacy_bonus')->comment('结婚魅力加成(戒指专用)'); + }); + } + + /** + * 回滚:删除字段。 + */ + public function down(): void + { + Schema::table('shop_items', function (Blueprint $table): void { + $table->dropColumn(['intimacy_bonus', 'charm_bonus']); + }); + } +}; diff --git a/database/seeders/RingItemsSeeder.php b/database/seeders/RingItemsSeeder.php new file mode 100644 index 0000000..1734de3 --- /dev/null +++ b/database/seeders/RingItemsSeeder.php @@ -0,0 +1,92 @@ + 'ring_silver', + 'name' => '银质戒指', + 'icon' => '💍', + 'description' => '朴素银戒,见证两心相许。', + 'price' => 500, + 'type' => 'ring', + 'intimacy_bonus' => 10, + 'charm_bonus' => 30, + 'sort_order' => 101, + ], + [ + 'slug' => 'ring_gold', + 'name' => '黄金戒指', + 'icon' => '💛', + 'description' => '18K黄金,情比金坚。', + 'price' => 2000, + 'type' => 'ring', + 'intimacy_bonus' => 30, + 'charm_bonus' => 80, + 'sort_order' => 102, + ], + [ + 'slug' => 'ring_ruby', + 'name' => '红宝石戒指', + 'icon' => '❤️', + 'description' => '鸽血红宝,热烈如初恋。', + 'price' => 8000, + 'type' => 'ring', + 'intimacy_bonus' => 80, + 'charm_bonus' => 200, + 'sort_order' => 103, + ], + [ + 'slug' => 'ring_diamond', + 'name' => '钻石戒指', + 'icon' => '💎', + 'description' => '一克拉钻石,誓言永恒。', + 'price' => 30000, + 'type' => 'ring', + 'intimacy_bonus' => 200, + 'charm_bonus' => 500, + 'sort_order' => 104, + ], + [ + 'slug' => 'ring_legendary', + 'name' => '传说神戒', + 'icon' => '🌟', + 'description' => '世间仅此一款,天命之环,天作之合。', + 'price' => 100000, + 'type' => 'ring', + 'intimacy_bonus' => 500, + 'charm_bonus' => 1000, + 'sort_order' => 105, + ], + ]; + + foreach ($rings as $ring) { + ShopItem::updateOrCreate( + ['slug' => $ring['slug']], + array_merge($ring, [ + 'is_active' => true, + 'duration_days' => null, + ]) + ); + } + + $this->command->info('✅ 5 枚结婚戒指已写入 shop_items。'); + } +} diff --git a/resources/views/chat/partials/shop-panel.blade.php b/resources/views/chat/partials/shop-panel.blade.php index dd5fe7a..749ab82 100644 --- a/resources/views/chat/partials/shop-panel.blade.php +++ b/resources/views/chat/partials/shop-panel.blade.php @@ -318,6 +318,8 @@ badge.style.display = 'inline-block'; } + const ringCounts = data.ring_counts || {}; + const groups = [{ label: '⚡ 单次特效卡', desc: '立即播放一次,仅自己可见', @@ -333,6 +335,11 @@ desc: '', type: 'one_time' }, + { + label: '💍 求婚戒指', + desc: '购买后存入背包,求婚时消耗(若被拒绝则遗失)', + type: 'ring' + }, ]; const itemsEl = document.getElementById('shop-items-list'); @@ -361,6 +368,8 @@ items.forEach(item => { const isRename = item.slug === 'rename_card'; const canUseRename = isRename && data.has_rename_card; + const isRing = item.type === 'ring'; + const ownedQty = isRing ? (ringCounts[item.id] || 0) : 0; const card = document.createElement('div'); card.className = 'shop-card'; @@ -369,11 +378,22 @@ const row = document.createElement('div'); row.className = 'shop-card-row'; - // 图标 + // 图标区(戒指加持有数徽标) + const iconWrap = document.createElement('span'); + iconWrap.style.cssText = + 'position:relative; flex-shrink:0; width:28px; text-align:center;'; const icon = document.createElement('span'); icon.className = 'shop-card-icon'; icon.textContent = item.icon; - row.appendChild(icon); + iconWrap.appendChild(icon); + if (isRing && ownedQty > 0) { + const badge = document.createElement('span'); + badge.style.cssText = + 'position:absolute; top:-4px; right:-4px; background:#f43f5e; color:#fff; font-size:8px; font-weight:800; min-width:14px; height:14px; border-radius:7px; text-align:center; line-height:14px; padding:0 2px;'; + badge.textContent = ownedQty; + iconWrap.appendChild(badge); + } + row.appendChild(iconWrap); // 名称 const name = document.createElement('span'); @@ -404,6 +424,25 @@ card.appendChild(desc); } + // 戒指:加成信息行 + if (isRing && (item.intimacy_bonus > 0 || item.charm_bonus > 0)) { + const bonus = document.createElement('div'); + bonus.style.cssText = + 'font-size:9px; color:#f43f5e; margin-top:3px; display:flex; gap:8px;'; + if (item.intimacy_bonus > 0) { + const b1 = document.createElement('span'); + b1.textContent = `💞 亲密 +${item.intimacy_bonus}`; + bonus.appendChild(b1); + } + if (item.charm_bonus > 0) { + const b2 = document.createElement('span'); + b2.style.color = '#a855f7'; + b2.textContent = `✨ 魅力 +${item.charm_bonus}`; + bonus.appendChild(b2); + } + card.appendChild(bonus); + } + section.appendChild(card); });