Reimplementa sistema de ranking com novos critérios V2
Mudanças principais: - Substitui 4 Componentes (A,B,C,D) por 3 Blocos (A,C,D) - Remove Componente B (Coordenação PPG = 0 pts no V1) - Adiciona novos tipos de atuação do Elasticsearch - Implementa critérios de pontuação com tetos individuais Bloco A - Coordenação CAPES: - CA (max 450), CAJ (max 370), CAJ_MP (max 315), CAM (max 280) - Calcula base + tempo + bônus atualidade + bônus retorno Bloco C - Consultoria: - CONS_ATIVO (base 150), CONS_HIST (base 100), CONS_FALECIDO (base 100) - Bônus continuidade: 3anos=+5, 5anos=+10, 8anos=+15 - Bônus retorno: +15 Bloco D - Premiações/Avaliações: - Inscrições (INSC_AUTOR, INSC_INST) - Avaliações (AVAL_COMIS_PREMIO, AVAL_COMIS_GP) - Coordenações (COORD_COMIS_PREMIO, COORD_COMIS_GP) - Premiações (PREMIACAO, PREMIACAO_GP, MENCAO) - Bolsas CNPQ, Participações, Orientações, Membros de Banca Frontend: - Header, ConsultorCard, CompararModal atualizados para 3 blocos - API service atualizado para nova estrutura de dados
This commit is contained in:
@@ -31,7 +31,7 @@ async def obter_ranking(
|
||||
limite: int = Query(default=100, ge=1, le=1000, description="Limite de consultores"),
|
||||
offset: int = Query(default=0, ge=0, description="Offset para paginação"),
|
||||
componente: Optional[str] = Query(
|
||||
default=None, description="Filtrar por componente (a, b, c, d)"
|
||||
default=None, description="Filtrar por bloco (a, c, d)"
|
||||
),
|
||||
repository: ConsultorRepositoryImpl = Depends(get_repository),
|
||||
):
|
||||
@@ -53,7 +53,7 @@ async def obter_ranking(
|
||||
async def obter_ranking_detalhado(
|
||||
limite: int = Query(default=100, ge=1, le=1000, description="Limite de consultores"),
|
||||
componente: Optional[str] = Query(
|
||||
default=None, description="Filtrar por componente (a, b, c, d)"
|
||||
default=None, description="Filtrar por bloco (a, c, d)"
|
||||
),
|
||||
repository: ConsultorRepositoryImpl = Depends(get_repository),
|
||||
):
|
||||
@@ -95,9 +95,6 @@ async def ranking_paginado(
|
||||
ativo: Optional[bool] = Query(default=None, description="Filtrar por status ativo"),
|
||||
ranking_repo = Depends(get_ranking_repository),
|
||||
):
|
||||
"""
|
||||
Retorna ranking paginado do Oracle (pré-calculado).
|
||||
"""
|
||||
total = ranking_repo.contar_total(filtro_ativo=ativo)
|
||||
consultores = ranking_repo.buscar_paginado(page=page, size=size, filtro_ativo=ativo)
|
||||
|
||||
@@ -132,50 +129,51 @@ async def buscar_por_nome(
|
||||
]
|
||||
|
||||
|
||||
def _calcular_continuidade(anos_consecutivos: int) -> int:
|
||||
if anos_consecutivos >= 8:
|
||||
return 15
|
||||
elif anos_consecutivos >= 5:
|
||||
return 10
|
||||
elif anos_consecutivos >= 3:
|
||||
return 5
|
||||
return 0
|
||||
|
||||
|
||||
def _consultor_resumo_from_ranking(c):
|
||||
consultoria = None
|
||||
coordenacoes_capes = None
|
||||
coordenacoes_programas = None
|
||||
inscricoes = None
|
||||
avaliacoes_comissao = None
|
||||
premiacoes = None
|
||||
bolsas_cnpq = None
|
||||
participacoes = None
|
||||
orientacoes = None
|
||||
membros_banca = None
|
||||
|
||||
try:
|
||||
jd = json.loads(c.json_detalhes) if c.json_detalhes else {}
|
||||
if isinstance(jd, dict):
|
||||
consultoria = jd.get("consultoria")
|
||||
coordenacoes_capes = jd.get("coordenacoes_capes")
|
||||
coordenacoes_programas = jd.get("coordenacoes_programas")
|
||||
inscricoes = jd.get("inscricoes")
|
||||
avaliacoes_comissao = jd.get("avaliacoes_comissao")
|
||||
premiacoes = jd.get("premiacoes")
|
||||
if consultoria and isinstance(consultoria, dict):
|
||||
anos_consec = consultoria.get("anos_consecutivos") or consultoria.get("anos_completos") or 0
|
||||
consultoria["continuidade"] = _calcular_continuidade(anos_consec)
|
||||
consultoria["anos_consecutivos"] = anos_consec
|
||||
bolsas_cnpq = jd.get("bolsas_cnpq")
|
||||
participacoes = jd.get("participacoes")
|
||||
orientacoes = jd.get("orientacoes")
|
||||
membros_banca = jd.get("membros_banca")
|
||||
except Exception:
|
||||
consultoria = None
|
||||
pass
|
||||
|
||||
return ConsultorRankingResumoSchema(
|
||||
id_pessoa=c.id_pessoa,
|
||||
nome=c.nome,
|
||||
posicao=c.posicao,
|
||||
pontuacao_total=c.pontuacao_total,
|
||||
componente_a=c.componente_a,
|
||||
componente_b=c.componente_b,
|
||||
componente_c=c.componente_c,
|
||||
componente_d=c.componente_d,
|
||||
bloco_a=c.componente_a,
|
||||
bloco_c=c.componente_c,
|
||||
bloco_d=c.componente_d,
|
||||
ativo=c.ativo,
|
||||
anos_atuacao=c.anos_atuacao,
|
||||
consultoria=consultoria,
|
||||
coordenacoes_capes=coordenacoes_capes,
|
||||
coordenacoes_programas=coordenacoes_programas,
|
||||
inscricoes=inscricoes,
|
||||
avaliacoes_comissao=avaliacoes_comissao,
|
||||
premiacoes=premiacoes,
|
||||
bolsas_cnpq=bolsas_cnpq,
|
||||
participacoes=participacoes,
|
||||
orientacoes=orientacoes,
|
||||
membros_banca=membros_banca,
|
||||
)
|
||||
|
||||
|
||||
@@ -183,23 +181,24 @@ def _consultor_resumo_from_ranking(c):
|
||||
async def ranking_estatisticas(
|
||||
ranking_repo = Depends(get_ranking_repository),
|
||||
):
|
||||
"""
|
||||
Retorna estatísticas do ranking.
|
||||
"""
|
||||
estatisticas = ranking_repo.obter_estatisticas()
|
||||
distribuicao = ranking_repo.obter_distribuicao()
|
||||
|
||||
return EstatisticasRankingSchema(
|
||||
**estatisticas,
|
||||
total_consultores=estatisticas.get("total_consultores", 0),
|
||||
total_ativos=estatisticas.get("total_ativos", 0),
|
||||
total_inativos=estatisticas.get("total_inativos", 0),
|
||||
ultima_atualizacao=estatisticas.get("ultima_atualizacao"),
|
||||
pontuacao_media=estatisticas.get("pontuacao_media", 0),
|
||||
pontuacao_maxima=estatisticas.get("pontuacao_maxima", 0),
|
||||
pontuacao_minima=estatisticas.get("pontuacao_minima", 0),
|
||||
media_blocos=estatisticas.get("media_componentes", {}),
|
||||
distribuicao=distribuicao
|
||||
)
|
||||
|
||||
|
||||
@router.get("/ranking/status", response_model=JobStatusSchema)
|
||||
async def status_processamento():
|
||||
"""
|
||||
Retorna o status do job de processamento do ranking.
|
||||
"""
|
||||
return JobStatusSchema(**job_status.to_dict())
|
||||
|
||||
|
||||
@@ -209,9 +208,6 @@ async def processar_ranking(
|
||||
request: ProcessarRankingRequestSchema = ProcessarRankingRequestSchema(),
|
||||
job = Depends(get_processar_job),
|
||||
):
|
||||
"""
|
||||
Dispara o processamento do ranking em background.
|
||||
"""
|
||||
if job_status.is_running:
|
||||
raise HTTPException(status_code=409, detail="Job já está em execução")
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ class PeriodoSchema(BaseModel):
|
||||
|
||||
|
||||
class CoordenacaoCapesSchema(BaseModel):
|
||||
codigo: str
|
||||
tipo: str
|
||||
area_avaliacao: str
|
||||
periodo: PeriodoSchema
|
||||
@@ -17,51 +18,84 @@ class CoordenacaoCapesSchema(BaseModel):
|
||||
ja_coordenou_antes: bool
|
||||
|
||||
|
||||
class CoordenacaoProgramaSchema(BaseModel):
|
||||
id_programa: int
|
||||
nome_programa: str
|
||||
codigo_programa: str
|
||||
nota_ppg: str
|
||||
modalidade: str
|
||||
area_avaliacao: str
|
||||
periodo: PeriodoSchema
|
||||
|
||||
|
||||
class ConsultoriaSchema(BaseModel):
|
||||
total_eventos: int
|
||||
eventos_recentes: int
|
||||
primeiro_evento: str
|
||||
ultimo_evento: str
|
||||
continuidade: int
|
||||
areas: List[str]
|
||||
codigo: str
|
||||
situacao: str
|
||||
anos_completos: int
|
||||
periodo: PeriodoSchema
|
||||
areas: List[str]
|
||||
anos_consecutivos: int
|
||||
retornos: int
|
||||
vezes_responsavel: int
|
||||
|
||||
|
||||
class InscricaoSchema(BaseModel):
|
||||
codigo: str
|
||||
tipo: str
|
||||
premio: str
|
||||
ano: int
|
||||
situacao: str
|
||||
|
||||
|
||||
class AvaliacaoComissaoSchema(BaseModel):
|
||||
codigo: str
|
||||
tipo: str
|
||||
premio: str
|
||||
ano: int
|
||||
comissao_tipo: str
|
||||
|
||||
|
||||
class PremiacaoSchema(BaseModel):
|
||||
codigo: str
|
||||
tipo: str
|
||||
nome_premio: str
|
||||
ano: int
|
||||
pontos: int
|
||||
|
||||
|
||||
class ComponentePontuacaoSchema(BaseModel):
|
||||
class BolsaCNPQSchema(BaseModel):
|
||||
codigo: str
|
||||
nivel: str
|
||||
area: str
|
||||
|
||||
|
||||
class ParticipacaoSchema(BaseModel):
|
||||
codigo: str
|
||||
tipo: str
|
||||
descricao: str
|
||||
ano: Optional[int] = None
|
||||
|
||||
|
||||
class OrientacaoSchema(BaseModel):
|
||||
codigo: str
|
||||
tipo: str
|
||||
nivel: str
|
||||
ano: Optional[int] = None
|
||||
|
||||
|
||||
class MembroBancaSchema(BaseModel):
|
||||
codigo: str
|
||||
tipo: str
|
||||
nivel: str
|
||||
ano: Optional[int] = None
|
||||
|
||||
|
||||
class PontuacaoAtuacaoSchema(BaseModel):
|
||||
codigo: str
|
||||
base: int
|
||||
tempo: int
|
||||
extras: int
|
||||
bonus: int
|
||||
retorno: int
|
||||
total: int
|
||||
quantidade: int
|
||||
|
||||
|
||||
class PontuacaoBlocoSchema(BaseModel):
|
||||
bloco: str
|
||||
total: int
|
||||
atuacoes: List[PontuacaoAtuacaoSchema]
|
||||
|
||||
|
||||
class PontuacaoCompletaSchema(BaseModel):
|
||||
componente_a: ComponentePontuacaoSchema
|
||||
componente_b: ComponentePontuacaoSchema
|
||||
componente_c: ComponentePontuacaoSchema
|
||||
componente_d: ComponentePontuacaoSchema
|
||||
bloco_a: PontuacaoBlocoSchema
|
||||
bloco_c: PontuacaoBlocoSchema
|
||||
bloco_d: PontuacaoBlocoSchema
|
||||
pontuacao_total: int
|
||||
|
||||
|
||||
@@ -72,6 +106,9 @@ class ConsultorResumoSchema(BaseModel):
|
||||
ativo: bool
|
||||
veterano: bool
|
||||
pontuacao_total: int
|
||||
bloco_a: int
|
||||
bloco_c: int
|
||||
bloco_d: int
|
||||
rank: Optional[int] = None
|
||||
|
||||
|
||||
@@ -83,9 +120,14 @@ class ConsultorDetalhadoSchema(BaseModel):
|
||||
ativo: bool
|
||||
veterano: bool
|
||||
coordenacoes_capes: List[CoordenacaoCapesSchema]
|
||||
coordenacoes_programas: List[CoordenacaoProgramaSchema]
|
||||
consultoria: Optional[ConsultoriaSchema] = None
|
||||
inscricoes: List[InscricaoSchema]
|
||||
avaliacoes_comissao: List[AvaliacaoComissaoSchema]
|
||||
premiacoes: List[PremiacaoSchema]
|
||||
bolsas_cnpq: List[BolsaCNPQSchema]
|
||||
participacoes: List[ParticipacaoSchema]
|
||||
orientacoes: List[OrientacaoSchema]
|
||||
membros_banca: List[MembroBancaSchema]
|
||||
pontuacao: PontuacaoCompletaSchema
|
||||
rank: Optional[int] = None
|
||||
|
||||
|
||||
@@ -8,16 +8,20 @@ class ConsultorRankingResumoSchema(BaseModel):
|
||||
nome: str
|
||||
posicao: Optional[int]
|
||||
pontuacao_total: float
|
||||
componente_a: float
|
||||
componente_b: float
|
||||
componente_c: float
|
||||
componente_d: float
|
||||
bloco_a: float
|
||||
bloco_c: float
|
||||
bloco_d: float
|
||||
ativo: bool
|
||||
anos_atuacao: float
|
||||
consultoria: Optional[dict] = None
|
||||
coordenacoes_capes: Optional[list] = None
|
||||
coordenacoes_programas: Optional[list] = None
|
||||
inscricoes: Optional[list] = None
|
||||
avaliacoes_comissao: Optional[list] = None
|
||||
premiacoes: Optional[list] = None
|
||||
bolsas_cnpq: Optional[list] = None
|
||||
participacoes: Optional[list] = None
|
||||
orientacoes: Optional[list] = None
|
||||
membros_banca: Optional[list] = None
|
||||
|
||||
|
||||
class RankingPaginadoResponseSchema(BaseModel):
|
||||
@@ -36,7 +40,7 @@ class EstatisticasRankingSchema(BaseModel):
|
||||
pontuacao_media: float
|
||||
pontuacao_maxima: float
|
||||
pontuacao_minima: float
|
||||
media_componentes: dict
|
||||
media_blocos: dict
|
||||
distribuicao: List[dict]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user