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:
@@ -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>
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
traz HTML junto. %>
|
||||
<div class="bg-[#111] border border-white/5 rounded-2xl overflow-hidden">
|
||||
<div class="px-4 py-3 border-b border-white/5 flex items-center justify-between">
|
||||
<h2 class="text-white font-semibold text-sm"><%= linhas.size %> paradas</h2>
|
||||
<%# Sem repetir a contagem aqui: ela agora é VIVA no bloco de filtros (muda
|
||||
conforme a busca esconde linhas). Dois números para a mesma coisa, um
|
||||
atualizando e outro não, é a divergência que a diretriz 1 proíbe. %>
|
||||
<h2 class="text-white font-semibold text-sm">Paradas de <%= @veiculo %></h2>
|
||||
<span class="text-xs text-gray-500" data-romaneio-target="status">Alterações salvam sozinhas</span>
|
||||
</div>
|
||||
|
||||
|
||||
78
app/views/admin/romaneios/_veiculos.html.erb
Normal file
78
app/views/admin/romaneios/_veiculos.html.erb
Normal file
@@ -0,0 +1,78 @@
|
||||
<%# Coluna "Veículos" — a lista INTEIRA visível, como no programa original.
|
||||
Antes era um <select> com ‹ ›: resolvia o scroll de 72 carros, mas o operador
|
||||
não conseguia VER o plano — via um carro por vez e perdia a noção de quantas
|
||||
paradas cada um tem, que é justamente a conferência que ele faz antes de
|
||||
mandar imprimir.
|
||||
|
||||
Adapta ao dispositivo (diretriz 3): no celular vira faixa horizontal, porque
|
||||
72 itens empilhados empurrariam a tabela para fora da primeira tela; no
|
||||
desktop é coluna com rolagem própria, do lado da tabela. %>
|
||||
<div class="bg-[#111] border border-white/5 rounded-2xl p-4 space-y-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-white font-semibold text-sm">Veículos</h2>
|
||||
<span class="text-xs text-gray-500"><%= @veiculos.size %> no plano</span>
|
||||
</div>
|
||||
|
||||
<div class="flex lg:flex-col gap-2 overflow-x-auto lg:overflow-x-visible
|
||||
lg:overflow-y-auto lg:max-h-[46vh] pb-1 lg:pb-0
|
||||
lg:pr-1 [scrollbar-width:thin]">
|
||||
<% @veiculos.each do |v| %>
|
||||
<% atual = v.veiculo == @veiculo %>
|
||||
<%# Link de verdade (não botão com JS): o veículo vive na query string, então
|
||||
ele é endereçável, volta com o "voltar" do navegador e sobrevive a um F5. %>
|
||||
<a href="<%= admin_romaneio_path(@romaneio, veiculo: v.veiculo) %>"
|
||||
data-romaneio-target="itemVeiculo" data-veiculo="<%= v.veiculo %>"
|
||||
<%= 'data-atual="1"'.html_safe if atual %>
|
||||
class="shrink-0 lg:shrink flex items-center justify-between gap-3 min-h-[48px]
|
||||
px-3 rounded-xl border transition-colors
|
||||
<%= atual ? 'bg-[#f97316] border-orange-400 text-white font-semibold'
|
||||
: 'bg-[#1a1a1a] border-white/10 text-gray-300 hover:border-orange-500 hover:text-white' %>">
|
||||
<span class="whitespace-nowrap"><%= v.veiculo %></span>
|
||||
<%# A contagem é o que o operador confere: carro sem parada ou com parada
|
||||
demais é erro de plano, e some quando só um veículo aparece por vez. %>
|
||||
<span class="text-xs px-2 py-0.5 rounded-lg
|
||||
<%= atual ? 'bg-black/25' : 'bg-white/5 text-gray-400' %>">
|
||||
<%= @romaneio.contagem_por_veiculo[v.veiculo].to_i %>
|
||||
</span>
|
||||
</a>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<button type="button" data-action="romaneio#anterior" aria-label="Veículo anterior"
|
||||
class="flex-1 min-h-[48px] bg-[#1a1a1a] border border-white/10 rounded-xl
|
||||
text-white hover:bg-[#242424]">‹</button>
|
||||
<button type="button" data-action="romaneio#proximo" aria-label="Próximo veículo"
|
||||
class="flex-1 min-h-[48px] bg-[#1a1a1a] border border-white/10 rounded-xl
|
||||
text-white hover:bg-[#242424]">›</button>
|
||||
</div>
|
||||
|
||||
<div class="pt-1 border-t border-white/5">
|
||||
<label class="block text-sm font-medium text-gray-300 mb-1.5 mt-3">
|
||||
Motorista deste veículo
|
||||
<span class="text-gray-500 font-normal">— só na tela</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]">
|
||||
<p class="text-xs text-gray-500 mt-1.5">
|
||||
Não sai impresso — a linha do rodapé é assinada à mão na retirada.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2 pt-1">
|
||||
<%= link_to pdf_admin_romaneio_path(@romaneio, veiculo: @veiculo),
|
||||
target: '_blank', rel: 'noopener',
|
||||
class: 'w-full min-h-[48px] flex items-center justify-center gap-2 bg-[#1a1a1a]
|
||||
hover:bg-[#242424] text-white border border-white/10 rounded-xl' do %>
|
||||
<%= icone :visualizar, cor: nil %> PDF deste veículo
|
||||
<% end %>
|
||||
<%= link_to pdf_admin_romaneio_path(@romaneio),
|
||||
class: 'w-full min-h-[48px] flex items-center justify-center gap-2 bg-[#f97316]
|
||||
hover:bg-orange-500 text-white font-semibold rounded-xl' do %>
|
||||
<%= icone :baixar, cor: nil %> PDF de TODOS os veículos
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -20,6 +20,37 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<%# Logo do cabeçalho — zona "Arquivos" do programa original.
|
||||
Fica ANTES da importação porque é configuração que vale para todos os
|
||||
romaneios, não escolha por plano: quem troca de contratante troca uma vez. %>
|
||||
<div class="bg-[#111] border border-white/5 rounded-2xl p-5">
|
||||
<%= form_with url: atualizar_logo_admin_romaneios_path, method: :post, multipart: true,
|
||||
data: { turbo: false },
|
||||
class: 'flex flex-col sm:flex-row sm:items-end gap-3' do %>
|
||||
<div class="flex-1">
|
||||
<label class="block text-sm font-medium text-gray-300 mb-1.5">
|
||||
Logo do romaneio
|
||||
<span class="text-gray-500 font-normal">— canto esquerdo da folha</span>
|
||||
</label>
|
||||
<p class="text-sm text-gray-400 mb-2">
|
||||
Em uso:
|
||||
<strong class="text-white"><%= @logo_atual.presence || 'logo-gade.png (padrão)' %></strong>
|
||||
</p>
|
||||
<input type="file" name="logo" accept="image/png,image/jpeg"
|
||||
class="w-full text-sm text-gray-300 file:mr-3 file:py-2.5 file:px-4 file:rounded-lg
|
||||
file:border-0 file:bg-[#1a1a1a] file:text-gray-200 file:cursor-pointer">
|
||||
<p class="text-xs text-gray-500 mt-2">
|
||||
PNG ou JPG, até 2 MB — é o que o PDF consegue embutir. Vale para os próximos PDFs gerados.
|
||||
</p>
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="px-5 py-3 bg-[#1a1a1a] hover:bg-[#242424] text-white border border-white/10
|
||||
rounded-xl min-h-[48px] whitespace-nowrap">
|
||||
Trocar logo
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%# Importação %>
|
||||
<div class="bg-[#111] border border-white/5 rounded-2xl p-5 space-y-4">
|
||||
<h2 class="text-white font-semibold">Importar plano</h2>
|
||||
|
||||
@@ -51,8 +51,16 @@
|
||||
<% else %>
|
||||
<%= render 'avisos' %>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_minmax(0,560px)] gap-5 items-start">
|
||||
<div class="space-y-4">
|
||||
<%# Três zonas, como no programa que a operação já usava: VEÍCULOS à esquerda,
|
||||
edição no meio, PDF de verdade à direita. Em telas médias a prévia desce
|
||||
para baixo (duas colunas); no celular vira uma coluna só. %>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-[minmax(0,260px)_minmax(0,1fr)]
|
||||
xl:grid-cols-[minmax(0,260px)_minmax(0,1fr)_minmax(0,520px)] gap-5 items-start">
|
||||
<div class="lg:sticky lg:top-4">
|
||||
<%= render 'veiculos' %>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4 lg:col-span-1">
|
||||
<%= render 'controles' %>
|
||||
<%= render 'tabela', linhas: @linhas %>
|
||||
<%= render 'removidas', linhas: @removidas %>
|
||||
@@ -60,8 +68,8 @@
|
||||
|
||||
<%# Prévia — no celular vira um bloco recolhido: 6 colunas em tela pequena
|
||||
exigiriam zoom, e o que importa ali é editar, não conferir o layout. %>
|
||||
<div class="lg:sticky lg:top-4">
|
||||
<details class="lg:hidden bg-[#111] border border-white/5 rounded-2xl p-4 mb-4">
|
||||
<div class="lg:col-span-2 xl:col-span-1 xl:sticky xl:top-4">
|
||||
<details class="xl:hidden bg-[#111] border border-white/5 rounded-2xl p-4 mb-4">
|
||||
<summary class="cursor-pointer text-white font-medium select-none min-h-[44px] flex items-center">
|
||||
<%= icone :visualizar %> Ver prévia do PDF
|
||||
</summary>
|
||||
@@ -70,7 +78,7 @@
|
||||
class: 'block mt-3 text-orange-400 hover:text-orange-300', target: '_blank', rel: 'noopener' %>
|
||||
</details>
|
||||
|
||||
<div class="hidden lg:block bg-[#111] border border-white/5 rounded-2xl p-4">
|
||||
<div class="hidden xl:block bg-[#111] border border-white/5 rounded-2xl p-4">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<h2 class="text-white font-semibold text-sm">Prévia — <%= @veiculo %></h2>
|
||||
<button type="button" data-action="romaneio#atualizarPreview"
|
||||
|
||||
Reference in New Issue
Block a user