66 lines
2.1 KiB
PHP
66 lines
2.1 KiB
PHP
<?php
|
||
|
||
/**
|
||
* 文件功能:自动关闭掉线职务日志指令
|
||
*
|
||
* 每 15 分钟由 Laravel Scheduler 调用,扫描 position_duty_logs 表中:
|
||
* - logout_at IS NULL(尚未结算的开放日志)
|
||
* - updated_at 超过 15 分钟未刷新(说明心跳已中断,用户已掉线/关闭浏览器)
|
||
*
|
||
* 对此类日志写入 logout_at = NOW(),保留 duration_seconds 现有值不清零,
|
||
* 确保累计时长计算准确,不因掉线而永久悬空。
|
||
*
|
||
* @author ChatRoom Laravel
|
||
*
|
||
* @version 1.0.0
|
||
*/
|
||
|
||
namespace App\Console\Commands;
|
||
|
||
use App\Models\PositionDutyLog;
|
||
use Illuminate\Console\Command;
|
||
use Illuminate\Support\Facades\DB;
|
||
|
||
class CloseStaleDutyLogs extends Command
|
||
{
|
||
/**
|
||
* Artisan 指令名称
|
||
*/
|
||
protected $signature = 'duty:close-stale-logs';
|
||
|
||
/**
|
||
* 指令描述(在 artisan list 中显示)
|
||
*/
|
||
protected $description = '自动关闭 15 分钟内无心跳的开放职务日志(解决掉线不结算问题)';
|
||
|
||
/**
|
||
* 指令入口:将长时间无心跳刷新的开放日志判定为掉线,写入 logout_at 完成结算。
|
||
*
|
||
* 判定标准:updated_at 超过 15 分钟(心跳间隔约 30 秒,5 分钟自动存点最长 5 分钟,
|
||
* 留足 10 分钟容差,总计 15 分钟无刷新即认为掉线)
|
||
*/
|
||
public function handle(): int
|
||
{
|
||
// 15 分钟无心跳 = 掉线判定阈值
|
||
$threshold = now()->subMinutes(15);
|
||
|
||
// 批量关闭符合条件的开放日志,保留现有 duration_seconds
|
||
$affected = PositionDutyLog::query()
|
||
->whereNull('logout_at')
|
||
->where('updated_at', '<=', $threshold)
|
||
->update([
|
||
'logout_at' => DB::raw('NOW()'),
|
||
// 补算最终在线时长,避免日榜 SUM 使用过时的旧值
|
||
'duration_seconds' => DB::raw('GREATEST(0, TIMESTAMPDIFF(SECOND, login_at, NOW()))'),
|
||
]);
|
||
|
||
if ($affected > 0) {
|
||
$this->info("共关闭 {$affected} 条掉线职务日志。");
|
||
} else {
|
||
$this->info('无需处理,无掉线日志。');
|
||
}
|
||
|
||
return Command::SUCCESS;
|
||
}
|
||
}
|