feat: extrair docencias PPG e simplificar blocos de pontuacao

Backend:
- Adicionar entidade DocenciaPPG para dados de docencia
- Extrair docencias do Elasticsearch (tipo "Docência")
- Serializar docencias no JSON de detalhes do consultor
- Aumentar batch size de 500 para 2000 para melhor performance

Frontend:
- Remover Bloco B (Coord. PPG) - reservado para V2
- Simplificar formula para: Bloco A + Bloco C + Bloco D
- Filtrar orientacoes/bancas da listagem (sao apenas selos)
- Atualizar Header com nota que PPG_COORD e apenas indicador
- Exibir pontuacao base nos modais de orientacao/banca
This commit is contained in:
Frederico Castro
2025-12-23 04:27:36 -03:00
parent d33695ed65
commit 8799a68c30
11 changed files with 154 additions and 123 deletions

View File

@@ -818,8 +818,8 @@ const ItemDetalheModal = ({ item, tipo, onClose }) => {
</div>
)}
<div className="modal-detalhe-row">
<span className="modal-detalhe-label">Pontuação</span>
<span className="modal-detalhe-value muted">Apenas selo (sem pontuação)</span>
<span className="modal-detalhe-label">Pontuação Base</span>
<span className="modal-detalhe-value pontos">{PONTOS_BASE[item.codigo] || 0} pts</span>
</div>
</div>
);
@@ -853,17 +853,13 @@ const FORMULAS = {
titulo: 'Coordenacao CAPES',
descricao: 'CA=200 | CAJ=150 | CAJ_MP=120 | CAM=100\nTempo: multiplicador por ano (anos completos)\nBônus atualidade (mandato vigente) + Retorno (mandato anterior)',
},
bloco_b: {
titulo: 'Coordenacao PPG',
descricao: 'Reservado no V1: PPG_COORD base=0 | teto=0 (dados incompletos no ATUACAPES para pontuar).',
},
bloco_c: {
titulo: 'Consultoria',
descricao: 'CONS_ATIVO=150 | CONS_HIST=100 | CONS_FALECIDO=100\nTempo: 5 pts/ano (max 50)\nContinuidade: 3a=+5, 5a=+10, 8a+=+20 (escalonado)\nRetorno (reativação): +15 (uma vez)',
},
bloco_d: {
titulo: 'Premiacoes/Avaliacoes',
descricao: 'Premiações: GP=100 (teto 300) | Prêmio=50 (teto 150) | Menção=30 (teto 90)\nBolsas: BPQ=30 (teto 60)\nInscrições/Avaliações/Comissões/Participações (com tetos por código)\nOrientações/Bancas: apenas selos (0 pts)',
descricao: 'Premiações: GP=100 (teto 300) | Prêmio=50 (teto 150) | Menção=30 (teto 90)\nBolsas: BPQ=30 (teto 60)\nInscrições/Avaliações/Comissões/Participações (com tetos por código)\nOrientações e Bancas: apenas selos (sem pontuação)',
},
};
@@ -876,9 +872,6 @@ const PONTOS_BASE = {
PREMIACAO_GP_AUTOR: 100, PREMIACAO_AUTOR: 50, MENCAO_AUTOR: 30,
BOL_BPQ_NIVEL: 30,
EVENTO: 1, PROJ: 10,
ORIENT_POS_DOC: 0, ORIENT_TESE: 0, ORIENT_DISS: 0,
CO_ORIENT_POS_DOC: 0, CO_ORIENT_TESE: 0, CO_ORIENT_DISS: 0,
MB_BANCA_POS_DOC: 0, MB_BANCA_TESE: 0, MB_BANCA_DISS: 0,
};
const TETOS = {
@@ -894,15 +887,6 @@ const TETOS = {
EVENTO: { teto: 5, doc: '3.5 Participações Acadêmicas', bonus: '+1/participação (max 10)' },
PROJ: { teto: 30, doc: '3.5 Participações Acadêmicas', bonus: '+2/participação (max 10)' },
BOL_BPQ_NIVEL: { teto: 60, doc: '3.4 Premiações e Bolsas' },
ORIENT_POS_DOC: { teto: 0, doc: 'Selo (sem pontuação)' },
ORIENT_TESE: { teto: 0, doc: 'Selo (sem pontuação)' },
ORIENT_DISS: { teto: 0, doc: 'Selo (sem pontuação)' },
CO_ORIENT_POS_DOC: { teto: 0, doc: 'Selo (sem pontuação)' },
CO_ORIENT_TESE: { teto: 0, doc: 'Selo (sem pontuação)' },
CO_ORIENT_DISS: { teto: 0, doc: 'Selo (sem pontuação)' },
MB_BANCA_POS_DOC: { teto: 0, doc: 'Selo (sem pontuação)' },
MB_BANCA_TESE: { teto: 0, doc: 'Selo (sem pontuação)' },
MB_BANCA_DISS: { teto: 0, doc: 'Selo (sem pontuação)' },
};
const PontuacaoModal = ({ dados, onClose }) => {
@@ -1054,7 +1038,7 @@ const PontuacaoModal = ({ dados, onClose }) => {
<div className="modal-formula-section">
<span className="modal-detalhe-label">Fórmula</span>
<div className="modal-formula-box">
<div className="modal-formula-line">Bloco A + Bloco B + Bloco C + Bloco D</div>
<div className="modal-formula-line">Bloco A + Bloco C + Bloco D</div>
</div>
</div>
</div>
@@ -1132,10 +1116,9 @@ const ConsultorCard = memo(({ consultor, highlight, selecionado, onToggleSelecio
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 = (blocoA.total || 0) + (blocoB.total || 0) + (blocoC.total || 0) + (blocoD.total || 0);
const pontuacaoTotal = Number(consultor.pontuacao_total ?? 0);
const selos = useMemo(() => gerarSelos(consultor), [consultor]);
@@ -1246,18 +1229,6 @@ const ConsultorCard = memo(({ consultor, highlight, selecionado, onToggleSelecio
bloco: blocoA
})}
/>
<ScoreItemClickable
value={blocoB.total}
label="BLOCO B"
style={{ color: blocoB.total > 0 ? 'var(--accent)' : 'var(--muted)' }}
onClick={() => setPontuacaoModal({
tipo: 'bloco',
label: 'BLOCO B - Coordenação PPG',
value: blocoB.total,
formula: FORMULAS.bloco_b.descricao,
bloco: blocoB
})}
/>
<ScoreItemClickable
value={blocoC.total}
label="BLOCO C"
@@ -1299,10 +1270,6 @@ const ConsultorCard = memo(({ consultor, highlight, selecionado, onToggleSelecio
<BlocoDetalhes titulo="A - Coordenacao CAPES" bloco={blocoA} cor="var(--accent-2)" onItemClick={setPontuacaoModal} />
)}
{(blocoB.total > 0 || (blocoB.atuacoes && blocoB.atuacoes.length > 0)) && (
<BlocoDetalhes titulo="B - Coordenacao PPG" bloco={blocoB} cor="var(--accent)" onItemClick={setPontuacaoModal} />
)}
{blocoC.atuacoes && blocoC.atuacoes.length > 0 && (
<BlocoDetalhes titulo="C - Consultoria" bloco={blocoC} cor="var(--gold)" onItemClick={setPontuacaoModal} />
)}
@@ -1571,11 +1538,23 @@ const ConsultorCard = memo(({ consultor, highlight, selecionado, onToggleSelecio
ConsultorCard.displayName = 'ConsultorCard';
const BlocoDetalhes = memo(({ titulo, bloco, cor, onItemClick }) => (
const CODIGOS_APENAS_SELO = [
'ORIENT_POS_DOC', 'ORIENT_TESE', 'ORIENT_DISS',
'CO_ORIENT_POS_DOC', 'CO_ORIENT_TESE', 'CO_ORIENT_DISS',
'MB_BANCA_POS_DOC', 'MB_BANCA_TESE', 'MB_BANCA_DISS',
'ORIENT_POS_DOC_PREM', 'ORIENT_TESE_PREM', 'ORIENT_DISS_PREM',
'CO_ORIENT_POS_DOC_PREM', 'CO_ORIENT_TESE_PREM', 'CO_ORIENT_DISS_PREM',
'MB_BANCA_POS_DOC_PREM', 'MB_BANCA_TESE_PREM', 'MB_BANCA_DISS_PREM',
];
const BlocoDetalhes = memo(({ titulo, bloco, cor, onItemClick }) => {
const atuacoesFiltradas = bloco.atuacoes?.filter(at => !CODIGOS_APENAS_SELO.includes(at.codigo)) || [];
return (
<div className="detail-section">
<h4 style={{ color: cor }}>{titulo}</h4>
<div className="score-breakdown">
{bloco.atuacoes?.map((at, idx) => (
{atuacoesFiltradas.map((at, idx) => (
<div
key={idx}
className="score-item-wrapper score-item-clicavel"
@@ -1608,7 +1587,8 @@ const BlocoDetalhes = memo(({ titulo, bloco, cor, onItemClick }) => (
</div>
</div>
</div>
));
);
});
BlocoDetalhes.displayName = 'BlocoDetalhes';