diff --git a/backend/src/interface/api/routes.py b/backend/src/interface/api/routes.py index 353d100..6d86cb4 100644 --- a/backend/src/interface/api/routes.py +++ b/backend/src/interface/api/routes.py @@ -157,14 +157,44 @@ def _consultor_resumo_from_ranking(c): except Exception: pass + # Ajusta pontuação detalhada para refletir os valores atuais do ranking (incluindo COMPONENTE_B), + # já que o JSON pode ter sido gerado antes do job de preenchimento do Componente B. + pontuacao_total = float(c.pontuacao_total or 0) + bloco_a = float(c.componente_a or 0) + bloco_b = float(c.componente_b or 0) + bloco_c = float(c.componente_c or 0) + bloco_d = float(c.componente_d or 0) + + if isinstance(pontuacao, dict): + pontuacao_ajustada = dict(pontuacao) + else: + pontuacao_ajustada = {} + + def _ajustar_bloco(chave: str, total: float, letra: str): + b = pontuacao_ajustada.get(chave) + if isinstance(b, dict): + b2 = dict(b) + b2["bloco"] = letra + b2["total"] = total + pontuacao_ajustada[chave] = b2 + else: + pontuacao_ajustada[chave] = {"bloco": letra, "total": total, "atuacoes": []} + + _ajustar_bloco("bloco_a", bloco_a, "A") + _ajustar_bloco("bloco_b", bloco_b, "B") + _ajustar_bloco("bloco_c", bloco_c, "C") + _ajustar_bloco("bloco_d", bloco_d, "D") + pontuacao_ajustada["pontuacao_total"] = pontuacao_total + return ConsultorRankingResumoSchema( id_pessoa=c.id_pessoa, nome=c.nome, posicao=c.posicao, - pontuacao_total=c.pontuacao_total, - bloco_a=c.componente_a, - bloco_c=c.componente_c, - bloco_d=c.componente_d, + pontuacao_total=pontuacao_total, + bloco_a=bloco_a, + bloco_b=bloco_b, + bloco_c=bloco_c, + bloco_d=bloco_d, ativo=c.ativo, anos_atuacao=c.anos_atuacao, consultoria=consultoria, @@ -176,7 +206,7 @@ def _consultor_resumo_from_ranking(c): participacoes=participacoes, orientacoes=orientacoes, membros_banca=membros_banca, - pontuacao=pontuacao, + pontuacao=pontuacao_ajustada if pontuacao_ajustada else None, ) diff --git a/backend/src/interface/schemas/ranking_schema.py b/backend/src/interface/schemas/ranking_schema.py index 1d39d73..9d63d8c 100644 --- a/backend/src/interface/schemas/ranking_schema.py +++ b/backend/src/interface/schemas/ranking_schema.py @@ -9,6 +9,7 @@ class ConsultorRankingResumoSchema(BaseModel): posicao: Optional[int] pontuacao_total: float bloco_a: float + bloco_b: float bloco_c: float bloco_d: float ativo: bool diff --git a/docker-compose.yml b/docker-compose.yml index 4e88af8..0106f60 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,6 +8,8 @@ services: - "8010:8000" env_file: - ./backend/.env + extra_hosts: + - "host.docker.internal:host-gateway" environment: - API_HOST=0.0.0.0 - API_PORT=8000 diff --git a/frontend/src/components/CompararModal.jsx b/frontend/src/components/CompararModal.jsx index 0f6d1b5..1758951 100644 --- a/frontend/src/components/CompararModal.jsx +++ b/frontend/src/components/CompararModal.jsx @@ -35,13 +35,15 @@ const CompararModal = ({ consultor1, consultor2, onClose }) => { const blocoA1 = p1.bloco_a || { total: consultor1.bloco_a || 0 }; const blocoA2 = p2.bloco_a || { total: consultor2.bloco_a || 0 }; + const blocoB1 = p1.bloco_b || { total: consultor1.bloco_b || 0 }; + const blocoB2 = p2.bloco_b || { total: consultor2.bloco_b || 0 }; const blocoC1 = p1.bloco_c || { total: consultor1.bloco_c || 0 }; const blocoC2 = p2.bloco_c || { total: consultor2.bloco_c || 0 }; const blocoD1 = p1.bloco_d || { total: consultor1.bloco_d || 0 }; const blocoD2 = p2.bloco_d || { total: consultor2.bloco_d || 0 }; - const total1 = p1.pontuacao_total || consultor1.pontuacao_total || 0; - const total2 = p2.pontuacao_total || consultor2.pontuacao_total || 0; + const total1 = (blocoA1.total || 0) + (blocoB1.total || 0) + (blocoC1.total || 0) + (blocoD1.total || 0); + const total2 = (blocoA2.total || 0) + (blocoB2.total || 0) + (blocoC2.total || 0) + (blocoD2.total || 0); const c1 = consultor1.consultoria; const c2 = consultor2.consultoria; @@ -97,6 +99,11 @@ const CompararModal = ({ consultor1, consultor2, onClose }) => { )} +
+

