feat: Add 'atas' (minutes/records) management feature, and implement various improvements across UI, backend logic, and authentication.
This commit is contained in:
@@ -1,35 +1,35 @@
|
||||
<script lang="ts">
|
||||
import { Clock, CheckCircle2, XCircle } from 'lucide-svelte';
|
||||
import { CheckCircle2, Clock, XCircle } from 'lucide-svelte';
|
||||
import { resolve } from '$app/paths';
|
||||
</script>
|
||||
|
||||
<div class="container mx-auto px-4 py-6">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center gap-4 mb-6">
|
||||
<div class="p-3 bg-primary/10 rounded-xl">
|
||||
<Clock class="h-8 w-8 text-primary" strokeWidth={2} />
|
||||
<div class="mb-6 flex items-center gap-4">
|
||||
<div class="bg-primary/10 rounded-xl p-3">
|
||||
<Clock class="text-primary h-8 w-8" strokeWidth={2} />
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-base-content">Controle de Ponto</h1>
|
||||
<h1 class="text-base-content text-3xl font-bold">Controle de Ponto</h1>
|
||||
<p class="text-base-content/60 mt-1">Gerencie registros, homologações e dispensas de ponto</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Grid de Cards -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-3">
|
||||
<!-- Card 1: Gestão de Pontos -->
|
||||
<a
|
||||
href={resolve('/(dashboard)/recursos-humanos/registro-pontos')}
|
||||
class="card bg-base-100 shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1"
|
||||
class="card bg-base-100 transform shadow-xl transition-all duration-300 hover:-translate-y-1 hover:shadow-2xl"
|
||||
>
|
||||
<div class="card-body">
|
||||
<div class="flex items-start justify-between mb-4">
|
||||
<div class="p-4 bg-blue-500/20 rounded-2xl">
|
||||
<div class="mb-4 flex items-start justify-between">
|
||||
<div class="rounded-2xl bg-blue-500/20 p-4">
|
||||
<Clock class="h-8 w-8 text-blue-600" strokeWidth={2} />
|
||||
</div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5 text-base-content/30"
|
||||
class="text-base-content/30 h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
@@ -42,7 +42,7 @@
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="card-title text-xl mb-2">Gestão de Pontos</h2>
|
||||
<h2 class="card-title mb-2 text-xl">Gestão de Pontos</h2>
|
||||
<p class="text-base-content/70">
|
||||
Visualizar e gerenciar registros de ponto dos funcionários, relatórios e histórico
|
||||
</p>
|
||||
@@ -52,16 +52,16 @@
|
||||
<!-- Card 2: Homologação de Registro -->
|
||||
<a
|
||||
href={resolve('/(dashboard)/recursos-humanos/controle-ponto/homologacao')}
|
||||
class="card bg-base-100 shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1"
|
||||
class="card bg-base-100 transform shadow-xl transition-all duration-300 hover:-translate-y-1 hover:shadow-2xl"
|
||||
>
|
||||
<div class="card-body">
|
||||
<div class="flex items-start justify-between mb-4">
|
||||
<div class="p-4 bg-green-500/20 rounded-2xl">
|
||||
<div class="mb-4 flex items-start justify-between">
|
||||
<div class="rounded-2xl bg-green-500/20 p-4">
|
||||
<CheckCircle2 class="h-8 w-8 text-green-600" strokeWidth={2} />
|
||||
</div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5 text-base-content/30"
|
||||
class="text-base-content/30 h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
@@ -74,9 +74,10 @@
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="card-title text-xl mb-2">Homologação de Registro</h2>
|
||||
<h2 class="card-title mb-2 text-xl">Homologação de Registro</h2>
|
||||
<p class="text-base-content/70">
|
||||
Edite registros de ponto do seu time, ajuste banco de horas (compensar, abonar ou descontar)
|
||||
Edite registros de ponto do seu time, ajuste banco de horas (compensar, abonar ou
|
||||
descontar)
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
@@ -84,16 +85,16 @@
|
||||
<!-- Card 3: Dispensa de Registro -->
|
||||
<a
|
||||
href={resolve('/(dashboard)/recursos-humanos/controle-ponto/dispensa')}
|
||||
class="card bg-base-100 shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1"
|
||||
class="card bg-base-100 transform shadow-xl transition-all duration-300 hover:-translate-y-1 hover:shadow-2xl"
|
||||
>
|
||||
<div class="card-body">
|
||||
<div class="flex items-start justify-between mb-4">
|
||||
<div class="p-4 bg-orange-500/20 rounded-2xl">
|
||||
<div class="mb-4 flex items-start justify-between">
|
||||
<div class="rounded-2xl bg-orange-500/20 p-4">
|
||||
<XCircle class="h-8 w-8 text-orange-600" strokeWidth={2} />
|
||||
</div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5 text-base-content/30"
|
||||
class="text-base-content/30 h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
@@ -106,7 +107,7 @@
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="card-title text-xl mb-2">Dispensa de Registro</h2>
|
||||
<h2 class="card-title mb-2 text-xl">Dispensa de Registro</h2>
|
||||
<p class="text-base-content/70">
|
||||
Gerencie períodos onde funcionários estão dispensados de registrar ponto
|
||||
</p>
|
||||
@@ -114,5 +115,3 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { useQuery, useConvexClient } from 'convex-svelte';
|
||||
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||
import { Clock, Plus, X, Trash2, AlertTriangle } from 'lucide-svelte';
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
import { useConvexClient, useQuery } from 'convex-svelte';
|
||||
import { AlertTriangle, Clock, Plus, Trash2, X } from 'lucide-svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
|
||||
const client = useConvexClient();
|
||||
@@ -35,7 +35,7 @@
|
||||
// Queries
|
||||
const subordinadosQuery = useQuery(api.times.listarSubordinadosDoGestorAtual, {});
|
||||
const dispensasQuery = useQuery(api.pontos.listarDispensas, {
|
||||
apenasAtivas: true, // Mostrar apenas dispensas ativas
|
||||
apenasAtivas: true // Mostrar apenas dispensas ativas
|
||||
});
|
||||
|
||||
const subordinados = $derived(subordinadosQuery?.data || []);
|
||||
@@ -43,14 +43,18 @@
|
||||
|
||||
// Lista de funcionários do time
|
||||
const funcionarios = $derived.by(() => {
|
||||
const funcs: Array<{ _id: Id<'funcionarios'>; nome: string; matricula?: string }> = [];
|
||||
const funcs: Array<{
|
||||
_id: Id<'funcionarios'>;
|
||||
nome: string;
|
||||
matricula?: string;
|
||||
}> = [];
|
||||
for (const time of subordinados) {
|
||||
for (const membro of time.membros) {
|
||||
if (membro.funcionario && !funcs.find((f) => f._id === membro.funcionario._id)) {
|
||||
funcs.push({
|
||||
_id: membro.funcionario._id,
|
||||
nome: membro.funcionario.nome,
|
||||
matricula: membro.funcionario.matricula,
|
||||
matricula: membro.funcionario.matricula
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -113,7 +117,7 @@
|
||||
horaFim: horaFim.hora,
|
||||
minutoFim: horaFim.minuto,
|
||||
motivo,
|
||||
isento,
|
||||
isento
|
||||
})
|
||||
);
|
||||
|
||||
@@ -144,7 +148,7 @@
|
||||
|
||||
try {
|
||||
await client.mutation(api.pontos.removerDispensaRegistro, {
|
||||
dispensaId: dispensaParaExcluir,
|
||||
dispensaId: dispensaParaExcluir
|
||||
});
|
||||
|
||||
toast.success('Dispensa removida com sucesso');
|
||||
@@ -162,13 +166,13 @@
|
||||
|
||||
<div class="container mx-auto px-4 py-6">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<div class="mb-6 flex items-center justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="p-3 bg-primary/10 rounded-xl">
|
||||
<Clock class="h-8 w-8 text-primary" strokeWidth={2} />
|
||||
<div class="bg-primary/10 rounded-xl p-3">
|
||||
<Clock class="text-primary h-8 w-8" strokeWidth={2} />
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-base-content">Dispensa de Registro</h1>
|
||||
<h1 class="text-base-content text-3xl font-bold">Dispensa de Registro</h1>
|
||||
<p class="text-base-content/60 mt-1">Gerencie períodos de dispensa de registro de ponto</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -182,7 +186,7 @@
|
||||
|
||||
<!-- Formulário de Criação -->
|
||||
{#if modoCriacao}
|
||||
<div class="card bg-base-100 shadow-xl mb-6">
|
||||
<div class="card bg-base-100 mb-6 shadow-xl">
|
||||
<div class="card-body space-y-6">
|
||||
<h2 class="card-title border-b pb-3 text-xl">Criar Dispensa de Registro</h2>
|
||||
|
||||
@@ -196,9 +200,11 @@
|
||||
</span>
|
||||
{/if}
|
||||
</label>
|
||||
<div class="max-h-60 overflow-y-auto border border-base-300 rounded-lg p-4 space-y-2">
|
||||
<div class="border-base-300 max-h-60 space-y-2 overflow-y-auto rounded-lg border p-4">
|
||||
{#each funcionarios as funcionario}
|
||||
<label class="flex items-center justify-between p-3 rounded-lg hover:bg-base-200 transition-colors cursor-pointer">
|
||||
<label
|
||||
class="hover:bg-base-200 flex cursor-pointer items-center justify-between rounded-lg p-3 transition-colors"
|
||||
>
|
||||
<span class="label-text font-medium">
|
||||
{funcionario.nome}
|
||||
{#if funcionario.matricula}
|
||||
@@ -214,15 +220,13 @@
|
||||
</label>
|
||||
{/each}
|
||||
{#if funcionarios.length === 0}
|
||||
<div class="text-center py-4 text-base-content/60">
|
||||
Nenhum funcionário disponível
|
||||
</div>
|
||||
<div class="text-base-content/60 py-4 text-center">Nenhum funcionário disponível</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Período -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Data Início</span>
|
||||
@@ -271,16 +275,17 @@
|
||||
<input type="checkbox" class="checkbox checkbox-primary" bind:checked={isento} />
|
||||
<div>
|
||||
<span class="label-text font-medium">Isento de Registro</span>
|
||||
<p class="text-sm text-base-content/70 mt-1">
|
||||
Caso excepcional - sem expiração. O funcionário ficará permanentemente dispensado de registrar ponto.
|
||||
<p class="text-base-content/70 mt-1 text-sm">
|
||||
Caso excepcional - sem expiração. O funcionário ficará permanentemente dispensado de
|
||||
registrar ponto.
|
||||
</p>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Ações -->
|
||||
<div class="flex gap-2 pt-4 border-t">
|
||||
<button class="btn btn-primary gap-2 flex-1" onclick={salvarDispensa}>
|
||||
<div class="flex gap-2 border-t pt-4">
|
||||
<button class="btn btn-primary flex-1 gap-2" onclick={salvarDispensa}>
|
||||
<Plus class="h-4 w-4" />
|
||||
Criar Dispensa
|
||||
</button>
|
||||
@@ -304,7 +309,7 @@
|
||||
</div>
|
||||
{:else}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table table-zebra">
|
||||
<table class="table-zebra table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Funcionário</th>
|
||||
@@ -322,7 +327,7 @@
|
||||
{dispensa.funcionario?.nome || '-'}
|
||||
{#if dispensa.funcionario?.matricula}
|
||||
<br />
|
||||
<span class="text-sm text-base-content/70">
|
||||
<span class="text-base-content/70 text-sm">
|
||||
Mat: {dispensa.funcionario.matricula}
|
||||
</span>
|
||||
{/if}
|
||||
@@ -331,7 +336,11 @@
|
||||
<div class="text-sm">
|
||||
<div>
|
||||
<strong>Início:</strong>{' '}
|
||||
{formatarDataHora(dispensa.dataInicio, dispensa.horaInicio, dispensa.minutoInicio)}
|
||||
{formatarDataHora(
|
||||
dispensa.dataInicio,
|
||||
dispensa.horaInicio,
|
||||
dispensa.minutoInicio
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Fim:</strong>{' '}
|
||||
@@ -372,11 +381,11 @@
|
||||
{#if mostrandoModalExcluir && dispensaParaExcluir}
|
||||
<dialog class="modal modal-open">
|
||||
<div class="modal-box">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="p-2 bg-error/10 rounded-lg">
|
||||
<AlertTriangle class="h-6 w-6 text-error" strokeWidth={2} />
|
||||
<div class="mb-4 flex items-center gap-3">
|
||||
<div class="bg-error/10 rounded-lg p-2">
|
||||
<AlertTriangle class="text-error h-6 w-6" strokeWidth={2} />
|
||||
</div>
|
||||
<h3 class="font-bold text-lg">Confirmar Remoção</h3>
|
||||
<h3 class="text-lg font-bold">Confirmar Remoção</h3>
|
||||
</div>
|
||||
<p class="text-base-content mb-6">
|
||||
Deseja realmente remover esta dispensa? Esta ação não pode ser desfeita.
|
||||
@@ -395,4 +404,3 @@
|
||||
</dialog>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { useQuery, useConvexClient } from 'convex-svelte';
|
||||
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||
import { Clock, Edit, TrendingUp, TrendingDown, Save, X, Trash2, Eye, MoreVertical } from 'lucide-svelte';
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
import { formatarHoraPonto, getTipoRegistroLabel } from '$lib/utils/ponto';
|
||||
import { useConvexClient, useQuery } from 'convex-svelte';
|
||||
import {
|
||||
Clock,
|
||||
Edit,
|
||||
Eye,
|
||||
MoreVertical,
|
||||
Save,
|
||||
Trash2,
|
||||
TrendingDown,
|
||||
TrendingUp,
|
||||
X
|
||||
} from 'lucide-svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { formatarHoraPonto, getTipoRegistroLabel } from '$lib/utils/ponto';
|
||||
|
||||
const client = useConvexClient();
|
||||
|
||||
@@ -18,16 +28,20 @@
|
||||
let homologacaoParaExcluir = $state<Id<'homologacoesPonto'> | null>(null);
|
||||
let mostrandoModalDetalhes = $state(false);
|
||||
let mostrandoModalExcluir = $state(false);
|
||||
|
||||
|
||||
// Filtros de período
|
||||
const hoje = new Date();
|
||||
const trintaDiasAtras = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
|
||||
let dataInicioFiltro = $state(trintaDiasAtras.toISOString().split('T')[0]!);
|
||||
let dataFimFiltro = $state(hoje.toISOString().split('T')[0]!);
|
||||
const dataInicioFiltro = $state(trintaDiasAtras.toISOString().split('T')[0]!);
|
||||
const dataFimFiltro = $state(hoje.toISOString().split('T')[0]!);
|
||||
|
||||
// Monitorar mudanças em funcionarioSelecionado
|
||||
$effect(() => {
|
||||
console.log('🔄 [DEBUG] funcionarioSelecionado mudou:', funcionarioSelecionado, typeof funcionarioSelecionado);
|
||||
console.log(
|
||||
'🔄 [DEBUG] funcionarioSelecionado mudou:',
|
||||
funcionarioSelecionado,
|
||||
typeof funcionarioSelecionado
|
||||
);
|
||||
});
|
||||
|
||||
// Formulário de edição
|
||||
@@ -94,7 +108,7 @@
|
||||
return data.toLocaleDateString('pt-BR', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric',
|
||||
year: 'numeric'
|
||||
});
|
||||
});
|
||||
|
||||
@@ -111,9 +125,9 @@
|
||||
|
||||
// Parâmetros reativos para queries
|
||||
const homologacoesParams = $derived({
|
||||
funcionarioId: funcionarioSelecionado || undefined,
|
||||
funcionarioId: funcionarioSelecionado || undefined
|
||||
});
|
||||
|
||||
|
||||
// Parâmetros para query de registros - só executa quando há funcionário selecionado
|
||||
const registrosQueryParams = $derived.by(() => {
|
||||
// Verificar se funcionarioSelecionado não é string vazia
|
||||
@@ -123,21 +137,19 @@
|
||||
return {
|
||||
funcionarioId: funcionarioSelecionado as Id<'funcionarios'>,
|
||||
dataInicio: dataInicioFiltro,
|
||||
dataFim: dataFimFiltro,
|
||||
dataFim: dataFimFiltro
|
||||
};
|
||||
});
|
||||
|
||||
const homologacoesQuery = useQuery(api.pontos.listarHomologacoes, homologacoesParams);
|
||||
const registrosQuery = $derived(
|
||||
registrosQueryParams
|
||||
? useQuery(api.pontos.listarRegistrosPeriodo, registrosQueryParams)
|
||||
: null
|
||||
registrosQueryParams ? useQuery(api.pontos.listarRegistrosPeriodo, registrosQueryParams) : null
|
||||
);
|
||||
|
||||
const subordinados = $derived(subordinadosQuery?.data || []);
|
||||
const motivos = $derived(motivosQuery?.data);
|
||||
const homologacoes = $derived(homologacoesQuery?.data || []);
|
||||
|
||||
|
||||
// Registros já filtrados pela query no backend
|
||||
const registros = $derived.by(() => {
|
||||
if (!funcionarioSelecionado || funcionarioSelecionado === '' || !registrosQuery) {
|
||||
@@ -150,20 +162,24 @@
|
||||
// A query do backend já filtra pelo funcionário, mas adicionamos verificação extra
|
||||
return dados.filter((r) => String(r.funcionarioId) === String(funcionarioSelecionado));
|
||||
});
|
||||
|
||||
|
||||
// Verificar se é gestor (tem subordinados)
|
||||
const isGestor = $derived(subordinados.length > 0);
|
||||
|
||||
// Lista de funcionários do time
|
||||
const funcionarios = $derived.by(() => {
|
||||
const funcs: Array<{ _id: Id<'funcionarios'>; nome: string; matricula?: string }> = [];
|
||||
const funcs: Array<{
|
||||
_id: Id<'funcionarios'>;
|
||||
nome: string;
|
||||
matricula?: string;
|
||||
}> = [];
|
||||
for (const time of subordinados) {
|
||||
for (const membro of time.membros) {
|
||||
if (membro.funcionario && !funcs.find((f) => f._id === membro.funcionario._id)) {
|
||||
funcs.push({
|
||||
_id: membro.funcionario._id,
|
||||
nome: membro.funcionario.nome,
|
||||
matricula: membro.funcionario.matricula,
|
||||
matricula: membro.funcionario.matricula
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -201,7 +217,7 @@
|
||||
observacoes = '';
|
||||
modoEdicao = true;
|
||||
abaAtiva = 'editar';
|
||||
|
||||
|
||||
// Resetar campos de ajuste
|
||||
tipoAjuste = 'compensar';
|
||||
const hoje = new Date().toISOString().split('T')[0]!;
|
||||
@@ -240,7 +256,7 @@
|
||||
motivoId: motivoId || undefined,
|
||||
motivoTipo: motivoTipo || undefined,
|
||||
motivoDescricao: motivoDescricao || undefined,
|
||||
observacoes: observacoes || undefined,
|
||||
observacoes: observacoes || undefined
|
||||
});
|
||||
|
||||
toast.success('Registro editado com sucesso');
|
||||
@@ -285,7 +301,7 @@
|
||||
motivoId: motivoId || undefined,
|
||||
motivoTipo: motivoTipo || undefined,
|
||||
motivoDescricao: motivoDescricao || undefined,
|
||||
observacoes: observacoes || undefined,
|
||||
observacoes: observacoes || undefined
|
||||
});
|
||||
|
||||
toast.success('Banco de horas ajustado com sucesso');
|
||||
@@ -321,7 +337,7 @@
|
||||
|
||||
try {
|
||||
await client.mutation(api.pontos.excluirHomologacao, {
|
||||
homologacaoId: homologacaoParaExcluir,
|
||||
homologacaoId: homologacaoParaExcluir
|
||||
});
|
||||
|
||||
toast.success('Homologação excluída com sucesso');
|
||||
@@ -342,7 +358,9 @@
|
||||
abrirEdicaoComAjuste(homologacao.registroId);
|
||||
} else {
|
||||
// Se for ajuste de banco de horas, não há como editar diretamente
|
||||
toast.info('Ajustes de banco de horas não podem ser editados. Crie um novo ajuste para corrigir.');
|
||||
toast.info(
|
||||
'Ajustes de banco de horas não podem ser editados. Crie um novo ajuste para corrigir.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,23 +372,23 @@
|
||||
|
||||
<div class="container mx-auto px-4 py-6">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<div class="mb-6 flex items-center justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="p-3 bg-primary/10 rounded-xl">
|
||||
<Clock class="h-8 w-8 text-primary" strokeWidth={2} />
|
||||
<div class="bg-primary/10 rounded-xl p-3">
|
||||
<Clock class="text-primary h-8 w-8" strokeWidth={2} />
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-base-content">Homologação de Registro</h1>
|
||||
<h1 class="text-base-content text-3xl font-bold">Homologação de Registro</h1>
|
||||
<p class="text-base-content/60 mt-1">Edite registros de ponto e ajuste banco de horas</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Seleção de Funcionário -->
|
||||
<div class="card bg-base-100 shadow-xl mb-6">
|
||||
<div class="card bg-base-100 mb-6 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title mb-4">Selecionar Funcionário</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-3">
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Funcionário</span>
|
||||
@@ -383,7 +401,8 @@
|
||||
<option value="">Selecione um funcionário</option>
|
||||
{#each funcionarios as funcionario}
|
||||
<option value={funcionario._id as string}>
|
||||
{funcionario.nome} {funcionario.matricula ? `(${funcionario.matricula})` : ''}
|
||||
{funcionario.nome}
|
||||
{funcionario.matricula ? `(${funcionario.matricula})` : ''}
|
||||
</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -418,23 +437,23 @@
|
||||
|
||||
<!-- Formulário Unificado de Edição e Ajuste -->
|
||||
{#if modoEdicao && registroSelecionado}
|
||||
<div class="card bg-base-100 shadow-xl mb-6 border-2 border-primary/20">
|
||||
<div class="card bg-base-100 border-primary/20 mb-6 border-2 shadow-xl">
|
||||
<div class="card-body p-8">
|
||||
<!-- Cabeçalho Elegante -->
|
||||
<div class="mb-8 pb-6 border-b border-base-300">
|
||||
<div class="border-base-300 mb-8 border-b pb-6">
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="p-3 bg-primary/10 rounded-xl">
|
||||
<Edit class="h-7 w-7 text-primary" strokeWidth={2} />
|
||||
<div class="bg-primary/10 rounded-xl p-3">
|
||||
<Edit class="text-primary h-7 w-7" strokeWidth={2} />
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h2 class="text-3xl font-bold text-base-content mb-2">
|
||||
Homologar Registro de Ponto
|
||||
</h2>
|
||||
<h2 class="text-base-content mb-2 text-3xl font-bold">Homologar Registro de Ponto</h2>
|
||||
{#if dataRegistroFormatada}
|
||||
<div class="flex items-center gap-2 text-base-content/70">
|
||||
<div class="text-base-content/70 flex items-center gap-2">
|
||||
<Clock class="h-4 w-4" />
|
||||
<span class="text-sm">
|
||||
Registro do dia <span class="font-semibold text-primary">{dataRegistroFormatada}</span>
|
||||
Registro do dia <span class="text-primary font-semibold"
|
||||
>{dataRegistroFormatada}</span
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -443,19 +462,23 @@
|
||||
</div>
|
||||
|
||||
<!-- Abas Modernas -->
|
||||
<div class="tabs tabs-boxed mb-8 bg-base-200/50 p-1 rounded-lg">
|
||||
<div class="tabs tabs-boxed bg-base-200/50 mb-8 rounded-lg p-1">
|
||||
<button
|
||||
class="tab tab-lg flex-1 transition-all {abaAtiva === 'editar' ? 'tab-active bg-primary text-primary-content shadow-md' : 'hover:bg-base-300'}"
|
||||
class="tab tab-lg flex-1 transition-all {abaAtiva === 'editar'
|
||||
? 'tab-active bg-primary text-primary-content shadow-md'
|
||||
: 'hover:bg-base-300'}"
|
||||
onclick={() => (abaAtiva = 'editar')}
|
||||
>
|
||||
<Edit class="h-4 w-4 mr-2" />
|
||||
<Edit class="mr-2 h-4 w-4" />
|
||||
Editar Horário
|
||||
</button>
|
||||
<button
|
||||
class="tab tab-lg flex-1 transition-all {abaAtiva === 'ajustar' ? 'tab-active bg-primary text-primary-content shadow-md' : 'hover:bg-base-300'}"
|
||||
class="tab tab-lg flex-1 transition-all {abaAtiva === 'ajustar'
|
||||
? 'tab-active bg-primary text-primary-content shadow-md'
|
||||
: 'hover:bg-base-300'}"
|
||||
onclick={() => (abaAtiva = 'ajustar')}
|
||||
>
|
||||
<TrendingUp class="h-4 w-4 mr-2" />
|
||||
<TrendingUp class="mr-2 h-4 w-4" />
|
||||
Ajustar Banco de Horas
|
||||
</button>
|
||||
</div>
|
||||
@@ -464,15 +487,19 @@
|
||||
{#if abaAtiva === 'editar'}
|
||||
<div class="space-y-8">
|
||||
<!-- Card: Nova Hora -->
|
||||
<div class="card bg-gradient-to-br from-primary/5 to-primary/10 border border-primary/20 shadow-sm">
|
||||
<div
|
||||
class="card from-primary/5 to-primary/10 border-primary/20 border bg-gradient-to-br shadow-sm"
|
||||
>
|
||||
<div class="card-body p-6">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="p-2 bg-primary/20 rounded-lg">
|
||||
<Clock class="h-5 w-5 text-primary" />
|
||||
<div class="mb-4 flex items-center gap-3">
|
||||
<div class="bg-primary/20 rounded-lg p-2">
|
||||
<Clock class="text-primary h-5 w-5" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-base-content">Nova Hora</h3>
|
||||
<p class="text-sm text-base-content/60">Defina o novo horário para este registro</p>
|
||||
<h3 class="text-base-content text-lg font-semibold">Nova Hora</h3>
|
||||
<p class="text-base-content/60 text-sm">
|
||||
Defina o novo horário para este registro
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
@@ -486,19 +513,22 @@
|
||||
</div>
|
||||
|
||||
<!-- Card: Motivo e Justificativa -->
|
||||
<div class="card bg-base-50 border border-base-300 shadow-sm">
|
||||
<div class="card bg-base-50 border-base-300 border shadow-sm">
|
||||
<div class="card-body p-6">
|
||||
<h3 class="text-lg font-semibold text-base-content mb-6 flex items-center gap-2">
|
||||
<div class="w-1 h-6 bg-primary rounded-full"></div>
|
||||
<h3 class="text-base-content mb-6 flex items-center gap-2 text-lg font-semibold">
|
||||
<div class="bg-primary h-6 w-1 rounded-full"></div>
|
||||
Motivo e Justificativa
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-semibold">Tipo de Motivo</span>
|
||||
<span class="label-text-alt text-error font-bold">*</span>
|
||||
</label>
|
||||
<select class="select select-bordered select-primary w-full" bind:value={motivoTipo}>
|
||||
<select
|
||||
class="select select-bordered select-primary w-full"
|
||||
bind:value={motivoTipo}
|
||||
>
|
||||
<option value="">Selecione um tipo</option>
|
||||
{#if motivos?.opcoesPadrao}
|
||||
{#each motivos.opcoesPadrao as opcao}
|
||||
@@ -524,10 +554,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Card: Observações -->
|
||||
<div class="card bg-base-50 border border-base-300 shadow-sm">
|
||||
<div class="card bg-base-50 border-base-300 border shadow-sm">
|
||||
<div class="card-body p-6">
|
||||
<h3 class="text-lg font-semibold text-base-content mb-4 flex items-center gap-2">
|
||||
<div class="w-1 h-6 bg-primary rounded-full"></div>
|
||||
<h3 class="text-base-content mb-4 flex items-center gap-2 text-lg font-semibold">
|
||||
<div class="bg-primary h-6 w-1 rounded-full"></div>
|
||||
Observações Adicionais
|
||||
</h3>
|
||||
<div class="form-control">
|
||||
@@ -542,12 +572,12 @@
|
||||
</div>
|
||||
|
||||
<!-- Botões de ação -->
|
||||
<div class="flex gap-3 justify-end pt-6 border-t border-base-300">
|
||||
<button class="btn btn-ghost gap-2 btn-lg" onclick={cancelar}>
|
||||
<div class="border-base-300 flex justify-end gap-3 border-t pt-6">
|
||||
<button class="btn btn-ghost btn-lg gap-2" onclick={cancelar}>
|
||||
<X class="h-5 w-5" />
|
||||
Cancelar
|
||||
</button>
|
||||
<button class="btn btn-primary gap-2 btn-lg shadow-lg" onclick={salvarEdicao}>
|
||||
<button class="btn btn-primary btn-lg gap-2 shadow-lg" onclick={salvarEdicao}>
|
||||
<Save class="h-5 w-5" />
|
||||
Salvar Alterações
|
||||
</button>
|
||||
@@ -559,19 +589,26 @@
|
||||
{#if abaAtiva === 'ajustar'}
|
||||
<div class="space-y-8">
|
||||
<!-- Card: Tipo de Ajuste -->
|
||||
<div class="card bg-gradient-to-br from-warning/5 to-warning/10 border border-warning/20 shadow-sm">
|
||||
<div
|
||||
class="card from-warning/5 to-warning/10 border-warning/20 border bg-gradient-to-br shadow-sm"
|
||||
>
|
||||
<div class="card-body p-6">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="p-2 bg-warning/20 rounded-lg">
|
||||
<TrendingUp class="h-5 w-5 text-warning" />
|
||||
<div class="mb-4 flex items-center gap-3">
|
||||
<div class="bg-warning/20 rounded-lg p-2">
|
||||
<TrendingUp class="text-warning h-5 w-5" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-base-content">Tipo de Ajuste</h3>
|
||||
<p class="text-sm text-base-content/60">Selecione o tipo de ajuste a ser aplicado</p>
|
||||
<h3 class="text-base-content text-lg font-semibold">Tipo de Ajuste</h3>
|
||||
<p class="text-base-content/60 text-sm">
|
||||
Selecione o tipo de ajuste a ser aplicado
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<select class="select select-bordered select-warning w-full max-w-md text-base font-medium" bind:value={tipoAjuste}>
|
||||
<select
|
||||
class="select select-bordered select-warning w-full max-w-md text-base font-medium"
|
||||
bind:value={tipoAjuste}
|
||||
>
|
||||
<option value="compensar">🕐 Compensar</option>
|
||||
<option value="abonar">✅ Abonar</option>
|
||||
<option value="descontar">❌ Descontar em Folha</option>
|
||||
@@ -581,28 +618,32 @@
|
||||
</div>
|
||||
|
||||
<!-- Card: Período com Data e Hora -->
|
||||
<div class="card bg-base-50 border border-base-300 shadow-sm">
|
||||
<div class="card bg-base-50 border-base-300 border shadow-sm">
|
||||
<div class="card-body p-6">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<div class="mb-6 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 bg-primary/20 rounded-lg">
|
||||
<Clock class="h-5 w-5 text-primary" />
|
||||
<div class="bg-primary/20 rounded-lg p-2">
|
||||
<Clock class="text-primary h-5 w-5" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-base-content">Período do Ajuste</h3>
|
||||
<p class="text-sm text-base-content/60">Defina o período de início e fim do ajuste</p>
|
||||
<h3 class="text-base-content text-lg font-semibold">Período do Ajuste</h3>
|
||||
<p class="text-base-content/60 text-sm">
|
||||
Defina o período de início e fim do ajuste
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<span class="badge badge-error badge-lg">Obrigatório</span>
|
||||
</div>
|
||||
|
||||
<!-- Data e Hora Início -->
|
||||
<div class="mb-6 p-4 bg-primary/5 rounded-lg border border-primary/10">
|
||||
<h4 class="text-base font-semibold text-base-content mb-4 flex items-center gap-2">
|
||||
<div class="w-3 h-3 rounded-full bg-primary shadow-sm"></div>
|
||||
<div class="bg-primary/5 border-primary/10 mb-6 rounded-lg border p-4">
|
||||
<h4
|
||||
class="text-base-content mb-4 flex items-center gap-2 text-base font-semibold"
|
||||
>
|
||||
<div class="bg-primary h-3 w-3 rounded-full shadow-sm"></div>
|
||||
Início do Período
|
||||
</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-semibold">Data Início</span>
|
||||
@@ -631,16 +672,18 @@
|
||||
|
||||
<!-- Separador Visual -->
|
||||
<div class="divider my-6">
|
||||
<Clock class="h-5 w-5 text-base-content/40" />
|
||||
<Clock class="text-base-content/40 h-5 w-5" />
|
||||
</div>
|
||||
|
||||
<!-- Data e Hora Fim -->
|
||||
<div class="p-4 bg-secondary/5 rounded-lg border border-secondary/10">
|
||||
<h4 class="text-base font-semibold text-base-content mb-4 flex items-center gap-2">
|
||||
<div class="w-3 h-3 rounded-full bg-secondary shadow-sm"></div>
|
||||
<div class="bg-secondary/5 border-secondary/10 rounded-lg border p-4">
|
||||
<h4
|
||||
class="text-base-content mb-4 flex items-center gap-2 text-base font-semibold"
|
||||
>
|
||||
<div class="bg-secondary h-3 w-3 rounded-full shadow-sm"></div>
|
||||
Fim do Período
|
||||
</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-semibold">Data Fim</span>
|
||||
@@ -670,17 +713,28 @@
|
||||
|
||||
<!-- Preview do Período Calculado -->
|
||||
{#if dataInicioAjuste && horaInicioAjuste && dataFimAjuste && horaFimAjuste}
|
||||
{@const periodoCalculado = calcularPeriodo(dataInicioAjuste, horaInicioAjuste, dataFimAjuste, horaFimAjuste)}
|
||||
{@const periodoCalculado = calcularPeriodo(
|
||||
dataInicioAjuste,
|
||||
horaInicioAjuste,
|
||||
dataFimAjuste,
|
||||
horaFimAjuste
|
||||
)}
|
||||
{#if periodoCalculado.dias > 0 || periodoCalculado.horas > 0 || periodoCalculado.minutos > 0}
|
||||
<div class="mt-6 p-4 bg-info/10 rounded-lg border border-info/30 shadow-sm">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<Clock class="h-4 w-4 text-info" />
|
||||
<div class="text-sm font-semibold text-info">Período Calculado</div>
|
||||
<div class="bg-info/10 border-info/30 mt-6 rounded-lg border p-4 shadow-sm">
|
||||
<div class="mb-2 flex items-center gap-2">
|
||||
<Clock class="text-info h-4 w-4" />
|
||||
<div class="text-info text-sm font-semibold">Período Calculado</div>
|
||||
</div>
|
||||
<div class="text-base font-bold text-base-content">
|
||||
{periodoCalculado.dias > 0 ? `${periodoCalculado.dias} dia${periodoCalculado.dias > 1 ? 's' : ''} ` : ''}
|
||||
{periodoCalculado.horas > 0 ? `${periodoCalculado.horas} hora${periodoCalculado.horas > 1 ? 's' : ''} ` : ''}
|
||||
{periodoCalculado.minutos > 0 ? `${periodoCalculado.minutos} minuto${periodoCalculado.minutos > 1 ? 's' : ''}` : ''}
|
||||
<div class="text-base-content text-base font-bold">
|
||||
{periodoCalculado.dias > 0
|
||||
? `${periodoCalculado.dias} dia${periodoCalculado.dias > 1 ? 's' : ''} `
|
||||
: ''}
|
||||
{periodoCalculado.horas > 0
|
||||
? `${periodoCalculado.horas} hora${periodoCalculado.horas > 1 ? 's' : ''} `
|
||||
: ''}
|
||||
{periodoCalculado.minutos > 0
|
||||
? `${periodoCalculado.minutos} minuto${periodoCalculado.minutos > 1 ? 's' : ''}`
|
||||
: ''}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -689,19 +743,22 @@
|
||||
</div>
|
||||
|
||||
<!-- Card: Motivo e Justificativa -->
|
||||
<div class="card bg-base-50 border border-base-300 shadow-sm">
|
||||
<div class="card bg-base-50 border-base-300 border shadow-sm">
|
||||
<div class="card-body p-6">
|
||||
<h3 class="text-lg font-semibold text-base-content mb-6 flex items-center gap-2">
|
||||
<div class="w-1 h-6 bg-warning rounded-full"></div>
|
||||
<h3 class="text-base-content mb-6 flex items-center gap-2 text-lg font-semibold">
|
||||
<div class="bg-warning h-6 w-1 rounded-full"></div>
|
||||
Motivo e Justificativa
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-semibold">Tipo de Motivo</span>
|
||||
<span class="label-text-alt text-error font-bold">*</span>
|
||||
</label>
|
||||
<select class="select select-bordered select-warning w-full" bind:value={motivoTipo}>
|
||||
<select
|
||||
class="select select-bordered select-warning w-full"
|
||||
bind:value={motivoTipo}
|
||||
>
|
||||
<option value="">Selecione um tipo</option>
|
||||
{#if motivos?.opcoesPadrao}
|
||||
{#each motivos.opcoesPadrao as opcao}
|
||||
@@ -727,10 +784,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Card: Observações -->
|
||||
<div class="card bg-base-50 border border-base-300 shadow-sm">
|
||||
<div class="card bg-base-50 border-base-300 border shadow-sm">
|
||||
<div class="card-body p-6">
|
||||
<h3 class="text-lg font-semibold text-base-content mb-4 flex items-center gap-2">
|
||||
<div class="w-1 h-6 bg-warning rounded-full"></div>
|
||||
<h3 class="text-base-content mb-4 flex items-center gap-2 text-lg font-semibold">
|
||||
<div class="bg-warning h-6 w-1 rounded-full"></div>
|
||||
Observações Adicionais
|
||||
</h3>
|
||||
<div class="form-control">
|
||||
@@ -745,12 +802,12 @@
|
||||
</div>
|
||||
|
||||
<!-- Botões de ação -->
|
||||
<div class="flex gap-3 justify-end pt-6 border-t border-base-300">
|
||||
<button class="btn btn-ghost gap-2 btn-lg" onclick={cancelar}>
|
||||
<div class="border-base-300 flex justify-end gap-3 border-t pt-6">
|
||||
<button class="btn btn-ghost btn-lg gap-2" onclick={cancelar}>
|
||||
<X class="h-5 w-5" />
|
||||
Cancelar
|
||||
</button>
|
||||
<button class="btn btn-warning gap-2 btn-lg shadow-lg" onclick={salvarAjuste}>
|
||||
<button class="btn btn-warning btn-lg gap-2 shadow-lg" onclick={salvarAjuste}>
|
||||
<Save class="h-5 w-5" />
|
||||
Salvar Ajuste
|
||||
</button>
|
||||
@@ -763,7 +820,7 @@
|
||||
|
||||
<!-- Lista de Registros -->
|
||||
{#if funcionarioSelecionado}
|
||||
<div class="card bg-base-100 shadow-xl mb-6">
|
||||
<div class="card bg-base-100 mb-6 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title mb-4">Registros do Funcionário</h2>
|
||||
|
||||
@@ -777,9 +834,9 @@
|
||||
</div>
|
||||
{:else}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="max-h-[600px] overflow-y-auto border border-base-300 rounded-lg">
|
||||
<table class="table table-zebra">
|
||||
<thead class="sticky top-0 bg-base-200 z-10 shadow-sm">
|
||||
<div class="border-base-300 max-h-[600px] overflow-y-auto rounded-lg border">
|
||||
<table class="table-zebra table">
|
||||
<thead class="bg-base-200 sticky top-0 z-10 shadow-sm">
|
||||
<tr>
|
||||
<th class="bg-base-200 whitespace-nowrap">Data</th>
|
||||
<th class="bg-base-200 whitespace-nowrap">Tipo</th>
|
||||
@@ -795,7 +852,9 @@
|
||||
<td class="whitespace-nowrap">
|
||||
{getTipoRegistroLabel(registro.tipo)}
|
||||
</td>
|
||||
<td class="whitespace-nowrap">{formatarHoraPonto(registro.hora, registro.minuto)}</td>
|
||||
<td class="whitespace-nowrap"
|
||||
>{formatarHoraPonto(registro.hora, registro.minuto)}</td
|
||||
>
|
||||
<td class="whitespace-nowrap">
|
||||
<span
|
||||
class="badge {registro.dentroDoPrazo ? 'badge-success' : 'badge-error'}"
|
||||
@@ -829,11 +888,9 @@
|
||||
<h2 class="card-title mb-4">
|
||||
Histórico de Homologações
|
||||
{#if funcionarioSelecionado}
|
||||
<span class="text-sm font-normal text-base-content/70">
|
||||
- Funcionário selecionado
|
||||
</span>
|
||||
<span class="text-base-content/70 text-sm font-normal"> - Funcionário selecionado </span>
|
||||
{:else}
|
||||
<span class="text-sm font-normal text-base-content/70">
|
||||
<span class="text-base-content/70 text-sm font-normal">
|
||||
- Todas as homologações do seu time
|
||||
</span>
|
||||
{/if}
|
||||
@@ -848,126 +905,132 @@
|
||||
<span>Nenhuma homologação encontrada</span>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table table-zebra">
|
||||
<thead>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table-zebra table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Data</th>
|
||||
{#if !funcionarioSelecionado}
|
||||
<th>Funcionário</th>
|
||||
{/if}
|
||||
<th>Tipo</th>
|
||||
<th>Detalhes</th>
|
||||
<th>Motivo</th>
|
||||
<th>Observações</th>
|
||||
{#if isGestor}
|
||||
<th>Ações</th>
|
||||
{/if}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each homologacoes as homologacao}
|
||||
<tr>
|
||||
<th>Data</th>
|
||||
<td>
|
||||
{new Date(homologacao.criadoEm).toLocaleDateString('pt-BR')}
|
||||
</td>
|
||||
{#if !funcionarioSelecionado}
|
||||
<th>Funcionário</th>
|
||||
{/if}
|
||||
<th>Tipo</th>
|
||||
<th>Detalhes</th>
|
||||
<th>Motivo</th>
|
||||
<th>Observações</th>
|
||||
{#if isGestor}
|
||||
<th>Ações</th>
|
||||
{/if}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each homologacoes as homologacao}
|
||||
<tr>
|
||||
<td>
|
||||
{new Date(homologacao.criadoEm).toLocaleDateString('pt-BR')}
|
||||
</td>
|
||||
{#if !funcionarioSelecionado}
|
||||
<td>
|
||||
{homologacao.funcionario?.nome || '-'}
|
||||
{#if homologacao.funcionario?.matricula}
|
||||
<br />
|
||||
<span class="text-xs text-base-content/70">
|
||||
Mat: {homologacao.funcionario.matricula}
|
||||
</span>
|
||||
{/if}
|
||||
</td>
|
||||
{/if}
|
||||
<td>
|
||||
{#if homologacao.registroId}
|
||||
<span class="badge badge-info">Edição de Registro</span>
|
||||
{:else if homologacao.tipoAjuste}
|
||||
<span class="badge badge-warning">
|
||||
Ajuste: {homologacao.tipoAjuste}
|
||||
{homologacao.funcionario?.nome || '-'}
|
||||
{#if homologacao.funcionario?.matricula}
|
||||
<br />
|
||||
<span class="text-base-content/70 text-xs">
|
||||
Mat: {homologacao.funcionario.matricula}
|
||||
</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
{#if homologacao.horaAnterior !== undefined}
|
||||
<div class="text-sm">
|
||||
<span class="line-through opacity-70">
|
||||
{formatarHoraPonto(homologacao.horaAnterior, homologacao.minutoAnterior || 0)}
|
||||
</span>
|
||||
{' → '}
|
||||
<span>
|
||||
{formatarHoraPonto(homologacao.horaNova || 0, homologacao.minutoNova || 0)}
|
||||
</span>
|
||||
</div>
|
||||
{:else if homologacao.ajusteMinutos}
|
||||
<div class="text-sm">
|
||||
{homologacao.periodoDias || 0}d {homologacao.periodoHoras || 0}h{' '}
|
||||
{homologacao.periodoMinutos || 0}min
|
||||
</div>
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
<div class="text-sm">
|
||||
{homologacao.motivoDescricao || homologacao.motivoTipo || '-'}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="text-sm max-w-xs truncate" title={homologacao.observacoes || ''}>
|
||||
{homologacao.observacoes || '-'}
|
||||
</div>
|
||||
</td>
|
||||
{#if isGestor}
|
||||
<td>
|
||||
<div class="flex gap-1">
|
||||
<button
|
||||
class="btn btn-sm btn-outline btn-info btn-square hover:btn-info hover:scale-110 transition-transform"
|
||||
onclick={() => abrirDetalhes(homologacao._id)}
|
||||
title="Ver detalhes"
|
||||
>
|
||||
<Eye class="h-4 w-4" />
|
||||
</button>
|
||||
{#if homologacao.registroId}
|
||||
<button
|
||||
class="btn btn-sm btn-square bg-primary/10 text-primary border-primary/20 hover:bg-primary/20 hover:border-primary/40 hover:shadow-md transition-all"
|
||||
onclick={() => editarHomologacao(homologacao._id)}
|
||||
title="Editar"
|
||||
>
|
||||
<Edit class="h-4 w-4" />
|
||||
</button>
|
||||
{/if}
|
||||
<button
|
||||
class="btn btn-sm btn-square bg-error/10 text-error border-error/20 hover:bg-error/20 hover:border-error/40 hover:shadow-md transition-all"
|
||||
onclick={() => abrirModalExcluir(homologacao._id)}
|
||||
title="Excluir"
|
||||
>
|
||||
<Trash2 class="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
{/if}
|
||||
<td>
|
||||
{#if homologacao.registroId}
|
||||
<span class="badge badge-info">Edição de Registro</span>
|
||||
{:else if homologacao.tipoAjuste}
|
||||
<span class="badge badge-warning">
|
||||
Ajuste: {homologacao.tipoAjuste}
|
||||
</span>
|
||||
{/if}
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{#if homologacao.horaAnterior !== undefined}
|
||||
<div class="text-sm">
|
||||
<span class="line-through opacity-70">
|
||||
{formatarHoraPonto(
|
||||
homologacao.horaAnterior,
|
||||
homologacao.minutoAnterior || 0
|
||||
)}
|
||||
</span>
|
||||
{' → '}
|
||||
<span>
|
||||
{formatarHoraPonto(
|
||||
homologacao.horaNova || 0,
|
||||
homologacao.minutoNova || 0
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{:else if homologacao.ajusteMinutos}
|
||||
<div class="text-sm">
|
||||
{homologacao.periodoDias || 0}d {homologacao.periodoHoras || 0}h{' '}
|
||||
{homologacao.periodoMinutos || 0}min
|
||||
</div>
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
<div class="text-sm">
|
||||
{homologacao.motivoDescricao || homologacao.motivoTipo || '-'}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="max-w-xs truncate text-sm" title={homologacao.observacoes || ''}>
|
||||
{homologacao.observacoes || '-'}
|
||||
</div>
|
||||
</td>
|
||||
{#if isGestor}
|
||||
<td>
|
||||
<div class="flex gap-1">
|
||||
<button
|
||||
class="btn btn-sm btn-outline btn-info btn-square hover:btn-info transition-transform hover:scale-110"
|
||||
onclick={() => abrirDetalhes(homologacao._id)}
|
||||
title="Ver detalhes"
|
||||
>
|
||||
<Eye class="h-4 w-4" />
|
||||
</button>
|
||||
{#if homologacao.registroId}
|
||||
<button
|
||||
class="btn btn-sm btn-square bg-primary/10 text-primary border-primary/20 hover:bg-primary/20 hover:border-primary/40 transition-all hover:shadow-md"
|
||||
onclick={() => editarHomologacao(homologacao._id)}
|
||||
title="Editar"
|
||||
>
|
||||
<Edit class="h-4 w-4" />
|
||||
</button>
|
||||
{/if}
|
||||
<button
|
||||
class="btn btn-sm btn-square bg-error/10 text-error border-error/20 hover:bg-error/20 hover:border-error/40 transition-all hover:shadow-md"
|
||||
onclick={() => abrirModalExcluir(homologacao._id)}
|
||||
title="Excluir"
|
||||
>
|
||||
<Trash2 class="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal de Detalhes da Homologação -->
|
||||
{#if mostrandoModalDetalhes && homologacaoSelecionada}
|
||||
<div class="modal modal-open">
|
||||
<div class="modal-box max-w-3xl">
|
||||
<h3 class="font-bold text-lg mb-4">Detalhes da Homologação</h3>
|
||||
|
||||
<h3 class="mb-4 text-lg font-bold">Detalhes da Homologação</h3>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- Informações Gerais -->
|
||||
<div class="card bg-base-200">
|
||||
<div class="card-body p-4">
|
||||
<h4 class="font-semibold mb-3">Informações Gerais</h4>
|
||||
<h4 class="mb-3 font-semibold">Informações Gerais</h4>
|
||||
<div class="grid grid-cols-2 gap-4 text-sm">
|
||||
<div>
|
||||
<span class="font-medium">Data:</span>{' '}
|
||||
@@ -984,7 +1047,7 @@
|
||||
{homologacaoSelecionada.funcionario?.nome || '-'}
|
||||
{#if homologacaoSelecionada.funcionario?.matricula}
|
||||
<br />
|
||||
<span class="text-xs text-base-content/70">
|
||||
<span class="text-base-content/70 text-xs">
|
||||
Mat: {homologacaoSelecionada.funcionario.matricula}
|
||||
</span>
|
||||
{/if}
|
||||
@@ -1011,18 +1074,24 @@
|
||||
{#if homologacaoSelecionada.registroId}
|
||||
<div class="card bg-base-200">
|
||||
<div class="card-body p-4">
|
||||
<h4 class="font-semibold mb-3">Edição de Registro</h4>
|
||||
<div class="text-sm space-y-2">
|
||||
<h4 class="mb-3 font-semibold">Edição de Registro</h4>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div>
|
||||
<span class="font-medium">Horário Anterior:</span>{' '}
|
||||
<span class="line-through opacity-70">
|
||||
{formatarHoraPonto(homologacaoSelecionada.horaAnterior || 0, homologacaoSelecionada.minutoAnterior || 0)}
|
||||
{formatarHoraPonto(
|
||||
homologacaoSelecionada.horaAnterior || 0,
|
||||
homologacaoSelecionada.minutoAnterior || 0
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-medium">Horário Novo:</span>{' '}
|
||||
<span>
|
||||
{formatarHoraPonto(homologacaoSelecionada.horaNova || 0, homologacaoSelecionada.minutoNova || 0)}
|
||||
{formatarHoraPonto(
|
||||
homologacaoSelecionada.horaNova || 0,
|
||||
homologacaoSelecionada.minutoNova || 0
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{#if homologacaoSelecionada.registro}
|
||||
@@ -1041,15 +1110,16 @@
|
||||
{:else if homologacaoSelecionada.tipoAjuste}
|
||||
<div class="card bg-base-200">
|
||||
<div class="card-body p-4">
|
||||
<h4 class="font-semibold mb-3">Ajuste de Banco de Horas</h4>
|
||||
<div class="text-sm space-y-2">
|
||||
<h4 class="mb-3 font-semibold">Ajuste de Banco de Horas</h4>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div>
|
||||
<span class="font-medium">Tipo de Ajuste:</span>{' '}
|
||||
{homologacaoSelecionada.tipoAjuste}
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-medium">Período:</span>{' '}
|
||||
{homologacaoSelecionada.periodoDias || 0}d {homologacaoSelecionada.periodoHoras || 0}h{' '}
|
||||
{homologacaoSelecionada.periodoDias || 0}d {homologacaoSelecionada.periodoHoras ||
|
||||
0}h{' '}
|
||||
{homologacaoSelecionada.periodoMinutos || 0}min
|
||||
</div>
|
||||
{#if homologacaoSelecionada.ajusteMinutos}
|
||||
@@ -1068,8 +1138,8 @@
|
||||
<!-- Motivo e Observações -->
|
||||
<div class="card bg-base-200">
|
||||
<div class="card-body p-4">
|
||||
<h4 class="font-semibold mb-3">Motivo e Observações</h4>
|
||||
<div class="text-sm space-y-2">
|
||||
<h4 class="mb-3 font-semibold">Motivo e Observações</h4>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div>
|
||||
<span class="font-medium">Tipo de Motivo:</span>{' '}
|
||||
{homologacaoSelecionada.motivoTipo || '-'}
|
||||
@@ -1081,7 +1151,7 @@
|
||||
{#if homologacaoSelecionada.observacoes}
|
||||
<div>
|
||||
<span class="font-medium">Observações:</span>
|
||||
<div class="mt-1 p-2 bg-base-100 rounded">
|
||||
<div class="bg-base-100 mt-1 rounded p-2">
|
||||
{homologacaoSelecionada.observacoes}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1103,14 +1173,14 @@
|
||||
{#if mostrandoModalExcluir && homologacaoParaExcluir}
|
||||
<div class="modal modal-open">
|
||||
<div class="modal-box">
|
||||
<h3 class="font-bold text-lg mb-4">Confirmar Exclusão</h3>
|
||||
<h3 class="mb-4 text-lg font-bold">Confirmar Exclusão</h3>
|
||||
<p class="mb-4">
|
||||
Tem certeza que deseja excluir esta homologação? Esta ação não pode ser desfeita.
|
||||
</p>
|
||||
<div class="modal-action">
|
||||
<button class="btn btn-ghost" onclick={fecharModalExcluir}>Cancelar</button>
|
||||
<button class="btn btn-error" onclick={excluirHomologacao}>
|
||||
<Trash2 class="h-4 w-4 mr-2" />
|
||||
<Trash2 class="mr-2 h-4 w-4" />
|
||||
Excluir
|
||||
</button>
|
||||
</div>
|
||||
@@ -1119,4 +1189,3 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user