diff --git a/app/controllers/operacoes_dashboard_controller.rb b/app/controllers/operacoes_dashboard_controller.rb index 930cb5c..710d102 100644 --- a/app/controllers/operacoes_dashboard_controller.rb +++ b/app/controllers/operacoes_dashboard_controller.rb @@ -7,6 +7,9 @@ class OperacoesDashboardController < ApplicationController MODOS = %w[operacao global comparar].freeze + # Linhas por página da tabela espelho (planilha da operação) + ESPELHO_POR_PAGINA = 15 + def index authorize :dashboard, :operacoes? @@ -32,10 +35,25 @@ class OperacoesDashboardController < ApplicationController @operacao = Operacao.sanitizar([params[:operacao]]).first || @tabelas_validas.first @metricas = montar([@operacao], filtros: @filtros, data: @data_filtro) if @operacao end + + montar_tabela_espelho if @metricas && %w[operacao global].include?(@modo) end private + # Tabela espelho da planilha da operação: busca textual (q) + paginação (pg) + # sobre as linhas já cross-filtradas. Ordena pelas mais recentes (checkout; + # sem checkout vai para o fim). + def montar_tabela_espelho + @busca = params[:q].to_s.strip + linhas = @metricas.buscar(@busca).sort_by { |r| r['checkout'].to_s }.reverse + + @espelho_total = linhas.size + @espelho_paginas = [(@espelho_total / ESPELHO_POR_PAGINA.to_f).ceil, 1].max + @espelho_pagina = params[:pg].to_i.clamp(1, @espelho_paginas) + @espelho_linhas = linhas[(@espelho_pagina - 1) * ESPELHO_POR_PAGINA, ESPELHO_POR_PAGINA] || [] + end + def montar(tabelas, inicio: nil, fim: nil, filtros: {}, data: nil) Analytics::OperacaoMetricas.new(tabelas: tabelas, inicio: inicio, fim: fim, filtros: filtros, data: data) end diff --git a/app/services/analytics/operacao_metricas.rb b/app/services/analytics/operacao_metricas.rb index 97c2834..e05bf31 100644 --- a/app/services/analytics/operacao_metricas.rb +++ b/app/services/analytics/operacao_metricas.rb @@ -45,6 +45,18 @@ module Analytics end end + # Campos pesquisáveis da tabela espelho (planilha da operação). + BUSCA_CAMPOS = %w[reference_id driver vehicle status observation contact_name + address nome_completo endereco_completo status_gade operacao].freeze + + # Busca textual da tabela espelho: filtra as linhas (já pós cross-filter) + # por qualquer campo exibido na planilha. + def buscar(texto) + termo = texto.to_s.strip.downcase + return linhas if termo.empty? + linhas.select { |r| BUSCA_CAMPOS.any? { |c| r[c].to_s.downcase.include?(termo) } } + end + # Taxas (úteis no comparativo). def taxa_sucesso pct(sucesso, total) diff --git a/app/views/operacoes_dashboard/_espelho.html.erb b/app/views/operacoes_dashboard/_espelho.html.erb new file mode 100644 index 0000000..0bf19d9 --- /dev/null +++ b/app/views/operacoes_dashboard/_espelho.html.erb @@ -0,0 +1,139 @@ +<%# app/views/operacoes_dashboard/_espelho.html.erb %> +<%# Tabela espelho da planilha da operação: uma linha por NF com resultado, + ocorrência, motorista etc. Busca textual (param q) e paginação (param pg) + são server-side; o restante da URL (modo/operação/período/cross-filters) + é preservado nos links e no form. %> + +<% pg_path = ->(n) { operacoes_dashboard_path(request.query_parameters.merge('pg' => n)) } %> +<% resultado_badge = ->(status) { + if status == 'completed' + ['Entregue', 'bg-green-500/10 text-green-400 border-green-500/30'] + elsif Entrega::STATUS_FALHA.include?(status) + ['Falha', 'bg-red-500/10 text-red-400 border-red-500/30'] + else + ['Pendente', 'bg-yellow-500/10 text-yellow-400 border-yellow-500/30'] + end + } %> + +
Espelho por NF — pesquise por nota, motorista, unidade, ocorrência, veículo...
++ <%= @busca.present? ? %(Nenhuma entrega encontrada para "#{@busca}".) : 'Nenhuma entrega para exibir.' %> +
+ <% else %> +| Data | +NF | + <% if @modo == 'global' %> +Operação | + <% end %> +Destinatário | +Unidade | +Motorista | +Veículo | +Resultado | +Ocorrência | +Status | +
|---|---|---|---|---|---|---|---|---|---|
| + <%= data.respond_to?(:strftime) ? data.strftime('%d/%m/%y %H:%M') : data.to_s.first(16) %> + | +<%= r['reference_id'] %> | + <% if @modo == 'global' %> +<%= r['operacao'] %> | + <% end %> ++ <%= (r['nome_completo'].presence || '—').truncate(28) %> + | +<%= r['contact_name'].to_s.truncate(24).presence || '—' %> | +<%= r['driver'].presence || '—' %> | +<%= r['vehicle'].presence || '—' %> | ++ + <%= rotulo %> + + | ++ <%= r['observation'].to_s.truncate(32).presence || '—' %> + | +<%= r['status_gade'].presence || '—' %> | +
+ <%= (@espelho_pagina - 1) * OperacoesDashboardController::ESPELHO_POR_PAGINA + 1 %>–<%= + [(@espelho_pagina) * OperacoesDashboardController::ESPELHO_POR_PAGINA, @espelho_total].min %> + de <%= @espelho_total %> entregas +
+ <% if @espelho_paginas > 1 %> +