重构猜谜活动并统一聊天室答题通知
This commit is contained in:
+4
-76
@@ -176,88 +176,16 @@ Schedule::call(function () {
|
||||
}
|
||||
})->everyMinute()->name('lottery:check')->withoutOverlapping();
|
||||
|
||||
// ──────────── 猜成语自动出题 ────────────────────────────────────
|
||||
// ──────────── 猜谜活动自动出题 ──────────────────────────────────
|
||||
//
|
||||
// 每分钟:检查是否到时间自动出题(仅 auto_start_interval > 0 时生效)
|
||||
// 每分钟:按房间范围 + 题型维度独立检查是否应自动出题
|
||||
Schedule::call(function () {
|
||||
if (! \App\Models\GameConfig::isEnabled('idiom')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 先统一结算超时回合,避免旧题长期占用进行中状态。
|
||||
$roomId = 1;
|
||||
app(\App\Services\IdiomGameService::class)->expireActiveRoundsForRoom($roomId);
|
||||
|
||||
$config = \App\Models\GameConfig::forGame('idiom')?->params ?? [];
|
||||
$interval = (int) ($config['auto_start_interval'] ?? 0);
|
||||
if ($interval <= 0) {
|
||||
return; // 仅手动模式
|
||||
}
|
||||
|
||||
// 检查每个房间是否有进行中的回合(先只处理 1 号房间)
|
||||
$activeRound = \App\Models\IdiomGameRound::where('room_id', $roomId)
|
||||
->whereIn('status', ['pending', 'active'])
|
||||
->first();
|
||||
if ($activeRound) {
|
||||
return; // 当前有未答完的题,跳过
|
||||
}
|
||||
|
||||
// 检查距上一题结束/创建时间是否已达到间隔
|
||||
$lastRound = \App\Models\IdiomGameRound::where('room_id', $roomId)
|
||||
->latest()
|
||||
->first();
|
||||
if ($lastRound) {
|
||||
$lastTime = $lastRound->ended_at ?? $lastRound->started_at ?? $lastRound->created_at;
|
||||
if ($lastTime && $lastTime->diffInMinutes(now()) < $interval) {
|
||||
return; // 还没到时间
|
||||
}
|
||||
}
|
||||
|
||||
// 随机选一道启用的题目
|
||||
$idiom = \App\Models\Idiom::where('is_active', true)->inRandomOrder()->first();
|
||||
if (! $idiom) {
|
||||
return; // 题库为空
|
||||
}
|
||||
|
||||
$rewardGold = (int) ($config['reward_gold'] ?? 50);
|
||||
$rewardExp = (int) ($config['reward_exp'] ?? 30);
|
||||
|
||||
// 创建新回合,并以 started_at 作为后续过期判断起点。
|
||||
$round = \App\Models\IdiomGameRound::create([
|
||||
'room_id' => $roomId,
|
||||
'idiom_id' => $idiom->id,
|
||||
'status' => 'active',
|
||||
'reward_gold' => $rewardGold,
|
||||
'reward_exp' => $rewardExp,
|
||||
'started_at' => now(),
|
||||
]);
|
||||
|
||||
// 广播到聊天室
|
||||
broadcast(new \App\Events\IdiomGameStarted(
|
||||
roomId: $roomId,
|
||||
hint: $idiom->hint,
|
||||
roundId: $round->id,
|
||||
rewardGold: $rewardGold,
|
||||
rewardExp: $rewardExp,
|
||||
));
|
||||
|
||||
// 同时推一条 MessageSent 消息显示在聊天窗口
|
||||
$msg = [
|
||||
'id' => app(\App\Services\ChatStateService::class)->nextMessageId($roomId),
|
||||
'room_id' => $roomId,
|
||||
'from_user' => '星海小博士',
|
||||
'to_user' => '大家',
|
||||
'content' => "🧩 猜成语时间!{$idiom->hint}",
|
||||
'is_secret' => false,
|
||||
'font_color' => '#7c3aed',
|
||||
'action' => '',
|
||||
'idiom_game_round_id' => $round->id,
|
||||
'idiom_reward_gold' => $rewardGold,
|
||||
'idiom_reward_exp' => $rewardExp,
|
||||
'sent_at' => now()->toDateTimeString(),
|
||||
];
|
||||
app(\App\Services\ChatStateService::class)->pushMessage($roomId, $msg);
|
||||
broadcast(new \App\Events\MessageSent($roomId, $msg));
|
||||
// 出题、过期结算、房间范围与题型独立判定统一交给服务层处理。
|
||||
app(\App\Services\RiddleGameService::class)->autoStartEligibleRounds();
|
||||
})->everyMinute()->name('idiom:auto-start')->withoutOverlapping();
|
||||
|
||||
// 每日 18:00:超级期预热广播(若当前期次为超级期,提醒用户购票)
|
||||
|
||||
+28
-13
@@ -292,11 +292,18 @@ Route::middleware(['chat.auth'])->group(function () {
|
||||
->middleware('throttle:chat-send')
|
||||
->name('chat.pat');
|
||||
|
||||
// 猜成语游戏
|
||||
// 猜谜活动游戏
|
||||
Route::prefix('riddle-quiz')->name('riddle-quiz.')->group(function () {
|
||||
Route::post('/start', [\App\Http\Controllers\RiddleQuizController::class, 'start'])->name('start');
|
||||
Route::post('/answer', [\App\Http\Controllers\RiddleQuizController::class, 'answer'])->name('answer');
|
||||
Route::get('/current', [\App\Http\Controllers\RiddleQuizController::class, 'current'])->name('current');
|
||||
});
|
||||
|
||||
// 兼容旧前端与历史脚本,暂时保留旧的 idiom-quiz 路由别名。
|
||||
Route::prefix('idiom-quiz')->name('idiom-quiz.')->group(function () {
|
||||
Route::post('/start', [\App\Http\Controllers\IdiomQuizController::class, 'start'])->name('start');
|
||||
Route::post('/answer', [\App\Http\Controllers\IdiomQuizController::class, 'answer'])->name('answer');
|
||||
Route::get('/current', [\App\Http\Controllers\IdiomQuizController::class, 'current'])->name('current');
|
||||
Route::post('/start', [\App\Http\Controllers\RiddleQuizController::class, 'start'])->name('start');
|
||||
Route::post('/answer', [\App\Http\Controllers\RiddleQuizController::class, 'answer'])->name('answer');
|
||||
Route::get('/current', [\App\Http\Controllers\RiddleQuizController::class, 'current'])->name('current');
|
||||
});
|
||||
|
||||
// 挂机心跳存点 (限制每分钟最多调用 6 次防止挂机脚本滥用)
|
||||
@@ -590,15 +597,23 @@ Route::middleware(['chat.auth', 'chat.has_position'])->prefix('admin')->name('ad
|
||||
Route::delete('/{fishing}', [\App\Http\Controllers\Admin\FishingEventController::class, 'destroy'])->name('destroy');
|
||||
});
|
||||
|
||||
// ── 猜成语题库 ──
|
||||
Route::prefix('idioms')->name('idioms.')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\Admin\IdiomController::class, 'index'])->name('index');
|
||||
Route::post('/', [\App\Http\Controllers\Admin\IdiomController::class, 'store'])->name('store');
|
||||
Route::put('/{idiom}', [\App\Http\Controllers\Admin\IdiomController::class, 'update'])->name('update');
|
||||
Route::post('/{idiom}/toggle', [\App\Http\Controllers\Admin\IdiomController::class, 'toggle'])->name('toggle');
|
||||
Route::delete('/{idiom}', [\App\Http\Controllers\Admin\IdiomController::class, 'destroy'])->name('destroy');
|
||||
Route::post('/settings', [\App\Http\Controllers\Admin\IdiomController::class, 'saveSettings'])->name('settings.save');
|
||||
});
|
||||
// ── 猜谜活动题库 ──
|
||||
Route::prefix('riddles')->name('riddles.')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\Admin\RiddleController::class, 'index'])->name('index');
|
||||
Route::post('/', [\App\Http\Controllers\Admin\RiddleController::class, 'store'])->name('store');
|
||||
Route::put('/{idiom}', [\App\Http\Controllers\Admin\RiddleController::class, 'update'])->name('update');
|
||||
Route::post('/{idiom}/toggle', [\App\Http\Controllers\Admin\RiddleController::class, 'toggle'])->name('toggle');
|
||||
Route::delete('/{idiom}', [\App\Http\Controllers\Admin\RiddleController::class, 'destroy'])->name('destroy');
|
||||
});
|
||||
|
||||
// 兼容旧后台路径与书签,先保留 idioms 别名入口。
|
||||
Route::prefix('idioms')->name('idioms.')->group(function () {
|
||||
Route::get('/', [\App\Http\Controllers\Admin\RiddleController::class, 'index'])->name('index');
|
||||
Route::post('/', [\App\Http\Controllers\Admin\RiddleController::class, 'store'])->name('store');
|
||||
Route::put('/{idiom}', [\App\Http\Controllers\Admin\RiddleController::class, 'update'])->name('update');
|
||||
Route::post('/{idiom}/toggle', [\App\Http\Controllers\Admin\RiddleController::class, 'toggle'])->name('toggle');
|
||||
Route::delete('/{idiom}', [\App\Http\Controllers\Admin\RiddleController::class, 'destroy'])->name('destroy');
|
||||
});
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user