Files
lotteryLaravel/app/Console/Commands/LotteryPerfDrawScheduleAuditCommand.php
kang 8ccf39dff5 refactor: 迁移彩票设置至 LotterySettings 服务
- 更新多个控制器和服务,使用 LotterySettings 服务获取彩票相关配置,如默认币种、开奖间隔、下注窗口等,提升代码一致性与可维护性。
- 移除 .env.example 中不再使用的配置项,建议通过后台管理进行设置。
2026-05-28 14:50:25 +08:00

98 lines
3.0 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 Carbon\Carbon;
use Illuminate\Console\Command;
use App\Services\LotterySettings;
use App\Services\Draw\DrawPlannerService;
/**
* PRD §17.2:校验期号计划相邻开奖时刻间隔是否符合 interval_minutes默认 5 分钟)。
*/
final class LotteryPerfDrawScheduleAuditCommand extends Command
{
protected $signature = 'lottery:perf-draw-schedule-audit
{--samples=48 : 抽检相邻期数}
{--tolerance-seconds=60 : 允许偏差(秒)}';
protected $description = 'Audit draw_time spacing for schedule punctuality (§17.2)';
public function handle(DrawPlannerService $planner): int
{
$samples = max(2, (int) $this->option('samples'));
$tolerance = max(0, (int) $this->option('tolerance-seconds'));
$intervalMinutes = LotterySettings::drawIntervalMinutes();
$expectedSeconds = $intervalMinutes * 60;
$planner->ensureBuffer(Carbon::now('UTC'));
$nowUtc = Carbon::now('UTC');
$horizon = $nowUtc->copy()->addDays(14);
$businessDate = Draw::query()
->whereNotNull('draw_time')
->where('draw_time', '>', $nowUtc)
->where('draw_time', '<=', $horizon)
->where('business_date', '<', '2090-01-01')
->orderByDesc('business_date')
->value('business_date');
if ($businessDate === null) {
$this->error('No upcoming draws found.');
return self::FAILURE;
}
$times = Draw::query()
->where('business_date', $businessDate)
->whereNotNull('draw_time')
->orderBy('sequence_no')
->limit($samples + 1)
->pluck('draw_time')
->map(fn ($t) => Carbon::parse($t)->utc())
->values()
->all();
$this->line('business_date='.$businessDate);
if (count($times) < 2) {
$this->error('Not enough draws to audit.');
return self::FAILURE;
}
$violations = [];
for ($i = 1; $i < count($times); $i++) {
$delta = $times[$i]->diffInSeconds($times[$i - 1], absolute: true);
if (abs($delta - $expectedSeconds) > $tolerance) {
$violations[] = [
'pair' => ($i - 1).'→'.$i,
'delta_seconds' => $delta,
'expected_seconds' => $expectedSeconds,
];
}
}
$this->info(sprintf(
'interval_minutes=%d expected_gap=%ds tolerance=±%ds pairs_checked=%d',
$intervalMinutes,
$expectedSeconds,
$tolerance,
count($times) - 1,
));
if ($violations === []) {
$this->info('PASS — all checked gaps within tolerance.');
return self::SUCCESS;
}
$this->error('FAIL — spacing violations:');
$this->table(['pair', 'delta_seconds', 'expected_seconds'], $violations);
return self::FAILURE;
}
}