feat: update PDF generation to use symbols for day types and implement confirmation modal for record deletion in absence and license management, enhancing user experience and data integrity
This commit is contained in:
@@ -216,14 +216,14 @@ function gerarTabelaRegistrosPDF(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Função auxiliar para obter ícone do tipo de dia
|
// Função auxiliar para obter símbolo do tipo de dia
|
||||||
const obterIconeTipoDia = (dia: DiaFichaPonto): string => {
|
const obterSimboloTipoDia = (dia: DiaFichaPonto): string => {
|
||||||
if (dia.atestado) return '🏥';
|
if (dia.atestado) return 'AT';
|
||||||
if (dia.ausencia) return '🚫';
|
if (dia.ausencia) return 'AUS';
|
||||||
if (dia.licenca) return '📋';
|
if (dia.licenca) return 'LIC';
|
||||||
if (dia.tipoDia === 'abonado') return '✅';
|
if (dia.tipoDia === 'abonado') return 'ABO';
|
||||||
if (dia.tipoDia === 'nao_computado') return '⏸';
|
if (dia.tipoDia === 'nao_computado') return 'NC';
|
||||||
if (dia.inconsistencias.length > 0) return '⚠';
|
if (dia.inconsistencias.length > 0) return 'INC';
|
||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -258,8 +258,10 @@ function gerarTabelaRegistrosPDF(
|
|||||||
|
|
||||||
// Coluna Data (apenas na primeira linha)
|
// Coluna Data (apenas na primeira linha)
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
|
const simbolo = obterSimboloTipoDia(dia);
|
||||||
|
const dataComSimbolo = simbolo ? `${dataFormatada} [${simbolo}]` : dataFormatada;
|
||||||
linha.push({
|
linha.push({
|
||||||
content: `${dataFormatada} ${obterIconeTipoDia(dia)}`,
|
content: dataComSimbolo,
|
||||||
styles: {
|
styles: {
|
||||||
fillColor: obterCorFundoTipoDia(dia.tipoDia),
|
fillColor: obterCorFundoTipoDia(dia.tipoDia),
|
||||||
fontStyle: 'bold'
|
fontStyle: 'bold'
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
import FuncionarioMatriculaAutocomplete from '$lib/components/FuncionarioMatriculaAutocomplete.svelte';
|
import FuncionarioMatriculaAutocomplete from '$lib/components/FuncionarioMatriculaAutocomplete.svelte';
|
||||||
import FileUpload from '$lib/components/FileUpload.svelte';
|
import FileUpload from '$lib/components/FileUpload.svelte';
|
||||||
import ErrorModal from '$lib/components/ErrorModal.svelte';
|
import ErrorModal from '$lib/components/ErrorModal.svelte';
|
||||||
|
import ConfirmModal from '$lib/components/ConfirmModal.svelte';
|
||||||
import CalendarioAfastamentos from '$lib/components/CalendarioAfastamentos.svelte';
|
import CalendarioAfastamentos from '$lib/components/CalendarioAfastamentos.svelte';
|
||||||
import AreaChart from '$lib/components/ti/charts/AreaChart.svelte';
|
import AreaChart from '$lib/components/ti/charts/AreaChart.svelte';
|
||||||
import UserAvatar from '$lib/components/chat/UserAvatar.svelte';
|
import UserAvatar from '$lib/components/chat/UserAvatar.svelte';
|
||||||
@@ -132,6 +133,14 @@
|
|||||||
titulo: ''
|
titulo: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Modal de exclusão
|
||||||
|
let exclusaoModal = $state({
|
||||||
|
aberto: false,
|
||||||
|
tipo: null as 'atestado' | 'licenca' | null,
|
||||||
|
id: null as string | null,
|
||||||
|
nome: ''
|
||||||
|
});
|
||||||
|
|
||||||
// Licenças maternidade para prorrogação (derivar dos dados já carregados)
|
// Licenças maternidade para prorrogação (derivar dos dados já carregados)
|
||||||
let licencasMaternidade = $derived.by(() => {
|
let licencasMaternidade = $derived.by(() => {
|
||||||
const dados = dadosQuery?.data;
|
const dados = dadosQuery?.data;
|
||||||
@@ -651,26 +660,42 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Excluir registro
|
// Abrir modal de exclusão
|
||||||
async function excluirRegistro(tipo: 'atestado' | 'licenca', id: string) {
|
function abrirModalExclusao(tipo: 'atestado' | 'licenca', id: string, nome: string) {
|
||||||
if (!confirm(`Tem certeza que deseja excluir este ${tipo}?`)) return;
|
exclusaoModal = {
|
||||||
|
aberto: true,
|
||||||
|
tipo,
|
||||||
|
id,
|
||||||
|
nome
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirmar exclusão
|
||||||
|
async function confirmarExclusao() {
|
||||||
|
if (!exclusaoModal.tipo || !exclusaoModal.id) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (tipo === 'atestado') {
|
if (exclusaoModal.tipo === 'atestado') {
|
||||||
await client.mutation(api.atestadosLicencas.excluirAtestado, {
|
await client.mutation(api.atestadosLicencas.excluirAtestado, {
|
||||||
id: id as Id<'atestados'>
|
id: exclusaoModal.id as Id<'atestados'>
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await client.mutation(api.atestadosLicencas.excluirLicenca, {
|
await client.mutation(api.atestadosLicencas.excluirLicenca, {
|
||||||
id: id as Id<'licencas'>
|
id: exclusaoModal.id as Id<'licencas'>
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
toast.success('Registro excluído com sucesso!');
|
toast.success('Registro excluído com sucesso!');
|
||||||
|
exclusaoModal.aberto = false;
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
toast.error(getErrorMessage(error, 'Erro ao excluir registro'));
|
toast.error(getErrorMessage(error, 'Erro ao excluir registro'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cancelar exclusão
|
||||||
|
function cancelarExclusao() {
|
||||||
|
exclusaoModal.aberto = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Filtrar registros
|
// Filtrar registros
|
||||||
let registrosFiltrados = $derived.by(() => {
|
let registrosFiltrados = $derived.by(() => {
|
||||||
const dados = dadosQuery?.data;
|
const dados = dadosQuery?.data;
|
||||||
@@ -1677,7 +1702,12 @@
|
|||||||
{/if}
|
{/if}
|
||||||
<button
|
<button
|
||||||
class="btn btn-xs btn-error"
|
class="btn btn-xs btn-error"
|
||||||
onclick={() => excluirRegistro('atestado', atestado._id)}
|
onclick={() =>
|
||||||
|
abrirModalExclusao(
|
||||||
|
'atestado',
|
||||||
|
atestado._id,
|
||||||
|
`${atestado.tipo === 'atestado_medico' ? 'Atestado Médico' : 'Declaração'} - ${atestado.funcionario?.nome || 'Funcionário'}`
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
Excluir
|
Excluir
|
||||||
</button>
|
</button>
|
||||||
@@ -1739,7 +1769,12 @@
|
|||||||
{/if}
|
{/if}
|
||||||
<button
|
<button
|
||||||
class="btn btn-xs btn-error"
|
class="btn btn-xs btn-error"
|
||||||
onclick={() => excluirRegistro('licenca', licenca._id)}
|
onclick={() =>
|
||||||
|
abrirModalExclusao(
|
||||||
|
'licenca',
|
||||||
|
licenca._id,
|
||||||
|
`${licenca.tipo === 'maternidade' ? 'Licença Maternidade' : 'Licença Paternidade'} - ${licenca.funcionario?.nome || 'Funcionário'}`
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
Excluir
|
Excluir
|
||||||
</button>
|
</button>
|
||||||
@@ -2438,6 +2473,17 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- Modal de Confirmação de Exclusão -->
|
||||||
|
<ConfirmModal
|
||||||
|
bind:open={exclusaoModal.aberto}
|
||||||
|
title="Confirmar Exclusão"
|
||||||
|
message="Tem certeza que deseja excluir este registro? Esta ação não pode ser desfeita e todos os dados relacionados serão removidos permanentemente."
|
||||||
|
confirmText="Excluir"
|
||||||
|
cancelText="Cancelar"
|
||||||
|
onConfirm={confirmarExclusao}
|
||||||
|
onCancel={cancelarExclusao}
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- Modal de Documento -->
|
<!-- Modal de Documento -->
|
||||||
{#if documentoModal.aberto}
|
{#if documentoModal.aberto}
|
||||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ export const listarTodos = query({
|
|||||||
fotoPerfilUrl,
|
fotoPerfilUrl,
|
||||||
criadoPorNome: criadoPor?.nome || 'Sistema',
|
criadoPorNome: criadoPor?.nome || 'Sistema',
|
||||||
dias: calcularDias(a.dataInicio, a.dataFim),
|
dias: calcularDias(a.dataInicio, a.dataFim),
|
||||||
status: new Date(a.dataFim) >= new Date() ? 'ativo' : 'finalizado'
|
status: new Date() > new Date(a.dataFim) ? 'finalizado' : 'ativo'
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erro ao buscar detalhes do atestado:', error);
|
console.error('Erro ao buscar detalhes do atestado:', error);
|
||||||
@@ -192,7 +192,7 @@ export const listarTodos = query({
|
|||||||
fotoPerfilUrl: null,
|
fotoPerfilUrl: null,
|
||||||
criadoPorNome: 'Sistema',
|
criadoPorNome: 'Sistema',
|
||||||
dias: calcularDias(a.dataInicio, a.dataFim),
|
dias: calcularDias(a.dataInicio, a.dataFim),
|
||||||
status: new Date(a.dataFim) >= new Date() ? 'ativo' : 'finalizado'
|
status: new Date() > new Date(a.dataFim) ? 'finalizado' : 'ativo'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -226,7 +226,7 @@ export const listarTodos = query({
|
|||||||
criadoPorNome: criadoPor?.nome || 'Sistema',
|
criadoPorNome: criadoPor?.nome || 'Sistema',
|
||||||
licencaOriginal,
|
licencaOriginal,
|
||||||
dias: calcularDias(l.dataInicio, l.dataFim),
|
dias: calcularDias(l.dataInicio, l.dataFim),
|
||||||
status: new Date(l.dataFim) >= new Date() ? 'ativo' : 'finalizado'
|
status: new Date() > new Date(l.dataFim) ? 'finalizado' : 'ativo'
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erro ao buscar detalhes da licença:', error);
|
console.error('Erro ao buscar detalhes da licença:', error);
|
||||||
@@ -237,7 +237,7 @@ export const listarTodos = query({
|
|||||||
criadoPorNome: 'Sistema',
|
criadoPorNome: 'Sistema',
|
||||||
licencaOriginal: null,
|
licencaOriginal: null,
|
||||||
dias: calcularDias(l.dataInicio, l.dataFim),
|
dias: calcularDias(l.dataInicio, l.dataFim),
|
||||||
status: new Date(l.dataFim) >= new Date() ? 'ativo' : 'finalizado'
|
status: new Date() > new Date(l.dataFim) ? 'finalizado' : 'ativo'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1255,6 +1255,32 @@ export const excluirAtestado = mutation({
|
|||||||
const dataInicio = atestado.dataInicio; // Data início do atestado
|
const dataInicio = atestado.dataInicio; // Data início do atestado
|
||||||
const dataFim = atestado.dataFim; // Data fim do atestado
|
const dataFim = atestado.dataFim; // Data fim do atestado
|
||||||
const atestadoId = args.id.toString(); // ID do atestado para remover ajustes
|
const atestadoId = args.id.toString(); // ID do atestado para remover ajustes
|
||||||
|
const documentoId = atestado.documentoId; // ID do documento para remover do storage
|
||||||
|
|
||||||
|
// Remover logs de atividades relacionados ao atestado
|
||||||
|
try {
|
||||||
|
const logs = await ctx.db
|
||||||
|
.query('logsAtividades')
|
||||||
|
.withIndex('by_recurso_id', (q) =>
|
||||||
|
q.eq('recurso', 'atestados').eq('recursoId', atestadoId)
|
||||||
|
)
|
||||||
|
.collect();
|
||||||
|
for (const log of logs) {
|
||||||
|
await ctx.db.delete(log._id);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[excluirAtestado] Erro ao remover logs de atividades:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remover documento do storage se existir
|
||||||
|
if (documentoId) {
|
||||||
|
try {
|
||||||
|
await ctx.storage.delete(documentoId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[excluirAtestado] Erro ao remover documento do storage:', error);
|
||||||
|
// Não falhar a exclusão se o documento não existir mais
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Excluir o registro do banco de dados
|
// Excluir o registro do banco de dados
|
||||||
await ctx.db.delete(args.id);
|
await ctx.db.delete(args.id);
|
||||||
@@ -1319,6 +1345,33 @@ export const excluirLicenca = mutation({
|
|||||||
const funcionarioId = licenca.funcionarioId;
|
const funcionarioId = licenca.funcionarioId;
|
||||||
const dataInicio = licenca.dataInicio; // Data início da licença
|
const dataInicio = licenca.dataInicio; // Data início da licença
|
||||||
const dataFim = licenca.dataFim; // Data fim da licença
|
const dataFim = licenca.dataFim; // Data fim da licença
|
||||||
|
const licencaId = args.id.toString(); // ID da licença para remover logs
|
||||||
|
const documentoId = licenca.documentoId; // ID do documento para remover do storage
|
||||||
|
|
||||||
|
// Remover logs de atividades relacionados à licença
|
||||||
|
try {
|
||||||
|
const logs = await ctx.db
|
||||||
|
.query('logsAtividades')
|
||||||
|
.withIndex('by_recurso_id', (q) =>
|
||||||
|
q.eq('recurso', 'licencas').eq('recursoId', licencaId)
|
||||||
|
)
|
||||||
|
.collect();
|
||||||
|
for (const log of logs) {
|
||||||
|
await ctx.db.delete(log._id);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[excluirLicenca] Erro ao remover logs de atividades:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remover documento do storage se existir
|
||||||
|
if (documentoId) {
|
||||||
|
try {
|
||||||
|
await ctx.storage.delete(documentoId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[excluirLicenca] Erro ao remover documento do storage:', error);
|
||||||
|
// Não falhar a exclusão se o documento não existir mais
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Excluir o registro do banco de dados
|
// Excluir o registro do banco de dados
|
||||||
await ctx.db.delete(args.id);
|
await ctx.db.delete(args.id);
|
||||||
@@ -1332,6 +1385,19 @@ export const excluirLicenca = mutation({
|
|||||||
args.id
|
args.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Remover ajustes automáticos relacionados à licença excluída
|
||||||
|
try {
|
||||||
|
await ctx.runMutation(internal.pontos.removerAjustesAutomaticosInternal, {
|
||||||
|
funcionarioId,
|
||||||
|
motivoTipo: 'licenca',
|
||||||
|
motivoId: licencaId,
|
||||||
|
dataInicio,
|
||||||
|
dataFim
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[excluirLicenca] Erro ao remover ajustes automáticos:', error);
|
||||||
|
}
|
||||||
|
|
||||||
// Recalcular banco de horas APENAS para o período específico da licença excluída
|
// Recalcular banco de horas APENAS para o período específico da licença excluída
|
||||||
// Isso garante que os dias da licença sejam removidos corretamente dos registros de ponto
|
// Isso garante que os dias da licença sejam removidos corretamente dos registros de ponto
|
||||||
await recalcularBancoHorasPeriodo(ctx, funcionarioId, dataInicio, dataFim);
|
await recalcularBancoHorasPeriodo(ctx, funcionarioId, dataInicio, dataFim);
|
||||||
|
|||||||
Reference in New Issue
Block a user