feat: enhance dashboard functionality by adding user statistics, improving data filtering for dispensas, and refining timestamp handling to ensure accurate time zone management

This commit is contained in:
2025-12-24 08:26:47 -03:00
parent e548c2c678
commit b248472d65
5 changed files with 500 additions and 837 deletions

View File

@@ -847,224 +847,3 @@ export const obterHistoricoAlertas = query({
}
});
/**
* Status consolidado do sistema para o dashboard
*/
export const getStatusSistema = query({
args: {},
returns: v.object({
usuariosOnline: v.number(),
totalRegistros: v.number(),
tempoMedioResposta: v.number(),
cpuUsada: v.number(),
memoriaUsada: v.number(),
ultimaAtualizacao: v.number()
}),
handler: async (ctx) => {
try {
// Última métrica, se existir
const ultimaMetrica = (await ctx.db.query('systemMetrics').order('desc').first()) ?? null;
// Usuários online: usar métrica se disponível, senão derivar de usuários
let usuariosOnline = 0;
if (ultimaMetrica?.usuariosOnline !== undefined) {
usuariosOnline = ultimaMetrica.usuariosOnline;
} else {
const usuarios = await ctx.db.query('usuarios').collect();
usuariosOnline = usuarios.filter((u) => u.statusPresenca === 'online').length;
}
// Total de registros (estimativa baseada em tabelas principais)
const [usuarios, funcionarios, simbolos, alertas, metricas] = await Promise.all([
ctx.db.query('usuarios').collect(),
ctx.db.query('funcionarios').collect(),
ctx.db.query('simbolos').collect(),
ctx.db.query('alertConfigurations').collect(),
ctx.db.query('systemMetrics').take(100) // não precisa contar tudo
]);
const totalRegistros =
usuarios.length + funcionarios.length + simbolos.length + alertas.length + metricas.length;
// Métricas de performance com fallbacks seguros
const tempoMedioResposta = ultimaMetrica?.tempoRespostaMedio ?? 0;
const cpuUsada = Math.max(
0,
Math.min(100, Math.round((ultimaMetrica?.cpuUsage ?? 0) * 100) / 100)
);
const memoriaUsada = Math.max(
0,
Math.min(100, Math.round((ultimaMetrica?.memoryUsage ?? 0) * 100) / 100)
);
const ultimaAtualizacao = ultimaMetrica?.timestamp ?? Date.now();
return {
usuariosOnline,
totalRegistros,
tempoMedioResposta,
cpuUsada,
memoriaUsada,
ultimaAtualizacao
};
} catch (error) {
console.error('Erro em getStatusSistema:', error);
// Retornar valores padrão em caso de erro
return {
usuariosOnline: 0,
totalRegistros: 0,
tempoMedioResposta: 0,
cpuUsada: 0,
memoriaUsada: 0,
ultimaAtualizacao: Date.now()
};
}
}
});
/**
* Atividade do banco no último minuto (agregada em buckets)
* Usa logsAtividades e systemMetrics para calcular atividade real.
*/
export const getAtividadeBancoDados = query({
args: {},
returns: v.object({
historico: v.array(
v.object({
entradas: v.number(),
saidas: v.number()
})
)
}),
handler: async (ctx) => {
try {
const agora = Date.now();
const haUmMinuto = agora - 60 * 1000;
// Buscar atividades reais do sistema
const atividadesRecentes = await ctx.db
.query('logsAtividades')
.withIndex('by_timestamp', (q) => q.gte('timestamp', haUmMinuto))
.order('asc')
.collect();
// Buscar métricas também (para mensagens se houver)
const metricasRecentes = await ctx.db
.query('systemMetrics')
.withIndex('by_timestamp', (q) => q.gte('timestamp', haUmMinuto))
.order('asc')
.collect();
// Bucketizar em 30 pontos (~2s cada) para visualização
const numBuckets = 30;
const bucketSizeMs = Math.ceil(60_000 / numBuckets);
const historico: Array<{ entradas: number; saidas: number }> = [];
for (let i = 0; i < numBuckets; i++) {
const inicio = haUmMinuto + i * bucketSizeMs;
const fim = inicio + bucketSizeMs;
// Contar atividades de criação/inserção (entradas)
const atividadesBucket = atividadesRecentes.filter(
(a) => a.timestamp >= inicio && a.timestamp < fim
);
const entradasAtividades = atividadesBucket.filter(
(a) => a.acao === 'criar' || a.acao === 'inserir' || a.acao === 'cadastrar'
).length;
// Contar atividades de exclusão/remoção (saídas)
const saidasAtividades = atividadesBucket.filter(
(a) => a.acao === 'excluir' || a.acao === 'remover' || a.acao === 'deletar'
).length;
// Usar mensagensPorMinuto como adicional se disponível
const bucketMetricas = metricasRecentes.filter(
(m) => m.timestamp >= inicio && m.timestamp < fim
);
const somaMensagens =
bucketMetricas.reduce((acc, m) => acc + (m.mensagensPorMinuto ?? 0), 0) || 0;
// Combinar atividades reais com métricas de mensagens
const entradas = Math.max(0, Math.round(entradasAtividades + somaMensagens * 0.3));
const saidas = Math.max(0, Math.round(saidasAtividades + somaMensagens * 0.2));
historico.push({ entradas, saidas });
}
return { historico };
} catch (error) {
console.error('Erro em getAtividadeBancoDados:', error);
// Retornar histórico vazio em caso de erro
return { historico: Array(30).fill({ entradas: 0, saidas: 0 }) };
}
}
});
/**
* Distribuição de operações (calculada a partir de logsAtividades e métricas)
*/
export const getDistribuicaoRequisicoes = query({
args: {},
returns: v.object({
queries: v.number(),
mutations: v.number(),
leituras: v.number(),
escritas: v.number()
}),
handler: async (ctx) => {
try {
const umaHoraAtras = Date.now() - 60 * 60 * 1000;
// Buscar atividades reais do sistema
const atividades = await ctx.db
.query('logsAtividades')
.withIndex('by_timestamp', (q) => q.gte('timestamp', umaHoraAtras))
.collect();
// Buscar métricas também
const metricas = await ctx.db
.query('systemMetrics')
.withIndex('by_timestamp', (q) => q.gte('timestamp', umaHoraAtras))
.order('desc')
.take(100);
// Contar operações de leitura (consultas, visualizações)
const leituras = atividades.filter(
(a) =>
a.acao === 'consultar' ||
a.acao === 'visualizar' ||
a.acao === 'listar' ||
a.acao === 'buscar'
).length;
// Contar operações de escrita (criar, editar, excluir)
const escritas = atividades.filter(
(a) =>
a.acao === 'criar' ||
a.acao === 'editar' ||
a.acao === 'excluir' ||
a.acao === 'inserir' ||
a.acao === 'atualizar' ||
a.acao === 'deletar' ||
a.acao === 'cadastrar' ||
a.acao === 'remover'
).length;
// Adicionar estimativa baseada em mensagens se disponível
const totalMensagens = Math.max(
0,
Math.round(metricas.reduce((acc, m) => acc + (m.mensagensPorMinuto ?? 0), 0))
);
// Queries são leituras + parte das mensagens (como consultas de chat)
const queries = leituras + Math.round(totalMensagens * 0.5);
// Mutations são escritas + parte das mensagens (como envio de mensagens)
const mutations = escritas + Math.round(totalMensagens * 0.3);
return { queries, mutations, leituras, escritas };
} catch (error) {
console.error('Erro em getDistribuicaoRequisicoes:', error);
// Retornar valores padrão em caso de erro
return { queries: 0, mutations: 0, leituras: 0, escritas: 0 };
}
}
});