feat(avaliacao): adicionar nome da comissão nas avaliações

- Adiciona campo nome_comissao em AvaliacaoComissao (entity, DTO, schema)
- Extrai nome da comissão do Elasticsearch no repository
- Propaga campo pelo job de processamento e use case
- Exibe nome da comissão no ConsultorCard (frontend)
- Remove link do manual PDF do footer
This commit is contained in:
Frederico Castro
2025-12-17 14:15:43 -03:00
parent 0f61b55944
commit 15570be9c9
12 changed files with 39 additions and 3 deletions

View File

@@ -47,6 +47,7 @@ class AvaliacaoComissaoDTO:
premio: str
ano: int
comissao_tipo: str
nome_comissao: str
@dataclass

View File

@@ -149,7 +149,8 @@ class ProcessarRankingJob:
"tipo": a.tipo,
"premio": a.premio,
"ano": a.ano,
"comissao_tipo": a.comissao_tipo
"comissao_tipo": a.comissao_tipo,
"nome_comissao": a.nome_comissao,
}
for a in consultor.avaliacoes_comissao
],

View File

@@ -109,6 +109,7 @@ class ObterRankingUseCase:
premio=a.premio,
ano=a.ano,
comissao_tipo=a.comissao_tipo,
nome_comissao=a.nome_comissao,
)
for a in consultor.avaliacoes_comissao
],

View File

@@ -44,6 +44,7 @@ class AvaliacaoComissao:
premio: str
ano: int
comissao_tipo: str = ""
nome_comissao: str = ""
@dataclass

View File

@@ -253,6 +253,7 @@ class ConsultorRepositoryImpl(ConsultorRepository):
comissao = dados.get("comissao", {}) or {}
comissao_tipo = comissao.get("tipo", "") if isinstance(comissao, dict) else ""
nome_comissao = comissao.get("nome", "") if isinstance(comissao, dict) else ""
is_grande_premio = "grande" in nome_premio.lower()
is_coordenador = "coordenador" in tipo_part.lower() or "presidente" in tipo_part.lower()
@@ -268,6 +269,7 @@ class ConsultorRepositoryImpl(ConsultorRepository):
premio=nome_premio,
ano=ano,
comissao_tipo=comissao_tipo,
nome_comissao=nome_comissao,
))
return avaliacoes

View File

@@ -1,9 +1,11 @@
import logging
import json
import asyncio
from pathlib import Path
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from contextlib import asynccontextmanager
from .routes import router
@@ -147,6 +149,10 @@ app.add_middleware(
app.include_router(router)
static_dir = Path(__file__).parent.parent.parent.parent / "static"
if static_dir.exists():
app.mount("/api/static", StaticFiles(directory=str(static_dir)), name="static")
@app.get("/")
async def root():

View File

@@ -42,6 +42,7 @@ class AvaliacaoComissaoSchema(BaseModel):
premio: str
ano: int
comissao_tipo: str
nome_comissao: str = ""
class PremiacaoSchema(BaseModel):

Binary file not shown.

View File

@@ -22,6 +22,7 @@ services:
volumes:
- ./backend/src:/app/src
- ./backend/scripts:/app/scripts
- ./backend/static:/app/static
- /etc/localtime:/etc/localtime:ro
networks:
- shared_network

View File

@@ -194,6 +194,28 @@ footer p + p {
font-size: 0.8rem;
}
.manual-link {
display: inline-flex;
align-items: center;
gap: 0.5rem;
margin-top: 1rem;
padding: 0.6rem 1.2rem;
background: linear-gradient(145deg, var(--accent), var(--accent-2));
color: white;
text-decoration: none;
border-radius: 8px;
font-weight: 600;
font-size: 0.9rem;
transition: all 200ms ease;
box-shadow: 0 4px 12px rgba(79, 70, 229, 0.3);
}
.manual-link:hover {
filter: brightness(1.1);
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(79, 70, 229, 0.4);
}
.selecao-flutuante {
position: fixed;
bottom: 2rem;

View File

@@ -262,7 +262,7 @@ function App() {
<footer>
<p>Dados: ATUACAPES (Elasticsearch) + Oracle</p>
<p>Critérios: Minuta Técnica - Ranking AtuaCAPES | Clique em qualquer consultor para ver detalhes</p>
<p>Clique em qualquer consultor para ver detalhes</p>
</footer>
</div>
);

View File

@@ -388,7 +388,7 @@ const ConsultorCard = memo(({ consultor, highlight, selecionado, onToggleSelecio
<div key={idx} className="list-item">
<span className="badge">{aval.codigo}</span>
<span className="pontos">{PONTOS_BASE[aval.codigo] || 0} pts</span>
<span>{aval.premio}</span>
<span>{aval.nome_comissao || aval.premio}</span>
<span className="muted">{aval.ano}</span>
</div>
))}