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

View File

@@ -1020,7 +1020,7 @@
Endereço e Contato Endereço e Contato
</h2> </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 --> <!-- CEP -->
<div class="form-control"> <div class="form-control">
<label class="label" for="cep"> <label class="label" for="cep">
@@ -1075,7 +1075,7 @@
</div> </div>
<!-- Endereço --> <!-- Endereço -->
<div class="form-control lg:col-span-4"> <div class="form-control md:col-span-2">
<label class="label" for="endereco"> <label class="label" for="endereco">
<span class="label-text font-medium">Endereço <span class="text-error">*</span></span> <span class="label-text font-medium">Endereço <span class="text-error">*</span></span>
</label> </label>
@@ -1525,7 +1525,7 @@
<h3 class="font-bold text-lg mb-3">Declaração de Veracidade</h3> <h3 class="font-bold text-lg mb-3">Declaração de Veracidade</h3>
<div class="prose text-sm max-w-none"> <div class="prose text-sm max-w-none">
<p> <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> </p>
</div> </div>
<div class="modal-action"> <div class="modal-action">

View File

@@ -15,7 +15,8 @@
month: '2-digit', month: '2-digit',
year: 'numeric', year: 'numeric',
hour: '2-digit', hour: '2-digit',
minute: '2-digit' minute: '2-digit',
second: '2-digit'
}); });
} }
@@ -30,55 +31,128 @@
}; };
return colors[acao] || "badge-neutral"; 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> </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 --> <!-- Header -->
<div class="flex items-center justify-between mb-6"> <div class="mb-6">
<div class="flex items-center gap-4"> <div class="flex items-center gap-4 mb-2">
<div class="p-3 bg-accent/10 rounded-xl"> <div class="p-3 bg-blue-500/20 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"> <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" /> <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> </svg>
</div> </div>
<div> <div>
<h1 class="text-3xl font-bold text-base-content">Auditoria e Logs</h1> <h1 class="text-3xl font-bold text-primary">Auditoria e Logs</h1>
<p class="text-base-content/60 mt-1">Histórico completo de atividades e acessos</p> <p class="text-base-content/70">Monitoramento completo de atividades e acessos do sistema</p>
</div> </div>
</div> </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 --> <!-- 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 <button
class="tab {abaAtiva === 'atividades' ? 'tab-active' : ''}" class="tab flex items-center gap-2 {abaAtiva === 'atividades' ? 'tab-active' : ''}"
onclick={() => abaAtiva = "atividades"} 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"> <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 2" /> <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> </svg>
Atividades no Sistema <span class="font-medium">Atividades no Sistema</span>
</button> </button>
<button <button
class="tab {abaAtiva === 'logins' ? 'tab-active' : ''}" class="tab flex items-center gap-2 {abaAtiva === 'logins' ? 'tab-active' : ''}"
onclick={() => abaAtiva = "logins"} 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" /> <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> </svg>
Histórico de Logins <span class="font-medium">Histórico de Logins</span>
</button> </button>
</div> </div>
<!-- Controles --> <!-- Controles -->
<div class="card bg-base-100 shadow-xl mb-6"> <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="flex flex-wrap items-center justify-between gap-4">
<div class="form-control"> <div class="form-control">
<label class="label"> <label class="label py-1">
<span class="label-text">Quantidade de registros</span> <span class="label-text font-medium">Quantidade de registros</span>
</label> </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={20}>20 registros</option>
<option value={50}>50 registros</option> <option value={50}>50 registros</option>
<option value={100}>100 registros</option> <option value={100}>100 registros</option>
@@ -87,14 +161,14 @@
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<button class="btn btn-outline btn-primary"> <button class="btn btn-outline btn-primary btn-sm gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <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" /> <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> </svg>
Exportar CSV Exportar CSV
</button> </button>
<button class="btn btn-outline btn-secondary"> <button class="btn btn-outline btn-secondary btn-sm gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <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" /> <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> </svg>
Filtros Avançados Filtros Avançados
@@ -108,45 +182,79 @@
{#if abaAtiva === "atividades"} {#if abaAtiva === "atividades"}
<div class="card bg-base-100 shadow-xl"> <div class="card bg-base-100 shadow-xl">
<div class="card-body"> <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} {#if !atividades?.data}
<div class="flex justify-center py-10"> <div class="flex flex-col items-center justify-center py-16">
<span class="loading loading-spinner loading-lg text-primary"></span> <span class="loading loading-spinner loading-lg text-primary mb-4"></span>
<p class="text-base-content/60">Carregando atividades...</p>
</div> </div>
{:else if atividades.data.length === 0} {:else if atividades.data.length === 0}
<div class="text-center py-10 text-base-content/60"> <div class="flex flex-col items-center justify-center py-16 text-base-content/60">
Nenhuma atividade registrada <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> </div>
{:else} {:else}
<div class="overflow-x-auto"> <div class="overflow-x-auto rounded-lg">
<table class="table table-sm"> <table class="table table-zebra">
<thead> <thead class="bg-base-200">
<tr> <tr>
<th>Data/Hora</th> <th class="font-semibold">Data/Hora</th>
<th>Usuário</th> <th class="font-semibold">Usuário</th>
<th>Ação</th> <th class="font-semibold">Ação</th>
<th>Recurso</th> <th class="font-semibold">Recurso</th>
<th>Detalhes</th> <th class="font-semibold">Detalhes</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{#each atividades.data as atividade} {#each atividades.data as atividade}
<tr class="hover"> <tr class="hover transition-colors">
<td class="font-mono text-xs">{formatarData(atividade.timestamp)}</td>
<td> <td>
<div class="font-medium">{atividade.usuarioNome || "Sistema"}</div> <div class="flex items-center gap-2">
<div class="text-xs opacity-60">{atividade.usuarioMatricula || "-"}</div> <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>
<td> <td>
<span class="badge {getAcaoColor(atividade.acao)} badge-sm"> <div class="flex flex-col">
{atividade.acao} <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> </span>
</td> </td>
<td class="font-medium">{atividade.recurso}</td>
<td> <td>
<div class="text-xs max-w-md truncate" title={atividade.detalhes}> <span class="font-medium text-sm">{atividade.recurso}</span>
{atividade.detalhes || "-"} </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> </div>
</td> </td>
</tr> </tr>
@@ -160,49 +268,98 @@
{:else} {:else}
<div class="card bg-base-100 shadow-xl"> <div class="card bg-base-100 shadow-xl">
<div class="card-body"> <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} {#if !logins?.data}
<div class="flex justify-center py-10"> <div class="flex flex-col items-center justify-center py-16">
<span class="loading loading-spinner loading-lg text-primary"></span> <span class="loading loading-spinner loading-lg text-primary mb-4"></span>
<p class="text-base-content/60">Carregando logins...</p>
</div> </div>
{:else if logins.data.length === 0} {:else if logins.data.length === 0}
<div class="text-center py-10 text-base-content/60"> <div class="flex flex-col items-center justify-center py-16 text-base-content/60">
Nenhum login registrado <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> </div>
{:else} {:else}
<div class="overflow-x-auto"> <div class="overflow-x-auto rounded-lg">
<table class="table table-sm"> <table class="table table-zebra">
<thead> <thead class="bg-base-200">
<tr> <tr>
<th>Data/Hora</th> <th class="font-semibold">Data/Hora</th>
<th>Usuário/Email</th> <th class="font-semibold">Usuário/Email</th>
<th>Status</th> <th class="font-semibold">Status</th>
<th>IP</th> <th class="font-semibold">IP</th>
<th>Dispositivo</th> <th class="font-semibold">Dispositivo</th>
<th>Navegador</th> <th class="font-semibold">Navegador</th>
<th>Sistema</th> <th class="font-semibold">Sistema</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{#each logins.data as login} {#each logins.data as login}
<tr class="hover"> <tr class="hover transition-colors">
<td class="font-mono text-xs">{formatarData(login.timestamp)}</td>
<td class="text-sm">{login.matriculaOuEmail}</td>
<td> <td>
{#if login.sucesso} <div class="flex items-center gap-2">
<span class="badge badge-success badge-sm">Sucesso</span> <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">
{:else} <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" />
<span class="badge badge-error badge-sm">Falhou</span> </svg>
{#if login.motivoFalha} <span class="font-mono text-xs">{formatarData(login.timestamp)}</span>
<div class="text-xs text-error mt-1">{login.motivoFalha}</div> </div>
{/if} </td>
{/if} <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>
<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> </tr>
{/each} {/each}
</tbody> </tbody>
@@ -214,11 +371,14 @@
{/if} {/if}
<!-- Informação --> <!-- 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"> <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> <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> </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>
</div> </main>