Adiciona suporte ao Bloco B (Coordenacao PPG) e melhora tooltips

- Adiciona Bloco B no ConsultorCard com formula e detalhes
- Ajusta calculo de pontuacao total para incluir Bloco B
- Melhora tooltips com informacoes de teto e calculo detalhado
- Ajusta routes.py para preencher blocos corretamente
- Adiciona bloco_b no schema de ranking
This commit is contained in:
Frederico Castro
2025-12-14 20:31:47 -03:00
parent 0707c14e05
commit 7000268261
6 changed files with 112 additions and 11 deletions

View File

@@ -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 }) => {
)}
</div>
<div className="comparacao-secao">
<h3 style={{ color: 'var(--accent)' }}>B - Coordenacao PPG</h3>
{renderLinhaComparacao('Total', blocoB1.total, blocoB2.total, 'var(--accent)')}
</div>
<div className="comparacao-secao">
<h3 style={{ color: 'var(--gold)' }}>C - Consultoria</h3>
{renderLinhaComparacao('Total', blocoC1.total, blocoC2.total, 'var(--gold)')}

View File

@@ -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 }) => (
<div className="score-item-wrapper">
<div className="score-item" style={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 (
<div ref={cardRef} className={`ranking-card ${expanded ? 'expanded' : ''} ${highlight ? 'highlight' : ''} ${selecionado ? 'selecionado' : ''}`} onClick={() => 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)' }}
/>
<ScoreItemWithTooltip
value={blocoB.total}
label="BLOCO B"
formula={FORMULAS.bloco_b.descricao}
style={{ color: blocoB.total > 0 ? 'var(--accent)' : 'var(--muted)' }}
/>
<ScoreItemWithTooltip
value={blocoC.total}
label="BLOCO C"
@@ -151,7 +184,7 @@ const ConsultorCard = ({ consultor, highlight, selecionado, onToggleSelecionado
<div className="score-item-value">{pontuacaoTotal}</div>
<div className="score-item-label">TOTAL</div>
</div>
<div className="score-tooltip">Bloco A + Bloco C + Bloco D</div>
<div className="score-tooltip">Bloco A + Bloco B + Bloco C + Bloco D</div>
</div>
</div>
</div>
@@ -160,6 +193,10 @@ const ConsultorCard = ({ consultor, highlight, selecionado, onToggleSelecionado
<BlocoDetalhes titulo="A - Coordenacao CAPES" bloco={blocoA} cor="var(--accent-2)" />
)}
{(blocoB.total > 0 || (blocoB.atuacoes && blocoB.atuacoes.length > 0)) && (
<BlocoDetalhes titulo="B - Coordenacao PPG" bloco={blocoB} cor="var(--accent)" />
)}
{blocoC.atuacoes && blocoC.atuacoes.length > 0 && (
<BlocoDetalhes titulo="C - Consultoria" bloco={blocoC} cor="var(--gold)" />
)}
@@ -270,8 +307,30 @@ const BlocoDetalhes = ({ titulo, bloco, cor }) => (
<div className="score-item-label">{at.codigo}</div>
</div>
<div className="score-tooltip">
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(" | ");
})()}
</div>
</div>
))}

View File

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