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: [] },
},