@@ -88,6 +87,7 @@
{{-- 参数配置区域 --}}
+
+
+ @include('admin.game-configs.partials.common-room-scope', [
+ 'availableRooms' => $availableRooms,
+ 'roomScopeConfig' => $roomScopeConfig,
+ 'roomScopeTitle' => '参与房间',
+ ])
+
@endif
@@ -189,7 +201,7 @@
style="padding:8px 16px; background:linear-gradient(135deg,#7f1d1d,#ef4444); color:#fff; border:none; border-radius:8px; font-size:13px; font-weight:700; cursor:pointer; transition:opacity .15s;">
☠️ 投放黑化箱
- 直接向 #1 房间投放,立即广播暗号
+ 投放到当前配置的首选房间,立即广播暗号。
@endif
@@ -461,4 +473,16 @@
->all(),
];
}
+
+ /**
+ * 解析通用游戏的房间范围配置。
+ *
+ * @return array{room_scope_mode:string,room_ids:array}
+ */
+ function gameRoomScopeConfig(array $params): array
+ {
+ $roomScopeService = app(\App\Services\GameRoomScopeService::class);
+
+ return $roomScopeService->getScopeConfigForParams($params);
+ }
@endphp
diff --git a/resources/views/admin/game-configs/partials/common-room-scope.blade.php b/resources/views/admin/game-configs/partials/common-room-scope.blade.php
new file mode 100644
index 0000000..559628f
--- /dev/null
+++ b/resources/views/admin/game-configs/partials/common-room-scope.blade.php
@@ -0,0 +1,79 @@
+@php
+ $roomScopeConfig = $roomScopeConfig ?? ['room_scope_mode' => 'single', 'room_ids' => [1]];
+ $roomScopeDataKey = $roomScopeDataKey ?? 'game';
+ $roomScopeTitle = $roomScopeTitle ?? '参与房间';
+ $roomScopeCheckedRoomIds = collect($roomScopeConfig['room_ids'] ?? [1])->map(fn ($roomId) => (int) $roomId)->all();
+@endphp
+
+
+
+
+
+
+
+
+
+
+ @foreach ($availableRooms as $room)
+
+ @endforeach
+
+
单选模式下只保留一个房间,多选模式可同时勾选多个房间。
+
+
+
+@once
+ @push('scripts')
+
+ @endpush
+@endonce
diff --git a/resources/views/admin/game-configs/partials/riddle-config-card.blade.php b/resources/views/admin/game-configs/partials/riddle-config-card.blade.php
index d731fb3..c0f8801 100644
--- a/resources/views/admin/game-configs/partials/riddle-config-card.blade.php
+++ b/resources/views/admin/game-configs/partials/riddle-config-card.blade.php
@@ -1,6 +1,5 @@
@php
$sharedConfig = gameRiddleSharedConfig($params);
- $checkedRoomIds = collect($sharedConfig['room_ids'])->map(fn ($roomId) => (int) $roomId)->all();
@endphp
@@ -53,33 +52,17 @@
class="w-full rounded-lg border border-gray-300 p-2 text-sm focus:border-indigo-400">
分钟,0 表示仅手动出题。
-
-
-
-
-
-
-
- @foreach ($availableRooms as $room)
-
- @endforeach
-
-
单选模式下只保留一个房间,多选模式可同时勾选多个房间。
-
+
+
+
+ @include('admin.game-configs.partials.common-room-scope', [
+ 'availableRooms' => $availableRooms,
+ 'roomScopeConfig' => [
+ 'room_scope_mode' => $sharedConfig['room_mode'],
+ 'room_ids' => $sharedConfig['room_ids'],
+ ],
+ 'roomScopeTitle' => '参与房间',
+ ])
@@ -121,41 +104,6 @@
window.alert(message);
}
- document.querySelectorAll('[data-idiom-config-form]').forEach(function (form) {
- form.addEventListener('submit', function (event) {
- let hasValidationError = false;
- const modeSelect = this.querySelector('[data-idiom-room-mode]');
- const roomCheckboxes = Array.from(this.querySelectorAll('[data-idiom-room-checkbox]'));
- const checkedRooms = roomCheckboxes.filter(function (checkbox) {
- return checkbox.checked;
- });
-
- if (modeSelect) {
- if (modeSelect.value === 'single' && checkedRooms.length > 1) {
- showAdminAlert('猜谜活动处于单选房间模式时,只能勾选一个房间。', '房间选择有误', '⚠️');
- hasValidationError = true;
- }
-
- if (modeSelect.value === 'single' && checkedRooms.length === 0) {
- const firstRoomCheckbox = roomCheckboxes[0];
-
- if (firstRoomCheckbox) {
- firstRoomCheckbox.checked = true;
- }
- }
-
- if (modeSelect.value === 'multiple' && checkedRooms.length === 0) {
- showAdminAlert('猜谜活动处于多选房间模式时,请至少选择一个房间。', '房间选择有误', '⚠️');
- hasValidationError = true;
- }
- }
-
- if (hasValidationError) {
- event.preventDefault();
- }
- });
- });
-
const manualStartButton = document.getElementById('idiom-manual-start-btn');
if (!manualStartButton) {
return;
diff --git a/routes/console.php b/routes/console.php
index a00cc71..e68c0ae 100644
--- a/routes/console.php
+++ b/routes/console.php
@@ -68,16 +68,21 @@ Schedule::call(function () {
$config = \App\Models\GameConfig::forGame('baccarat')?->params ?? [];
$interval = (int) ($config['interval_minutes'] ?? 2);
+ $roomScopeService = app(\App\Services\GameRoomScopeService::class);
- // 检查距上一局触发时间是否已达到间隔
- $lastRound = \App\Models\BaccaratRound::latest()->first();
- if ($lastRound && $lastRound->created_at->diffInMinutes(now()) < $interval) {
- return; // 还没到开局时间
- }
+ foreach ($roomScopeService->getScopedRoomIdsForGame('baccarat') as $roomId) {
+ $lastRound = \App\Models\BaccaratRound::query()
+ ->where('room_id', $roomId)
+ ->latest()
+ ->first();
- // 无当前进行中的局才开新局
- if (! \App\Models\BaccaratRound::currentRound()) {
- \App\Jobs\OpenBaccaratRoundJob::dispatch();
+ if ($lastRound && $lastRound->created_at->diffInMinutes(now()) < $interval) {
+ continue;
+ }
+
+ if (! \App\Models\BaccaratRound::currentRound($roomId)) {
+ \App\Jobs\OpenBaccaratRoundJob::dispatch($roomId);
+ }
}
})->everyMinute()->name('baccarat:open-round')->withoutOverlapping();
@@ -96,30 +101,33 @@ Schedule::call(function () {
return;
}
- // 当前已有可领取的箱子时跳过(一次只投放一个)
- if (\App\Models\MysteryBox::currentOpenBox()) {
- return;
- }
-
$intervalHours = (float) ($config['auto_interval_hours'] ?? 2);
+ $roomScopeService = app(\App\Services\GameRoomScopeService::class);
- // 检查距上次投放时间
- $lastBox = \App\Models\MysteryBox::latest()->first();
- if ($lastBox && $lastBox->created_at->diffInHours(now()) < $intervalHours) {
- return;
+ foreach ($roomScopeService->getScopedRoomIdsForGame('mystery_box') as $roomId) {
+ if (\App\Models\MysteryBox::currentOpenBox($roomId)) {
+ continue;
+ }
+
+ $lastBox = \App\Models\MysteryBox::query()
+ ->where('room_id', $roomId)
+ ->latest()
+ ->first();
+ if ($lastBox && $lastBox->created_at->diffInHours(now()) < $intervalHours) {
+ continue;
+ }
+
+ $trapChance = (int) ($config['trap_chance_percent'] ?? 10);
+ $rand = random_int(1, 100);
+
+ $boxType = match (true) {
+ $rand <= $trapChance => 'trap',
+ $rand <= $trapChance + 15 => 'rare',
+ default => 'normal',
+ };
+
+ \App\Jobs\DropMysteryBoxJob::dispatch($boxType, $roomId);
}
-
- // 按配置的陷阱概率决定箱子类型
- $trapChance = (int) ($config['trap_chance_percent'] ?? 10);
- $rand = random_int(1, 100);
-
- $boxType = match (true) {
- $rand <= $trapChance => 'trap',
- $rand <= $trapChance + 15 => 'rare',
- default => 'normal',
- };
-
- \App\Jobs\DropMysteryBoxJob::dispatch($boxType);
})->everyMinute()->name('mystery-box:auto-drop')->withoutOverlapping();
// ──────────── 赛马竞猜定时任务 ─────────────────────────────────
@@ -130,21 +138,25 @@ Schedule::call(function () {
return;
}
- // 当前已有进行中的场次(押注中/跑马中),跳过
- if (\App\Models\HorseRace::currentRace()) {
- return;
- }
-
$config = \App\Models\GameConfig::forGame('horse_racing')?->params ?? [];
$interval = (int) ($config['interval_minutes'] ?? 30);
+ $roomScopeService = app(\App\Services\GameRoomScopeService::class);
- // 检查距上一场触发时间是否已达到间隔
- $lastRace = \App\Models\HorseRace::latest()->first();
- if ($lastRace && $lastRace->created_at->diffInMinutes(now()) < $interval) {
- return;
+ foreach ($roomScopeService->getScopedRoomIdsForGame('horse_racing') as $roomId) {
+ if (\App\Models\HorseRace::currentRace($roomId)) {
+ continue;
+ }
+
+ $lastRace = \App\Models\HorseRace::query()
+ ->where('room_id', $roomId)
+ ->latest()
+ ->first();
+ if ($lastRace && $lastRace->created_at->diffInMinutes(now()) < $interval) {
+ continue;
+ }
+
+ \App\Jobs\OpenHorseRaceJob::dispatch($roomId)->delay(now()->addSeconds(30));
}
-
- \App\Jobs\OpenHorseRaceJob::dispatch()->delay(now()->addSeconds(30));
})->everyMinute()->name('horse-race:open-race')->withoutOverlapping();
// ──────────── 双色球彩票定时任务 ─────────────────────────────────
@@ -155,24 +167,29 @@ Schedule::call(function () {
return;
}
- $issue = \App\Models\LotteryIssue::query()->whereIn('status', ['open', 'closed'])->latest()->first();
+ $roomScopeService = app(\App\Services\GameRoomScopeService::class);
- // 无进行中期次则自动创建一期
- if (! $issue) {
- \App\Jobs\OpenLotteryIssueJob::dispatch();
+ foreach ($roomScopeService->getScopedRoomIdsForGame('lottery') as $roomId) {
+ $issue = \App\Models\LotteryIssue::query()
+ ->where('room_id', $roomId)
+ ->whereIn('status', ['open', 'closed'])
+ ->latest()
+ ->first();
- return;
- }
+ if (! $issue) {
+ \App\Jobs\OpenLotteryIssueJob::dispatch($roomId);
- // open 状态:检查是否已到停售时间
- if ($issue->status === 'open' && $issue->sell_closes_at && now()->gte($issue->sell_closes_at)) {
- $issue->update(['status' => 'closed']);
- $issue->refresh();
- }
+ continue;
+ }
- // closed 状态:检查是否已到开奖时间
- if ($issue->status === 'closed' && $issue->draw_at && now()->gte($issue->draw_at)) {
- \App\Jobs\DrawLotteryJob::dispatch($issue);
+ if ($issue->status === 'open' && $issue->sell_closes_at && now()->gte($issue->sell_closes_at)) {
+ $issue->update(['status' => 'closed']);
+ $issue->refresh();
+ }
+
+ if ($issue->status === 'closed' && $issue->draw_at && now()->gte($issue->draw_at)) {
+ \App\Jobs\DrawLotteryJob::dispatch($issue);
+ }
}
})->everyMinute()->name('lottery:check')->withoutOverlapping();
@@ -194,8 +211,12 @@ Schedule::call(function () {
return;
}
- $issue = \App\Models\LotteryIssue::currentIssue();
- if ($issue && $issue->is_super_issue) {
- \App\Jobs\OpenLotteryIssueJob::dispatch(); // 触发广播
+ $roomScopeService = app(\App\Services\GameRoomScopeService::class);
+
+ foreach ($roomScopeService->getScopedRoomIdsForGame('lottery') as $roomId) {
+ $issue = \App\Models\LotteryIssue::currentIssue($roomId);
+ if ($issue && $issue->is_super_issue) {
+ \App\Jobs\OpenLotteryIssueJob::dispatch($roomId); // 触发广播
+ }
}
})->dailyAt('18:00')->name('lottery:super-reminder');