refactor: improve UI and functionality in employee registration and audit pages

- Enhanced the employee registration form by adding a dependents management section, allowing users to input details such as relationship, name, CPF, and birth date.
- Updated the layout and styling of the audit page, including improved statistics display and user feedback elements.
- Refined the handling of user actions in the audit logs, providing clearer labels and better organization of information.
- Improved the overall user experience by ensuring consistent design patterns and responsive elements across the registration and audit interfaces.
This commit is contained in:
2025-11-04 06:31:28 -03:00
parent d5c01aabab
commit f7cc758d33
3 changed files with 1848 additions and 1708 deletions

View File

@@ -702,71 +702,51 @@
</div>
{/if}
<!-- Filtros -->
<div class="card bg-base-100 shadow-xl mb-6">
<div class="card-body">
<h2 class="card-title mb-4">Filtros</h2>
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
<div class="form-control">
<label class="label">
<span class="label-text">Tipo</span>
</label>
<select
bind:value={filtroTipo}
class="select select-bordered"
>
<!-- Filtros -->
<div class="card bg-base-100 shadow-xl mb-6">
<div class="card-body">
<h2 class="card-title mb-4">Filtros</h2>
<div class="grid grid-cols-1 md:grid-cols-5 gap-4 items-end">
<div class="form-control">
<label class="label cursor-pointer flex flex-col gap-2" for="filtro-tipo">
<span class="label-text">Tipo</span>
<select id="filtro-tipo" class="select select-bordered" bind:value={filtroTipo}>
<option value="todos">Todos</option>
<option value="atestado_medico">Atestado Médico</option>
<option value="declaracao_comparecimento">Declaração</option>
<option value="maternidade">Licença Maternidade</option>
<option value="paternidade">Licença Paternidade</option>
</select>
</div>
</label>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Funcionário</span>
</label>
<input
type="text"
bind:value={filtroFuncionario}
placeholder="Buscar por nome..."
class="input input-bordered"
/>
</div>
<div class="form-control">
<label class="label cursor-pointer flex flex-col gap-2" for="filtro-funcionario">
<span class="label-text">Funcionário</span>
<input id="filtro-funcionario" class="input input-bordered" type="text" bind:value={filtroFuncionario} placeholder="Nome do colaborador" />
</label>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Data Início</span>
</label>
<input
type="date"
bind:value={filtroDataInicio}
class="input input-bordered"
/>
</div>
<div class="form-control">
<label class="label cursor-pointer flex flex-col gap-2" for="filtro-data-inicio">
<span class="label-text">Data Início</span>
<input id="filtro-data-inicio" class="input input-bordered" type="date" bind:value={filtroDataInicio} />
</label>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Data Fim</span>
</label>
<div class="flex gap-2">
<input
type="date"
bind:value={filtroDataFim}
class="input input-bordered flex-1"
/>
<button
class="btn btn-outline"
onclick={limparFiltros}
>
Limpar
</button>
</div>
</div>
<div class="form-control">
<label class="label cursor-pointer flex flex-col gap-2" for="filtro-data-fim">
<span class="label-text">Data Fim</span>
<input id="filtro-data-fim" class="input input-bordered" type="date" bind:value={filtroDataFim} />
</label>
</div>
<div class="flex gap-2 justify-end">
<button class="btn btn-outline" onclick={limparFiltros}>Limpar</button>
</div>
</div>
</div>
</div>
<!-- Calendário Interativo -->
{#if eventosQuery?.data}
@@ -1136,8 +1116,8 @@
: "Declaração"}
</span>
</td>
<td>{formatarData(atestado.dataInicio)}</td>
<td>{formatarData(atestado.dataFim)}</td>
<td class="whitespace-nowrap font-mono text-xs">{formatarData(atestado.dataInicio)}</td>
<td class="whitespace-nowrap font-mono text-xs">{formatarData(atestado.dataFim)}</td>
<td>{atestado.dias}</td>
<td>
<span
@@ -1203,8 +1183,8 @@
{licenca.ehProrrogacao ? " (Prorrogação)" : ""}
</span>
</td>
<td>{formatarData(licenca.dataInicio)}</td>
<td>{formatarData(licenca.dataFim)}</td>
<td class="whitespace-nowrap font-mono text-xs">{formatarData(licenca.dataInicio)}</td>
<td class="whitespace-nowrap font-mono text-xs">{formatarData(licenca.dataFim)}</td>
<td>{licenca.dias}</td>
<td>
<span
@@ -1279,9 +1259,9 @@
/>
<div class="form-control">
<label class="label">
<div class="label">
<span class="label-text font-medium">Data Início <span class="text-error">*</span></span>
</label>
</div>
<input
type="date"
bind:value={atestadoMedico.dataInicio}
@@ -1291,9 +1271,9 @@
</div>
<div class="form-control">
<label class="label">
<div class="label">
<span class="label-text font-medium">Data Fim <span class="text-error">*</span></span>
</label>
</div>
<input
type="date"
bind:value={atestadoMedico.dataFim}
@@ -1303,9 +1283,9 @@
</div>
<div class="form-control">
<label class="label">
<div class="label">
<span class="label-text font-medium">CID <span class="text-error">*</span></span>
</label>
</div>
<input
type="text"
bind:value={atestadoMedico.cid}
@@ -1333,9 +1313,9 @@
</div>
<div class="form-control md:col-span-2">
<label class="label">
<div class="label">
<span class="label-text font-medium">Observações</span>
</label>
</div>
<textarea
bind:value={atestadoMedico.observacoes}
class="textarea textarea-bordered h-24"
@@ -1379,9 +1359,9 @@
/>
<div class="form-control">
<label class="label">
<div class="label">
<span class="label-text font-medium">Data Início <span class="text-error">*</span></span>
</label>
</div>
<input
type="date"
bind:value={declaracao.dataInicio}
@@ -1391,9 +1371,9 @@
</div>
<div class="form-control">
<label class="label">
<div class="label">
<span class="label-text font-medium">Data Fim <span class="text-error">*</span></span>
</label>
</div>
<input
type="date"
bind:value={declaracao.dataFim}
@@ -1417,9 +1397,9 @@
</div>
<div class="form-control md:col-span-2">
<label class="label">
<div class="label">
<span class="label-text font-medium">Observações</span>
</label>
</div>
<textarea
bind:value={declaracao.observacoes}
class="textarea textarea-bordered h-24"
@@ -1463,9 +1443,9 @@
/>
<div class="form-control">
<label class="label">
<div class="label">
<span class="label-text font-medium">Data Início <span class="text-error">*</span></span>
</label>
</div>
<input
type="date"
bind:value={licencaMaternidade.dataInicio}
@@ -1475,18 +1455,18 @@
</div>
<div class="form-control">
<label class="label">
<div class="label">
<span class="label-text font-medium">Data Fim <span class="text-error">*</span></span>
</label>
</div>
<input
type="date"
bind:value={licencaMaternidade.dataFim}
class="input input-bordered"
required
/>
<label class="label">
<div class="label">
<span class="label-text-alt">Calculado automaticamente (120 dias)</span>
</label>
</div>
</div>
<div class="form-control md:col-span-2">
@@ -1502,9 +1482,9 @@
{#if licencaMaternidade.ehProrrogacao}
<div class="form-control md:col-span-2">
<label class="label">
<div class="label">
<span class="label-text font-medium">Licença Original <span class="text-error">*</span></span>
</label>
</div>
<select
bind:value={licencaMaternidade.licencaOriginalId}
class="select select-bordered"
@@ -1539,9 +1519,9 @@
</div>
<div class="form-control md:col-span-2">
<label class="label">
<div class="label">
<span class="label-text font-medium">Observações</span>
</label>
</div>
<textarea
bind:value={licencaMaternidade.observacoes}
class="textarea textarea-bordered h-24"
@@ -1585,9 +1565,9 @@
/>
<div class="form-control">
<label class="label">
<div class="label">
<span class="label-text font-medium">Data Início <span class="text-error">*</span></span>
</label>
</div>
<input
type="date"
bind:value={licencaPaternidade.dataInicio}
@@ -1597,18 +1577,18 @@
</div>
<div class="form-control">
<label class="label">
<div class="label">
<span class="label-text font-medium">Data Fim <span class="text-error">*</span></span>
</label>
</div>
<input
type="date"
bind:value={licencaPaternidade.dataFim}
class="input input-bordered"
required
/>
<label class="label">
<div class="label">
<span class="label-text-alt">Calculado automaticamente (20 dias)</span>
</label>
</div>
</div>
<div class="form-control md:col-span-2">
@@ -1628,9 +1608,9 @@
</div>
<div class="form-control md:col-span-2">
<label class="label">
<div class="label">
<span class="label-text font-medium">Observações</span>
</label>
</div>
<textarea
bind:value={licencaPaternidade.observacoes}
class="textarea textarea-bordered h-24"

View File

@@ -1020,7 +1020,7 @@
Endereço e Contato
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
<!-- CEP -->
<div class="form-control">
<label class="label" for="cep">
@@ -1075,7 +1075,7 @@
</div>
<!-- Endereço -->
<div class="form-control lg:col-span-4">
<div class="form-control md:col-span-2">
<label class="label" for="endereco">
<span class="label-text font-medium">Endereço <span class="text-error">*</span></span>
</label>
@@ -1525,7 +1525,7 @@
<h3 class="font-bold text-lg mb-3">Declaração de Veracidade</h3>
<div class="prose text-sm max-w-none">
<p>
Declaro, sob as penas da lei (art. 299 do Código Penal Brasileiro, que trata do crime de falsidade ideológica, e demais cominações legais aplicáveis), a veracidade e autenticidade de todas as informações e documentos por mim prestados/enviados neste ato. Tenho ciência de que a falsidade das informações implicará nas penalidades cabíveis, podendo resultar na nulidade do ato ou no dever de ressarcir eventuais valores recebidos indevidamente.
Declaro, sob as penas da lei (art. 299 do Código Penal Brasileiro, que trata do crime de falsidade ideológica, e demais cominações legais aplicáveis), a veracidade e autenticidade de todas as informações e documentos por mim prestados/enviados neste ato. Tenho ciência de que a falsidade das informações implicará nas penalidades cabíveis, podendo resultar na nulidade do ato.
</p>
</div>
<div class="modal-action">

View File

@@ -15,7 +15,8 @@
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
minute: '2-digit',
second: '2-digit'
});
}
@@ -30,55 +31,128 @@
};
return colors[acao] || "badge-neutral";
}
function getAcaoLabel(acao: string) {
const labels: Record<string, string> = {
criar: "Criar",
editar: "Editar",
excluir: "Excluir",
bloquear: "Bloquear",
desbloquear: "Desbloquear",
resetar_senha: "Resetar Senha"
};
return labels[acao] || acao;
}
// Estatísticas
const totalAtividades = $derived(atividades?.data?.length || 0);
const totalLogins = $derived(logins?.data?.length || 0);
const loginsSucesso = $derived(logins?.data?.filter(l => l.sucesso).length || 0);
const loginsFalha = $derived(logins?.data?.filter(l => !l.sucesso).length || 0);
</script>
<div class="container mx-auto px-4 py-6 max-w-7xl">
<main class="container mx-auto px-4 py-6 max-w-7xl">
<!-- Breadcrumb -->
<div class="text-sm breadcrumbs mb-4">
<ul>
<li><a href="/ti" class="text-primary hover:underline">TI</a></li>
<li>Auditoria e Logs</li>
</ul>
</div>
<!-- Header -->
<div class="flex items-center justify-between mb-6">
<div class="flex items-center gap-4">
<div class="p-3 bg-accent/10 rounded-xl">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-accent" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<div class="mb-6">
<div class="flex items-center gap-4 mb-2">
<div class="p-3 bg-blue-500/20 rounded-xl">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-blue-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
</div>
<div>
<h1 class="text-3xl font-bold text-base-content">Auditoria e Logs</h1>
<p class="text-base-content/60 mt-1">Histórico completo de atividades e acessos</p>
<h1 class="text-3xl font-bold text-primary">Auditoria e Logs</h1>
<p class="text-base-content/70">Monitoramento completo de atividades e acessos do sistema</p>
</div>
</div>
</div>
<!-- Cards de Estatísticas -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
<div class="stat bg-base-100 shadow-lg rounded-lg">
<div class="stat-figure text-primary">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
</div>
<div class="stat-title text-xs">Atividades</div>
<div class="stat-value text-2xl">{totalAtividades}</div>
<div class="stat-desc">Registros exibidos</div>
</div>
<div class="stat bg-base-100 shadow-lg rounded-lg">
<div class="stat-figure text-success">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
</svg>
</div>
<div class="stat-title text-xs">Logins Totais</div>
<div class="stat-value text-2xl">{totalLogins}</div>
<div class="stat-desc">Tentativas de acesso</div>
</div>
<div class="stat bg-base-100 shadow-lg rounded-lg">
<div class="stat-figure text-success">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div class="stat-title text-xs">Logins Bem-sucedidos</div>
<div class="stat-value text-2xl text-success">{loginsSucesso}</div>
<div class="stat-desc">{totalLogins > 0 ? Math.round((loginsSucesso / totalLogins) * 100) : 0}% de sucesso</div>
</div>
<div class="stat bg-base-100 shadow-lg rounded-lg">
<div class="stat-figure text-error">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div class="stat-title text-xs">Logins Falhados</div>
<div class="stat-value text-2xl text-error">{loginsFalha}</div>
<div class="stat-desc">{totalLogins > 0 ? Math.round((loginsFalha / totalLogins) * 100) : 0}% de falhas</div>
</div>
</div>
<!-- Tabs -->
<div class="tabs tabs-boxed mb-6 bg-base-100 shadow-lg p-2">
<div class="tabs tabs-boxed mb-6 bg-base-100 shadow-lg p-1">
<button
class="tab {abaAtiva === 'atividades' ? 'tab-active' : ''}"
class="tab flex items-center gap-2 {abaAtiva === 'atividades' ? 'tab-active' : ''}"
onclick={() => abaAtiva = "atividades"}
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" />
</svg>
Atividades no Sistema
<span class="font-medium">Atividades no Sistema</span>
</button>
<button
class="tab {abaAtiva === 'logins' ? 'tab-active' : ''}"
class="tab flex items-center gap-2 {abaAtiva === 'logins' ? 'tab-active' : ''}"
onclick={() => abaAtiva = "logins"}
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
</svg>
Histórico de Logins
<span class="font-medium">Histórico de Logins</span>
</button>
</div>
<!-- Controles -->
<div class="card bg-base-100 shadow-xl mb-6">
<div class="card-body">
<div class="card-body py-4">
<div class="flex flex-wrap items-center justify-between gap-4">
<div class="form-control">
<label class="label">
<span class="label-text">Quantidade de registros</span>
<label class="label py-1">
<span class="label-text font-medium">Quantidade de registros</span>
</label>
<select bind:value={limite} class="select select-bordered">
<select bind:value={limite} class="select select-bordered select-sm w-full max-w-xs">
<option value={20}>20 registros</option>
<option value={50}>50 registros</option>
<option value={100}>100 registros</option>
@@ -87,14 +161,14 @@
</div>
<div class="flex gap-2">
<button class="btn btn-outline btn-primary">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<button class="btn btn-outline btn-primary btn-sm gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
Exportar CSV
</button>
<button class="btn btn-outline btn-secondary">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<button class="btn btn-outline btn-secondary btn-sm gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
</svg>
Filtros Avançados
@@ -108,45 +182,79 @@
{#if abaAtiva === "atividades"}
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4">Atividades Recentes</h2>
<div class="flex items-center justify-between mb-4">
<h2 class="card-title text-xl">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
Atividades Recentes
</h2>
{#if atividades?.data}
<div class="badge badge-outline badge-lg">{atividades.data.length} registro{atividades.data.length !== 1 ? 's' : ''}</div>
{/if}
</div>
{#if !atividades?.data}
<div class="flex justify-center py-10">
<span class="loading loading-spinner loading-lg text-primary"></span>
<div class="flex flex-col items-center justify-center py-16">
<span class="loading loading-spinner loading-lg text-primary mb-4"></span>
<p class="text-base-content/60">Carregando atividades...</p>
</div>
{:else if atividades.data.length === 0}
<div class="text-center py-10 text-base-content/60">
Nenhuma atividade registrada
<div class="flex flex-col items-center justify-center py-16 text-base-content/60">
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 mb-4 opacity-50" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
<p class="text-lg font-medium">Nenhuma atividade registrada</p>
<p class="text-sm mt-1">As atividades do sistema aparecerão aqui</p>
</div>
{:else}
<div class="overflow-x-auto">
<table class="table table-sm">
<thead>
<div class="overflow-x-auto rounded-lg">
<table class="table table-zebra">
<thead class="bg-base-200">
<tr>
<th>Data/Hora</th>
<th>Usuário</th>
<th>Ação</th>
<th>Recurso</th>
<th>Detalhes</th>
<th class="font-semibold">Data/Hora</th>
<th class="font-semibold">Usuário</th>
<th class="font-semibold">Ação</th>
<th class="font-semibold">Recurso</th>
<th class="font-semibold">Detalhes</th>
</tr>
</thead>
<tbody>
{#each atividades.data as atividade}
<tr class="hover">
<td class="font-mono text-xs">{formatarData(atividade.timestamp)}</td>
<tr class="hover transition-colors">
<td>
<div class="font-medium">{atividade.usuarioNome || "Sistema"}</div>
<div class="text-xs opacity-60">{atividade.usuarioMatricula || "-"}</div>
<div class="flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-base-content/40" 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>
<span class="font-mono text-xs">{formatarData(atividade.timestamp)}</span>
</div>
</td>
<td>
<span class="badge {getAcaoColor(atividade.acao)} badge-sm">
{atividade.acao}
<div class="flex flex-col">
<div class="font-semibold text-sm">{atividade.usuarioNome || "Sistema"}</div>
{#if atividade.usuarioMatricula}
<div class="text-xs text-base-content/50 font-mono">{atividade.usuarioMatricula}</div>
{/if}
</div>
</td>
<td>
<span class="badge {getAcaoColor(atividade.acao)} badge-sm gap-1">
{getAcaoLabel(atividade.acao)}
</span>
</td>
<td class="font-medium">{atividade.recurso}</td>
<td>
<div class="text-xs max-w-md truncate" title={atividade.detalhes}>
{atividade.detalhes || "-"}
<span class="font-medium text-sm">{atividade.recurso}</span>
</td>
<td>
<div class="max-w-md">
{#if atividade.detalhes}
<div class="text-xs text-base-content/70 truncate" title={atividade.detalhes}>
{atividade.detalhes}
</div>
{:else}
<span class="text-base-content/40 text-xs">-</span>
{/if}
</div>
</td>
</tr>
@@ -160,49 +268,98 @@
{:else}
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4">Histórico de Logins</h2>
<div class="flex items-center justify-between mb-4">
<h2 class="card-title text-xl">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
</svg>
Histórico de Logins
</h2>
{#if logins?.data}
<div class="badge badge-outline badge-lg">{logins.data.length} registro{logins.data.length !== 1 ? 's' : ''}</div>
{/if}
</div>
{#if !logins?.data}
<div class="flex justify-center py-10">
<span class="loading loading-spinner loading-lg text-primary"></span>
<div class="flex flex-col items-center justify-center py-16">
<span class="loading loading-spinner loading-lg text-primary mb-4"></span>
<p class="text-base-content/60">Carregando logins...</p>
</div>
{:else if logins.data.length === 0}
<div class="text-center py-10 text-base-content/60">
Nenhum login registrado
<div class="flex flex-col items-center justify-center py-16 text-base-content/60">
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 mb-4 opacity-50" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
</svg>
<p class="text-lg font-medium">Nenhum login registrado</p>
<p class="text-sm mt-1">Os acessos ao sistema aparecerão aqui</p>
</div>
{:else}
<div class="overflow-x-auto">
<table class="table table-sm">
<thead>
<div class="overflow-x-auto rounded-lg">
<table class="table table-zebra">
<thead class="bg-base-200">
<tr>
<th>Data/Hora</th>
<th>Usuário/Email</th>
<th>Status</th>
<th>IP</th>
<th>Dispositivo</th>
<th>Navegador</th>
<th>Sistema</th>
<th class="font-semibold">Data/Hora</th>
<th class="font-semibold">Usuário/Email</th>
<th class="font-semibold">Status</th>
<th class="font-semibold">IP</th>
<th class="font-semibold">Dispositivo</th>
<th class="font-semibold">Navegador</th>
<th class="font-semibold">Sistema</th>
</tr>
</thead>
<tbody>
{#each logins.data as login}
<tr class="hover">
<td class="font-mono text-xs">{formatarData(login.timestamp)}</td>
<td class="text-sm">{login.matriculaOuEmail}</td>
<tr class="hover transition-colors">
<td>
{#if login.sucesso}
<span class="badge badge-success badge-sm">Sucesso</span>
{:else}
<span class="badge badge-error badge-sm">Falhou</span>
{#if login.motivoFalha}
<div class="text-xs text-error mt-1">{login.motivoFalha}</div>
{/if}
{/if}
<div class="flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-base-content/40" 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>
<span class="font-mono text-xs">{formatarData(login.timestamp)}</span>
</div>
</td>
<td>
<div class="flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-base-content/40" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
<span class="text-sm font-medium">{login.matriculaOuEmail}</span>
</div>
</td>
<td>
<div class="flex flex-col gap-1">
{#if login.sucesso}
<span class="badge badge-success badge-sm gap-1">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
</svg>
Sucesso
</span>
{:else}
<span class="badge badge-error badge-sm gap-1">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
Falhou
</span>
{#if login.motivoFalha}
<div class="text-xs text-error mt-1 font-medium">{login.motivoFalha}</div>
{/if}
{/if}
</div>
</td>
<td>
<span class="font-mono text-xs bg-base-200 px-2 py-1 rounded">{login.ipAddress || "-"}</span>
</td>
<td>
<div class="text-xs text-base-content/70">{login.device || "-"}</div>
</td>
<td>
<div class="text-xs text-base-content/70">{login.browser || "-"}</div>
</td>
<td>
<div class="text-xs text-base-content/70">{login.sistema || "-"}</div>
</td>
<td class="font-mono text-xs">{login.ipAddress || "-"}</td>
<td class="text-xs">{login.device || "-"}</td>
<td class="text-xs">{login.browser || "-"}</td>
<td class="text-xs">{login.sistema || "-"}</td>
</tr>
{/each}
</tbody>
@@ -214,11 +371,14 @@
{/if}
<!-- Informação -->
<div class="alert alert-info mt-6">
<div class="alert alert-info shadow-lg mt-6">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="stroke-current shrink-0 w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<span>Os logs são armazenados permanentemente e não podem ser alterados ou excluídos.</span>
<div>
<h3 class="font-bold">Informação Importante</h3>
<div class="text-sm">Os logs são armazenados permanentemente e não podem ser alterados ou excluídos.</div>
</div>
</div>
</div>
</main>