feat: add Excel and PDF report generation functionality for employee leave and certificate data, integrating XLSX and jsPDF libraries for enhanced reporting capabilities
This commit is contained in:
@@ -5,15 +5,23 @@
|
||||
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import FuncionarioSelect from '$lib/components/FuncionarioSelect.svelte';
|
||||
import FuncionarioNomeAutocomplete from '$lib/components/FuncionarioNomeAutocomplete.svelte';
|
||||
import FuncionarioMatriculaAutocomplete from '$lib/components/FuncionarioMatriculaAutocomplete.svelte';
|
||||
import FileUpload from '$lib/components/FileUpload.svelte';
|
||||
import ErrorModal from '$lib/components/ErrorModal.svelte';
|
||||
import CalendarioAfastamentos from '$lib/components/CalendarioAfastamentos.svelte';
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
import jsPDF from 'jspdf';
|
||||
import autoTable from 'jspdf-autotable';
|
||||
import * as XLSX from 'xlsx';
|
||||
import logoGovPE from '$lib/assets/logo_governo_PE.png';
|
||||
import { format } from 'date-fns';
|
||||
import { ptBR } from 'date-fns/locale';
|
||||
|
||||
const client = useConvexClient();
|
||||
|
||||
// Estado da aba ativa
|
||||
let abaAtiva = $state<'dashboard' | 'atestado' | 'declaracao' | 'maternidade' | 'paternidade'>(
|
||||
let abaAtiva = $state<'dashboard' | 'atestado' | 'declaracao' | 'maternidade' | 'paternidade' | 'relatorios'>(
|
||||
'dashboard'
|
||||
);
|
||||
|
||||
@@ -489,6 +497,389 @@
|
||||
filtroDataInicio = '';
|
||||
filtroDataFim = '';
|
||||
}
|
||||
|
||||
// Estados para relatórios
|
||||
let relatorioPeriodoInicio = $state('');
|
||||
let relatorioPeriodoFim = $state('');
|
||||
let relatorioFuncionarioNome = $state('');
|
||||
let relatorioFuncionarioMatricula = $state('');
|
||||
let relatorioCampos = $state({
|
||||
atestados: false,
|
||||
licencaPaternidade: false,
|
||||
licencaMaternidade: false,
|
||||
declaracao: false,
|
||||
todos: false
|
||||
});
|
||||
let gerandoRelatorio = $state(false);
|
||||
|
||||
// Função para obter dados filtrados para relatório
|
||||
async function obterDadosRelatorio() {
|
||||
const dados = dadosQuery?.data;
|
||||
if (!dados) return { atestados: [], licencas: [] };
|
||||
|
||||
let atestados = dados.atestados;
|
||||
let licencas = dados.licencas;
|
||||
|
||||
// Filtro por período
|
||||
if (relatorioPeriodoInicio && relatorioPeriodoFim) {
|
||||
const inicio = new Date(relatorioPeriodoInicio);
|
||||
const fim = new Date(relatorioPeriodoFim);
|
||||
atestados = atestados.filter((a) => {
|
||||
const aInicio = new Date(a.dataInicio);
|
||||
const aFim = new Date(a.dataFim);
|
||||
return (
|
||||
(aInicio >= inicio && aInicio <= fim) ||
|
||||
(aFim >= inicio && aFim <= fim) ||
|
||||
(aInicio <= inicio && aFim >= fim)
|
||||
);
|
||||
});
|
||||
licencas = licencas.filter((l) => {
|
||||
const lInicio = new Date(l.dataInicio);
|
||||
const lFim = new Date(l.dataFim);
|
||||
return (
|
||||
(lInicio >= inicio && lInicio <= fim) ||
|
||||
(lFim >= inicio && lFim <= fim) ||
|
||||
(lInicio <= inicio && lFim >= fim)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Filtro por funcionário (nome ou matrícula)
|
||||
if (relatorioFuncionarioNome || relatorioFuncionarioMatricula) {
|
||||
const termoNome = relatorioFuncionarioNome.toLowerCase();
|
||||
const termoMatricula = relatorioFuncionarioMatricula.toLowerCase();
|
||||
atestados = atestados.filter((a) => {
|
||||
const nomeMatch = !termoNome || a.funcionario?.nome?.toLowerCase().includes(termoNome);
|
||||
const matriculaMatch = !termoMatricula || a.funcionario?.matricula?.toLowerCase().includes(termoMatricula);
|
||||
return nomeMatch && matriculaMatch;
|
||||
});
|
||||
licencas = licencas.filter((l) => {
|
||||
const nomeMatch = !termoNome || l.funcionario?.nome?.toLowerCase().includes(termoNome);
|
||||
const matriculaMatch = !termoMatricula || l.funcionario?.matricula?.toLowerCase().includes(termoMatricula);
|
||||
return nomeMatch && matriculaMatch;
|
||||
});
|
||||
}
|
||||
|
||||
// Filtro por campos selecionados
|
||||
if (!relatorioCampos.todos) {
|
||||
if (!relatorioCampos.atestados) {
|
||||
atestados = atestados.filter((a) => a.tipo !== 'atestado_medico');
|
||||
}
|
||||
if (!relatorioCampos.declaracao) {
|
||||
atestados = atestados.filter((a) => a.tipo !== 'declaracao_comparecimento');
|
||||
}
|
||||
if (!relatorioCampos.licencaMaternidade) {
|
||||
licencas = licencas.filter((l) => l.tipo !== 'maternidade');
|
||||
}
|
||||
if (!relatorioCampos.licencaPaternidade) {
|
||||
licencas = licencas.filter((l) => l.tipo !== 'paternidade');
|
||||
}
|
||||
}
|
||||
|
||||
return { atestados, licencas };
|
||||
}
|
||||
|
||||
// Função para gerar PDF
|
||||
async function gerarPDF() {
|
||||
if (!relatorioPeriodoInicio || !relatorioPeriodoFim) {
|
||||
toast.error('Selecione o período para gerar o relatório');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!relatorioCampos.todos && !relatorioCampos.atestados && !relatorioCampos.declaracao && !relatorioCampos.licencaMaternidade && !relatorioCampos.licencaPaternidade) {
|
||||
toast.error('Selecione pelo menos um tipo de campo para incluir no relatório');
|
||||
return;
|
||||
}
|
||||
|
||||
gerandoRelatorio = true;
|
||||
try {
|
||||
const { atestados, licencas } = await obterDadosRelatorio();
|
||||
const doc = new jsPDF();
|
||||
|
||||
// Logo
|
||||
let yPosition = 20;
|
||||
try {
|
||||
const logoImg = new Image();
|
||||
logoImg.src = logoGovPE;
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
logoImg.onload = () => resolve();
|
||||
logoImg.onerror = () => reject();
|
||||
setTimeout(() => reject(), 3000);
|
||||
});
|
||||
|
||||
const logoWidth = 30;
|
||||
const aspectRatio = logoImg.height / logoImg.width;
|
||||
const logoHeight = logoWidth * aspectRatio;
|
||||
|
||||
doc.addImage(logoImg, 'PNG', 15, 10, logoWidth, logoHeight);
|
||||
yPosition = Math.max(25, 10 + logoHeight / 2);
|
||||
} catch (err) {
|
||||
console.warn('Não foi possível carregar a logo:', err);
|
||||
}
|
||||
|
||||
// Título
|
||||
doc.setFontSize(18);
|
||||
doc.setTextColor(41, 128, 185);
|
||||
doc.text('RELATÓRIO DE ATESTADOS E LICENÇAS', 105, yPosition, { align: 'center' });
|
||||
|
||||
yPosition += 10;
|
||||
|
||||
// Período
|
||||
doc.setFontSize(11);
|
||||
doc.setTextColor(0, 0, 0);
|
||||
doc.text(
|
||||
`Período: ${format(new Date(relatorioPeriodoInicio), 'dd/MM/yyyy', { locale: ptBR })} até ${format(new Date(relatorioPeriodoFim), 'dd/MM/yyyy', { locale: ptBR })}`,
|
||||
105,
|
||||
yPosition,
|
||||
{ align: 'center' }
|
||||
);
|
||||
|
||||
yPosition += 8;
|
||||
|
||||
// Filtros aplicados
|
||||
doc.setFontSize(9);
|
||||
doc.setTextColor(100, 100, 100);
|
||||
let filtrosTexto = 'Filtros: ';
|
||||
if (relatorioFuncionarioNome) filtrosTexto += `Nome: ${relatorioFuncionarioNome}; `;
|
||||
if (relatorioFuncionarioMatricula) filtrosTexto += `Matrícula: ${relatorioFuncionarioMatricula}; `;
|
||||
if (relatorioCampos.todos) filtrosTexto += 'Todos os tipos';
|
||||
else {
|
||||
const tipos = [];
|
||||
if (relatorioCampos.atestados) tipos.push('Atestados');
|
||||
if (relatorioCampos.declaracao) tipos.push('Declarações');
|
||||
if (relatorioCampos.licencaMaternidade) tipos.push('Licença Maternidade');
|
||||
if (relatorioCampos.licencaPaternidade) tipos.push('Licença Paternidade');
|
||||
filtrosTexto += tipos.join(', ');
|
||||
}
|
||||
doc.text(filtrosTexto, 105, yPosition, { align: 'center', maxWidth: 180 });
|
||||
|
||||
yPosition += 10;
|
||||
|
||||
// Data de geração
|
||||
doc.setFontSize(9);
|
||||
doc.text(`Gerado em: ${format(new Date(), 'dd/MM/yyyy HH:mm', { locale: ptBR })}`, 15, yPosition);
|
||||
|
||||
yPosition += 12;
|
||||
|
||||
// Preparar dados para tabela
|
||||
const dadosTabela: string[][] = [];
|
||||
|
||||
// Adicionar atestados
|
||||
if (relatorioCampos.todos || relatorioCampos.atestados || relatorioCampos.declaracao) {
|
||||
atestados.forEach((a) => {
|
||||
const tipo = a.tipo === 'atestado_medico' ? 'Atestado Médico' : 'Declaração';
|
||||
dadosTabela.push([
|
||||
a.funcionario?.nome || '-',
|
||||
a.funcionario?.matricula || '-',
|
||||
tipo,
|
||||
formatarData(a.dataInicio),
|
||||
formatarData(a.dataFim),
|
||||
a.dias.toString(),
|
||||
a.cid || '-',
|
||||
a.status === 'ativo' ? 'Ativo' : 'Finalizado'
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
// Adicionar licenças
|
||||
if (relatorioCampos.todos || relatorioCampos.licencaMaternidade || relatorioCampos.licencaPaternidade) {
|
||||
licencas.forEach((l) => {
|
||||
const tipo = l.tipo === 'maternidade' ? 'Licença Maternidade' : 'Licença Paternidade';
|
||||
dadosTabela.push([
|
||||
l.funcionario?.nome || '-',
|
||||
l.funcionario?.matricula || '-',
|
||||
tipo + (l.ehProrrogacao ? ' (Prorrogação)' : ''),
|
||||
formatarData(l.dataInicio),
|
||||
formatarData(l.dataFim),
|
||||
l.dias.toString(),
|
||||
'-',
|
||||
l.status === 'ativo' ? 'Ativo' : 'Finalizado'
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
// Ordenar por data de início
|
||||
dadosTabela.sort((a, b) => {
|
||||
const dataA = new Date(a[3].split('/').reverse().join('-'));
|
||||
const dataB = new Date(b[3].split('/').reverse().join('-'));
|
||||
return dataA.getTime() - dataB.getTime();
|
||||
});
|
||||
|
||||
// Tabela
|
||||
if (dadosTabela.length > 0) {
|
||||
autoTable(doc, {
|
||||
startY: yPosition,
|
||||
head: [['Funcionário', 'Matrícula', 'Tipo', 'Data Início', 'Data Fim', 'Dias', 'CID', 'Status']],
|
||||
body: dadosTabela,
|
||||
theme: 'striped',
|
||||
headStyles: {
|
||||
fillColor: [41, 128, 185],
|
||||
textColor: [255, 255, 255],
|
||||
fontStyle: 'bold'
|
||||
},
|
||||
styles: { fontSize: 8 },
|
||||
columnStyles: {
|
||||
0: { cellWidth: 50 },
|
||||
1: { cellWidth: 25 },
|
||||
2: { cellWidth: 40 },
|
||||
3: { cellWidth: 25 },
|
||||
4: { cellWidth: 25 },
|
||||
5: { cellWidth: 15 },
|
||||
6: { cellWidth: 20 },
|
||||
7: { cellWidth: 20 }
|
||||
}
|
||||
});
|
||||
|
||||
// Rodapé
|
||||
const pageCount = doc.getNumberOfPages();
|
||||
for (let i = 1; i <= pageCount; i++) {
|
||||
doc.setPage(i);
|
||||
doc.setFontSize(8);
|
||||
doc.setTextColor(128, 128, 128);
|
||||
doc.text(
|
||||
`SGSE - Sistema de Gerenciamento de Secretaria | Página ${i} de ${pageCount}`,
|
||||
doc.internal.pageSize.getWidth() / 2,
|
||||
doc.internal.pageSize.getHeight() - 10,
|
||||
{ align: 'center' }
|
||||
);
|
||||
}
|
||||
} else {
|
||||
doc.setFontSize(12);
|
||||
doc.setTextColor(150, 150, 150);
|
||||
doc.text('Nenhum registro encontrado para os filtros selecionados', 105, yPosition + 20, {
|
||||
align: 'center'
|
||||
});
|
||||
}
|
||||
|
||||
// Salvar
|
||||
const nomeArquivo = `relatorio-atestados-licencas-${format(new Date(), 'yyyy-MM-dd-HHmm')}.pdf`;
|
||||
doc.save(nomeArquivo);
|
||||
toast.success('Relatório PDF gerado com sucesso!');
|
||||
} catch (error) {
|
||||
console.error('Erro ao gerar PDF:', error);
|
||||
toast.error('Erro ao gerar relatório PDF. Tente novamente.');
|
||||
} finally {
|
||||
gerandoRelatorio = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Função para gerar Excel
|
||||
async function gerarExcel() {
|
||||
if (!relatorioPeriodoInicio || !relatorioPeriodoFim) {
|
||||
toast.error('Selecione o período para gerar o relatório');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!relatorioCampos.todos && !relatorioCampos.atestados && !relatorioCampos.declaracao && !relatorioCampos.licencaMaternidade && !relatorioCampos.licencaPaternidade) {
|
||||
toast.error('Selecione pelo menos um tipo de campo para incluir no relatório');
|
||||
return;
|
||||
}
|
||||
|
||||
gerandoRelatorio = true;
|
||||
try {
|
||||
const { atestados, licencas } = await obterDadosRelatorio();
|
||||
|
||||
// Preparar dados
|
||||
const dados: Array<Record<string, string | number>> = [];
|
||||
|
||||
// Adicionar atestados
|
||||
if (relatorioCampos.todos || relatorioCampos.atestados || relatorioCampos.declaracao) {
|
||||
atestados.forEach((a) => {
|
||||
const tipo = a.tipo === 'atestado_medico' ? 'Atestado Médico' : 'Declaração';
|
||||
dados.push({
|
||||
'Funcionário': a.funcionario?.nome || '-',
|
||||
'Matrícula': a.funcionario?.matricula || '-',
|
||||
'Tipo': tipo,
|
||||
'Data Início': formatarData(a.dataInicio),
|
||||
'Data Fim': formatarData(a.dataFim),
|
||||
'Dias': a.dias,
|
||||
'CID': a.cid || '-',
|
||||
'Status': a.status === 'ativo' ? 'Ativo' : 'Finalizado'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Adicionar licenças
|
||||
if (relatorioCampos.todos || relatorioCampos.licencaMaternidade || relatorioCampos.licencaPaternidade) {
|
||||
licencas.forEach((l) => {
|
||||
const tipo = l.tipo === 'maternidade' ? 'Licença Maternidade' : 'Licença Paternidade';
|
||||
dados.push({
|
||||
'Funcionário': l.funcionario?.nome || '-',
|
||||
'Matrícula': l.funcionario?.matricula || '-',
|
||||
'Tipo': tipo + (l.ehProrrogacao ? ' (Prorrogação)' : ''),
|
||||
'Data Início': formatarData(l.dataInicio),
|
||||
'Data Fim': formatarData(l.dataFim),
|
||||
'Dias': l.dias,
|
||||
'CID': '-',
|
||||
'Status': l.status === 'ativo' ? 'Ativo' : 'Finalizado'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Ordenar por data de início
|
||||
dados.sort((a, b) => {
|
||||
const dataAStr = a['Data Início'] as string;
|
||||
const dataBStr = b['Data Início'] as string;
|
||||
const dataA = new Date(dataAStr.split('/').reverse().join('-'));
|
||||
const dataB = new Date(dataBStr.split('/').reverse().join('-'));
|
||||
return dataA.getTime() - dataB.getTime();
|
||||
});
|
||||
|
||||
// Criar workbook
|
||||
const wb = XLSX.utils.book_new();
|
||||
|
||||
// Criar worksheet
|
||||
const ws = XLSX.utils.json_to_sheet(dados);
|
||||
|
||||
// Ajustar largura das colunas
|
||||
const colWidths = [
|
||||
{ wch: 30 }, // Funcionário
|
||||
{ wch: 15 }, // Matrícula
|
||||
{ wch: 25 }, // Tipo
|
||||
{ wch: 12 }, // Data Início
|
||||
{ wch: 12 }, // Data Fim
|
||||
{ wch: 8 }, // Dias
|
||||
{ wch: 12 }, // CID
|
||||
{ wch: 12 } // Status
|
||||
];
|
||||
ws['!cols'] = colWidths;
|
||||
|
||||
// Adicionar worksheet ao workbook
|
||||
XLSX.utils.book_append_sheet(wb, ws, 'Relatório');
|
||||
|
||||
// Gerar arquivo
|
||||
const nomeArquivo = `relatorio-atestados-licencas-${format(new Date(), 'yyyy-MM-dd-HHmm')}.xlsx`;
|
||||
XLSX.writeFile(wb, nomeArquivo);
|
||||
|
||||
toast.success('Relatório Excel gerado com sucesso!');
|
||||
} catch (error) {
|
||||
console.error('Erro ao gerar Excel:', error);
|
||||
toast.error('Erro ao gerar relatório Excel. Tente novamente.');
|
||||
} finally {
|
||||
gerandoRelatorio = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Função para selecionar/deselecionar todos os campos
|
||||
function toggleTodosCampos() {
|
||||
if (relatorioCampos.todos) {
|
||||
relatorioCampos = {
|
||||
atestados: false,
|
||||
licencaPaternidade: false,
|
||||
licencaMaternidade: false,
|
||||
declaracao: false,
|
||||
todos: false
|
||||
};
|
||||
} else {
|
||||
relatorioCampos = {
|
||||
atestados: true,
|
||||
licencaPaternidade: true,
|
||||
licencaMaternidade: true,
|
||||
declaracao: true,
|
||||
todos: true
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -611,6 +1002,26 @@
|
||||
>
|
||||
Licença Paternidade
|
||||
</button>
|
||||
<button
|
||||
class="tab {abaAtiva === 'relatorios' ? 'tab-active' : ''}"
|
||||
onclick={() => (abaAtiva = 'relatorios')}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="mr-2 h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"
|
||||
/>
|
||||
</svg>
|
||||
Imprimir Relatórios
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Conteúdo das Abas -->
|
||||
@@ -1657,10 +2068,198 @@
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else if abaAtiva === 'relatorios'}
|
||||
<!-- Aba Imprimir Relatórios -->
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title mb-6">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"
|
||||
/>
|
||||
</svg>
|
||||
Imprimir Relatórios
|
||||
</h2>
|
||||
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||
<!-- Filtro de Período -->
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium"
|
||||
>Data Início <span class="text-error">*</span></span
|
||||
>
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
bind:value={relatorioPeriodoInicio}
|
||||
class="input input-bordered"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Data Fim <span class="text-error">*</span></span>
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
bind:value={relatorioPeriodoFim}
|
||||
class="input input-bordered"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Filtro de Funcionário por Nome -->
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Funcionário (Nome)</span>
|
||||
</label>
|
||||
<FuncionarioNomeAutocomplete
|
||||
bind:value={relatorioFuncionarioNome}
|
||||
placeholder="Digite o nome do funcionário"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Filtro de Funcionário por Matrícula -->
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Funcionário (Matrícula)</span>
|
||||
</label>
|
||||
<FuncionarioMatriculaAutocomplete
|
||||
bind:value={relatorioFuncionarioMatricula}
|
||||
placeholder="Digite a matrícula do funcionário"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Seleção de Campos -->
|
||||
<div class="mt-6">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium"
|
||||
>Campos a incluir no relatório <span class="text-error">*</span></span
|
||||
>
|
||||
</label>
|
||||
<div class="grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3">
|
||||
<label class="label cursor-pointer justify-start gap-3 rounded-lg border border-base-300 p-4 hover:bg-base-200">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={relatorioCampos.todos}
|
||||
onchange={toggleTodosCampos}
|
||||
class="checkbox checkbox-primary"
|
||||
/>
|
||||
<span class="label-text font-medium">Todos</span>
|
||||
</label>
|
||||
|
||||
<label class="label cursor-pointer justify-start gap-3 rounded-lg border border-base-300 p-4 hover:bg-base-200">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={relatorioCampos.atestados}
|
||||
class="checkbox checkbox-primary"
|
||||
disabled={relatorioCampos.todos}
|
||||
/>
|
||||
<span class="label-text font-medium">Atestados</span>
|
||||
</label>
|
||||
|
||||
<label class="label cursor-pointer justify-start gap-3 rounded-lg border border-base-300 p-4 hover:bg-base-200">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={relatorioCampos.licencaPaternidade}
|
||||
class="checkbox checkbox-primary"
|
||||
disabled={relatorioCampos.todos}
|
||||
/>
|
||||
<span class="label-text font-medium">Licença Paternidade</span>
|
||||
</label>
|
||||
|
||||
<label class="label cursor-pointer justify-start gap-3 rounded-lg border border-base-300 p-4 hover:bg-base-200">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={relatorioCampos.licencaMaternidade}
|
||||
class="checkbox checkbox-primary"
|
||||
disabled={relatorioCampos.todos}
|
||||
/>
|
||||
<span class="label-text font-medium">Licença Maternidade</span>
|
||||
</label>
|
||||
|
||||
<label class="label cursor-pointer justify-start gap-3 rounded-lg border border-base-300 p-4 hover:bg-base-200">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={relatorioCampos.declaracao}
|
||||
class="checkbox checkbox-primary"
|
||||
disabled={relatorioCampos.todos}
|
||||
/>
|
||||
<span class="label-text font-medium">Declaração</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botões de Ação -->
|
||||
<div class="card-actions mt-8 justify-end gap-3">
|
||||
<button
|
||||
class="btn btn-outline btn-error gap-2"
|
||||
onclick={gerarPDF}
|
||||
disabled={gerandoRelatorio}
|
||||
>
|
||||
{#if gerandoRelatorio}
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
{:else}
|
||||
<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="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
{/if}
|
||||
Imprimir PDF
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-outline btn-success gap-2"
|
||||
onclick={gerarExcel}
|
||||
disabled={gerandoRelatorio}
|
||||
>
|
||||
{#if gerandoRelatorio}
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
{:else}
|
||||
<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="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 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>
|
||||
{/if}
|
||||
Exportar Excel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</main>
|
||||
</main>
|
||||
|
||||
<!-- Modal de Erro -->
|
||||
<ErrorModal
|
||||
|
||||
Reference in New Issue
Block a user