feat: enhance point registration and location validation features
- Refactored the RegistroPonto component to improve the layout and user experience, including a new section for displaying standard hours. - Updated RelogioSincronizado to include GMT offset adjustments for accurate time display. - Introduced new location validation logic in the backend to ensure point registrations are within allowed geofenced areas. - Enhanced the device information schema to capture additional GPS data, improving the reliability of location checks. - Added new endpoints for managing allowed marking addresses, facilitating better control over where points can be registered.
This commit is contained in:
@@ -65,9 +65,9 @@
|
||||
$: needsScroll = filtered.length > 8;
|
||||
</script>
|
||||
|
||||
<main class="container mx-auto px-4 py-4">
|
||||
<main class="container mx-auto px-4 py-4 max-w-7xl flex flex-col" style="height: calc(100vh - 8rem); min-height: 600px;">
|
||||
<!-- Breadcrumb -->
|
||||
<div class="breadcrumbs mb-4 text-sm">
|
||||
<div class="breadcrumbs mb-4 text-sm flex-shrink-0">
|
||||
<ul>
|
||||
<li><a href={resolve('/recursos-humanos')} class="text-primary hover:underline">Recursos Humanos</a></li>
|
||||
<li>Funcionários</li>
|
||||
@@ -75,7 +75,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Cabeçalho -->
|
||||
<div class="mb-6">
|
||||
<div class="mb-6 flex-shrink-0">
|
||||
<div class="flex flex-col items-start justify-between gap-4 sm:flex-row sm:items-center">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="rounded-xl bg-blue-500/20 p-3">
|
||||
@@ -99,7 +99,7 @@
|
||||
<p class="text-base-content/70">Gerencie os funcionários da secretaria</p>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-lg gap-2" onclick={navCadastro}>
|
||||
<button class="btn btn-primary btn-lg gap-2 shadow-md hover:shadow-lg transition-all" onclick={navCadastro}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
@@ -118,7 +118,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Filtros -->
|
||||
<div class="card bg-base-100 mb-6 shadow-xl">
|
||||
<div class="card bg-base-100/90 backdrop-blur-sm border border-base-300 mb-4 shadow-xl flex-shrink-0">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title mb-4 text-lg">
|
||||
<svg
|
||||
@@ -223,82 +223,133 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tabela de Funcionários -->
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body p-0">
|
||||
<div class="overflow-x-auto">
|
||||
<div class="overflow-y-auto" style="max-height: {filtered.length > 8 ? '600px' : 'none'};">
|
||||
<table class="table-zebra table w-full">
|
||||
<thead class="bg-base-200 sticky top-0 z-10">
|
||||
<tr>
|
||||
<th class="font-bold">Nome</th>
|
||||
<th class="font-bold">CPF</th>
|
||||
<th class="font-bold">Matrícula</th>
|
||||
<th class="font-bold">Tipo</th>
|
||||
<th class="font-bold">Cidade</th>
|
||||
<th class="font-bold">UF</th>
|
||||
<th class="text-right font-bold">Ações</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each filtered as f}
|
||||
<tr class="hover">
|
||||
<td class="font-medium">{f.nome}</td>
|
||||
<td>{f.cpf}</td>
|
||||
<td>{f.matricula}</td>
|
||||
<td>{f.simboloTipo}</td>
|
||||
<td>{f.cidade}</td>
|
||||
<td>{f.uf}</td>
|
||||
<td class="text-right">
|
||||
<div class="dropdown dropdown-end" class:dropdown-open={openMenuId === f._id}>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Abrir menu"
|
||||
class="btn btn-sm"
|
||||
onclick={() => toggleMenu(f._id)}
|
||||
>
|
||||
<!-- Container da Tabela com altura responsiva -->
|
||||
<div class="flex-1 flex flex-col min-h-0">
|
||||
<!-- Tabela de Funcionários -->
|
||||
<div class="card bg-base-100/90 backdrop-blur-sm border border-base-300 shadow-xl flex-1 flex flex-col min-h-0">
|
||||
<div class="card-body p-0 flex-1 flex flex-col min-h-0">
|
||||
<!-- Container com scroll -->
|
||||
<div class="flex-1 overflow-hidden flex flex-col">
|
||||
<div class="overflow-x-auto flex-1 overflow-y-auto">
|
||||
<table class="table table-zebra w-full">
|
||||
<thead class="sticky top-0 z-10 shadow-md bg-gradient-to-r from-base-300 to-base-200">
|
||||
<tr>
|
||||
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Nome</th>
|
||||
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">CPF</th>
|
||||
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Matrícula</th>
|
||||
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Tipo</th>
|
||||
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">Cidade</th>
|
||||
<th class="whitespace-nowrap font-bold text-base-content border-b border-base-400">UF</th>
|
||||
<th class="text-right whitespace-nowrap font-bold text-base-content border-b border-base-400">Ações</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if filtered.length === 0}
|
||||
<tr>
|
||||
<td colspan="7" class="text-center py-12">
|
||||
<div class="flex flex-col items-center justify-center gap-4">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
><path
|
||||
d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z"
|
||||
/></svg
|
||||
class="h-16 w-16 text-base-content/30"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
</button>
|
||||
<ul
|
||||
class="dropdown-content menu bg-base-100 rounded-box border-base-300 z-10 w-52 border p-2 shadow-lg"
|
||||
>
|
||||
<li>
|
||||
<a href={`/recursos-humanos/funcionarios/${f._id}`}>Ver Detalhes</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href={`/recursos-humanos/funcionarios/${f._id}/editar`}>Editar</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href={`/recursos-humanos/funcionarios/${f._id}/documentos`}
|
||||
>Ver Documentos</a
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="1.5"
|
||||
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 class="text-base-content/60 text-center">
|
||||
<p class="font-semibold text-lg mb-1">Nenhum funcionário encontrado</p>
|
||||
<p class="text-sm">
|
||||
{#if filtroNome || filtroCPF || filtroMatricula || filtroTipo}
|
||||
Tente ajustar os filtros ou
|
||||
{/if}
|
||||
<button class="btn btn-link btn-sm p-0 h-auto min-h-0" onclick={navCadastro}>
|
||||
cadastre um novo funcionário
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{:else}
|
||||
{#each filtered as f}
|
||||
<tr class="hover:bg-base-200/50 transition-colors">
|
||||
<td class="whitespace-nowrap font-medium">{f.nome}</td>
|
||||
<td class="whitespace-nowrap">{f.cpf}</td>
|
||||
<td class="whitespace-nowrap">{f.matricula}</td>
|
||||
<td class="whitespace-nowrap">
|
||||
<span class="badge badge-outline badge-sm">
|
||||
{f.simboloTipo === 'cargo_comissionado' ? 'Cargo Comissionado' :
|
||||
f.simboloTipo === 'funcao_gratificada' ? 'Função Gratificada' :
|
||||
f.simboloTipo || '-'}
|
||||
</span>
|
||||
</td>
|
||||
<td class="whitespace-nowrap">{f.cidade || '-'}</td>
|
||||
<td class="whitespace-nowrap">{f.uf || '-'}</td>
|
||||
<td class="text-right whitespace-nowrap">
|
||||
<div class="dropdown dropdown-end" class:dropdown-open={openMenuId === f._id}>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Abrir menu"
|
||||
class="btn btn-sm btn-ghost hover:btn-primary transition-all"
|
||||
onclick={() => toggleMenu(f._id)}
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<button onclick={() => openPrintModal(f._id)}>Imprimir Ficha</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<ul
|
||||
class="dropdown-content menu bg-base-100 rounded-box border-base-300 z-20 w-52 border p-2 shadow-xl"
|
||||
>
|
||||
<li>
|
||||
<a href={`/recursos-humanos/funcionarios/${f._id}`} class="hover:bg-primary/10">
|
||||
Ver Detalhes
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href={`/recursos-humanos/funcionarios/${f._id}/editar`} class="hover:bg-primary/10">
|
||||
Editar
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href={`/recursos-humanos/funcionarios/${f._id}/documentos`} class="hover:bg-primary/10">
|
||||
Ver Documentos
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<button onclick={() => openPrintModal(f._id)} class="hover:bg-primary/10">
|
||||
Imprimir Ficha
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
{/if}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Informação sobre resultados -->
|
||||
<div class="text-base-content/70 mt-4 text-center text-sm">
|
||||
Exibindo {filtered.length} de {list.length} funcionário(s)
|
||||
<!-- Informação sobre resultados -->
|
||||
<div class="text-base-content/70 mt-3 text-center text-sm flex-shrink-0 border-t border-base-300 pt-3 bg-base-100/50">
|
||||
Exibindo <span class="font-semibold">{filtered.length}</span> de <span class="font-semibold">{list.length}</span> funcionário(s)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal de Impressão -->
|
||||
|
||||
Reference in New Issue
Block a user