, Teste e correçoes
This commit is contained in:
@@ -32,6 +32,10 @@ class Admin::RomaneiosController < ApplicationController
|
|||||||
# Mesma lista da tela de criação: o vínculo manual da operação acontece aqui
|
# Mesma lista da tela de criação: o vínculo manual da operação acontece aqui
|
||||||
# também, porque é aqui que se descobre que APARELHO saiu vazio.
|
# também, porque é aqui que se descobre que APARELHO saiu vazio.
|
||||||
@operacoes_agrupadas = Operacao.agrupadas_por_mes
|
@operacoes_agrupadas = Operacao.agrupadas_por_mes
|
||||||
|
# A prévia aberta é ESTADO NA URL (?previa=1), não estado de navegador. Ver o
|
||||||
|
# comentário em _previa.html.erb: hash (#previa) não sobrevive ao Turbo e
|
||||||
|
# checkbox não sobrevive à troca de folha.
|
||||||
|
@previa = params[:previa].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Caminho A: busca o plano no SimpliRoute (API, com queda para o espelho).
|
# Caminho A: busca o plano no SimpliRoute (API, com queda para o espelho).
|
||||||
|
|||||||
@@ -131,13 +131,13 @@ export default class extends Controller {
|
|||||||
this.buscaTarget.focus()
|
this.buscaTarget.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Prévia (pop-up por :target, CSS puro) ───────────────────────────────
|
// ── Prévia (pop-up; estado na URL, ?previa=1) ───────────────────────────
|
||||||
// Abrir, fechar e trocar de folha são do NAVEGADOR: link para `#previa`,
|
// Abrir, fechar e trocar de folha são LINKS comuns — nada disso depende deste
|
||||||
// link para `#sem-previa` e links `?veiculo=X#previa`. Nada disso depende
|
// controller, e é o que mantém a prévia viva quando o JS não carrega. O
|
||||||
// deste controller — é o que mantém a prévia viva quando o JS não carrega.
|
// overlay só existe no DOM quando a prévia está aberta, então a presença do
|
||||||
// O que sobra aqui é recarregar a folha depois de uma edição.
|
// alvo já é a resposta. O que sobra aqui é recarregar a folha após uma edição.
|
||||||
previewAberta() {
|
previewAberta() {
|
||||||
return this.hasOverlayTarget && this.overlayTarget.matches(":target")
|
return this.hasOverlayTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
carregarPreview() {
|
carregarPreview() {
|
||||||
@@ -161,11 +161,6 @@ export default class extends Controller {
|
|||||||
this.carregarPreview()
|
this.carregarPreview()
|
||||||
}
|
}
|
||||||
|
|
||||||
// O operador pode abrir a prévia DEPOIS de editar: aí o iframe ainda mostra a
|
|
||||||
// folha antiga. Como quem abre é o `:target`, o gancho é o hashchange.
|
|
||||||
aoTrocarHash() {
|
|
||||||
if (this.previewAberta() && this.previewDesatualizado) this.carregarPreview()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Infra ───────────────────────────────────────────────────────────────
|
// ── Infra ───────────────────────────────────────────────────────────────
|
||||||
gravar(linhaId, campo, valor, input, botao, aoConcluir) {
|
gravar(linhaId, campo, valor, input, botao, aoConcluir) {
|
||||||
|
|||||||
@@ -1,40 +1,44 @@
|
|||||||
<%# Prévia do PDF em POP-UP, com navegação de veículo igual à do carrossel do
|
<%# Prévia do PDF em POP-UP, com navegação entre as folhas no mesmo desenho do
|
||||||
motorista (setas grandes + contador "3 de 72").
|
carrossel do motorista (setas grandes + contador "3 de 72").
|
||||||
|
|
||||||
── POR QUE É CSS PURO E NÃO JAVASCRIPT ────────────────────────────────────
|
── O ESTADO "ABERTA" MORA NA URL (?previa=1) ──────────────────────────────
|
||||||
Abrir/fechar sai do `:target`: o botão é um link para `#previa` e o pop-up só
|
Foram três tentativas até aqui, e cada uma quebrou de um jeito:
|
||||||
aparece quando ele é o alvo da URL. As setas são links de verdade para
|
|
||||||
`?veiculo=X#previa`, então trocar de folha mantém o pop-up aberto.
|
|
||||||
|
|
||||||
Isso não é preciosismo: a prévia é a ÚNICA conferência antes de imprimir e
|
1. modal por JavaScript → morreu junto com os assets 404 no servidor: o
|
||||||
já morreu três vezes junto com o JavaScript (assets 404 no servidor, com a
|
botão não fazia NADA e a tela abria normal, sem erro visível;
|
||||||
tela abrindo normal e o botão sem reação). Do jeito atual ela funciona com o
|
2. <details> nativo → funcionava, mas não é pop-up e não dava para
|
||||||
JS quebrado, sem JS, no celular, e continua endereçável — dá para mandar o
|
navegar entre as folhas sem fechar;
|
||||||
link já com a prévia aberta.
|
3. :target (#previa) → abria com o JS fora do ar e parava de abrir
|
||||||
|
quando ele voltava: o Turbo intercepta o clique, revisita a página e o
|
||||||
|
hash se perde no caminho. Pior dos mundos — funcionava no ambiente
|
||||||
|
quebrado e falhava no ambiente são.
|
||||||
|
|
||||||
`loading="lazy"` no iframe: fechado, o pop-up é `display:none` e o navegador
|
Com a prévia na query string nada disso se aplica: é uma página como outra
|
||||||
NÃO busca o PDF. É o que preserva a economia de não gerar um documento a cada
|
qualquer, o Turbo trata como navegação normal, funciona sem JavaScript,
|
||||||
carregamento da tela.
|
sobrevive ao F5 e ao "voltar", e o link pode ser enviado para outra pessoa
|
||||||
|
já com a folha aberta.
|
||||||
|
|
||||||
|
Fechado, este partial não renderiza NADA: o iframe nem existe, então o
|
||||||
|
servidor não monta um PDF que ninguém pediu (era o custo do desenho
|
||||||
|
original, que montava o iframe a cada carregamento da tela).
|
||||||
|
|
||||||
<iframe> e não <embed>/<object>: o CSP está enforcing com `object_src :none`
|
<iframe> e não <embed>/<object>: o CSP está enforcing com `object_src :none`
|
||||||
e sem `frame_src`, então cai em `default_src :self` — o iframe de mesma
|
e sem `frame_src`, então cai em `default_src :self` — o iframe de mesma
|
||||||
origem passa, os outros dois não.
|
origem passa, os outros dois não. %>
|
||||||
|
|
||||||
Fechar leva para `#sem-previa`, um id que não existe em lugar nenhum: o
|
|
||||||
`:target` deixa de casar e o pop-up some sem o salto ao topo que um `href="#"`
|
|
||||||
causaria. %>
|
|
||||||
<% nomes = @veiculos.map(&:veiculo) %>
|
<% nomes = @veiculos.map(&:veiculo) %>
|
||||||
<% posicao = nomes.index(@veiculo) %>
|
<% posicao = nomes.index(@veiculo) %>
|
||||||
<% anterior = posicao&.positive? ? nomes[posicao - 1] : nil %>
|
<% anterior = posicao&.positive? ? nomes[posicao - 1] : nil %>
|
||||||
<% proximo = posicao && posicao < nomes.size - 1 ? nomes[posicao + 1] : nil %>
|
<% proximo = posicao && posicao < nomes.size - 1 ? nomes[posicao + 1] : nil %>
|
||||||
|
<% fechar = admin_romaneio_path(@romaneio, veiculo: @veiculo) %>
|
||||||
|
|
||||||
<div id="previa" data-romaneio-target="overlay"
|
<div data-romaneio-target="overlay"
|
||||||
class="hidden target:flex fixed inset-0 z-50 items-center justify-center p-3 sm:p-6
|
class="fixed inset-0 z-50 flex items-center justify-center p-3 sm:p-6
|
||||||
bg-black/80 backdrop-blur-sm">
|
bg-black/80 backdrop-blur-sm">
|
||||||
|
|
||||||
<%# O fundo escuro fecha ao ser clicado — um link cobrindo a área, atrás da
|
<%# O fundo escuro fecha ao ser clicado — um link cobrindo a área, atrás da
|
||||||
caixa (que é `relative`). Sem isso, só o ✕ fecharia. %>
|
caixa (que é `relative`). Sem isso, só o ✕ fecharia. %>
|
||||||
<a href="#sem-previa" tabindex="-1" aria-label="Fechar prévia" class="absolute inset-0"></a>
|
<%= link_to '', fechar, tabindex: -1, 'aria-label': 'Fechar prévia',
|
||||||
|
class: 'absolute inset-0' %>
|
||||||
|
|
||||||
<div class="relative w-full max-w-6xl h-[92vh] flex flex-col gap-3">
|
<div class="relative w-full max-w-6xl h-[92vh] flex flex-col gap-3">
|
||||||
<div class="flex items-center justify-between gap-3">
|
<div class="flex items-center justify-between gap-3">
|
||||||
@@ -46,24 +50,44 @@
|
|||||||
pdf_admin_romaneio_path(@romaneio, veiculo: @veiculo),
|
pdf_admin_romaneio_path(@romaneio, veiculo: @veiculo),
|
||||||
target: '_blank', rel: 'noopener',
|
target: '_blank', rel: 'noopener',
|
||||||
class: 'text-sm text-gray-300 hover:text-white px-3 py-2 rounded-lg hover:bg-white/10' %>
|
class: 'text-sm text-gray-300 hover:text-white px-3 py-2 rounded-lg hover:bg-white/10' %>
|
||||||
<a href="#sem-previa" aria-label="Fechar prévia"
|
<%= link_to fechar, 'aria-label': 'Fechar prévia',
|
||||||
class="min-w-[48px] min-h-[48px] flex items-center justify-center rounded-xl
|
class: 'min-w-[48px] min-h-[48px] flex items-center justify-center rounded-xl
|
||||||
bg-[#1a1a1a] border border-white/10 text-white hover:bg-[#242424]">✕</a>
|
bg-[#1a1a1a] border border-white/10 text-white hover:bg-[#242424]' do %>
|
||||||
|
✕
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<iframe data-romaneio-target="preview" loading="lazy"
|
<iframe data-romaneio-target="preview"
|
||||||
src="<%= pdf_admin_romaneio_path(@romaneio, veiculo: @veiculo) %>"
|
src="<%= pdf_admin_romaneio_path(@romaneio, veiculo: @veiculo) %>"
|
||||||
class="flex-1 w-full rounded-xl border border-white/10 bg-white"
|
class="flex-1 w-full rounded-xl border border-white/10 bg-white"
|
||||||
title="Pré-visualização do romaneio"></iframe>
|
title="Pré-visualização do romaneio"></iframe>
|
||||||
|
|
||||||
|
<%# AVISO SEMPRE VISÍVEL, não um alerta que aparece só no erro: quando o
|
||||||
|
navegador se recusa a desenhar o PDF, ele não avisa ninguém — o quadro
|
||||||
|
fica branco e a leitura natural é "o sistema está quebrado". O navegador
|
||||||
|
tem uma opção, ligada por padrão em algumas instalações, de BAIXAR PDF em
|
||||||
|
vez de exibir; bloqueador de conteúdo (Brave Shields, uBlock) e bloqueio
|
||||||
|
de pop-up derrubam o mesmo quadro. Como não dá para detectar isso de
|
||||||
|
dentro da página (o iframe é opaco por segurança), a saída honesta é
|
||||||
|
dizer onde fica a alternativa. %>
|
||||||
|
<p class="text-xs text-gray-400 text-center">
|
||||||
|
Quadro em branco? O navegador pode estar configurado para <strong>baixar</strong> PDF
|
||||||
|
em vez de exibir, ou um bloqueador está barrando —
|
||||||
|
<%= link_to 'abra em outra aba',
|
||||||
|
pdf_admin_romaneio_path(@romaneio, veiculo: @veiculo),
|
||||||
|
target: '_blank', rel: 'noopener',
|
||||||
|
class: 'underline text-gray-300 hover:text-white' %>
|
||||||
|
ou libere PDF para este site nas permissões (cadeado da barra de endereço).
|
||||||
|
</p>
|
||||||
|
|
||||||
<%# Controles no mesmo desenho do carrossel do motorista (redondos, 56px,
|
<%# Controles no mesmo desenho do carrossel do motorista (redondos, 56px,
|
||||||
próximo em laranja), mas como LINKS: cada folha é uma URL. Na ponta vira
|
próximo em laranja), mas como LINKS: cada folha é uma URL. Na ponta vira
|
||||||
<span> apagado em vez de sumir — botão que some muda o layout no meio da
|
<span> apagado em vez de sumir — botão que some muda o layout no meio da
|
||||||
conferência e o operador perde o alvo do clique. %>
|
conferência e o operador perde o alvo do clique. %>
|
||||||
<div class="flex items-center justify-center gap-3">
|
<div class="flex items-center justify-center gap-3">
|
||||||
<% if anterior %>
|
<% if anterior %>
|
||||||
<%= link_to admin_romaneio_path(@romaneio, veiculo: anterior, anchor: 'previa'),
|
<%= link_to admin_romaneio_path(@romaneio, veiculo: anterior, previa: 1),
|
||||||
'aria-label': "Folha anterior (#{anterior})",
|
'aria-label': "Folha anterior (#{anterior})",
|
||||||
class: 'w-14 h-14 rounded-full flex items-center justify-center
|
class: 'w-14 h-14 rounded-full flex items-center justify-center
|
||||||
bg-[#1a1a1a]/90 backdrop-blur border border-white/15 text-white
|
bg-[#1a1a1a]/90 backdrop-blur border border-white/15 text-white
|
||||||
@@ -83,7 +107,7 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<% if proximo %>
|
<% if proximo %>
|
||||||
<%= link_to admin_romaneio_path(@romaneio, veiculo: proximo, anchor: 'previa'),
|
<%= link_to admin_romaneio_path(@romaneio, veiculo: proximo, previa: 1),
|
||||||
'aria-label': "Próxima folha (#{proximo})",
|
'aria-label': "Próxima folha (#{proximo})",
|
||||||
class: 'w-14 h-14 rounded-full flex items-center justify-center
|
class: 'w-14 h-14 rounded-full flex items-center justify-center
|
||||||
bg-orange-500/90 backdrop-blur border border-orange-400 text-black
|
bg-orange-500/90 backdrop-blur border border-orange-400 text-black
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<% atual = v.veiculo == @veiculo %>
|
<% atual = v.veiculo == @veiculo %>
|
||||||
<%# Link de verdade (não botão com JS): o veículo vive na query string, então
|
<%# 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. %>
|
ele é endereçável, volta com o "voltar" do navegador e sobrevive a um F5. %>
|
||||||
<a href="<%= admin_romaneio_path(@romaneio, veiculo: v.veiculo) %>"
|
<a href="<%= admin_romaneio_path(@romaneio, veiculo: v.veiculo, previa: (1 if @previa)) %>"
|
||||||
data-romaneio-target="itemVeiculo" data-veiculo="<%= v.veiculo %>"
|
data-romaneio-target="itemVeiculo" data-veiculo="<%= v.veiculo %>"
|
||||||
<%= 'data-atual="1"'.html_safe if atual %>
|
<%= 'data-atual="1"'.html_safe if atual %>
|
||||||
class="shrink-0 lg:shrink flex items-center justify-between gap-3 min-h-[48px]
|
class="shrink-0 lg:shrink flex items-center justify-between gap-3 min-h-[48px]
|
||||||
@@ -47,13 +47,13 @@
|
|||||||
<% prox_v = pos_v && pos_v < nomes_v.size - 1 ? nomes_v[pos_v + 1] : nil %>
|
<% prox_v = pos_v && pos_v < nomes_v.size - 1 ? nomes_v[pos_v + 1] : nil %>
|
||||||
<% base_v = 'flex-1 min-h-[48px] flex items-center justify-center rounded-xl border' %>
|
<% base_v = 'flex-1 min-h-[48px] flex items-center justify-center rounded-xl border' %>
|
||||||
<% if ant_v %>
|
<% if ant_v %>
|
||||||
<a href="<%= admin_romaneio_path(@romaneio, veiculo: ant_v) %>" aria-label="Veículo anterior"
|
<a href="<%= admin_romaneio_path(@romaneio, veiculo: ant_v, previa: (1 if @previa)) %>" aria-label="Veículo anterior"
|
||||||
class="<%= base_v %> bg-[#1a1a1a] border-white/10 text-white hover:bg-[#242424]">‹</a>
|
class="<%= base_v %> bg-[#1a1a1a] border-white/10 text-white hover:bg-[#242424]">‹</a>
|
||||||
<% else %>
|
<% else %>
|
||||||
<span class="<%= base_v %> bg-[#1a1a1a]/50 border-white/5 text-gray-600">‹</span>
|
<span class="<%= base_v %> bg-[#1a1a1a]/50 border-white/5 text-gray-600">‹</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if prox_v %>
|
<% if prox_v %>
|
||||||
<a href="<%= admin_romaneio_path(@romaneio, veiculo: prox_v) %>" aria-label="Próximo veículo"
|
<a href="<%= admin_romaneio_path(@romaneio, veiculo: prox_v, previa: (1 if @previa)) %>" aria-label="Próximo veículo"
|
||||||
class="<%= base_v %> bg-[#1a1a1a] border-white/10 text-white hover:bg-[#242424]">›</a>
|
class="<%= base_v %> bg-[#1a1a1a] border-white/10 text-white hover:bg-[#242424]">›</a>
|
||||||
<% else %>
|
<% else %>
|
||||||
<span class="<%= base_v %> bg-[#1a1a1a]/50 border-white/5 text-gray-600">›</span>
|
<span class="<%= base_v %> bg-[#1a1a1a]/50 border-white/5 text-gray-600">›</span>
|
||||||
@@ -61,9 +61,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pt-4 mt-1 border-t border-white/5">
|
<div class="pt-4 mt-1 border-t border-white/5">
|
||||||
|
<%# "Motorista deste veículo — só na tela" não cabe numa linha na coluna
|
||||||
|
estreita; o complemento vai embaixo, como legenda, em vez de quebrar no
|
||||||
|
meio do travessão. %>
|
||||||
<label class="block text-sm font-medium text-gray-300 mb-1.5">
|
<label class="block text-sm font-medium text-gray-300 mb-1.5">
|
||||||
Motorista deste veículo
|
Motorista deste veículo
|
||||||
<span class="text-gray-500 font-normal">— só na tela</span>
|
<span class="block text-xs text-gray-500 font-normal">só na tela, não sai impresso</span>
|
||||||
</label>
|
</label>
|
||||||
<% atual = @veiculos.find { |v| v.veiculo == @veiculo } %>
|
<% atual = @veiculos.find { |v| v.veiculo == @veiculo } %>
|
||||||
<input type="text" value="<%= atual&.motorista %>" placeholder="Quem leva este carro"
|
<input type="text" value="<%= atual&.motorista %>" placeholder="Quem leva este carro"
|
||||||
@@ -71,29 +74,38 @@
|
|||||||
class="w-full bg-[#1a1a1a] border border-white/10 rounded-xl px-3 py-3 text-white
|
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]">
|
placeholder-gray-600 focus:outline-none focus:border-orange-500 min-h-[48px]">
|
||||||
<p class="text-xs text-gray-500 mt-1.5">
|
<p class="text-xs text-gray-500 mt-1.5">
|
||||||
Não sai impresso — a linha do rodapé é assinada à mão na retirada.
|
A linha do rodapé é assinada à mão na retirada.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="space-y-3 pt-4 mt-4 border-t border-white/5">
|
<div class="space-y-3 pt-4 mt-4 border-t border-white/5">
|
||||||
<%# Link, não botão: abre o pop-up da prévia pelo `:target` do CSS (ver
|
<%# Link, não botão: a prévia aberta é a URL `?previa=1` (ver `_previa`),
|
||||||
`_previa`), então continua funcionando com o JavaScript fora do ar — foi
|
então isto funciona com o JavaScript fora do ar — foi o botão daqui que
|
||||||
o botão daqui que ficou morto três vezes seguidas. %>
|
ficou morto três vezes seguidas. %>
|
||||||
<a href="#previa"
|
<%= link_to admin_romaneio_path(@romaneio, veiculo: @veiculo, previa: 1),
|
||||||
class="w-full min-h-[48px] flex items-center justify-center gap-2 bg-[#1a1a1a]
|
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">
|
hover:bg-[#242424] text-white border border-white/10 rounded-xl' do %>
|
||||||
<%= icone :visualizar, cor: nil, espaco: false %> Ver prévia do PDF
|
<%= icone :visualizar, cor: nil, espaco: false %> Ver prévia do PDF
|
||||||
</a>
|
<% end %>
|
||||||
<%= link_to pdf_admin_romaneio_path(@romaneio, veiculo: @veiculo),
|
<%= link_to pdf_admin_romaneio_path(@romaneio, veiculo: @veiculo),
|
||||||
target: '_blank', rel: 'noopener',
|
target: '_blank', rel: 'noopener',
|
||||||
class: 'w-full min-h-[48px] flex items-center justify-center gap-2 bg-[#1a1a1a]
|
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 %>
|
hover:bg-[#242424] text-white border border-white/10 rounded-xl' do %>
|
||||||
<%= icone :baixar, cor: nil, espaco: false %> PDF deste veículo
|
<%= icone :baixar, cor: nil, espaco: false %> PDF deste veículo
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<%# Rótulo em DUAS linhas de propósito. "PDF de TODOS os veículos" numa linha
|
||||||
|
só não cabe nos 260px da coluna: quebrava sozinho e deixava o ícone
|
||||||
|
pendurado num degrau ao lado do texto. Aqui a quebra é intencional — o
|
||||||
|
ícone fica centrado na altura e a contagem vira a segunda linha, que
|
||||||
|
ainda informa quantas folhas saem. %>
|
||||||
<%= link_to pdf_admin_romaneio_path(@romaneio),
|
<%= link_to pdf_admin_romaneio_path(@romaneio),
|
||||||
class: 'w-full min-h-[48px] flex items-center justify-center gap-2 bg-[#f97316]
|
class: 'w-full min-h-[56px] flex items-center justify-center gap-2.5 px-3 py-2
|
||||||
hover:bg-orange-500 text-white font-semibold rounded-xl' do %>
|
bg-[#f97316] hover:bg-orange-500 text-white rounded-xl text-left' do %>
|
||||||
<%= icone :baixar, cor: nil, espaco: false %> PDF de TODOS os veículos
|
<%= icone :baixar, cor: nil, espaco: false, classe: 'shrink-0' %>
|
||||||
|
<span class="leading-tight">
|
||||||
|
<span class="block font-semibold">PDF de todos</span>
|
||||||
|
<span class="block text-xs text-white/80"><%= @veiculos.size %> veículos, uma folha cada</span>
|
||||||
|
</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
<%# app/views/admin/romaneios/show.html.erb
|
<%# app/views/admin/romaneios/show.html.erb
|
||||||
Editor do romaneio: veículos à esquerda, tabela editável à direita, e o PDF
|
Editor do romaneio: veículos à esquerda, tabela editável à direita, e o PDF
|
||||||
REAL num pop-up com navegação entre as folhas (partial `_previa`, que explica
|
REAL num pop-up com navegação entre as folhas (partial `_previa`, que explica
|
||||||
por que abrir/fechar/trocar de folha é CSS puro e não JavaScript). %>
|
por que a prévia aberta é estado na URL e não estado de JavaScript). %>
|
||||||
<div class="space-y-5"
|
<div class="space-y-5"
|
||||||
data-controller="romaneio"
|
data-controller="romaneio"
|
||||||
data-action="hashchange@window->romaneio#aoTrocarHash"
|
|
||||||
data-romaneio-url-value="<%= admin_romaneio_path(@romaneio) %>"
|
data-romaneio-url-value="<%= admin_romaneio_path(@romaneio) %>"
|
||||||
data-romaneio-pdf-url-value="<%= pdf_admin_romaneio_path(@romaneio) %>"
|
data-romaneio-pdf-url-value="<%= pdf_admin_romaneio_path(@romaneio) %>"
|
||||||
data-romaneio-veiculo-value="<%= @veiculo %>">
|
data-romaneio-veiculo-value="<%= @veiculo %>">
|
||||||
@@ -81,8 +80,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%# Pop-up da prévia: FORA da grade porque cobre a tela inteira quando
|
<%# Pop-up da prévia: FORA da grade porque cobre a tela inteira. Só existe no
|
||||||
aberto (`:target`). Fechado não ocupa espaço nem busca o PDF. %>
|
HTML quando ?previa=1 — fechado, nem o iframe é criado, então o servidor
|
||||||
<%= render 'previa' %>
|
não monta um PDF que ninguém pediu (ver `_previa`). %>
|
||||||
|
<%= render 'previa' if @previa %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -44,6 +44,21 @@ agent-browser network requests | grep -E " (4[0-9]{2}|5[0-9]{2})$" # deve vir
|
|||||||
- Qualquer request com status ≥ 400 ⇒ FALHOU (anote a URL — um asset
|
- Qualquer request com status ≥ 400 ⇒ FALHOU (anote a URL — um asset
|
||||||
`*_controller-*.js` com 404 significa Stimulus quebrado na página inteira; foi
|
`*_controller-*.js` com 404 significa Stimulus quebrado na página inteira; foi
|
||||||
exatamente assim que o bug do preview do romaneio passou despercebido).
|
exatamente assim que o bug do preview do romaneio passou despercebido).
|
||||||
|
|
||||||
|
⚠️ **404 de asset engana duas vezes.** O Cloudflare guarda os arquivos por um ano,
|
||||||
|
então uma tela pode parecer boa enquanto a origem já não serve nada — sempre
|
||||||
|
confira com cache-buster:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -o /dev/null -w "%{http_code}\n" "https://teste.reemtransportes.com.br/assets/controllers/<arquivo>.js?cb=$RANDOM"
|
||||||
|
```
|
||||||
|
|
||||||
|
E se **todos** derem 404, o problema é o build inteiro, não os arquivos: a tarefa
|
||||||
|
`tailwindcss:build` aborta o `assets:precompile` quando falta
|
||||||
|
`app/assets/tailwind/application.css`. O Propshaft, sem manifesto, continua
|
||||||
|
gerando URLs com o digest certo — por isso a página abre normal e o JS some em
|
||||||
|
silêncio. Confira no servidor com
|
||||||
|
`docker compose logs app | grep '\[boot\] assets'`.
|
||||||
- Exceção: chamadas para domínios de terceiros (cloudflareinsights etc.) com
|
- Exceção: chamadas para domínios de terceiros (cloudflareinsights etc.) com
|
||||||
falha não reprovam o caso; registre como observação.
|
falha não reprovam o caso; registre como observação.
|
||||||
|
|
||||||
@@ -115,34 +130,65 @@ agent-browser wait --load networkidle
|
|||||||
|
|
||||||
Na tela do romaneio:
|
Na tela do romaneio:
|
||||||
|
|
||||||
A prévia é um `<details>` nativo — abre e fecha **sem JavaScript**, de propósito
|
A prévia é um pop-up cujo estado mora na **URL** (`?previa=1`) — abre, fecha e
|
||||||
(quando os assets caem, ela precisa continuar funcionando):
|
troca de folha por navegação normal, sem JavaScript. **Teste sempre navegando de
|
||||||
|
verdade**, nunca com `.click()` de dentro do `eval`: o clique programático já
|
||||||
|
mascarou um bug (com o Turbo carregado, o mecanismo anterior por `#hash` não
|
||||||
|
abria, mas o `.click()` fazia parecer que abria).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 4a. Fechada ao carregar, e o PDF ainda NÃO foi buscado (iframe é loading=lazy):
|
# 4a. Fechada, o pop-up NÃO existe no HTML (e nenhum PDF é gerado):
|
||||||
agent-browser eval "(()=>{const d=document.querySelector('details[data-romaneio-target=overlay]'); return d ? 'aberto:'+d.open : 'PREVIA AUSENTE';})()"
|
agent-browser open "https://teste.reemtransportes.com.br/admin/romaneios/13"
|
||||||
# esperado: "aberto:false"
|
agent-browser eval "document.querySelector('[data-romaneio-target=overlay]') ? 'PRESENTE (erro)' : 'ausente (correto)'"
|
||||||
|
|
||||||
# 4b. Abrir e conferir que o iframe aponta para o PDF:
|
# 4b. Abrir pelo botão, com clique REAL:
|
||||||
agent-browser eval "document.querySelector('details[data-romaneio-target=overlay] summary').click()"
|
agent-browser snapshot -i | grep -i "prévia" # pegar o ref do link
|
||||||
agent-browser eval "(()=>{const d=document.querySelector('details[data-romaneio-target=overlay]'); const f=d.querySelector('iframe'); return 'aberto:'+d.open+' src:'+(f?.getAttribute('src')||'sem src');})()"
|
agent-browser click @eN
|
||||||
# esperado: "aberto:true src:/admin/romaneios/<id>/pdf?veiculo=..."
|
agent-browser eval "(()=>{const o=document.querySelector('[data-romaneio-target=overlay]'); if(!o) return 'NAO ABRIU'; const c=[...o.querySelectorAll('span')].find(s=>s.textContent.includes(' de ')); return 'aberto | '+c.textContent.trim()+' | url='+location.search;})()"
|
||||||
|
# esperado: "aberto | 1 de 72 · GADE_001 | url=?veiculo=GADE_001&previa=1"
|
||||||
|
|
||||||
# 4c. Fechar de novo:
|
# 4c. Avançar de folha SEM fechar (é o carrossel):
|
||||||
agent-browser eval "document.querySelector('details[data-romaneio-target=overlay] summary').click()"
|
agent-browser eval "(()=>{const o=document.querySelector('[data-romaneio-target=overlay]'); const a=[...o.querySelectorAll('a')].filter(x=>(x.getAttribute('href')||'').includes('previa')); return a.at(-1).getAttribute('href');})()"
|
||||||
|
# copie o href e navegue nele com `agent-browser open`; o pop-up tem que continuar
|
||||||
|
# aberto e o contador virar "2 de 72".
|
||||||
|
|
||||||
# 4d. O PDF responde e é PDF de verdade (não a página de login):
|
# 4d. Fechar pelo ✕ (volta para a URL sem previa) e o pop-up sumir do HTML.
|
||||||
agent-browser eval "(async()=>{const r=await fetch(document.querySelector('details[data-romaneio-target=overlay] iframe').src); const b=await r.blob(); return r.status+' '+b.type+' '+Math.round(b.size/1024)+'KB';})()"
|
|
||||||
|
# 4e. O PDF responde e é PDF de verdade (não a página de login):
|
||||||
|
agent-browser eval "(async()=>{const r=await fetch('/admin/romaneios/13/pdf?veiculo=GADE_001&cb='+Math.random()); const b=await r.blob(); return r.status+' '+b.type+' '+Math.round(b.size/1024)+'KB';})()"
|
||||||
# esperado: "200 application/pdf <N>KB"
|
# esperado: "200 application/pdf <N>KB"
|
||||||
```
|
```
|
||||||
|
|
||||||
**PASSOU se**: 4a fechada, 4b abre com src do PDF, 4c fecha, 4d devolve
|
**PASSOU se**: 4a ausente, 4b abre com o contador certo, 4c avança mantendo
|
||||||
`application/pdf`, Teste 0 limpo. **NÃO** clicar em "Reimportar plano" (tem
|
aberto, 4d fecha, 4e devolve `application/pdf`. **NÃO** clicar em "Reimportar
|
||||||
confirmação).
|
plano" (tem confirmação).
|
||||||
|
|
||||||
⚠️ Se 4d devolver `text/html`, a sessão caiu no meio do teste — refaça o login e
|
⚠️ Se 4e devolver `text/html`, a sessão caiu no meio do teste — refaça o login e
|
||||||
repita, **não** registre como falha do PDF (já deu falso positivo assim).
|
repita, **não** registre como falha do PDF (já deu falso positivo assim).
|
||||||
|
|
||||||
|
### Caso 4f — Prévia em branco é o NAVEGADOR, não o sistema
|
||||||
|
|
||||||
|
O quadro do PDF pode aparecer branco mesmo com tudo funcionando, porque o
|
||||||
|
navegador se recusa a desenhar PDF em iframe. As três causas conhecidas:
|
||||||
|
|
||||||
|
1. **"Baixar PDFs em vez de abri-los"** ligado (Chrome/Brave/Edge:
|
||||||
|
`chrome://settings/content/pdfDocuments`);
|
||||||
|
2. **bloqueador de conteúdo** (Brave Shields, uBlock) barrando o quadro;
|
||||||
|
3. **bloqueio de pop-up/redirecionamento** do navegador.
|
||||||
|
|
||||||
|
O sistema **não consegue detectar isso** (o iframe é opaco por segurança), por
|
||||||
|
isso o pop-up traz um aviso fixo com a saída ("abra em outra aba"). Antes de
|
||||||
|
abrir bug de "prévia não aparece", confirme que **não** é o navegador:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Se ISTO devolve application/pdf, o servidor está certo e o problema é o navegador:
|
||||||
|
agent-browser eval "(async()=>{const r=await fetch('/admin/romaneios/13/pdf?veiculo=GADE_001&cb='+Math.random()); const b=await r.blob(); return r.status+' '+b.type;})()"
|
||||||
|
```
|
||||||
|
|
||||||
|
**PASSOU se**: o aviso está visível no rodapé do pop-up e o `fetch` acima devolve
|
||||||
|
`application/pdf`. Se o fetch devolve PDF e o quadro está branco, o veredito é
|
||||||
|
**"configuração do navegador"**, não falha do sistema — registre assim.
|
||||||
|
|
||||||
### Caso 4e — Vínculo manual da operação (só leitura)
|
### Caso 4e — Vínculo manual da operação (só leitura)
|
||||||
|
|
||||||
O bloco "Operação do mês" tem que aparecer em todo romaneio, e o formulário
|
O bloco "Operação do mês" tem que aparecer em todo romaneio, e o formulário
|
||||||
|
|||||||
Reference in New Issue
Block a user