refactor: update better-auth configuration and clean up code

- Changed the version of "better-auth" to use a catalog reference in package.json and bun.lock for better dependency management.
- Removed unnecessary comments and cleaned up the code in various files to enhance readability and maintainability.
- Updated the authentication handling in hooks.server.ts to ensure proper token retrieval.
- Simplified the layout and structure of Svelte components for improved clarity and performance.
This commit is contained in:
2025-11-07 11:18:34 -03:00
parent 57dd9492ef
commit 427c78ec37
10 changed files with 385 additions and 229 deletions

View File

@@ -0,0 +1,9 @@
import { api } from "@sgse-app/backend/convex/_generated/api";
import { createConvexHttpClient } from "@mmailaender/convex-better-auth-svelte/sveltekit";
export const load = async ({ locals }) => {
const client = createConvexHttpClient({ token: locals.token });
const currentUser = await client.query(api.auth.getCurrentUser, {});
return { currentUser };
};

View File

@@ -5,55 +5,72 @@
import { page } from "$app/stores";
import { goto } from "$app/navigation";
import { UserPlus, Mail } from "lucide-svelte";
import { useAuth } from "@mmailaender/convex-better-auth-svelte/svelte";
let { data } = $props();
const auth = useAuth();
const isLoading = $derived(auth.isLoading && !data.currentUser);
const isAuthenticated = $derived(auth.isAuthenticated || !!data.currentUser);
$inspect({ isLoading, isAuthenticated });
// Queries para dados do dashboard
const statsQuery = useQuery(api.dashboard.getStats, {});
const activityQuery = useQuery(api.dashboard.getRecentActivity, {});
// Queries para monitoramento em tempo real
const statusSistemaQuery = useQuery(api.monitoramento.getStatusSistema, {});
const atividadeBDQuery = useQuery(api.monitoramento.getAtividadeBancoDados, {});
const distribuicaoQuery = useQuery(api.monitoramento.getDistribuicaoRequisicoes, {});
const atividadeBDQuery = useQuery(
api.monitoramento.getAtividadeBancoDados,
{},
);
const distribuicaoQuery = useQuery(
api.monitoramento.getDistribuicaoRequisicoes,
{},
);
// Estado para animações
let mounted = $state(false);
let currentTime = $state(new Date());
let showAlert = $state(false);
let alertType = $state<"auth_required" | "access_denied" | "invalid_token" | null>(null);
let alertType = $state<
"auth_required" | "access_denied" | "invalid_token" | null
>(null);
let redirectRoute = $state("");
// Forçar atualização das queries de monitoramento a cada 1 segundo
let refreshKey = $state(0);
onMount(() => {
mounted = true;
// Verificar se há mensagem de erro na URL
const urlParams = new URLSearchParams(window.location.search);
const error = urlParams.get("error");
const route = urlParams.get("route") || urlParams.get("redirect") || "";
if (error) {
alertType = error as any;
redirectRoute = route;
showAlert = true;
// Limpar URL
const newUrl = window.location.pathname;
window.history.replaceState({}, "", newUrl);
// Auto-fechar após 10 segundos
setTimeout(() => {
showAlert = false;
}, 10000);
}
// Atualizar relógio e forçar refresh das queries a cada segundo
const interval = setInterval(() => {
currentTime = new Date();
refreshKey = (refreshKey + 1) % 1000; // Incrementar para forçar re-render
}, 1000);
return () => clearInterval(interval);
});
@@ -67,25 +84,25 @@
return {
title: "Autenticação Necessária",
message: `Para acessar "${redirectRoute}", você precisa fazer login no sistema.`,
icon: "🔐"
icon: "🔐",
};
case "access_denied":
return {
title: "Acesso Negado",
message: `Você não tem permissão para acessar "${redirectRoute}". Entre em contato com a equipe de TI para solicitar acesso.`,
icon: "⛔"
icon: "⛔",
};
case "invalid_token":
return {
title: "Sessão Expirada",
message: "Sua sessão expirou. Por favor, faça login novamente.",
icon: "⏰"
icon: "⏰",
};
default:
return {
title: "Aviso",
message: "Ocorreu um erro. Tente novamente.",
icon: "⚠️"
icon: "⚠️",
};
}
}
@@ -114,7 +131,13 @@
<!-- Alerta de Acesso Negado / Autenticação -->
{#if showAlert}
{@const alertData = getAlertMessage()}
<div class="alert {alertType === 'access_denied' ? 'alert-error' : alertType === 'auth_required' ? 'alert-warning' : 'alert-info'} mb-6 shadow-xl animate-pulse">
<div
class="alert {alertType === 'access_denied'
? 'alert-error'
: alertType === 'auth_required'
? 'alert-warning'
: 'alert-info'} mb-6 shadow-xl animate-pulse"
>
<div class="flex items-start gap-4">
<span class="text-4xl">{alertData.icon}</span>
<div class="flex-1">
@@ -123,7 +146,11 @@
{#if alertType === "access_denied"}
<div class="mt-3 flex gap-2">
<a href="/solicitar-acesso" class="btn btn-sm btn-primary">
<svelte:component this={UserPlus} class="h-4 w-4" strokeWidth={2} />
<svelte:component
this={UserPlus}
class="h-4 w-4"
strokeWidth={2}
/>
Solicitar Acesso
</a>
<a href="/ti" class="btn btn-sm btn-ghost">
@@ -133,14 +160,22 @@
</div>
{/if}
</div>
<button type="button" class="btn btn-sm btn-circle btn-ghost" onclick={closeAlert}>✕</button>
<button
type="button"
class="btn btn-sm btn-circle btn-ghost"
onclick={closeAlert}>✕</button
>
</div>
</div>
{/if}
<!-- Cabeçalho com Boas-vindas -->
<div class="bg-gradient-to-r from-primary/20 to-secondary/20 rounded-2xl p-8 mb-6 shadow-lg">
<div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
<div
class="bg-gradient-to-r from-primary/20 to-secondary/20 rounded-2xl p-8 mb-6 shadow-lg"
>
<div
class="flex flex-col md:flex-row justify-between items-start md:items-center gap-4"
>
<div>
<h1 class="text-4xl font-bold text-primary mb-2">
{getSaudacao()}! 👋
@@ -174,11 +209,15 @@
{:else if statsQuery.data}
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6">
<!-- Total de Funcionários -->
<div class="card bg-gradient-to-br from-blue-500/10 to-blue-600/20 shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1">
<div
class="card bg-gradient-to-br from-blue-500/10 to-blue-600/20 shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1"
>
<div class="card-body">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-base-content/70 font-semibold">Total de Funcionários</p>
<p class="text-sm text-base-content/70 font-semibold">
Total de Funcionários
</p>
<h2 class="text-4xl font-bold text-primary mt-2">
{formatNumber(statsQuery.data.totalFuncionarios)}
</h2>
@@ -186,19 +225,34 @@
{statsQuery.data.funcionariosAtivos} ativos
</p>
</div>
<div class="radial-progress text-primary" style="--value:{calcPercentage(statsQuery.data.funcionariosAtivos, statsQuery.data.totalFuncionarios)}; --size:4rem;">
<span class="text-xs font-bold">{calcPercentage(statsQuery.data.funcionariosAtivos, statsQuery.data.totalFuncionarios)}%</span>
<div
class="radial-progress text-primary"
style="--value:{calcPercentage(
statsQuery.data.funcionariosAtivos,
statsQuery.data.totalFuncionarios,
)}; --size:4rem;"
>
<span class="text-xs font-bold"
>{calcPercentage(
statsQuery.data.funcionariosAtivos,
statsQuery.data.totalFuncionarios,
)}%</span
>
</div>
</div>
</div>
</div>
<!-- Solicitações Pendentes -->
<div class="card bg-gradient-to-br from-yellow-500/10 to-yellow-600/20 shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1">
<div
class="card bg-gradient-to-br from-yellow-500/10 to-yellow-600/20 shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1"
>
<div class="card-body">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-base-content/70 font-semibold">Solicitações Pendentes</p>
<p class="text-sm text-base-content/70 font-semibold">
Solicitações Pendentes
</p>
<h2 class="text-4xl font-bold text-warning mt-2">
{formatNumber(statsQuery.data.solicitacoesPendentes)}
</h2>
@@ -207,8 +261,19 @@
</p>
</div>
<div class="p-4 bg-warning/20 rounded-full">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-warning" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-8 w-8 text-warning"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</div>
</div>
@@ -216,21 +281,37 @@
</div>
<!-- Símbolos Cadastrados -->
<div class="card bg-gradient-to-br from-green-500/10 to-green-600/20 shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1">
<div
class="card bg-gradient-to-br from-green-500/10 to-green-600/20 shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1"
>
<div class="card-body">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-base-content/70 font-semibold">Símbolos Cadastrados</p>
<p class="text-sm text-base-content/70 font-semibold">
Símbolos Cadastrados
</p>
<h2 class="text-4xl font-bold text-success mt-2">
{formatNumber(statsQuery.data.totalSimbolos)}
</h2>
<p class="text-xs text-base-content/60 mt-1">
{statsQuery.data.cargoComissionado} CC / {statsQuery.data.funcaoGratificada} FG
{statsQuery.data.cargoComissionado} CC / {statsQuery.data
.funcaoGratificada} FG
</p>
</div>
<div class="p-4 bg-success/20 rounded-full">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-success" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" />
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-8 w-8 text-success"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z"
/>
</svg>
</div>
</div>
@@ -239,21 +320,39 @@
<!-- Atividade 24h -->
{#if activityQuery.data}
<div class="card bg-gradient-to-br from-purple-500/10 to-purple-600/20 shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1">
<div
class="card bg-gradient-to-br from-purple-500/10 to-purple-600/20 shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1"
>
<div class="card-body">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-base-content/70 font-semibold">Atividade (24h)</p>
<p class="text-sm text-base-content/70 font-semibold">
Atividade (24h)
</p>
<h2 class="text-4xl font-bold text-secondary mt-2">
{formatNumber(activityQuery.data.funcionariosCadastrados24h + activityQuery.data.solicitacoesAcesso24h)}
{formatNumber(
activityQuery.data.funcionariosCadastrados24h +
activityQuery.data.solicitacoesAcesso24h,
)}
</h2>
<p class="text-xs text-base-content/60 mt-1">
{activityQuery.data.funcionariosCadastrados24h} cadastros
</p>
</div>
<div class="p-4 bg-secondary/20 rounded-full">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-secondary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" />
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-8 w-8 text-secondary"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"
/>
</svg>
</div>
</div>
@@ -267,23 +366,41 @@
{@const status = statusSistemaQuery.data}
{@const atividade = atividadeBDQuery.data}
{@const distribuicao = distribuicaoQuery.data}
<div class="mb-6">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-error/10 rounded-lg animate-pulse">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-error" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 text-error"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 10V3L4 14h7v7l9-11h-7z"
/>
</svg>
</div>
<div>
<h2 class="text-2xl font-bold text-base-content">Monitoramento em Tempo Real</h2>
<h2 class="text-2xl font-bold text-base-content">
Monitoramento em Tempo Real
</h2>
<p class="text-sm text-base-content/60">
Atualizado a cada segundo • {new Date(status.ultimaAtualizacao).toLocaleTimeString('pt-BR')}
Atualizado a cada segundo • {new Date(
status.ultimaAtualizacao,
).toLocaleTimeString("pt-BR")}
</p>
</div>
<div class="ml-auto badge badge-error badge-lg gap-2">
<span class="animate-ping absolute inline-flex h-3 w-3 rounded-full bg-error opacity-75"></span>
<span class="relative inline-flex rounded-full h-3 w-3 bg-error"></span>
<span
class="animate-ping absolute inline-flex h-3 w-3 rounded-full bg-error opacity-75"
></span>
<span class="relative inline-flex rounded-full h-3 w-3 bg-error"
></span>
LIVE
</div>
</div>
@@ -291,17 +408,38 @@
<!-- Cards de Status do Sistema -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
<!-- Usuários Online -->
<div class="card bg-gradient-to-br from-primary/10 to-primary/5 border-2 border-primary/20 shadow-lg">
<div
class="card bg-gradient-to-br from-primary/10 to-primary/5 border-2 border-primary/20 shadow-lg"
>
<div class="card-body p-4">
<div class="flex items-center justify-between">
<div>
<p class="text-xs text-base-content/70 font-semibold uppercase">Usuários Online</p>
<h3 class="text-3xl font-bold text-primary mt-1">{status.usuariosOnline}</h3>
<p class="text-xs text-base-content/60 mt-1">sessões ativas</p>
<p
class="text-xs text-base-content/70 font-semibold uppercase"
>
Usuários Online
</p>
<h3 class="text-3xl font-bold text-primary mt-1">
{status.usuariosOnline}
</h3>
<p class="text-xs text-base-content/60 mt-1">
sessões ativas
</p>
</div>
<div class="p-3 bg-primary/20 rounded-full">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 text-primary"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"
/>
</svg>
</div>
</div>
@@ -309,17 +447,38 @@
</div>
<!-- Total de Registros -->
<div class="card bg-gradient-to-br from-success/10 to-success/5 border-2 border-success/20 shadow-lg">
<div
class="card bg-gradient-to-br from-success/10 to-success/5 border-2 border-success/20 shadow-lg"
>
<div class="card-body p-4">
<div class="flex items-center justify-between">
<div>
<p class="text-xs text-base-content/70 font-semibold uppercase">Total Registros</p>
<h3 class="text-3xl font-bold text-success mt-1">{status.totalRegistros.toLocaleString('pt-BR')}</h3>
<p class="text-xs text-base-content/60 mt-1">no banco de dados</p>
<p
class="text-xs text-base-content/70 font-semibold uppercase"
>
Total Registros
</p>
<h3 class="text-3xl font-bold text-success mt-1">
{status.totalRegistros.toLocaleString("pt-BR")}
</h3>
<p class="text-xs text-base-content/60 mt-1">
no banco de dados
</p>
</div>
<div class="p-3 bg-success/20 rounded-full">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-success" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" />
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 text-success"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"
/>
</svg>
</div>
</div>
@@ -327,17 +486,36 @@
</div>
<!-- Tempo Médio de Resposta -->
<div class="card bg-gradient-to-br from-info/10 to-info/5 border-2 border-info/20 shadow-lg">
<div
class="card bg-gradient-to-br from-info/10 to-info/5 border-2 border-info/20 shadow-lg"
>
<div class="card-body p-4">
<div class="flex items-center justify-between">
<div>
<p class="text-xs text-base-content/70 font-semibold uppercase">Tempo Resposta</p>
<h3 class="text-3xl font-bold text-info mt-1">{status.tempoMedioResposta}ms</h3>
<p
class="text-xs text-base-content/70 font-semibold uppercase"
>
Tempo Resposta
</p>
<h3 class="text-3xl font-bold text-info mt-1">
{status.tempoMedioResposta}ms
</h3>
<p class="text-xs text-base-content/60 mt-1">média atual</p>
</div>
<div class="p-3 bg-info/20 rounded-full">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-info" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 text-info"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 10V3L4 14h7v7l9-11h-7z"
/>
</svg>
</div>
</div>
@@ -345,24 +523,42 @@
</div>
<!-- Uso de Sistema -->
<div class="card bg-gradient-to-br from-warning/10 to-warning/5 border-2 border-warning/20 shadow-lg">
<div
class="card bg-gradient-to-br from-warning/10 to-warning/5 border-2 border-warning/20 shadow-lg"
>
<div class="card-body p-4">
<div>
<p class="text-xs text-base-content/70 font-semibold uppercase mb-2">Uso do Sistema</p>
<p
class="text-xs text-base-content/70 font-semibold uppercase mb-2"
>
Uso do Sistema
</p>
<div class="space-y-2">
<div>
<div class="flex justify-between text-xs mb-1">
<span class="text-base-content/70">CPU</span>
<span class="font-bold text-warning">{status.cpuUsada}%</span>
<span class="font-bold text-warning"
>{status.cpuUsada}%</span
>
</div>
<progress class="progress progress-warning w-full" value={status.cpuUsada} max="100"></progress>
<progress
class="progress progress-warning w-full"
value={status.cpuUsada}
max="100"
></progress>
</div>
<div>
<div class="flex justify-between text-xs mb-1">
<span class="text-base-content/70">Memória</span>
<span class="font-bold text-warning">{status.memoriaUsada}%</span>
<span class="font-bold text-warning"
>{status.memoriaUsada}%</span
>
</div>
<progress class="progress progress-warning w-full" value={status.memoriaUsada} max="100"></progress>
<progress
class="progress progress-warning w-full"
value={status.memoriaUsada}
max="100"
></progress>
</div>
</div>
</div>
@@ -375,8 +571,12 @@
<div class="card-body">
<div class="flex items-center justify-between mb-4">
<div>
<h3 class="text-xl font-bold text-base-content">Atividade do Banco de Dados</h3>
<p class="text-sm text-base-content/60">Entradas e saídas em tempo real (último minuto)</p>
<h3 class="text-xl font-bold text-base-content">
Atividade do Banco de Dados
</h3>
<p class="text-sm text-base-content/60">
Entradas e saídas em tempo real (último minuto)
</p>
</div>
<div class="badge badge-success gap-2">
<span class="loading loading-spinner loading-xs"></span>
@@ -386,7 +586,9 @@
<div class="relative h-64">
<!-- Eixo Y -->
<div class="absolute left-0 top-0 bottom-8 w-10 flex flex-col justify-between text-right pr-2">
<div
class="absolute left-0 top-0 bottom-8 w-10 flex flex-col justify-between text-right pr-2"
>
{#each [10, 8, 6, 4, 2, 0] as val}
<span class="text-xs text-base-content/60">{val}</span>
{/each}
@@ -395,30 +597,43 @@
<!-- Grid e Barras -->
<div class="absolute left-12 right-4 top-0 bottom-8">
<!-- Grid horizontal -->
{#each Array.from({length: 6}) as _, i}
<div class="absolute left-0 right-0 border-t border-base-content/10" style="top: {(i / 5) * 100}%;"></div>
{#each Array.from({ length: 6 }) as _, i}
<div
class="absolute left-0 right-0 border-t border-base-content/10"
style="top: {(i / 5) * 100}%;"
></div>
{/each}
<!-- Barras de atividade -->
<div class="flex items-end justify-around h-full gap-1">
{#each atividade.historico as ponto, idx}
{@const maxAtividade = Math.max(...atividade.historico.map(p => Math.max(p.entradas, p.saidas)))}
{@const maxAtividade = Math.max(
...atividade.historico.map((p) =>
Math.max(p.entradas, p.saidas),
),
)}
<div class="flex-1 flex items-end gap-0.5 h-full group">
<!-- Entradas (verde) -->
<div
<div
class="flex-1 bg-gradient-to-t from-success to-success/70 rounded-t transition-all duration-300 hover:scale-110"
style="height: {ponto.entradas / Math.max(maxAtividade, 1) * 100}%; min-height: 2px;"
style="height: {(ponto.entradas /
Math.max(maxAtividade, 1)) *
100}%; min-height: 2px;"
title="Entradas: {ponto.entradas}"
></div>
<!-- Saídas (vermelho) -->
<div
<div
class="flex-1 bg-gradient-to-t from-error to-error/70 rounded-t transition-all duration-300 hover:scale-110"
style="height: {ponto.saidas / Math.max(maxAtividade, 1) * 100}%; min-height: 2px;"
style="height: {(ponto.saidas /
Math.max(maxAtividade, 1)) *
100}%; min-height: 2px;"
title="Saídas: {ponto.saidas}"
></div>
<!-- Tooltip no hover -->
<div class="absolute bottom-full mb-2 left-1/2 -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity bg-base-300 text-base-content px-2 py-1 rounded text-xs whitespace-nowrap shadow-lg z-10">
<div
class="absolute bottom-full mb-2 left-1/2 -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity bg-base-300 text-base-content px-2 py-1 rounded text-xs whitespace-nowrap shadow-lg z-10"
>
<div>{ponto.entradas} entradas</div>
<div>{ponto.saidas} saídas</div>
</div>
@@ -428,10 +643,14 @@
</div>
<!-- Linha do eixo X -->
<div class="absolute left-12 right-4 bottom-8 border-t-2 border-base-content/30"></div>
<div
class="absolute left-12 right-4 bottom-8 border-t-2 border-base-content/30"
></div>
<!-- Labels do eixo X -->
<div class="absolute left-12 right-4 bottom-0 flex justify-between text-xs text-base-content/60">
<div
class="absolute left-12 right-4 bottom-0 flex justify-between text-xs text-base-content/60"
>
<span>-60s</span>
<span>-30s</span>
<span>agora</span>
@@ -439,13 +658,19 @@
</div>
<!-- Legenda -->
<div class="flex justify-center gap-6 mt-4 pt-4 border-t border-base-300">
<div
class="flex justify-center gap-6 mt-4 pt-4 border-t border-base-300"
>
<div class="flex items-center gap-2">
<div class="w-4 h-4 bg-gradient-to-t from-success to-success/70 rounded"></div>
<div
class="w-4 h-4 bg-gradient-to-t from-success to-success/70 rounded"
></div>
<span class="text-sm text-base-content/70">Entradas no BD</span>
</div>
<div class="flex items-center gap-2">
<div class="w-4 h-4 bg-gradient-to-t from-error to-error/70 rounded"></div>
<div
class="w-4 h-4 bg-gradient-to-t from-error to-error/70 rounded"
></div>
<span class="text-sm text-base-content/70">Saídas do BD</span>
</div>
</div>
@@ -456,21 +681,35 @@
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h3 class="text-lg font-bold text-base-content mb-4">Tipos de Operações</h3>
<h3 class="text-lg font-bold text-base-content mb-4">
Tipos de Operações
</h3>
<div class="space-y-3">
<div>
<div class="flex justify-between text-sm mb-1">
<span>Queries (Leituras)</span>
<span class="font-bold text-primary">{distribuicao.queries}</span>
<span class="font-bold text-primary"
>{distribuicao.queries}</span
>
</div>
<progress class="progress progress-primary w-full" value={distribuicao.queries} max={distribuicao.queries + distribuicao.mutations}></progress>
<progress
class="progress progress-primary w-full"
value={distribuicao.queries}
max={distribuicao.queries + distribuicao.mutations}
></progress>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span>Mutations (Escritas)</span>
<span class="font-bold text-secondary">{distribuicao.mutations}</span>
<span class="font-bold text-secondary"
>{distribuicao.mutations}</span
>
</div>
<progress class="progress progress-secondary w-full" value={distribuicao.mutations} max={distribuicao.queries + distribuicao.mutations}></progress>
<progress
class="progress progress-secondary w-full"
value={distribuicao.mutations}
max={distribuicao.queries + distribuicao.mutations}
></progress>
</div>
</div>
</div>
@@ -478,21 +717,35 @@
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h3 class="text-lg font-bold text-base-content mb-4">Operações no Banco</h3>
<h3 class="text-lg font-bold text-base-content mb-4">
Operações no Banco
</h3>
<div class="space-y-3">
<div>
<div class="flex justify-between text-sm mb-1">
<span>Leituras</span>
<span class="font-bold text-info">{distribuicao.leituras}</span>
<span class="font-bold text-info"
>{distribuicao.leituras}</span
>
</div>
<progress class="progress progress-info w-full" value={distribuicao.leituras} max={distribuicao.leituras + distribuicao.escritas}></progress>
<progress
class="progress progress-info w-full"
value={distribuicao.leituras}
max={distribuicao.leituras + distribuicao.escritas}
></progress>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span>Escritas</span>
<span class="font-bold text-warning">{distribuicao.escritas}</span>
<span class="font-bold text-warning"
>{distribuicao.escritas}</span
>
</div>
<progress class="progress progress-warning w-full" value={distribuicao.escritas} max={distribuicao.leituras + distribuicao.escritas}></progress>
<progress
class="progress progress-warning w-full"
value={distribuicao.escritas}
max={distribuicao.leituras + distribuicao.escritas}
></progress>
</div>
</div>
</div>
@@ -501,7 +754,6 @@
</div>
{/if}
<!-- Cards de Status -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="card bg-base-100 shadow-xl">
@@ -528,18 +780,27 @@
<div class="card-body">
<h3 class="card-title text-lg">Acesso Rápido</h3>
<div class="space-y-2 mt-4">
<a href="/recursos-humanos/funcionarios/cadastro" class="btn btn-sm btn-primary w-full">
<a
href="/recursos-humanos/funcionarios/cadastro"
class="btn btn-sm btn-primary w-full"
>
Novo Funcionário
</a>
<a href="/recursos-humanos/simbolos/cadastro" class="btn btn-sm btn-primary w-full">
<a
href="/recursos-humanos/simbolos/cadastro"
class="btn btn-sm btn-primary w-full"
>
Novo Símbolo
</a>
<a href="/ti/painel-administrativo" class="btn btn-sm btn-primary w-full">
<a
href="/ti/painel-administrativo"
class="btn btn-sm btn-primary w-full"
>
Painel Admin
</a>
</div>
</div>
</div>
</div>
</div>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
@@ -549,7 +810,8 @@
<strong>Versão:</strong> 1.0.0
</p>
<p class="text-base-content/70">
<strong>Última Atualização:</strong> {new Date().toLocaleDateString("pt-BR")}
<strong>Última Atualização:</strong>
{new Date().toLocaleDateString("pt-BR")}
</p>
<p class="text-base-content/70">
<strong>Suporte:</strong> TI SGSE