diff --git a/frontend/src/App.css b/frontend/src/App.css
index abd08dd..6b4fe5f 100644
--- a/frontend/src/App.css
+++ b/frontend/src/App.css
@@ -49,7 +49,7 @@
.controls {
margin: 1.5rem 0;
display: flex;
- gap: 1rem;
+ gap: 1.5rem;
flex-wrap: wrap;
align-items: center;
}
@@ -77,6 +77,37 @@
border-color: var(--accent-2);
}
+.pagination {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ flex-wrap: wrap;
+}
+
+.pagination button {
+ padding: 0.6rem 0.9rem;
+ border-radius: 8px;
+ border: 1px solid var(--stroke);
+ background: rgba(255,255,255,0.06);
+ color: var(--text);
+ cursor: pointer;
+ transition: all 150ms ease;
+}
+
+.pagination button:hover:not(:disabled) {
+ border-color: var(--accent-2);
+}
+
+.pagination button:disabled {
+ opacity: 0.4;
+ cursor: not-allowed;
+}
+
+.page-info {
+ color: var(--muted);
+ font-weight: 500;
+}
+
.ranking-list {
display: flex;
flex-direction: column;
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 4549c6e..418ac3f 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -9,19 +9,23 @@ function App() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [total, setTotal] = useState(0);
- const [limite, setLimite] = useState(100);
+ const [page, setPage] = useState(1);
+ const [pageSize, setPageSize] = useState(50);
+ const [totalPages, setTotalPages] = useState(0);
useEffect(() => {
loadRanking();
- }, [limite]);
+ }, [page, pageSize]);
const loadRanking = async () => {
try {
setLoading(true);
setError(null);
- const response = await rankingService.getRanking(limite);
+ const response = await rankingService.getRanking(page, pageSize);
setConsultores(response.consultores);
setTotal(response.total);
+ setTotalPages(response.total_pages || 0);
+ setPage(response.page || page);
} catch (err) {
console.error('Erro ao carregar ranking:', err);
setError('Erro ao carregar ranking. Verifique se a API está rodando.');
@@ -57,7 +61,7 @@ function App() {
+
+
+
+
+
+ Página {page} de {totalPages || '?'}
+
+
+
+
diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js
index d4c2821..183e916 100644
--- a/frontend/src/services/api.js
+++ b/frontend/src/services/api.js
@@ -9,13 +9,12 @@ const api = axios.create({
});
export const rankingService = {
- async getRanking(limite = 100) {
- // Usa ranking paginado (Oracle) para não depender do Elasticsearch
- const params = { page: 1, size: limite };
+ async getRanking(page = 1, size = 100) {
+ // Usa ranking paginado (Oracle) para percorrer os 350k
+ const params = { page, size };
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) => {
@@ -35,35 +34,38 @@ export const rankingService = {
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: [],
- }});
+ 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: anos,
+ 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,
+ page: data.page ?? page,
+ size: data.size ?? size,
consultores,
};
},