Automatiza componente B e ajuste frontend do ranking
This commit is contained in:
@@ -46,36 +46,6 @@
|
||||
background: var(--accent-2);
|
||||
}
|
||||
|
||||
.mode-selector {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin: 1.5rem 0;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mode-selector button {
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: rgba(255,255,255,0.06);
|
||||
border: 1px solid var(--stroke);
|
||||
border-radius: 8px;
|
||||
color: var(--muted);
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 200ms;
|
||||
}
|
||||
|
||||
.mode-selector button:hover {
|
||||
border-color: var(--accent-2);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.mode-selector button.active {
|
||||
background: var(--accent);
|
||||
border-color: var(--accent);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.controls {
|
||||
margin: 1.5rem 0;
|
||||
display: flex;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import Header from './components/Header';
|
||||
import ConsultorCard from './components/ConsultorCard';
|
||||
import RankingPaginado from './components/RankingPaginado';
|
||||
import { rankingService } from './services/api';
|
||||
import './App.css';
|
||||
|
||||
@@ -10,8 +9,7 @@ function App() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [limite, setLimite] = useState(10);
|
||||
const [modo, setModo] = useState('completo');
|
||||
const [limite, setLimite] = useState(100);
|
||||
|
||||
useEffect(() => {
|
||||
loadRanking();
|
||||
@@ -56,45 +54,24 @@ function App() {
|
||||
<div className="container">
|
||||
<Header total={total} />
|
||||
|
||||
<div className="mode-selector">
|
||||
<button
|
||||
className={modo === 'top' ? 'active' : ''}
|
||||
onClick={() => setModo('top')}
|
||||
>
|
||||
Top N (Rápido)
|
||||
</button>
|
||||
<button
|
||||
className={modo === 'completo' ? 'active' : ''}
|
||||
onClick={() => setModo('completo')}
|
||||
>
|
||||
Ranking Completo (300k)
|
||||
</button>
|
||||
<div className="controls">
|
||||
<label>
|
||||
Limite de consultores:
|
||||
<select value={limite} onChange={(e) => setLimite(Number(e.target.value))}>
|
||||
<option value={10}>Top 10</option>
|
||||
<option value={50}>Top 50</option>
|
||||
<option value={100}>Top 100</option>
|
||||
<option value={200}>Top 200</option>
|
||||
<option value={500}>Top 500</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{modo === 'top' ? (
|
||||
<>
|
||||
<div className="controls">
|
||||
<label>
|
||||
Limite de consultores:
|
||||
<select value={limite} onChange={(e) => setLimite(Number(e.target.value))}>
|
||||
<option value={10}>Top 10</option>
|
||||
<option value={50}>Top 50</option>
|
||||
<option value={100}>Top 100</option>
|
||||
<option value={200}>Top 200</option>
|
||||
<option value={500}>Top 500</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="ranking-list">
|
||||
{consultores.map((consultor) => (
|
||||
<ConsultorCard key={consultor.id_pessoa} consultor={consultor} />
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<RankingPaginado />
|
||||
)}
|
||||
<div className="ranking-list">
|
||||
{consultores.map((consultor) => (
|
||||
<ConsultorCard key={consultor.id_pessoa} consultor={consultor} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>Dados: ATUACAPES (Elasticsearch) + SUCUPIRA_PAINEL (Oracle)</p>
|
||||
|
||||
@@ -55,7 +55,7 @@ const ConsultorCard = ({ consultor }) => {
|
||||
</>
|
||||
)}
|
||||
<div className="stat">
|
||||
<div className="score-value">{pontuacao.pontuacao_total}</div>
|
||||
<div className="score-value">{consultor.pontuacao_total}</div>
|
||||
<div className="stat-label">Score</div>
|
||||
</div>
|
||||
<div className="expand-icon">{expanded ? '▲' : '▼'}</div>
|
||||
|
||||
@@ -9,11 +9,63 @@ const api = axios.create({
|
||||
});
|
||||
|
||||
export const rankingService = {
|
||||
async getRanking(limite = 100, componente = null) {
|
||||
const params = { limite };
|
||||
if (componente) params.componente = componente;
|
||||
const response = await api.get('/ranking/detalhado', { params });
|
||||
return response.data;
|
||||
async getRanking(limite = 100) {
|
||||
// Usa ranking paginado (Oracle) para não depender do Elasticsearch
|
||||
const params = { page: 1, size: limite };
|
||||
const response = await api.get('/ranking/paginado', { params });
|
||||
const data = response.data;
|
||||
|
||||
// Adapta para o formato esperado pelo frontend
|
||||
const hoje = new Date();
|
||||
|
||||
const consultores = (data.consultores || []).map((c) => {
|
||||
const anos = Number(c.anos_atuacao || 0);
|
||||
const consultoria = c.consultoria || {};
|
||||
const primeiroEvento = consultoria.primeiro_evento
|
||||
? new Date(consultoria.primeiro_evento)
|
||||
: (() => {
|
||||
const d = new Date(hoje);
|
||||
d.setFullYear(d.getFullYear() - Math.floor(anos));
|
||||
return d;
|
||||
})();
|
||||
|
||||
return {
|
||||
id_pessoa: c.id_pessoa,
|
||||
nome: c.nome,
|
||||
rank: c.posicao,
|
||||
posicao: c.posicao,
|
||||
pontuacao_total: c.pontuacao_total,
|
||||
componente_a: c.componente_a,
|
||||
componente_b: c.componente_b,
|
||||
componente_c: c.componente_c,
|
||||
componente_d: c.componente_d,
|
||||
ativo: c.ativo,
|
||||
anos_atuacao: c.anos_atuacao,
|
||||
veterano: anos >= 10,
|
||||
pontuacao: {
|
||||
pontuacao_total: c.pontuacao_total,
|
||||
componente_a: { base: c.componente_a, tempo: 0, extras: 0, bonus: 0, retorno: 0, total: c.componente_a },
|
||||
componente_b: { base: c.componente_b, tempo: 0, extras: 0, bonus: 0, retorno: 0, total: c.componente_b },
|
||||
componente_c: { base: c.componente_c, tempo: 0, extras: 0, bonus: 0, retorno: 0, total: c.componente_c },
|
||||
componente_d: { base: c.componente_d, tempo: 0, extras: 0, bonus: 0, retorno: 0, total: c.componente_d },
|
||||
},
|
||||
consultoria: {
|
||||
total_eventos: consultoria.total_eventos ?? 0,
|
||||
eventos_recentes: consultoria.eventos_recentes ?? 0,
|
||||
vezes_responsavel: consultoria.vezes_responsavel ?? 0,
|
||||
primeiro_evento: consultoria.primeiro_evento || primeiroEvento.toISOString(),
|
||||
ultimo_evento: consultoria.ultimo_evento || null,
|
||||
},
|
||||
coordenacoes_capes: [],
|
||||
coordenacoes_programas: [],
|
||||
premiacoes: [],
|
||||
}});
|
||||
|
||||
return {
|
||||
total: data.total,
|
||||
total_pages: data.total_pages,
|
||||
consultores,
|
||||
};
|
||||
},
|
||||
|
||||
async getConsultor(idPessoa) {
|
||||
|
||||
Reference in New Issue
Block a user