@extends('layouts.app')
@section('title', 'Dashboard')
@section('content')
Dashboard
@if($contest)
{{ $contest->name }} |
{{ \Carbon\Carbon::parse($contest->start_date)->format('d/m/Y H:i') }} –
{{ \Carbon\Carbon::parse($contest->end_date)->format('d/m/Y H:i') }} UTC
@if($contest->limit_log)
| Prazo de LOG: {{ \Carbon\Carbon::parse($contest->limit_log)->format('d/m/Y') }}
@endif
@else
⚠️ Nenhum contest ativo encontrado na tabela contest_date (flag = 1).
As etapas de processamento estão desabilitadas até que um contest seja ativado.
@endif
{{-- Cards de métricas --}}
{{ number_format($stats['total_logs']) }}
LOGs Recebidos
Etapa A
{{ number_format($stats['total_result']) }}
QSOs em Result
Etapa 1
@if($stats['total_validos'] !== null)
{{ number_format($stats['total_validos']) }}
QSOs Válidos
Etapa 2
{{ number_format($stats['total_invalidos']) }}
QSOs Inválidos
Etapa 2
@endif
@if($stats['total_validos_tempo'] !== null)
{{ number_format($stats['total_validos_tempo']) }}
Válidos (tempo)
Etapa 3
@endif
@if($stats['total_confirmados'] !== null)
{{ number_format($stats['total_confirmados']) }}
QSOs Confirmados
Etapa 5
@endif
{{-- Grid de etapas --}}
Etapas de Processamento
@php
$etapasDef = [
['A', 'Importar LOGs', 'processamento.importar', null],
['1', 'Juntar LOGs', 'processamento.juntar', 'A'],
['2', 'Validar QSOs', 'processamento.validar-qsos', '1'],
['3', 'Validar Tempo', 'processamento.validar-tempo', '2'],
['4', 'Claimed Score', 'processamento.claimed-score', '3'],
['5', 'Val. Contatos', 'processamento.validar-contatos', '4'],
['6', 'Sem LOGs/DUPs', 'processamento.sem-logs', '5'],
['7', 'Pontos+Multi+FS', 'processamento.pontuar', '6'],
['8', 'Final Score', 'processamento.final-score', '7'],
['9', 'Resultado', 'processamento.resultado', '8'],
['10', 'Records', 'processamento.records', '9'],
['11', 'Encerrar Contest','processamento.encerrar.index', '10'],
];
$tooltips = [
'A' => 'Lê os arquivos Cabrillo (.log) e importa para logs_cabecalhos e logs_qsos. Ponto de partida do processamento.',
'1' => 'Consolida todos os QSOs de logs_qsos na tabela qsos_result, enriquecendo com dados do cabeçalho e convertendo frequência em banda.',
'2' => 'Valida cada QSO: contest, período, exchanges, categoria e estações HQ. Preenche valid_qso.',
'3' => 'Verifica limites de tempo de operação por categoria (SINGLE-OP 36h, YL/YOUTH 24h) e trocas de banda para MULTI-OP (máx. 10/hora).',
'4' => 'Calcula e atualiza o Claimed Score e Raw Score de cada participante.',
'5' => 'Cruzamento bilateral dos logs — confirma QSOs encontrados em ambos os lados. Preenche o campo confirmado.',
'6' => 'Lista indicativos sem LOG enviado, revalida contatos e detecta duplicidades.',
'7' => 'Calcula pontos por QSO (1-6pts conforme banda/DXCC/continente), multiplicadores (UF + DXCC + HQ por banda) e Final Score individual (pontos × multiplicadores).',
'8' => 'Calcula o Final Score de cada participante: pontos × multiplicadores. Gera ranking por categoria com percentual de redução em relação ao Claimed Score informado.',
'9' => 'Gera o Resultado Final consolidado por categoria, com ranking completo e percentual de redução. Popula a tabela resultados_final.',
'10' => 'Identifica e registra novos recordes por categoria, comparando Final Score atual com o record anterior. Atualiza a tabela records.',
'11' => 'Encerra a apuração: faz backup dos dados, move records atuais para anteriores, limpa tabelas de processamento e prepara o sistema para o próximo contest.',
];
@endphp
@foreach($etapasDef as [$num, $nome, $rota, $dep])
@php
$status = $etapas[$num] ?? 'pendente';
$depOk = $dep === null || ($etapas[$dep] ?? 'pendente') === 'concluida';
$habilitada= $contest && $depOk;
$tooltip = $tooltips[$num] ?? '';
// Se dependência não ok, sobrescreve tooltip
if (!$depOk) {
$depNome = collect($etapasDef)->firstWhere(0, $dep)[1] ?? "Etapa {$dep}";
$tooltip = "⛔ Execute primeiro: Etapa {$dep} — {$depNome}";
}
if (!$contest) {
$tooltip = "⚠️ Nenhum contest ativo. Ative um contest na tabela contest_date (flag = 1).";
}
@endphp
@if($habilitada)
{{ $num }}
{{ $nome }}
{{ $status === 'concluida' ? '✅' : ($status === 'executando' ? '⏳' : ($status === 'erro' ? '❌' : '')) }}
@else
@endif
@endforeach
{{-- Painel de tempo de processamento --}}
@php
$algumaConcluida = collect($todasEtapas)->where('status','concluida')->count() > 0;
@endphp
@if($algumaConcluida)
⏱️ Tempo de Processamento por Etapa
| Etapa |
Nome |
Executada em |
Tempo Gasto |
Processados |
@foreach($todasEtapas as $et)
@if($et->status === 'concluida')
| {{ $et->etapa }} |
{{ $et->nome }} |
{{ $et->executada_em?->format('d/m/Y H:i:s') ?? '—' }}
|
@if($et->tempo_gasto)
{{ $et->tempo_gasto }}
@else
não disponível
@endif
|
{{ number_format($et->total_processados) }} |
@endif
@endforeach
|
⏱️ Tempo Total de Apuração:
@if($totalSegundos == 0)
(execute as etapas para registrar)
@endif
|
@php
$etapasConcluidas = collect($todasEtapas)->where('status','concluida');
$tempoTextos = $etapasConcluidas->pluck('tempo_gasto')->filter()->values();
// Soma os segundos_gastos; se for 0 (restaurado), soma minutos do texto
$totalSeg = (int) $etapasConcluidas->sum('segundos_gastos');
if ($totalSeg > 0) {
$h = intdiv($totalSeg, 3600);
$m = intdiv($totalSeg % 3600, 60);
$s = $totalSeg % 60;
echo $h > 0 ? "{$h}h {$m}min {$s}s" : ($m > 0 ? "{$m}min {$s}s" : "{$s}s");
} else {
echo '—';
}
@endphp
|
|
@endif
{{-- Botão de reset --}}
↺ Resetar Processamento
Volta todas as etapas para pendente e zera os contadores de tempo.
Os dados do banco não são apagados.
{{-- Tooltip overlay --}}
@endsection