B - Coordenacao PPG

+ {renderLinhaComparacao('Total', blocoB1.total, blocoB2.total, 'var(--accent)')} +
+

C - Consultoria

{renderLinhaComparacao('Total', blocoC1.total, blocoC2.total, 'var(--gold)')} diff --git a/frontend/src/components/ConsultorCard.jsx b/frontend/src/components/ConsultorCard.jsx index 2eabedd..c0c8beb 100644 --- a/frontend/src/components/ConsultorCard.jsx +++ b/frontend/src/components/ConsultorCard.jsx @@ -6,6 +6,10 @@ const FORMULAS = { titulo: 'Coordenacao CAPES', descricao: 'CA=200 | CAJ=150 | CAJ_MP=120 | CAM=100\nTempo: multiplicador por ano\nBonus atualidade + Retorno', }, + bloco_b: { + titulo: 'Coordenacao PPG', + descricao: 'Base=70 | Tempo=5 pts/ano (max 50)\nExtras por programas distintos (max 40)\nBonus por maior nota do programa (max 20)', + }, bloco_c: { titulo: 'Consultoria', descricao: 'CONS_ATIVO=150 | CONS_HIST=100 | CONS_FALECIDO=100\nTempo: 5 pts/ano (max 50)\nContinuidade 8a+=15 | Retorno=15', @@ -30,6 +34,28 @@ const PONTOS_BASE = { MB_BANCA_POS_DOC: 3, MB_BANCA_TESE: 3, MB_BANCA_DISS: 2, }; +// Teto oficial por código, conforme documento de critérios (seção 3.x) +const TETOS = { + // 3.3 Inscrições + INSC_AUTOR: { teto: 20, doc: '3.3 Inscrições' }, + INSC_INST: { teto: 60, doc: '3.3 Inscrições' }, + // 3.4 Avaliação / Coordenação de Comissão + AVAL_COMIS_PREMIO: { teto: 60, doc: '3.4 Avaliação/Comissão' }, + AVAL_COMIS_GP: { teto: 100, doc: '3.4 Avaliação/Comissão' }, + COORD_COMIS_PREMIO: { teto: 100, doc: '3.4 Avaliação/Comissão' }, + COORD_COMIS_GP: { teto: 120, doc: '3.4 Avaliação/Comissão' }, + // 3.6 Premiações + PREMIACAO: { teto: 180, doc: '3.6 Premiações' }, + PREMIACAO_GP: { teto: 60, doc: '3.6 Premiações' }, + MENCAO: { teto: 20, doc: '3.6 Premiações' }, + // 3.7 Participações + EVENTO: { teto: 5, doc: '3.7 Participações' }, + PROJ: { teto: 40, doc: '3.7 Participações' }, + // 3.5 Bolsas CNPQ (nomes resumidos) + BOL_BPQ_SUPERIOR: { teto: 60, doc: '3.5 Bolsas CNPQ' }, + BOL_BPQ_INTERMEDIARIO: { teto: 100, doc: '3.5 Bolsas CNPQ' }, +}; + const ScoreItemWithTooltip = ({ value, label, formula, style }) => (
@@ -71,9 +97,10 @@ const ConsultorCard = ({ consultor, highlight, selecionado, onToggleSelecionado const { consultoria, pontuacao } = consultor; const blocoA = pontuacao?.bloco_a || { total: consultor.bloco_a || 0 }; + const blocoB = pontuacao?.bloco_b || { total: consultor.bloco_b || 0 }; const blocoC = pontuacao?.bloco_c || { total: consultor.bloco_c || 0 }; const blocoD = pontuacao?.bloco_d || { total: consultor.bloco_d || 0 }; - const pontuacaoTotal = pontuacao?.pontuacao_total || consultor.pontuacao_total || 0; + const pontuacaoTotal = (blocoA.total || 0) + (blocoB.total || 0) + (blocoC.total || 0) + (blocoD.total || 0); return (
setExpanded(!expanded)}> @@ -134,6 +161,12 @@ const ConsultorCard = ({ consultor, highlight, selecionado, onToggleSelecionado formula={FORMULAS.bloco_a.descricao} style={{ color: blocoA.total > 0 ? 'var(--accent-2)' : 'var(--muted)' }} /> + 0 ? 'var(--accent)' : 'var(--muted)' }} + /> {pontuacaoTotal}
TOTAL
-
Bloco A + Bloco C + Bloco D
+
Bloco A + Bloco B + Bloco C + Bloco D
@@ -160,6 +193,10 @@ const ConsultorCard = ({ consultor, highlight, selecionado, onToggleSelecionado )} + {(blocoB.total > 0 || (blocoB.atuacoes && blocoB.atuacoes.length > 0)) && ( + + )} + {blocoC.atuacoes && blocoC.atuacoes.length > 0 && ( )} @@ -270,8 +307,30 @@ const BlocoDetalhes = ({ titulo, bloco, cor }) => (
{at.codigo}
- Base: {at.base} | Tempo: {at.tempo} | Bonus: {at.bonus} - {at.quantidade > 1 && ` | Qtd: ${at.quantidade}`} + {(() => { + const base = at.base || 0; + const tempo = at.tempo || 0; + const bonus = at.bonus || 0; + const bruto = base + tempo + bonus; + const meta = TETOS[at.codigo]; + const capped = bruto !== at.total; + const unidade = at.quantidade > 1 ? Math.round(base / at.quantidade) : null; + + const partes = []; + partes.push( + unidade + ? `Base ${unidade} x ${at.quantidade} = ${base}` + : `Base ${base}` + ); + if (capped) { + partes.push(`Bruto ${bruto}`); + } + if (tempo) partes.push(`Tempo ${tempo}`); + if (bonus) partes.push(`Bônus ${bonus}`); + if (meta) partes.push(`Teto ${meta.teto}`); + partes.push(capped && meta ? `Total ${at.total} (teto)` : `Total ${at.total}`); + return partes.join(" | "); + })()}
))} diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index 4c78249..3c902af 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -44,6 +44,7 @@ export const rankingService = { posicao: c.posicao, pontuacao_total: c.pontuacao_total, bloco_a: c.bloco_a, + bloco_b: c.bloco_b, bloco_c: c.bloco_c, bloco_d: c.bloco_d, ativo: c.ativo, @@ -52,6 +53,7 @@ export const rankingService = { pontuacao: c.pontuacao || { pontuacao_total: c.pontuacao_total, bloco_a: { total: c.bloco_a, atuacoes: [] }, + bloco_b: { total: c.bloco_b, atuacoes: [] }, bloco_c: { total: c.bloco_c, atuacoes: [] }, bloco_d: { total: c.bloco_d, atuacoes: [] }, },