diff --git a/portal_api/nao_conformidades/classificacao.py b/portal_api/nao_conformidades/classificacao.py
index 41b996f..ec1ed66 100644
--- a/portal_api/nao_conformidades/classificacao.py
+++ b/portal_api/nao_conformidades/classificacao.py
@@ -17,6 +17,15 @@ STATUS_VENCE_30 = "vence_30_dias"
STATUS_NO_PRAZO = "no_prazo"
STATUS_SEM_VENCIMENTO = "sem_vencimento"
+# Não é uma classificação por-ação real (status_prazo() nunca retorna isto) —
+# é só um nome de bucket agregado usado por `_filtra_status_prazo()`
+# (portal_api/views.py) e pelo chip "Em aberto" do frontend, equivalente a
+# "qualquer bucket exceto finalizada". NUNCA adicionar em STATUS_PRAZO_LABELS:
+# esse dict é iterado pra montar os contadores do dashboard, uma contagem por
+# classificação mutuamente exclusiva de ação — "não finalizada" não é
+# mutuamente exclusiva com vencida/vence_7_dias/etc, é a união delas.
+STATUS_NAO_FINALIZADA = "nao_finalizada"
+
STATUS_PRAZO_LABELS = {
STATUS_FINALIZADA: "Finalizada",
STATUS_VENCIDA: "Vencida",
diff --git a/portal_api/serializers.py b/portal_api/serializers.py
index 8eb1410..7529ec6 100644
--- a/portal_api/serializers.py
+++ b/portal_api/serializers.py
@@ -2085,6 +2085,7 @@ class NCAcaoSerializer(serializers.ModelSerializer):
# da Gestão e drill-down dos rankings do Dashboard) sem duplicar o dado.
ocorrencia_clientes = serializers.CharField(source="ocorrencia.clientes_relacionados", read_only=True)
ocorrencia_area = serializers.CharField(source="ocorrencia.area", read_only=True)
+ ocorrencia_tipo_ocorrencia = serializers.CharField(source="ocorrencia.tipo_ocorrencia", read_only=True)
status_prazo = serializers.SerializerMethodField()
status_prazo_label = serializers.SerializerMethodField()
dias_para_vencer = serializers.SerializerMethodField()
@@ -2098,6 +2099,7 @@ class NCAcaoSerializer(serializers.ModelSerializer):
"ocorrencia_assunto",
"ocorrencia_clientes",
"ocorrencia_area",
+ "ocorrencia_tipo_ocorrencia",
"codigo",
"data_emissao",
"tipo_acao",
diff --git a/portal_api/views.py b/portal_api/views.py
index 9d6c0fe..a12caf4 100644
--- a/portal_api/views.py
+++ b/portal_api/views.py
@@ -3020,6 +3020,8 @@ def _filtra_status_prazo(queryset: QuerySet[NCAcao], bucket: str, hoje: date) ->
return queryset.filter(data_finalizacao__isnull=False)
queryset = queryset.filter(data_finalizacao__isnull=True)
+ if bucket == nc_classificacao.STATUS_NAO_FINALIZADA:
+ return queryset
if bucket == nc_classificacao.STATUS_VENCIDA:
return queryset.filter(vencimento_efetivo__lt=hoje)
if bucket == nc_classificacao.STATUS_VENCE_7:
diff --git a/static/css/nao-conformidades.css b/static/css/nao-conformidades.css
index cf64f37..0d72ef7 100644
--- a/static/css/nao-conformidades.css
+++ b/static/css/nao-conformidades.css
@@ -144,6 +144,118 @@
color: var(--accent-contrast);
}
+/* Ordenação por clique no cabeçalho — mesma linguagem visual de #ua-table
+ (perfis-acesso.css, th[data-sort]/.ua-sort-icon), duplicado aqui porque
+ essa folha não compartilha código com a de usuários. Escopado pela classe
+ compartilhada .ncf-table-sortable (as 3 tabelas da Gestão), não por ID
+ individual. */
+.ncf-table-sortable th[data-sort] {
+ cursor: pointer;
+ user-select: none;
+ white-space: nowrap;
+}
+
+.ncf-sort-icon {
+ color: var(--text-muted);
+ font-size: 0.75rem;
+}
+
+.ncf-table-sortable th[data-sort].is-sort-asc .ncf-sort-icon,
+.ncf-table-sortable th[data-sort].is-sort-desc .ncf-sort-icon {
+ color: var(--accent);
+}
+
+/* Filtro por coluna (só "Tipo de Ocorrência"/"Vencimento", tabela de Ações) —
+ mesmo espírito de .ind-info-wrap/.ind-info-popover (indicador-desempenho.css),
+ mas com uma diferença importante: aqui o popover é position:fixed (não
+ absolute), com top/left calculados em JS a partir do
+ getBoundingClientRect() do botão (ver pidNcfAbrirPopoverColuna() em
+ nao-conformidades.js). position:fixed escapa do overflow:hidden de
+ .pa-table-wrap (perfis-acesso.css, usado pra arredondar o canto da
+ tabela) sem precisar reabrir esse overflow — uma primeira versão fazia
+ isso com overflow:visible no wrapper, mas isso quebrava a contenção da
+ tabela (12 colunas já é bem larga) e estourava a largura da página. */
+.ncf-th-filterable {
+ position: relative;
+}
+
+.ncf-th-sort-label {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+}
+
+.ncf-col-filtro-btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 18px;
+ height: 18px;
+ margin-left: var(--space-2);
+ padding: 0;
+ border-radius: var(--radius-sm);
+ border: 1px solid var(--border-subtle);
+ color: var(--text-muted);
+ background: transparent;
+ cursor: pointer;
+ transition: color var(--transition-fast), border-color var(--transition-fast);
+}
+
+.ncf-col-filtro-btn:hover,
+.ncf-col-filtro-btn[aria-expanded="true"] {
+ color: var(--accent);
+ border-color: var(--accent);
+}
+
+.ncf-col-filtro-popover {
+ position: fixed;
+ z-index: 30;
+ width: 240px;
+ padding: var(--space-3);
+ border-radius: var(--radius-md);
+ border: 1px solid var(--border-subtle);
+ background: var(--bg-surface-raised);
+ box-shadow: var(--shadow-lg);
+ animation: pidFadeSlideUp 140ms ease;
+ /* .pa-table th força uppercase/letter-spacing/tamanho pequeno no
+ cabeçalho — resetado aqui pra virar texto normal de novo. */
+ font-size: 0.82rem;
+ font-weight: 400;
+ text-transform: none;
+ letter-spacing: normal;
+ line-height: 1.4;
+ color: var(--text-primary);
+ white-space: normal;
+ text-align: left;
+}
+
+.ncf-col-filtro-popover .checklist-box {
+ max-height: 160px;
+}
+
+.ncf-col-filtro-popover .modal-field {
+ margin-bottom: var(--space-2);
+}
+
+.ncf-col-filtro-popover__actions {
+ display: flex;
+ justify-content: flex-end;
+ gap: var(--space-2);
+ margin-top: var(--space-3);
+}
+
+.ncf-col-filtro-popover__actions .btn-outline,
+.ncf-col-filtro-popover__actions .btn-solid {
+ padding: 4px 12px;
+ font-size: 0.78rem;
+}
+
+/* Ação já finalizada no Sigsistem — não há nada pra Qualidade tratar, então
+ a coluna de ação mostra só um traço em vez do botão "Marcar como tratado". */
+.ncf-sem-acao-necessaria {
+ color: var(--text-muted);
+}
+
/* Dashboard */
.ncf-dashboard-toolbar {
display: flex;
@@ -450,6 +562,32 @@
text-align: left;
}
+/* A linha principal de uma Ação não fecha com borda embaixo — quem fecha é
+ a linha de descrição logo abaixo (ver .ncf-acao-descricao-row), pra as
+ duas lerem como um bloco só, não duas linhas de tabela separadas. */
+.pa-table tr.ncf-acao-main-row td {
+ border-bottom: none;
+}
+
+/* Linha full-width com a descrição da Ação, logo abaixo da linha principal
+ (não é mais uma coluna própria — não cabia na largura da tabela). Classe
+ própria com maior especificidade que .pa-table td:last-child
+ (text-align:right) pelo mesmo motivo de .ncf-detail-cell acima: como usa
+ colspan, é sempre "a última" célula da linha. */
+.pa-table tr.ncf-acao-descricao-row td.ncf-acao-descricao-cell {
+ padding-top: 0;
+ padding-bottom: var(--space-3);
+ text-align: left;
+ font-size: 0.82rem;
+ color: var(--text-secondary);
+}
+
+.ncf-acao-descricao-label {
+ font-weight: 600;
+ color: var(--text-muted);
+ margin-right: 4px;
+}
+
.ncf-detail-panel {
font-size: 0.85rem;
color: var(--text-secondary);
diff --git a/static/js/nao-conformidades.js b/static/js/nao-conformidades.js
index 08fd21b..5a40328 100644
--- a/static/js/nao-conformidades.js
+++ b/static/js/nao-conformidades.js
@@ -42,6 +42,68 @@ const PID_NCF_STATUS_PRAZO_CLASSES = {
sem_vencimento: "status-pill status-pill--neutral",
};
+// Compara duas strings tratando conteúdo numérico como número (ex.: "92" <
+// "150"), senão cai pra comparação alfabética pt-BR — mesmo critério de
+// comparaValoresUsuario() em users-admin.js/comparaValoresLista() em
+// importacao-plano-saude.js, copiado localmente porque cada tela do Portal
+// tem seu próprio arquivo JS autocontido, sem módulo compartilhado.
+function pidNcfCompara(a, b) {
+ const an = Number(a);
+ const bn = Number(b);
+ const ambosNumeros = a !== "" && b !== "" && a != null && b != null && !Number.isNaN(an) && !Number.isNaN(bn);
+ if (ambosNumeros) return an - bn;
+ return String(a ?? "").localeCompare(String(b ?? ""), "pt-BR", { sensitivity: "base" });
+}
+
+// Ordena por severidade, não alfabeticamente (ex.: "Vencida" precisa vir
+// antes de "No prazo", não é isso que localeCompare faria).
+const PID_NCF_STATUS_PRAZO_RANK = {
+ vencida: 0,
+ vence_7_dias: 1,
+ vence_30_dias: 2,
+ no_prazo: 3,
+ sem_vencimento: 4,
+ finalizada: 5,
+};
+const PID_NCF_STATUS_TRATATIVA_RANK = { pendente: 0, tratado: 1 };
+
+function pidNcfAplicarSort(itens, sortKey, sortDir, sortValorMap) {
+ if (!sortKey) return itens; // preserva a ordem que já veio do servidor até o usuário clicar um cabeçalho
+ const extrator = sortValorMap[sortKey];
+ if (!extrator) return itens;
+ return itens.slice().sort((a, b) => pidNcfCompara(extrator(a), extrator(b)) * sortDir);
+}
+
+function pidNcfAtualizarSortHeaders(headers, sortKey, sortDir) {
+ headers.forEach((th) => {
+ const key = th.getAttribute("data-sort");
+ th.classList.toggle("is-sort-asc", key === sortKey && sortDir === 1);
+ th.classList.toggle("is-sort-desc", key === sortKey && sortDir === -1);
+ });
+}
+
+// Liga o clique de ordenação nos
de uma tabela — clicar
+// alterna asc/desc na mesma coluna ou reseta pra asc numa coluna nova. Ignora
+// cliques que vieram do ícone/popover de filtro de coluna (só a tabela de
+// Ações tem isso hoje), pra sort e filtro de coluna nunca disparar juntos.
+function pidNcfBindSortHeaders(tableId, getSortState, setSortState, rerender) {
+ const headers = Array.from(document.querySelectorAll(`#${tableId} th[data-sort]`));
+ headers.forEach((th) => {
+ th.addEventListener("click", (evento) => {
+ if (evento.target.closest("[data-ncf-col-filtro], .ncf-col-filtro-popover")) return;
+ const key = th.getAttribute("data-sort");
+ const { sortKey, sortDir } = getSortState();
+ if (sortKey === key) {
+ setSortState(key, sortDir * -1);
+ } else {
+ setSortState(key, 1);
+ }
+ rerender();
+ });
+ });
+ return headers;
+}
+
/** Botão de expandir (chevron que gira) + linha de detalhe associada, mesmo
* padrão de `.cc-painel-fiscal__toggle` (custo-contratacao.js), adaptado pra
* uma linha de tabela — `montarConteudo(painelEl)` só roda na primeira vez
@@ -153,14 +215,39 @@ document.addEventListener("DOMContentLoaded", async () => {
let semAnaliseTodos = [];
let analiseSemAcaoTodos = [];
let acoesTodos = [];
- let prazoFiltroAtual = "todas";
+ // "nao_finalizada" (não "todas") é o padrão — a tela deve abrir só com o
+ // que ainda está em aberto (data_finalizacao vazia no Sigsistem), pedido
+ // explícito do usuário; "Todas" continua disponível como chip separado.
+ let prazoFiltroAtual = "nao_finalizada";
let tratativaFiltroAtual = "pendente";
+ let semAnaliseTratativaFiltroAtual = "pendente";
+ let analiseSemAcaoTratativaFiltroAtual = "pendente";
let buscaGestao = "";
+ // Ordenação por clique no cabeçalho — estado independente por tabela.
+ // sortKey=null preserva a ordenação vinda do servidor até o usuário clicar
+ // um cabeçalho pela primeira vez.
+ let semAnaliseSortKey = null;
+ let semAnaliseSortDir = 1;
+ let analiseSemAcaoSortKey = null;
+ let analiseSemAcaoSortDir = 1;
+ let acoesSortKey = null;
+ let acoesSortDir = 1;
+
+ // Filtros de coluna da tabela de Ações (só "Tipo de Ocorrência" e
+ // "Vencimento" têm isso, e só nessa tabela) — sempre client-side, sobre o
+ // `acoesTodos` já carregado (ver carregarAcoes()/renderAcoes()).
+ let tipoOcorrenciaFiltroSelecionados = new Set(); // vazio = sem filtro (mostra tudo)
+ let tipoOcorrenciaOpcoesDisponiveis = [];
+ let vencimentoFiltroDe = "";
+ let vencimentoFiltroAte = "";
+
const gestaoSearch = document.getElementById("ncf-gestao-search");
const gestaoSearchClearBtn = document.getElementById("ncf-gestao-search-clear-btn");
const filtroPrazoEl = document.getElementById("ncf-filtro-prazo");
const filtroTratativaEl = document.getElementById("ncf-filtro-tratativa");
+ const filtroTratativaSemAnaliseEl = document.getElementById("ncf-filtro-tratativa-sem-analise");
+ const filtroTratativaAnaliseSemAcaoEl = document.getElementById("ncf-filtro-tratativa-analise-sem-acao");
function filtrarPorBusca(itens, campos) {
const termo = buscaGestao.trim().toLowerCase();
@@ -206,6 +293,20 @@ document.addEventListener("DOMContentLoaded", async () => {
atualizarChipsAtivos(filtroTratativaEl, "ncfTratativa", tratativaFiltroAtual);
carregarAcoes();
});
+ filtroTratativaSemAnaliseEl.addEventListener("click", (evento) => {
+ const btn = evento.target.closest("[data-ncf-tratativa]");
+ if (!btn) return;
+ semAnaliseTratativaFiltroAtual = btn.dataset.ncfTratativa;
+ atualizarChipsAtivos(filtroTratativaSemAnaliseEl, "ncfTratativa", semAnaliseTratativaFiltroAtual);
+ carregarSemAnalise();
+ });
+ filtroTratativaAnaliseSemAcaoEl.addEventListener("click", (evento) => {
+ const btn = evento.target.closest("[data-ncf-tratativa]");
+ if (!btn) return;
+ analiseSemAcaoTratativaFiltroAtual = btn.dataset.ncfTratativa;
+ atualizarChipsAtivos(filtroTratativaAnaliseSemAcaoEl, "ncfTratativa", analiseSemAcaoTratativaFiltroAtual);
+ carregarAnaliseSemAcao();
+ });
async function garantirGestaoCarregada() {
if (gestaoCarregada) return;
@@ -217,20 +318,41 @@ document.addEventListener("DOMContentLoaded", async () => {
const semAnaliseBody = document.getElementById("ncf-sem-analise-body");
const semAnaliseEmpty = document.getElementById("ncf-sem-analise-empty");
const semAnaliseCount = document.getElementById("ncf-sem-analise-count");
+ const PID_NCF_SEM_ANALISE_SORT_VALOR = {
+ codigo: (oc) => oc.codigo,
+ data_emissao: (oc) => oc.data_emissao || "",
+ area: (oc) => oc.area || "",
+ emissor_relato: (oc) => oc.emissor_relato || "",
+ indicado_analise: (oc) => oc.indicado_analise || "",
+ status_tratativa: (oc) => PID_NCF_STATUS_TRATATIVA_RANK[oc.status_tratativa] ?? 0,
+ };
+ const semAnaliseSortHeaders = pidNcfBindSortHeaders(
+ "ncf-table-sem-analise",
+ () => ({ sortKey: semAnaliseSortKey, sortDir: semAnaliseSortDir }),
+ (key, dir) => {
+ semAnaliseSortKey = key;
+ semAnaliseSortDir = dir;
+ },
+ renderSemAnalise
+ );
async function carregarSemAnalise() {
- semAnaliseTodos = await pidApiRequest("/nao-conformidades/ocorrencias/?sem_analise=true");
+ const params = new URLSearchParams({ sem_analise: "true" });
+ if (semAnaliseTratativaFiltroAtual !== "todas") params.set("status_tratativa", semAnaliseTratativaFiltroAtual);
+ semAnaliseTodos = await pidApiRequest(`/nao-conformidades/ocorrencias/?${params.toString()}`);
renderSemAnalise();
}
function renderSemAnalise() {
- const itens = filtrarPorBusca(semAnaliseTodos, [
+ let itens = filtrarPorBusca(semAnaliseTodos, [
"indicado_analise",
"responsavel_analise",
"clientes_relacionados",
"assunto",
"emissor_relato",
]);
+ itens = pidNcfAplicarSort(itens, semAnaliseSortKey, semAnaliseSortDir, PID_NCF_SEM_ANALISE_SORT_VALOR);
+ pidNcfAtualizarSortHeaders(semAnaliseSortHeaders, semAnaliseSortKey, semAnaliseSortDir);
pidNcfAtualizarContador(semAnaliseCount, itens.length);
semAnaliseBody.innerHTML = "";
semAnaliseEmpty.hidden = itens.length > 0;
@@ -272,20 +394,41 @@ document.addEventListener("DOMContentLoaded", async () => {
const analiseSemAcaoBody = document.getElementById("ncf-analise-sem-acao-body");
const analiseSemAcaoEmpty = document.getElementById("ncf-analise-sem-acao-empty");
const analiseSemAcaoCount = document.getElementById("ncf-analise-sem-acao-count");
+ const PID_NCF_ANALISE_SEM_ACAO_SORT_VALOR = {
+ codigo: (oc) => oc.codigo,
+ data_emissao: (oc) => oc.data_emissao || "",
+ area: (oc) => oc.area || "",
+ responsavel_analise: (oc) => oc.responsavel_analise || "",
+ descricao_analise: (oc) => oc.descricao_analise || "",
+ status_tratativa: (oc) => PID_NCF_STATUS_TRATATIVA_RANK[oc.status_tratativa] ?? 0,
+ };
+ const analiseSemAcaoSortHeaders = pidNcfBindSortHeaders(
+ "ncf-table-analise-sem-acao",
+ () => ({ sortKey: analiseSemAcaoSortKey, sortDir: analiseSemAcaoSortDir }),
+ (key, dir) => {
+ analiseSemAcaoSortKey = key;
+ analiseSemAcaoSortDir = dir;
+ },
+ renderAnaliseSemAcao
+ );
async function carregarAnaliseSemAcao() {
- analiseSemAcaoTodos = await pidApiRequest("/nao-conformidades/ocorrencias/?analise_sem_acao=true");
+ const params = new URLSearchParams({ analise_sem_acao: "true" });
+ if (analiseSemAcaoTratativaFiltroAtual !== "todas") params.set("status_tratativa", analiseSemAcaoTratativaFiltroAtual);
+ analiseSemAcaoTodos = await pidApiRequest(`/nao-conformidades/ocorrencias/?${params.toString()}`);
renderAnaliseSemAcao();
}
function renderAnaliseSemAcao() {
- const itens = filtrarPorBusca(analiseSemAcaoTodos, [
+ let itens = filtrarPorBusca(analiseSemAcaoTodos, [
"indicado_analise",
"responsavel_analise",
"clientes_relacionados",
"assunto",
"descricao_analise",
]);
+ itens = pidNcfAplicarSort(itens, analiseSemAcaoSortKey, analiseSemAcaoSortDir, PID_NCF_ANALISE_SEM_ACAO_SORT_VALOR);
+ pidNcfAtualizarSortHeaders(analiseSemAcaoSortHeaders, analiseSemAcaoSortKey, analiseSemAcaoSortDir);
pidNcfAtualizarContador(analiseSemAcaoCount, itens.length);
analiseSemAcaoBody.innerHTML = "";
analiseSemAcaoEmpty.hidden = itens.length > 0;
@@ -381,6 +524,26 @@ document.addEventListener("DOMContentLoaded", async () => {
const acoesBody = document.getElementById("ncf-acoes-body");
const acoesEmpty = document.getElementById("ncf-acoes-empty");
const acoesCount = document.getElementById("ncf-acoes-count");
+ const PID_NCF_ACOES_SORT_VALOR = {
+ ocorrencia_codigo: (a) => Number(a.ocorrencia_codigo) * 1000000 + Number(a.codigo || 0),
+ ocorrencia_area: (a) => a.ocorrencia_area || "",
+ tipo_acao: (a) => a.tipo_acao || "",
+ ocorrencia_tipo_ocorrencia: (a) => a.ocorrencia_tipo_ocorrencia || "",
+ executor: (a) => a.executor || "",
+ vencimento_efetivo: (a) => a.vencimento_efetivo || "",
+ ultimo_acompanhamento_em: (a) => a.ultimo_acompanhamento_em || "",
+ status_prazo: (a) => PID_NCF_STATUS_PRAZO_RANK[a.status_prazo] ?? 99,
+ status_tratativa: (a) => PID_NCF_STATUS_TRATATIVA_RANK[a.status_tratativa] ?? 0,
+ };
+ const acoesSortHeaders = pidNcfBindSortHeaders(
+ "ncf-table-acoes",
+ () => ({ sortKey: acoesSortKey, sortDir: acoesSortDir }),
+ (key, dir) => {
+ acoesSortKey = key;
+ acoesSortDir = dir;
+ },
+ renderAcoes
+ );
async function carregarAcoes() {
const params = new URLSearchParams();
@@ -388,31 +551,65 @@ document.addEventListener("DOMContentLoaded", async () => {
if (tratativaFiltroAtual !== "todas") params.set("status_tratativa", tratativaFiltroAtual);
const query = params.toString();
acoesTodos = await pidApiRequest(`/nao-conformidades/acoes/${query ? "?" + query : ""}`);
+
+ // Opções do checklist "Tipo de Ocorrência" vêm do array cheio, ANTES de
+ // qualquer filtro de coluna/busca — recalculado só aqui (uma vez por
+ // carregamento do servidor), nunca dentro de renderAcoes(), pra
+ // desmarcar um tipo nunca fazer os outros sumirem da lista.
+ tipoOcorrenciaOpcoesDisponiveis = Array.from(
+ new Set(acoesTodos.map((a) => a.ocorrencia_tipo_ocorrencia).filter(Boolean))
+ ).sort((a, b) => a.localeCompare(b, "pt-BR", { sensitivity: "base" }));
+ tipoOcorrenciaFiltroSelecionados = new Set(
+ Array.from(tipoOcorrenciaFiltroSelecionados).filter((v) => tipoOcorrenciaOpcoesDisponiveis.includes(v))
+ );
+ renderTipoOcorrenciaChecklist();
+
renderAcoes();
}
+ function pidNcfFiltraColunaAcoes(itens) {
+ let out = itens;
+ if (tipoOcorrenciaFiltroSelecionados.size > 0) {
+ out = out.filter((a) => tipoOcorrenciaFiltroSelecionados.has(a.ocorrencia_tipo_ocorrencia));
+ }
+ if (vencimentoFiltroDe) out = out.filter((a) => a.vencimento_efetivo && a.vencimento_efetivo >= vencimentoFiltroDe);
+ if (vencimentoFiltroAte) out = out.filter((a) => a.vencimento_efetivo && a.vencimento_efetivo <= vencimentoFiltroAte);
+ return out;
+ }
+
function renderAcoes() {
- const itens = filtrarPorBusca(acoesTodos, ["executor", "ocorrencia_clientes", "ocorrencia_codigo", "acao_texto"]);
+ let itens = filtrarPorBusca(acoesTodos, ["executor", "ocorrencia_clientes", "ocorrencia_codigo", "acao_texto"]);
+ itens = pidNcfFiltraColunaAcoes(itens);
+ itens = pidNcfAplicarSort(itens, acoesSortKey, acoesSortDir, PID_NCF_ACOES_SORT_VALOR);
+ pidNcfAtualizarSortHeaders(acoesSortHeaders, acoesSortKey, acoesSortDir);
pidNcfAtualizarContador(acoesCount, itens.length);
acoesBody.innerHTML = "";
acoesEmpty.hidden = itens.length > 0;
itens.forEach((acaoItem) => {
const tratado = acaoItem.status_tratativa === "tratado";
- const { btn, trDetalhe } = pidNcfCriarLinhaExpandivel(10, (painel) => montarPainelAcao(painel, acaoItem));
+ // 11 colunas — a descrição da Ação não é mais uma coluna própria (não
+ // cabia mais na largura da tabela junto com as outras); vira uma linha
+ // full-width logo abaixo, ver trDescricao mais adiante.
+ const { btn, trDetalhe } = pidNcfCriarLinhaExpandivel(11, (painel) => montarPainelAcao(painel, acaoItem));
const tr = document.createElement("tr");
+ tr.className = "ncf-acao-main-row";
const tdBtn = document.createElement("td");
tdBtn.className = "ncf-expand-col";
tdBtn.appendChild(btn);
tr.appendChild(tdBtn);
+ const ultimoAcompHtml = acaoItem.ultimo_acompanhamento_eh_prorrogacao
+ ? ` Prorrogação`
+ : "";
tr.insertAdjacentHTML(
"beforeend",
`