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
250 lines
11 KiB
JavaScript
250 lines
11 KiB
JavaScript
import React from 'react';
|
|
import './CompararModal.css';
|
|
|
|
const SELOS = {
|
|
PRESID_CAMARA: { label: 'Pres. Câmara', icone: '👑' },
|
|
COORD_PPG: { label: 'Coord. PPG', icone: '🎓' },
|
|
BPQ: { label: 'BPQ', icone: '🏅' },
|
|
AUTOR_GP: { label: 'Autor GP', icone: '🏆' },
|
|
AUTOR_PREMIO: { label: 'Autor Prêmio', icone: '🥇' },
|
|
AUTOR_MENCAO: { label: 'Autor Menção', icone: '🥈' },
|
|
ORIENT_GP: { label: 'Orient. GP', icone: '🏆' },
|
|
ORIENT_PREMIO: { label: 'Orient. Prêmio', icone: '🎖️' },
|
|
ORIENT_MENCAO: { label: 'Orient. Menção', icone: '📜' },
|
|
COORIENT_GP: { label: 'Coorient. GP', icone: '🏆' },
|
|
COORIENT_PREMIO: { label: 'Coorient. Prêmio', icone: '🎖️' },
|
|
COORIENT_MENCAO: { label: 'Coorient. Menção', icone: '📜' },
|
|
ORIENT_POS_DOC: { label: 'Orient. Pós-Doc', icone: '🔬' },
|
|
ORIENT_TESE: { label: 'Orient. Tese', icone: '📚' },
|
|
ORIENT_DISS: { label: 'Orient. Diss.', icone: '📄' },
|
|
CO_ORIENT_POS_DOC: { label: 'Coorient. Pós-Doc', icone: '🔬' },
|
|
CO_ORIENT_TESE: { label: 'Coorient. Tese', icone: '📚' },
|
|
CO_ORIENT_DISS: { label: 'Coorient. Diss.', icone: '📄' },
|
|
};
|
|
|
|
const gerarSelos = (consultor) => {
|
|
const selos = [];
|
|
|
|
const isPresidCamara = consultor.coordenacoes_capes?.some(
|
|
(c) => c.codigo === 'CAM' && c.presidente && (c.ativo ?? !c.fim)
|
|
);
|
|
if (isPresidCamara) selos.push({ ...SELOS.PRESID_CAMARA, qtd: 1 });
|
|
|
|
if (consultor.coordenador_ppg) selos.push({ ...SELOS.COORD_PPG, qtd: 1 });
|
|
|
|
const bolsas = Array.isArray(consultor.bolsas_cnpq) ? consultor.bolsas_cnpq : [];
|
|
if (bolsas.length > 0) selos.push({ ...SELOS.BPQ, qtd: bolsas.length });
|
|
|
|
const premiacoes = Array.isArray(consultor.premiacoes) ? consultor.premiacoes : [];
|
|
const contarPrem = (papel, codigo) => premiacoes.filter(
|
|
(p) => (p.papel || '').toLowerCase() === papel && p.codigo === codigo
|
|
).length;
|
|
|
|
const addPremSelo = (papel, codBase, seloGP, seloPremio, seloMencao) => {
|
|
const gp = contarPrem(papel, 'PREMIACAO_GP_AUTOR');
|
|
const premio = contarPrem(papel, 'PREMIACAO_AUTOR');
|
|
const mencao = contarPrem(papel, 'MENCAO_AUTOR');
|
|
if (gp > 0) selos.push({ ...seloGP, qtd: gp });
|
|
if (premio > 0) selos.push({ ...seloPremio, qtd: premio });
|
|
if (mencao > 0) selos.push({ ...seloMencao, qtd: mencao });
|
|
};
|
|
|
|
addPremSelo('autor', '', SELOS.AUTOR_GP, SELOS.AUTOR_PREMIO, SELOS.AUTOR_MENCAO);
|
|
addPremSelo('orientador', '', SELOS.ORIENT_GP, SELOS.ORIENT_PREMIO, SELOS.ORIENT_MENCAO);
|
|
addPremSelo('coorientador', '', SELOS.COORIENT_GP, SELOS.COORIENT_PREMIO, SELOS.COORIENT_MENCAO);
|
|
|
|
const orientacoes = Array.isArray(consultor.orientacoes) ? consultor.orientacoes : [];
|
|
const contarOrient = (codigo, coorient) => orientacoes.filter(
|
|
(o) => o.codigo === codigo && (coorient ? o.coorientacao : !o.coorientacao)
|
|
).length;
|
|
|
|
const addOrientSelo = (codigo, coorient, selo) => {
|
|
const qtd = contarOrient(codigo, coorient);
|
|
if (qtd > 0) selos.push({ ...selo, qtd });
|
|
};
|
|
|
|
addOrientSelo('ORIENT_POS_DOC', false, SELOS.ORIENT_POS_DOC);
|
|
addOrientSelo('ORIENT_TESE', false, SELOS.ORIENT_TESE);
|
|
addOrientSelo('ORIENT_DISS', false, SELOS.ORIENT_DISS);
|
|
addOrientSelo('CO_ORIENT_POS_DOC', true, SELOS.CO_ORIENT_POS_DOC);
|
|
addOrientSelo('CO_ORIENT_TESE', true, SELOS.CO_ORIENT_TESE);
|
|
addOrientSelo('CO_ORIENT_DISS', true, SELOS.CO_ORIENT_DISS);
|
|
|
|
return selos;
|
|
};
|
|
|
|
const CompararModal = ({ consultor1, consultor2, onClose }) => {
|
|
if (!consultor1 || !consultor2) return null;
|
|
|
|
const calcularDiferenca = (val1, val2) => {
|
|
const diff = val1 - val2;
|
|
if (diff === 0) return { texto: '=', classe: 'igual' };
|
|
if (diff > 0) return { texto: `+${diff}`, classe: 'maior' };
|
|
return { texto: `${diff}`, classe: 'menor' };
|
|
};
|
|
|
|
const renderLinhaComparacao = (label, val1, val2, cor) => {
|
|
const diff1 = calcularDiferenca(val1, val2);
|
|
const diff2 = calcularDiferenca(val2, val1);
|
|
|
|
return (
|
|
<div className="linha-comparacao">
|
|
<div className={`valor ${diff1.classe}`} style={{ '--cor-componente': cor }}>
|
|
<span className="valor-diff">{diff1.texto}</span>
|
|
<span className="valor-numero">{val1}</span>
|
|
</div>
|
|
<div className="label-centro">{label}</div>
|
|
<div className={`valor ${diff2.classe}`} style={{ '--cor-componente': cor }}>
|
|
<span className="valor-numero">{val2}</span>
|
|
<span className="valor-diff">{diff2.texto}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const p1 = consultor1.pontuacao || {};
|
|
const p2 = consultor2.pontuacao || {};
|
|
|
|
const blocoA1 = p1.bloco_a || { total: consultor1.bloco_a || 0 };
|
|
const blocoA2 = p2.bloco_a || { total: consultor2.bloco_a || 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 = Number(consultor1.pontuacao_total ?? 0);
|
|
const total2 = Number(consultor2.pontuacao_total ?? 0);
|
|
|
|
const c1 = consultor1.consultoria;
|
|
const c2 = consultor2.consultoria;
|
|
|
|
const somarAtuacoes = (atuacoes, campo) => {
|
|
if (!atuacoes || !Array.isArray(atuacoes)) return 0;
|
|
return atuacoes.reduce((sum, a) => sum + (a[campo] || 0), 0);
|
|
};
|
|
|
|
return (
|
|
<div className="modal-overlay" onClick={onClose}>
|
|
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
|
|
<button className="modal-close" onClick={onClose}>×</button>
|
|
|
|
<h2 className="modal-titulo">Comparar Consultores</h2>
|
|
|
|
<div className="comparacao-header">
|
|
<div className="consultor-header consultor-1">
|
|
<div className="rank-badge">#{consultor1.posicao || consultor1.rank}</div>
|
|
<div className="info">
|
|
<span className="nome">{consultor1.nome}</span>
|
|
<span className="anos">{consultor1.anos_atuacao} anos</span>
|
|
{consultor1.ativo && <span className="badge badge-ativo">ATIVO</span>}
|
|
{!consultor1.ativo && <span className="badge badge-historico">HIST.</span>}
|
|
</div>
|
|
</div>
|
|
<div className="vs">VS</div>
|
|
<div className="consultor-header consultor-2">
|
|
<div className="rank-badge">#{consultor2.posicao || consultor2.rank}</div>
|
|
<div className="info">
|
|
<span className="nome">{consultor2.nome}</span>
|
|
<span className="anos">{consultor2.anos_atuacao} anos</span>
|
|
{consultor2.ativo && <span className="badge badge-ativo">ATIVO</span>}
|
|
{!consultor2.ativo && <span className="badge badge-historico">HIST.</span>}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="comparacao-selos">
|
|
<div className="selos-lista selos-1">
|
|
{gerarSelos(consultor1).map((selo, i) => (
|
|
<span key={i} className="selo-badge" title={selo.label}>
|
|
<span className="selo-icone">{selo.icone}</span>
|
|
{selo.qtd > 1 && <span className="selo-qtd">{selo.qtd}</span>}
|
|
</span>
|
|
))}
|
|
{gerarSelos(consultor1).length === 0 && <span className="sem-selos">Sem selos</span>}
|
|
</div>
|
|
<div className="selos-label">SELOS</div>
|
|
<div className="selos-lista selos-2">
|
|
{gerarSelos(consultor2).map((selo, i) => (
|
|
<span key={i} className="selo-badge" title={selo.label}>
|
|
<span className="selo-icone">{selo.icone}</span>
|
|
{selo.qtd > 1 && <span className="selo-qtd">{selo.qtd}</span>}
|
|
</span>
|
|
))}
|
|
{gerarSelos(consultor2).length === 0 && <span className="sem-selos">Sem selos</span>}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="comparacao-secao">
|
|
<h3>Pontuacao Total</h3>
|
|
{renderLinhaComparacao('TOTAL', total1, total2, 'var(--accent)')}
|
|
</div>
|
|
|
|
<div className="comparacao-secao">
|
|
<h3 style={{ color: 'var(--accent-2)' }}>A - Coordenacao CAPES</h3>
|
|
{renderLinhaComparacao('Total', blocoA1.total, blocoA2.total, 'var(--accent-2)')}
|
|
{blocoA1.atuacoes && blocoA2.atuacoes && (
|
|
<>
|
|
{renderLinhaComparacao('Base', somarAtuacoes(blocoA1.atuacoes, 'base'), somarAtuacoes(blocoA2.atuacoes, 'base'), 'var(--accent-2)')}
|
|
{renderLinhaComparacao('Tempo', somarAtuacoes(blocoA1.atuacoes, 'tempo'), somarAtuacoes(blocoA2.atuacoes, 'tempo'), 'var(--accent-2)')}
|
|
{renderLinhaComparacao('Bonus', somarAtuacoes(blocoA1.atuacoes, 'bonus'), somarAtuacoes(blocoA2.atuacoes, 'bonus'), 'var(--accent-2)')}
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
<div className="comparacao-secao">
|
|
<h3 style={{ color: 'var(--gold)' }}>C - Consultoria</h3>
|
|
{renderLinhaComparacao('Total', blocoC1.total, blocoC2.total, 'var(--gold)')}
|
|
{blocoC1.atuacoes && blocoC2.atuacoes && (
|
|
<>
|
|
{renderLinhaComparacao('Base', somarAtuacoes(blocoC1.atuacoes, 'base'), somarAtuacoes(blocoC2.atuacoes, 'base'), 'var(--gold)')}
|
|
{renderLinhaComparacao('Tempo', somarAtuacoes(blocoC1.atuacoes, 'tempo'), somarAtuacoes(blocoC2.atuacoes, 'tempo'), 'var(--gold)')}
|
|
{renderLinhaComparacao('Bonus', somarAtuacoes(blocoC1.atuacoes, 'bonus'), somarAtuacoes(blocoC2.atuacoes, 'bonus'), 'var(--gold)')}
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
<div className="comparacao-secao">
|
|
<h3 style={{ color: 'var(--bronze)' }}>D - Premiacoes/Avaliacoes</h3>
|
|
{renderLinhaComparacao('Total', blocoD1.total, blocoD2.total, 'var(--bronze)')}
|
|
{blocoD1.atuacoes && blocoD2.atuacoes && (
|
|
<>
|
|
{renderLinhaComparacao('Base', somarAtuacoes(blocoD1.atuacoes, 'base'), somarAtuacoes(blocoD2.atuacoes, 'base'), 'var(--bronze)')}
|
|
{renderLinhaComparacao('Tempo', somarAtuacoes(blocoD1.atuacoes, 'tempo'), somarAtuacoes(blocoD2.atuacoes, 'tempo'), 'var(--bronze)')}
|
|
{renderLinhaComparacao('Bonus', somarAtuacoes(blocoD1.atuacoes, 'bonus'), somarAtuacoes(blocoD2.atuacoes, 'bonus'), 'var(--bronze)')}
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{(c1 || c2) && (
|
|
<div className="comparacao-secao">
|
|
<h3>Dados de Consultoria</h3>
|
|
{renderLinhaComparacao('Anos Consec.', c1?.anos_consecutivos || 0, c2?.anos_consecutivos || 0, 'var(--muted)')}
|
|
{renderLinhaComparacao('Retornos', c1?.retornos || 0, c2?.retornos || 0, 'var(--muted)')}
|
|
</div>
|
|
)}
|
|
|
|
<div className="comparacao-resumo">
|
|
<div className="resumo-item">
|
|
<span className="resumo-label">Vencedor por pontuacao:</span>
|
|
<span className="resumo-valor">
|
|
{total1 > total2
|
|
? consultor1.nome.split(' ').slice(0, 2).join(' ')
|
|
: total2 > total1
|
|
? consultor2.nome.split(' ').slice(0, 2).join(' ')
|
|
: 'Empate'}
|
|
</span>
|
|
</div>
|
|
<div className="resumo-item">
|
|
<span className="resumo-label">Diferenca total:</span>
|
|
<span className="resumo-valor diferenca">
|
|
{Math.abs(total1 - total2)} pts
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default CompararModal;
|