Romaneio: lista de veículos visível, busca com contador e logo escolhível

Traz para a tela as funções do programa original (Romaneiro PDF), na linha de
design do projeto:
- Veículos deixam de ser um <select> e viram lista visível com a contagem de
  paradas de cada carro — que é a conferência feita antes de imprimir e ficava
  invisível mostrando um veículo por vez. Cada item é link (?veiculo=), então
  sobrevive ao 'voltar' e ao F5. No celular vira faixa horizontal.
- Na mesma coluna: motorista do veículo, 'PDF deste veículo' e 'PDF de TODOS'.
- Busca ganha 'Limpar busca' e contador vivo ('4 de 31 paradas'). A contagem
  saiu do cabeçalho da tabela: dois números para a mesma coisa, um atualizando e
  o outro não, é a divergência que a diretriz 1 proíbe.
- Logo do cabeçalho escolhível (Configuracao 'romaneio_logo', separado do
  empresa_logo — o romaneio é documento do cliente). PNG/JPG até 2MB, gravado em
  storage/logos/ e não em public/, com nome gerado pelo sistema.
This commit is contained in:
2026-08-27 19:20:49 -03:00
parent 7fa2336b35
commit b3464e3acd
11 changed files with 274 additions and 65 deletions

View File

@@ -1,55 +1,42 @@
<%# Seletor de veículo + os dois campos de cabeçalho da folha. %>
<%# Zona "Filtros" — busca e o rótulo do cabeçalho do PDF.
O seletor de veículo saiu daqui para o _veiculos.html.erb, que mostra a lista
inteira; aqui fica só o que age sobre a FOLHA em edição. %>
<div class="bg-[#111] border border-white/5 rounded-2xl p-4 space-y-4">
<div>
<label class="block text-sm font-medium text-gray-300 mb-1.5">Veículo</label>
<div class="flex gap-2">
<%# ao lado do select: com 72 veículos, uma lista lateral vira armadilha
de scroll, mas percorrer o plano carro a carro é o que o operador faz. %>
<button type="button" data-action="romaneio#anterior" aria-label="Veículo anterior"
class="px-3 min-w-[48px] min-h-[48px] bg-[#1a1a1a] border border-white/10 rounded-xl
text-white hover:bg-[#242424]"></button>
<select data-romaneio-target="veiculo" data-action="romaneio#trocarVeiculo"
class="flex-1 bg-[#1a1a1a] border border-white/10 rounded-xl px-3 py-3 text-white
focus:outline-none focus:border-orange-500 min-h-[48px]">
<% @veiculos.each do |v| %>
<option value="<%= v.veiculo %>" <%= 'selected' if v.veiculo == @veiculo %>>
<%= v.veiculo %> (<%= @romaneio.contagem_por_veiculo[v.veiculo].to_i %>)
</option>
<% end %>
</select>
<button type="button" data-action="romaneio#proximo" aria-label="Próximo veículo"
class="px-3 min-w-[48px] min-h-[48px] bg-[#1a1a1a] border border-white/10 rounded-xl
text-white hover:bg-[#242424]"></button>
<div class="grid grid-cols-1 sm:grid-cols-[minmax(0,1fr)_minmax(0,280px)] gap-3">
<div>
<label class="block text-sm font-medium text-gray-300 mb-1.5">Buscar nesta folha</label>
<div class="flex gap-2">
<input type="search" placeholder="NF, nome ou bairro/rua…"
data-romaneio-target="busca" data-action="input->romaneio#filtrar"
class="flex-1 bg-[#1a1a1a] border border-white/10 rounded-xl px-3 py-3 text-white
placeholder-gray-600 focus:outline-none focus:border-orange-500 min-h-[48px]">
<%# Rótulo que descreve o que o controle faz (diretriz 2): limpa a BUSCA,
não o romaneio. %>
<button type="button" data-action="romaneio#limparBusca"
class="px-4 min-h-[48px] bg-[#1a1a1a] border border-white/10 rounded-xl
text-gray-300 hover:text-white hover:bg-[#242424] whitespace-nowrap">
Limpar busca
</button>
</div>
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
<div>
<label class="block text-sm font-medium text-gray-300 mb-1.5">
PLANO <span class="text-gray-500 font-normal">— texto do canto direito do PDF</span>
PLANO <span class="text-gray-500 font-normal">— canto direito do PDF</span>
</label>
<input type="text" value="<%= @romaneio.rotulo_plano %>"
data-romaneio-target="rotulo" data-action="change->romaneio#salvarRotulo"
class="w-full bg-[#1a1a1a] border border-white/10 rounded-xl px-3 py-3 text-white
focus:outline-none focus:border-orange-500 min-h-[48px]">
</div>
<div>
<label class="block text-sm font-medium text-gray-300 mb-1.5">
Motorista <span class="text-gray-500 font-normal">— só na tela, não sai impresso</span>
</label>
<% atual = @veiculos.find { |v| v.veiculo == @veiculo } %>
<input type="text" value="<%= atual&.motorista %>" placeholder="Quem leva este carro"
data-romaneio-target="motorista" data-action="change->romaneio#salvarMotorista"
class="w-full bg-[#1a1a1a] border border-white/10 rounded-xl px-3 py-3 text-white
placeholder-gray-600 focus:outline-none focus:border-orange-500 min-h-[48px]">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-300 mb-1.5">Buscar nesta folha</label>
<input type="search" placeholder="NF, nome ou endereço…"
data-action="input->romaneio#filtrar"
class="w-full bg-[#1a1a1a] border border-white/10 rounded-xl px-3 py-3 text-white
placeholder-gray-600 focus:outline-none focus:border-orange-500 min-h-[48px]">
</div>
<%# Contador: no programa original ele fica no rodapé da tabela ("0 registros")
e é como se percebe que a busca escondeu tudo — sem ele, a tabela vazia
parece plano vazio. %>
<%# Sem um segundo alvo "status" aqui: ele já existe no _tabela.html.erb
("Alterações salvam sozinhas") e o Stimulus devolveria só o primeiro. %>
<p class="text-xs text-gray-500" data-romaneio-target="contador">
<%= @linhas.size %> <%= @linhas.size == 1 ? 'parada' : 'paradas' %> nesta folha
</p>
</div>