- 更新多个控制器和服务,使用 LotterySettings 服务获取彩票相关配置,如默认币种、开奖间隔、下注窗口等,提升代码一致性与可维护性。 - 移除 .env.example 中不再使用的配置项,建议通过后台管理进行设置。
98 lines
3.0 KiB
PHP
98 lines
3.0 KiB
PHP
<?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;
|
||
}
|
||
}
|