feat(filtros): adicionar filtro multi-select por selos no ranking

- Backend: extrair selos de detalhes e filtrar por eles
- API: endpoint /ranking/selos e parâmetro selos em /ranking/paginado
- Frontend: componente FiltroSelos com dropdown e seleção múltipla
- Selos disponíveis: funções, premiações, orientações
This commit is contained in:
Frederico Castro
2025-12-15 12:32:24 -03:00
parent d215e9ac76
commit c294d4cc77
6 changed files with 527 additions and 11 deletions

View File

@@ -3,7 +3,82 @@ from __future__ import annotations
import asyncio
from dataclasses import dataclass
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
from typing import Any, Dict, List, Optional, Set, Tuple
SELOS_DISPONIVEIS = [
"PRESID_CAMARA",
"COORD_PPG",
"BPQ",
"AUTOR_GP",
"AUTOR_PREMIO",
"AUTOR_MENCAO",
"ORIENT_GP",
"ORIENT_PREMIO",
"ORIENT_MENCAO",
"COORIENT_GP",
"COORIENT_PREMIO",
"COORIENT_MENCAO",
"ORIENT_POS_DOC",
"ORIENT_TESE",
"ORIENT_DISS",
"CO_ORIENT_POS_DOC",
"CO_ORIENT_TESE",
"CO_ORIENT_DISS",
]
def extrair_selos_entry(detalhes: Dict[str, Any]) -> Set[str]:
selos = set()
for c in detalhes.get("coordenacoes_capes", []):
if c.get("presidente"):
selos.add("PRESID_CAMARA")
if detalhes.get("coordenador_ppg"):
selos.add("COORD_PPG")
if detalhes.get("bolsas_cnpq"):
selos.add("BPQ")
for prem in detalhes.get("premiacoes", []):
papel = (prem.get("papel") or "").lower()
codigo = prem.get("codigo", "")
if "GP" in codigo or "grande" in codigo.lower():
tipo_prem = "GP"
elif "MENCAO" in codigo or "menção" in codigo.lower():
tipo_prem = "MENCAO"
else:
tipo_prem = "PREMIO"
if "autor" in papel:
selos.add(f"AUTOR_{tipo_prem}")
elif "orientador" in papel:
selos.add(f"ORIENT_{tipo_prem}")
elif "coorientador" in papel or "co-orientador" in papel:
selos.add(f"COORIENT_{tipo_prem}")
for orient in detalhes.get("orientacoes", []):
codigo = orient.get("codigo", "")
is_coorient = orient.get("coorientacao", False)
if is_coorient:
if "POS_DOC" in codigo:
selos.add("CO_ORIENT_POS_DOC")
elif "TESE" in codigo:
selos.add("CO_ORIENT_TESE")
elif "DISS" in codigo:
selos.add("CO_ORIENT_DISS")
else:
if "POS_DOC" in codigo:
selos.add("ORIENT_POS_DOC")
elif "TESE" in codigo:
selos.add("ORIENT_TESE")
elif "DISS" in codigo:
selos.add("ORIENT_DISS")
return selos
@dataclass(frozen=True)
@@ -51,17 +126,28 @@ class RankingStore:
return sum(1 for e in self._entries if e.ativo == filtro_ativo)
def get_page(
self, page: int, size: int, filtro_ativo: Optional[bool] = None
self,
page: int,
size: int,
filtro_ativo: Optional[bool] = None,
filtro_selos: Optional[List[str]] = None,
) -> Tuple[int, List[RankingEntry]]:
if page < 1:
page = 1
if size < 1:
size = 1
if filtro_ativo is None:
entries = self._entries
else:
entries = [e for e in self._entries if e.ativo == filtro_ativo]
entries = self._entries
if filtro_ativo is not None:
entries = [e for e in entries if e.ativo == filtro_ativo]
if filtro_selos:
selos_set = set(filtro_selos)
entries = [
e for e in entries
if selos_set & extrair_selos_entry(e.detalhes)
]
total = len(entries)
start = (page - 1) * size