diff --git a/app/Console/Commands/CloseStaleDutyLogs.php b/app/Console/Commands/CloseStaleDutyLogs.php new file mode 100644 index 0000000..a136105 --- /dev/null +++ b/app/Console/Commands/CloseStaleDutyLogs.php @@ -0,0 +1,63 @@ +subMinutes(15); + + // 批量关闭符合条件的开放日志,保留现有 duration_seconds + $affected = PositionDutyLog::query() + ->whereNull('logout_at') + ->where('updated_at', '<=', $threshold) + ->update([ + 'logout_at' => DB::raw('NOW()'), + ]); + + if ($affected > 0) { + $this->info("共关闭 {$affected} 条掉线职务日志。"); + } else { + $this->info('无需处理,无掉线日志。'); + } + + return Command::SUCCESS; + } +} diff --git a/app/Http/Controllers/ChatController.php b/app/Http/Controllers/ChatController.php index 784698e..a2b32ae 100644 --- a/app/Http/Controllers/ChatController.php +++ b/app/Http/Controllers/ChatController.php @@ -1025,14 +1025,14 @@ class ChatController extends Controller 'duration_seconds' => DB::raw('GREATEST(0, TIMESTAMPDIFF(SECOND, login_at, NOW()))'), ]); - // 清理历史遭留未关闭的日志(login_at 非今日),直接将它们的时长置 0,避免被算入任何榜单 + // 关闭历史遗留的跨天未关闭日志(login_at 非今日) + // 保留最后一次心跳刷新的 duration_seconds,确保已积累时长不丢失 PositionDutyLog::query() ->where('user_id', $userId) ->whereNull('logout_at') ->whereDate('login_at', '<', today()) ->update([ - 'logout_at' => DB::raw('login_at'), // 时长 = 0 - 'duration_seconds' => 0, + 'logout_at' => DB::raw('login_at + INTERVAL duration_seconds SECOND'), ]); } diff --git a/routes/console.php b/routes/console.php index e0f637b..00a5095 100644 --- a/routes/console.php +++ b/routes/console.php @@ -14,6 +14,9 @@ Schedule::command('messages:purge')->dailyAt('03:00'); // 每 5 分钟为所有在线用户自动存点(经验/金币/等级) Schedule::command('chatroom:auto-save-exp')->everyFiveMinutes(); +// 每 15 分钟:关闭掉线用户的开放职务日志(久无心跳 = 掉线,自动写入 logout_at) +Schedule::command('duty:close-stale-logs')->everyFifteenMinutes(); + // ──────────── 婚姻系统定时任务 ──────────────────────────────────── // 每 5 分钟:扫描超时求婚(48h后失效 + 戒指消失 + 广播通知)