Files
lotteryLaravel/app/Console/Commands/LotteryDevPruneDrawBacklogCommand.php
kang 6a8cdbe3b8 feat: 新增命令和迁移以优化抽奖数据管理
- 新增 `LotteryDevPruneDrawBacklogCommand` 命令,用于按营业日区间删除积压的抽奖期号,并支持干运行和级联删除相关数据。
- 添加多个迁移文件以同步数据库结构,包括重命名重复的迁移文件、添加用户名字段、迁移抽奖状态到领域字典、合并显示名称字段、扩展审计日志目标类型字段,以及细化后台权限管理。
- 更新 `AdminRbacAndUserSeeder` 以包含角色代码字段,确保一致性与可维护性。
2026-05-25 15:33:33 +08:00

120 lines
3.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Console\Commands;
use App\Models\Draw;
use Illuminate\Console\Command;
use App\Services\Draw\DrawTickService;
use Illuminate\Support\Facades\DB;
/**
* 开发/测试库:按营业日区间删除积压期号(级联清理关联数据)。
*
* 仅允许 local / testing 环境执行。
*/
final class LotteryDevPruneDrawBacklogCommand extends Command
{
protected $signature = 'lottery:dev-prune-draw-backlog
{--from=2026-05-11 : 营业日起Y-m-d}
{--to=2026-05-22 : 营业日止Y-m-d}
{--dry-run : 只统计,不删除}
{--force : 跳过确认}
{--tick : 删除后执行 lottery:draw-tick积压多时可能占内存}';
protected $description = '【仅 dev/test】删除指定营业日区间的期号积压cascade';
public function handle(DrawTickService $tickService): int
{
if (! app()->environment(['local', 'testing'])) {
$this->error('Refused: only allowed in local or testing environment.');
return self::FAILURE;
}
$from = (string) $this->option('from');
$to = (string) $this->option('to');
$dryRun = (bool) $this->option('dry-run');
$query = Draw::query()->whereBetween('business_date', [$from, $to]);
$total = (int) $query->count();
if ($total === 0) {
$this->info("No draws found between {$from} and {$to}.");
return self::SUCCESS;
}
$byStatus = (clone $query)
->selectRaw('status, count(*) as c')
->groupBy('status')
->orderByDesc('c')
->pluck('c', 'status');
$drawIds = (clone $query)->pluck('id');
$ticketOrders = (int) DB::table('ticket_orders')->whereIn('draw_id', $drawIds)->count();
$this->table(
['Metric', 'Value'],
[
['Date range', "{$from} .. {$to}"],
['Draws to delete', (string) $total],
['Ticket orders (cascade)', (string) $ticketOrders],
],
);
$this->line('By status:');
foreach ($byStatus as $status => $count) {
$this->line(" {$status}: {$count}");
}
if ($dryRun) {
$this->info('Dry run — no rows deleted.');
return self::SUCCESS;
}
if (! $this->option('force') && ! $this->confirm("Delete {$total} draws and related rows?", false)) {
$this->warn('Aborted.');
return self::SUCCESS;
}
$deleted = 0;
(clone $query)->orderBy('id')->chunkById(200, function ($draws) use (&$deleted): void {
foreach ($draws as $draw) {
$draw->delete();
$deleted++;
}
$this->output->write('.');
});
$this->newLine();
$this->info("Deleted {$deleted} draws.");
if ($this->option('tick')) {
$report = $tickService->tick();
$this->info(sprintf(
'Post-tick: status_updates=%d rng=%d planned_created=%d',
array_sum($report['status_updates'] ?? []),
$report['rng_rung'],
$report['planned']['created'] ?? 0,
));
} else {
$this->comment('Skipped tick (pass --tick to run draw-tick after prune).');
}
$head = Draw::query()
->whereNotIn('status', ['settled', 'cancelled'])
->orderBy('draw_time')
->first(['draw_no', 'status', 'draw_time']);
if ($head !== null) {
$this->info("Hall pipeline head is now: {$head->draw_no} ({$head->status}) @ {$head->draw_time}");
} else {
$this->info('Hall pipeline head: none (all settled/cancelled).');
}
return self::SUCCESS;
}
}