@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
{{ $num }}
{{ $nome }}
🔒
@endif @endforeach
{{-- Painel de tempo de processamento --}} @php $algumaConcluida = collect($todasEtapas)->where('status','concluida')->count() > 0; @endphp @if($algumaConcluida)

⏱️ Tempo de Processamento por Etapa

@foreach($todasEtapas as $et) @if($et->status === 'concluida') @endif @endforeach
Etapa Nome Executada em Tempo Gasto Processados
{{ $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) }}
⏱️ 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