diff --git a/app/Console/Commands/PurgeOldMessages.php b/app/Console/Commands/PurgeOldMessages.php new file mode 100644 index 0000000..525f535 --- /dev/null +++ b/app/Console/Commands/PurgeOldMessages.php @@ -0,0 +1,91 @@ + sysparam 配置 > 默认 30 天 + $days = (int) ($this->option('days') + ?: Sysparam::getValue('message_retention_days', '30')); + + $cutoff = Carbon::now()->subDays($days); + $isDryRun = $this->option('dry-run'); + + // 统计待清理数量 + $totalCount = Message::where('sent_at', '<', $cutoff)->count(); + + if ($totalCount === 0) { + $this->info("✅ 没有超过 {$days} 天的聊天记录需要清理。"); + + return self::SUCCESS; + } + + if ($isDryRun) { + $this->warn("🔍 [预览模式] 将删除 {$totalCount} 条超过 {$days} 天的聊天记录(截止 {$cutoff->toDateTimeString()})"); + + return self::SUCCESS; + } + + $this->info("🧹 开始清理超过 {$days} 天的聊天记录(截止 {$cutoff->toDateTimeString()})..."); + $this->info(" 待清理数量:{$totalCount} 条"); + + // 分批删除,每批 1000 条,避免长时间锁表 + $deleted = 0; + $batchSize = 1000; + + do { + $batch = Message::where('sent_at', '<', $cutoff) + ->limit($batchSize) + ->delete(); + + $deleted += $batch; + + if ($batch > 0) { + $this->line(" 已删除 {$deleted}/{$totalCount} 条..."); + } + } while ($batch === $batchSize); + + $this->info("✅ 清理完成!共删除 {$deleted} 条聊天记录。"); + + return self::SUCCESS; + } +} diff --git a/routes/console.php b/routes/console.php index 3c9adf1..16042f6 100644 --- a/routes/console.php +++ b/routes/console.php @@ -2,7 +2,11 @@ use Illuminate\Foundation\Inspiring; use Illuminate\Support\Facades\Artisan; +use Illuminate\Support\Facades\Schedule; Artisan::command('inspire', function () { $this->comment(Inspiring::quote()); })->purpose('Display an inspiring quote'); + +// 每天凌晨 3 点清理超过 30 天的聊天记录 +Schedule::command('messages:purge')->dailyAt('03:00');