Atualização dos icones para um modelo chapado

This commit is contained in:
2026-07-20 15:08:09 -03:00
parent 7d3753f9c5
commit 42d06c50a7
34 changed files with 550 additions and 337 deletions

View File

@@ -52,9 +52,9 @@
<h1 class="text-2xl font-bold text-white">Dashboard de Operações</h1>
<p class="text-gray-400 text-sm mt-0.5">
<% if @modo == 'global' %>
🌐 Global · <%= @periodo_inicio.strftime('%d/%m/%Y') %> <%= @periodo_fim.strftime('%d/%m/%Y') %>
<%= icone :global %> Global · <%= @periodo_inicio.strftime('%d/%m/%Y') %> <%= @periodo_fim.strftime('%d/%m/%Y') %>
<% elsif @modo == 'comparar' %>
⚖️ Comparação entre operações (cada uma no seu próprio período)
<%= icone :comparar %> Comparação entre operações (cada uma no seu próprio período)
<% elsif @metricas&.data_inicio %>
<%= @metricas.operacoes_label %> · <%= @metricas.data_inicio.strftime('%d/%m/%Y') %> <%= @metricas.data_fim.strftime('%d/%m/%Y') %>
<% elsif @operacao %>
@@ -69,7 +69,7 @@
<% if @modo == 'global' %>
<div class="flex flex-wrap items-center gap-2">
<div class="relative">
<span class="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-orange-500">📅</span>
<span class="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2"><%= icone :calendario %></span>
<input type="text" id="periodo-range" readonly placeholder="Selecione o período"
value="<%= @periodo_inicio.strftime('%d/%m/%Y') %> até <%= @periodo_fim.strftime('%d/%m/%Y') %>"
class="cursor-pointer pl-4 pr-10 py-2.5 bg-[#1a1a1a] border border-white/10 rounded-xl
@@ -89,12 +89,12 @@
</div>
<%# ── Abas de modo + atalho para a planilha ─────────────── %>
<% modos = { 'operacao' => '🏥 Operação', 'global' => '🌐 Global', 'comparar' => '⚖️ Comparar' } %>
<% modos = { 'operacao' => [:operacao, 'Operação'], 'global' => [:global, 'Global'], 'comparar' => [:comparar, 'Comparar'] } %>
<div class="flex flex-wrap items-center justify-between gap-2 border-b border-white/5 pb-3">
<div class="flex flex-wrap items-center gap-2">
<% modos.each do |m, label| %>
<% modos.each do |m, (ic, label)| %>
<% ativo = @modo == m %>
<%= link_to label,
<%= link_to rotulo(ic, label, cor: (ativo ? nil : 'text-brand-laranja')),
operacoes_dashboard_path(ctx_ops.merge(modo: m, inicio: ini_iso, fim: fim_iso)),
data: { turbo: false },
class: "px-4 py-2 rounded-xl text-sm font-semibold whitespace-nowrap #{ativo ? 'bg-orange-500 text-black' : 'bg-[#1a1a1a] text-gray-300 border border-white/10 hover:border-orange-500'}" %>
@@ -106,7 +106,7 @@
.slice('f_driver', 'f_sts', 'f_status', 'f_obs', 'f_resultado', 'f_data')
.merge(modo: (@modo == 'global' ? 'global' : 'operacao'), inicio: ini_iso, fim: fim_iso) %>
<% planilha_ctx[:operacao] = @operacao if @operacao %>
<%= link_to '📋 Planilha da operação', operacoes_planilha_path(planilha_ctx),
<%= link_to rotulo(:planilha, 'Planilha da operação', cor: nil), operacoes_planilha_path(planilha_ctx),
data: { turbo: false },
class: 'px-4 py-2 rounded-xl text-sm font-semibold whitespace-nowrap bg-[#1a1a1a]
text-orange-400 border border-orange-500/40 hover:bg-orange-500 hover:text-black' %>
@@ -125,7 +125,7 @@
<% @chips.each do |chip| %>
<span class="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-orange-500/15 border border-orange-500/30 text-orange-300 text-xs">
<%= chip[:rotulo] %>: <strong class="text-white"><%= chip[:display] || chip[:valor] %></strong>
<%= link_to '✕', operacoes_dashboard_path(request.query_parameters.except(chip[:param])),
<%= link_to icone(:fechar, cor: nil, tamanho: 'w-3 h-3'), operacoes_dashboard_path(request.query_parameters.except(chip[:param])),
data: { turbo: false }, class: 'hover:text-white font-bold', title: 'Remover filtro' %>
</span>
<% end %>
@@ -160,7 +160,7 @@
<% elsif @modo == 'global' %>
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-4 text-sm text-gray-300">
🌐 Visão <strong class="text-white">Global</strong> — todas as
<%= icone :global %> Visão <strong class="text-white">Global</strong> — todas as
<%= @tabelas_validas.size %> operações agregadas no período.
</div>
<% if @metricas %>
@@ -208,7 +208,7 @@
<%# Detalhe completo de cada operação (recolhível) %>
<details class="bg-[#1a1a1a] rounded-2xl border border-white/5">
<summary class="cursor-pointer px-6 py-4 text-sm text-gray-300 hover:text-white select-none">
🔎 Ver detalhe completo de cada operação
<%= icone :buscar %> Ver detalhe completo de cada operação
</summary>
<div class="grid grid-cols-1 xl:grid-cols-2 gap-6 p-4 pt-0">
<div>
@@ -442,6 +442,12 @@
});
}
// Ícone do sprite (public/icons.svg) — mesmos SVG usados no resto do sistema.
function ico(id, cor) {
return '<svg width="12" height="12" fill="' + (cor || '#f97316') + '" style="vertical-align:-1px">' +
'<use href="/icons.svg#' + id + '"></use></svg>';
}
function popupHtml(p) {
const linha = (icone, val) => val ? ('<div>' + icone + ' ' + escapeHtml(val) + '</div>') : '';
const foto = p.foto
@@ -449,22 +455,22 @@
'<img src="' + escapeHtml(p.foto) + '" alt="Fachada" loading="lazy" ' +
'onerror="this.style.display=\'none\';this.parentNode.nextElementSibling.style.display=\'block\'" ' +
'style="margin-top:8px;width:100%;max-height:160px;object-fit:cover;border-radius:6px;display:block"></a>' +
'<div style="display:none;margin-top:6px;color:#9ca3af;font-size:11px">📷 Foto indisponível (link expirado/sem acesso)</div>'
: '<div style="margin-top:6px;color:#6b7280;font-size:11px">📷 Sem foto da fachada para esta entrega</div>';
'<div style="display:none;margin-top:6px;color:#9ca3af;font-size:11px">' + ico('camera-fill', '#9ca3af') + ' Foto indisponível (link expirado/sem acesso)</div>'
: '<div style="margin-top:6px;color:#6b7280;font-size:11px">' + ico('camera-fill', '#6b7280') + ' Sem foto da fachada para esta entrega</div>';
const statusLinha = p.sucesso
? '<div style="color:#16a34a;font-size:11px;margin-bottom:6px"> Entrega realizada</div>'
: '<div style="color:#3b82f6;font-size:11px;margin-bottom:6px"> Insucesso' +
? '<div style="color:#16a34a;font-size:11px;margin-bottom:6px">' + ico('check-lg', '#16a34a') + ' Entrega realizada</div>'
: '<div style="color:#3b82f6;font-size:11px;margin-bottom:6px">' + ico('x-lg', '#3b82f6') + ' Insucesso' +
(p.motivo ? ' — ' + escapeHtml(p.motivo) : '') + '</div>';
return '' +
'<div style="min-width:210px;max-width:240px">' +
'<div style="font-weight:700;color:#f97316">NF ' + escapeHtml(p.nf) + '</div>' +
'<div style="font-weight:600;margin-bottom:4px">' + escapeHtml(p.nome) + '</div>' +
statusLinha +
linha('📍', p.endereco) +
linha('🏥', p.unidade) +
linha('🚚', p.motorista) +
linha('🚗', p.veiculo) +
linha('🕒', p.checkout) +
linha(ico('geo-alt-fill'), p.endereco) +
linha(ico('hospital-fill'), p.unidade) +
linha(ico('truck'), p.motorista) +
linha(ico('car-front-fill'), p.veiculo) +
linha(ico('clock-fill'), p.checkout) +
foto +
'</div>';
}
@@ -513,7 +519,9 @@
const mapa = L.map(el, { layers: [escuro] }).setView(centro, 11);
L.control.layers(
{ '🌙 Escuro': escuro, '🗺️ Claro': claro, '🛰️ Satélite': satelite },
{ [ico('moon-fill') + ' Escuro']: escuro,
[ico('map-fill') + ' Claro']: claro,
[ico('broadcast-pin') + ' Satélite']: satelite },
{}, { position: 'topright', collapsed: true }
).addTo(mapa);