Files
Reem-Notas/app/views/operacoes_dashboard/_painel.html.erb
2026-07-03 15:18:51 -03:00

141 lines
7.8 KiB
Plaintext
Raw Permalink 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.
<%# locals: metricas (Analytics::OperacaoMetricas), titulo (opcional),
filtravel (opcional, default false) — torna as tabelas clicáveis p/ cross-filter %>
<% titulo = local_assigns[:titulo] %>
<% filtravel = local_assigns.fetch(:filtravel, false) %>
<% ins = metricas.insucessos_pct %>
<% pd = metricas.por_dia %>
<div class="space-y-4">
<% if titulo.present? %>
<div class="flex items-center justify-between">
<h2 class="text-lg font-bold text-white"><%= titulo %></h2>
<span class="text-xs text-gray-500">
<%= metricas.total %> entregas<% if metricas.data_inicio %> · <%= metricas.data_inicio.strftime('%d/%m/%Y') %><%= metricas.data_fim.strftime('%d/%m/%Y') %><% end %>
</span>
</div>
<% end %>
<%# ── Layout 2 colunas: cards empilhados (esquerda, estreito) + resto (direita) ── %>
<% pct_total = ->(parte) { metricas.total.zero? ? 0 : (parte * 100.0 / metricas.total).round(1) } %>
<div class="flex flex-col lg:flex-row gap-4">
<%# Coluna esquerda — 4 cards de status EMPILHADOS na vertical (orientação da img 13). %>
<div class="w-full lg:w-[21rem] lg:shrink-0 space-y-4">
<div class="group bg-[#1a1a1a] rounded-2xl border border-white/5 p-7 transition-all duration-200 hover:border-white/20 hover:bg-[#202020] hover:-translate-y-0.5 hover:shadow-lg hover:shadow-black/40">
<p class="text-gray-400 text-sm font-medium mb-1">Total de Entregas</p>
<p class="text-6xl font-black text-white leading-none inline-block origin-left transition-transform duration-200 group-hover:scale-110"><%= metricas.total %></p>
<p class="text-xs text-gray-500 mt-2 h-0 overflow-hidden opacity-0 transition-all duration-200 group-hover:h-4 group-hover:opacity-100">
✅ <%= metricas.sucesso %> · <span class="text-blue-500">●</span> <%= metricas.recusas %> · ⏳ <%= metricas.pendentes %>
</p>
</div>
<div class="group bg-[#1a1a1a] rounded-2xl border border-white/5 p-7 transition-all duration-200 hover:border-green-500/40 hover:bg-[#202020] hover:-translate-y-0.5 hover:shadow-lg hover:shadow-black/40">
<p class="text-gray-400 text-sm font-medium mb-1">Total de Sucesso</p>
<p class="text-6xl font-black text-green-400 leading-none inline-block origin-left transition-transform duration-200 group-hover:scale-110"><%= metricas.sucesso %></p>
<p class="text-xs text-gray-500 mt-2 h-0 overflow-hidden opacity-0 transition-all duration-200 group-hover:h-4 group-hover:opacity-100">
<%= pct_total.(metricas.sucesso) %>% do total
</p>
</div>
<div class="group bg-[#1a1a1a] rounded-2xl border border-white/5 p-7 transition-all duration-200 hover:border-blue-500/40 hover:bg-[#202020] hover:-translate-y-0.5 hover:shadow-lg hover:shadow-black/40">
<p class="text-gray-400 text-sm font-medium mb-1">Total de Recusas</p>
<p class="text-6xl font-black text-blue-500 leading-none inline-block origin-left transition-transform duration-200 group-hover:scale-110"><%= metricas.recusas %></p>
<p class="text-xs text-gray-500 mt-2 h-0 overflow-hidden opacity-0 transition-all duration-200 group-hover:h-4 group-hover:opacity-100">
<%= pct_total.(metricas.recusas) %>% do total
</p>
</div>
<div class="group bg-[#1a1a1a] rounded-2xl border border-white/5 p-7 transition-all duration-200 hover:border-yellow-500/40 hover:bg-[#202020] hover:-translate-y-0.5 hover:shadow-lg hover:shadow-black/40">
<p class="text-gray-400 text-sm font-medium mb-1">Entregas Pendentes</p>
<p class="text-6xl font-black text-yellow-400 leading-none inline-block origin-left transition-transform duration-200 group-hover:scale-110"><%= metricas.pendentes %></p>
<p class="text-xs text-gray-500 mt-2 h-0 overflow-hidden opacity-0 transition-all duration-200 group-hover:h-4 group-hover:opacity-100">
<%= pct_total.(metricas.pendentes) %>% do total
</p>
</div>
</div>
<%# Coluna direita — gráficos/tabelas ocupam o espaço ao lado dos cards. %>
<div class="flex-1 min-w-0 space-y-4">
<%# ── Insucessos % + Índices de falha + Status ─────────── %>
<div class="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4">
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-6">
<p class="text-gray-400 text-sm font-medium mb-4">Insucessos %</p>
<% if metricas.total.zero? %>
<p class="text-center py-8 text-gray-500 text-sm">Sem dados no período.</p>
<% else %>
<div class="relative h-56">
<canvas class="dash-donut"
data-completed="<%= ins[:completed] %>"
data-failed="<%= ins[:failed] %>"></canvas>
</div>
<div class="flex justify-center gap-4 mt-3 text-xs">
<span class="text-orange-400">● Completas <%= ins[:pct_completed] %>%</span>
<span class="text-blue-500">● Falhas <%= ins[:pct_failed] %>%</span>
</div>
<% end %>
</div>
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-6">
<p class="text-gray-400 text-sm font-medium mb-4">Índices de Falha</p>
<%= render 'tabela_simples',
cabecalhos: ['Observação', 'Total', '%'],
linhas: metricas.indices_falha.map { |h| [h[:observation], h[:total], "#{h[:pct]}%"] },
vazio: 'Nenhuma falha no período.',
filtro: (filtravel ? 'f_obs' : nil) %>
</div>
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-6">
<p class="text-gray-400 text-sm font-medium mb-4">Por Status</p>
<%= render 'tabela_simples',
cabecalhos: ['Status', 'Quantidade'],
linhas: metricas.por_status_gade.map { |h| [h[:status], h[:total]] },
vazio: 'Sem dados.',
total: metricas.total,
filtro: (filtravel ? 'f_status' : nil) %>
</div>
</div>
<%# ── Motoristas + STS ─────────────────────────────────── %>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-6">
<p class="text-gray-400 text-sm font-medium mb-4">Notas fiscais por Motorista</p>
<div class="max-h-80 overflow-y-auto pr-2">
<%= render 'tabela_simples',
cabecalhos: ['Motorista', 'Notas fiscais'],
linhas: metricas.por_motorista.map { |h| [h[:nome], h[:total]] },
vazio: 'Sem dados.',
total: metricas.total,
filtro: (filtravel ? 'f_driver' : nil) %>
</div>
</div>
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-6">
<p class="text-gray-400 text-sm font-medium mb-4">Entregas por STS (Unidade)</p>
<div class="max-h-80 overflow-y-auto pr-2">
<%= render 'tabela_simples',
cabecalhos: ['Unidade', 'NFs entregues'],
linhas: metricas.por_sts.map { |h| [h[:nome], h[:total]] },
vazio: 'Sem dados.',
total: metricas.sucesso,
filtro: (filtravel ? 'f_sts' : nil) %>
</div>
</div>
</div>
<%# ── Entregas por dia ─────────────────────────────────── %>
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-6">
<p class="text-gray-400 text-sm font-medium mb-4">Entregas por Dia</p>
<% if pd[:labels].empty? %>
<p class="text-center py-8 text-gray-500 text-sm">Sem dados no período.</p>
<% else %>
<div class="relative h-72">
<canvas class="dash-bars"
data-labels="<%= pd[:labels].to_json %>"
data-completed="<%= pd[:completed].to_json %>"
data-failed="<%= pd[:failed].to_json %>"></canvas>
</div>
<% end %>
</div>
</div><%# fim coluna direita %>
</div><%# fim layout 2 colunas %>
</div>