feat: integrate jsPDF and jsPDF-autotable for document generation; enhance employee management with print functionality and improved data handling in employee forms
This commit is contained in:
400
fix-editar.js
Normal file
400
fix-editar.js
Normal file
@@ -0,0 +1,400 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const baseDir = 'apps/web/src/routes/(dashboard)/recursos-humanos/funcionarios';
|
||||
const cadastroPath = path.join(baseDir, 'cadastro/+page.svelte');
|
||||
const editarPath = path.join(baseDir, '[funcionarioId]/editar/+page.svelte');
|
||||
|
||||
console.log('Reading files...');
|
||||
const cadastro = fs.readFileSync(cadastroPath, 'utf8');
|
||||
|
||||
// Create the edit file from scratch
|
||||
const editContent = `<script lang="ts">
|
||||
import { useConvexClient } from "convex-svelte";
|
||||
import { api } from "@sgse-app/backend/convex/_generated/api";
|
||||
import { goto } from "$app/navigation";
|
||||
import { page } from "$app/stores";
|
||||
import type { SimboloTipo } from "@sgse-app/backend/convex/schema";
|
||||
import FileUpload from "$lib/components/FileUpload.svelte";
|
||||
import {
|
||||
maskCPF, maskCEP, maskPhone, maskDate, onlyDigits,
|
||||
validateCPF, validateDate
|
||||
} from "$lib/utils/masks";
|
||||
import {
|
||||
SEXO_OPTIONS, ESTADO_CIVIL_OPTIONS, GRAU_INSTRUCAO_OPTIONS,
|
||||
GRUPO_SANGUINEO_OPTIONS, FATOR_RH_OPTIONS, APOSENTADO_OPTIONS, UFS_BRASIL
|
||||
} from "$lib/utils/constants";
|
||||
import { documentos, categoriasDocumentos, getDocumentosByCategoria } from "$lib/utils/documentos";
|
||||
import ModelosDeclaracoes from "$lib/components/ModelosDeclaracoes.svelte";
|
||||
|
||||
const client = useConvexClient();
|
||||
|
||||
let funcionarioId = $derived($page.params.funcionarioId as string);
|
||||
|
||||
let simbolos: Array<{
|
||||
_id: string;
|
||||
nome: string;
|
||||
tipo: SimboloTipo;
|
||||
descricao: string;
|
||||
}> = [];
|
||||
|
||||
let tipo: SimboloTipo = "cargo_comissionado";
|
||||
let loading = $state(false);
|
||||
let loadingData = $state(true);
|
||||
let notice = $state<{ kind: "success" | "error"; text: string } | null>(null);
|
||||
|
||||
// Campos obrigatórios
|
||||
let nome = $state("");
|
||||
let matricula = $state("");
|
||||
let cpf = $state("");
|
||||
let rg = $state("");
|
||||
let nascimento = $state("");
|
||||
let email = $state("");
|
||||
let telefone = $state("");
|
||||
let endereco = $state("");
|
||||
let cep = $state("");
|
||||
let cidade = $state("");
|
||||
let uf = $state("");
|
||||
let simboloId = $state("");
|
||||
let admissaoData = $state("");
|
||||
|
||||
// Dados Pessoais Adicionais
|
||||
let nomePai = $state("");
|
||||
let nomeMae = $state("");
|
||||
let naturalidade = $state("");
|
||||
let naturalidadeUF = $state("");
|
||||
let sexo = $state("");
|
||||
let estadoCivil = $state("");
|
||||
let nacionalidade = $state("Brasileira");
|
||||
|
||||
// Documentos Pessoais
|
||||
let rgOrgaoExpedidor = $state("");
|
||||
let rgDataEmissao = $state("");
|
||||
let carteiraProfissionalNumero = $state("");
|
||||
let carteiraProfissionalSerie = $state("");
|
||||
let carteiraProfissionalDataEmissao = $state("");
|
||||
let reservistaNumero = $state("");
|
||||
let reservistaSerie = $state("");
|
||||
let tituloEleitorNumero = $state("");
|
||||
let tituloEleitorZona = $state("");
|
||||
let tituloEleitorSecao = $state("");
|
||||
let pisNumero = $state("");
|
||||
|
||||
// Formação e Saúde
|
||||
let grauInstrucao = $state("");
|
||||
let formacao = $state("");
|
||||
let formacaoRegistro = $state("");
|
||||
let grupoSanguineo = $state("");
|
||||
let fatorRH = $state("");
|
||||
|
||||
// Cargo e Vínculo
|
||||
let descricaoCargo = $state("");
|
||||
let nomeacaoPortaria = $state("");
|
||||
let nomeacaoData = $state("");
|
||||
let nomeacaoDOE = $state("");
|
||||
let pertenceOrgaoPublico = $state(false);
|
||||
let orgaoOrigem = $state("");
|
||||
let aposentado = $state("nao");
|
||||
|
||||
// Dados Bancários
|
||||
let contaBradescoNumero = $state("");
|
||||
let contaBradescoDV = $state("");
|
||||
let contaBradescoAgencia = $state("");
|
||||
|
||||
// Documentos (Storage IDs)
|
||||
let documentosStorage: Record<string, string | undefined> = $state({});
|
||||
|
||||
async function loadSimbolos() {
|
||||
const list = await client.query(api.simbolos.getAll, {} as any);
|
||||
simbolos = list.map((s: any) => ({
|
||||
_id: s._id,
|
||||
nome: s.nome,
|
||||
tipo: s.tipo,
|
||||
descricao: s.descricao
|
||||
}));
|
||||
}
|
||||
|
||||
async function loadFuncionario() {
|
||||
try {
|
||||
const func = await client.query(api.funcionarios.getById, { id: funcionarioId as any });
|
||||
|
||||
// Preencher campos
|
||||
nome = func.nome;
|
||||
matricula = func.matricula;
|
||||
cpf = maskCPF(func.cpf);
|
||||
rg = func.rg;
|
||||
nascimento = func.nascimento;
|
||||
email = func.email;
|
||||
telefone = maskPhone(func.telefone);
|
||||
endereco = func.endereco;
|
||||
cep = maskCEP(func.cep);
|
||||
cidade = func.cidade;
|
||||
uf = func.uf;
|
||||
simboloId = func.simboloId;
|
||||
tipo = func.simboloTipo;
|
||||
admissaoData = func.admissaoData || "";
|
||||
|
||||
// Dados adicionais
|
||||
nomePai = func.nomePai || "";
|
||||
nomeMae = func.nomeMae || "";
|
||||
naturalidade = func.naturalidade || "";
|
||||
naturalidadeUF = func.naturalidadeUF || "";
|
||||
sexo = func.sexo || "";
|
||||
estadoCivil = func.estadoCivil || "";
|
||||
nacionalidade = func.nacionalidade || "Brasileira";
|
||||
|
||||
rgOrgaoExpedidor = func.rgOrgaoExpedidor || "";
|
||||
rgDataEmissao = func.rgDataEmissao || "";
|
||||
carteiraProfissionalNumero = func.carteiraProfissionalNumero || "";
|
||||
carteiraProfissionalSerie = func.carteiraProfissionalSerie || "";
|
||||
carteiraProfissionalDataEmissao = func.carteiraProfissionalDataEmissao || "";
|
||||
reservistaNumero = func.reservistaNumero || "";
|
||||
reservistaSerie = func.reservistaSerie || "";
|
||||
tituloEleitorNumero = func.tituloEleitorNumero || "";
|
||||
tituloEleitorZona = func.tituloEleitorZona || "";
|
||||
tituloEleitorSecao = func.tituloEleitorSecao || "";
|
||||
pisNumero = func.pisNumero || "";
|
||||
|
||||
grauInstrucao = func.grauInstrucao || "";
|
||||
formacao = func.formacao || "";
|
||||
formacaoRegistro = func.formacaoRegistro || "";
|
||||
grupoSanguineo = func.grupoSanguineo || "";
|
||||
fatorRH = func.fatorRH || "";
|
||||
|
||||
descricaoCargo = func.descricaoCargo || "";
|
||||
nomeacaoPortaria = func.nomeacaoPortaria || "";
|
||||
nomeacaoData = func.nomeacaoData || "";
|
||||
nomeacaoDOE = func.nomeacaoDOE || "";
|
||||
pertenceOrgaoPublico = func.pertenceOrgaoPublico || false;
|
||||
orgaoOrigem = func.orgaoOrigem || "";
|
||||
aposentado = func.aposentado || "nao";
|
||||
|
||||
contaBradescoNumero = func.contaBradescoNumero || "";
|
||||
contaBradescoDV = func.contaBradescoDV || "";
|
||||
contaBradescoAgencia = func.contaBradescoAgencia || "";
|
||||
|
||||
// Documentos
|
||||
documentosStorage = {};
|
||||
documentos.forEach(doc => {
|
||||
const storageId = (func as any)[doc.campo];
|
||||
if (storageId) {
|
||||
documentosStorage[doc.campo] = storageId;
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Erro ao carregar funcionário:", error);
|
||||
notice = { kind: "error", text: "Erro ao carregar dados do funcionário" };
|
||||
} finally {
|
||||
loadingData = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function fillFromCEP(cepValue: string) {
|
||||
const cepDigits = onlyDigits(cepValue);
|
||||
if (cepDigits.length !== 8) return;
|
||||
|
||||
try {
|
||||
const res = await fetch(\`https://viacep.com.br/ws/\${cepDigits}/json/\`);
|
||||
const data = await res.json();
|
||||
if (!data || data.erro) return;
|
||||
|
||||
const enderecoFull = [data.logradouro, data.bairro].filter(Boolean).join(", ");
|
||||
endereco = enderecoFull;
|
||||
cidade = data.localidade || "";
|
||||
uf = data.uf || "";
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function handleDocumentoUpload(campo: string, file: File) {
|
||||
try {
|
||||
const uploadUrl = await client.mutation(api.documentos.generateUploadUrl, {});
|
||||
|
||||
const result = await fetch(uploadUrl, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": file.type },
|
||||
body: file,
|
||||
});
|
||||
|
||||
const { storageId } = await result.json();
|
||||
documentosStorage[campo] = storageId;
|
||||
} catch (err: any) {
|
||||
throw new Error(err?.message || "Erro ao fazer upload");
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDocumentoRemove(campo: string) {
|
||||
documentosStorage[campo] = undefined;
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!nome || !matricula || !cpf || !rg || !nascimento || !email || !telefone) {
|
||||
notice = { kind: "error", text: "Preencha todos os campos obrigatórios" };
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateCPF(cpf)) {
|
||||
notice = { kind: "error", text: "CPF inválido" };
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateDate(nascimento)) {
|
||||
notice = { kind: "error", text: "Data de nascimento inválida" };
|
||||
return;
|
||||
}
|
||||
|
||||
if (!simboloId) {
|
||||
notice = { kind: "error", text: "Selecione um símbolo" };
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
loading = true;
|
||||
|
||||
const payload = {
|
||||
nome,
|
||||
matricula,
|
||||
cpf: onlyDigits(cpf),
|
||||
rg: onlyDigits(rg),
|
||||
nascimento,
|
||||
email,
|
||||
telefone: onlyDigits(telefone),
|
||||
endereco,
|
||||
cep: onlyDigits(cep),
|
||||
cidade,
|
||||
uf: uf.toUpperCase(),
|
||||
simboloId: simboloId as any,
|
||||
simboloTipo: tipo,
|
||||
admissaoData: admissaoData || undefined,
|
||||
|
||||
nomePai: nomePai || undefined,
|
||||
nomeMae: nomeMae || undefined,
|
||||
naturalidade: naturalidade || undefined,
|
||||
naturalidadeUF: naturalidadeUF ? naturalidadeUF.toUpperCase() : undefined,
|
||||
sexo: sexo || undefined,
|
||||
estadoCivil: estadoCivil || undefined,
|
||||
nacionalidade: nacionalidade || undefined,
|
||||
|
||||
rgOrgaoExpedidor: rgOrgaoExpedidor || undefined,
|
||||
rgDataEmissao: rgDataEmissao || undefined,
|
||||
carteiraProfissionalNumero: carteiraProfissionalNumero || undefined,
|
||||
carteiraProfissionalSerie: carteiraProfissionalSerie || undefined,
|
||||
carteiraProfissionalDataEmissao: carteiraProfissionalDataEmissao || undefined,
|
||||
reservistaNumero: reservistaNumero || undefined,
|
||||
reservistaSerie: reservistaSerie || undefined,
|
||||
tituloEleitorNumero: tituloEleitorNumero || undefined,
|
||||
tituloEleitorZona: tituloEleitorZona || undefined,
|
||||
tituloEleitorSecao: tituloEleitorSecao || undefined,
|
||||
pisNumero: pisNumero || undefined,
|
||||
|
||||
grauInstrucao: grauInstrucao || undefined,
|
||||
formacao: formacao || undefined,
|
||||
formacaoRegistro: formacaoRegistro || undefined,
|
||||
grupoSanguineo: grupoSanguineo || undefined,
|
||||
fatorRH: fatorRH || undefined,
|
||||
|
||||
descricaoCargo: descricaoCargo || undefined,
|
||||
nomeacaoPortaria: nomeacaoPortaria || undefined,
|
||||
nomeacaoData: nomeacaoData || undefined,
|
||||
nomeacaoDOE: nomeacaoDOE || undefined,
|
||||
pertenceOrgaoPublico: pertenceOrgaoPublico || undefined,
|
||||
orgaoOrigem: orgaoOrigem || undefined,
|
||||
aposentado: aposentado || undefined,
|
||||
|
||||
contaBradescoNumero: contaBradescoNumero || undefined,
|
||||
contaBradescoDV: contaBradescoDV || undefined,
|
||||
contaBradescoAgencia: contaBradescoAgencia || undefined,
|
||||
|
||||
...Object.fromEntries(
|
||||
Object.entries(documentosStorage).map(([key, value]) => [key, value as any])
|
||||
),
|
||||
};
|
||||
|
||||
await client.mutation(api.funcionarios.update, { id: funcionarioId as any, ...payload as any });
|
||||
notice = { kind: "success", text: "Funcionário atualizado com sucesso!" };
|
||||
setTimeout(() => goto("/recursos-humanos/funcionarios"), 600);
|
||||
} catch (e: any) {
|
||||
notice = { kind: "error", text: "Erro ao atualizar funcionário." };
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function init() {
|
||||
await loadSimbolos();
|
||||
await loadFuncionario();
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
if (funcionarioId) {
|
||||
init();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if loadingData}
|
||||
<div class="flex items-center justify-center min-h-screen">
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
</div>
|
||||
{:else}
|
||||
<main class="container mx-auto px-4 py-4 max-w-7xl">
|
||||
<!-- Breadcrumb -->
|
||||
<div class="text-sm breadcrumbs mb-4">
|
||||
<ul>
|
||||
<li><a href="/recursos-humanos" class="text-primary hover:underline">Recursos Humanos</a></li>
|
||||
<li><a href="/recursos-humanos/funcionarios" class="text-primary hover:underline">Funcionários</a></li>
|
||||
<li>Editar</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Cabeçalho -->
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center gap-4 mb-2">
|
||||
<div class="p-3 bg-yellow-500/20 rounded-xl">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-yellow-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-primary">Editar Funcionário</h1>
|
||||
<p class="text-base-content/70">Atualize as informações do funcionário</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alertas -->
|
||||
{#if notice}
|
||||
<div class="alert mb-6 shadow-lg" class:alert-success={notice.kind === "success"} class:alert-error={notice.kind === "error"}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24">
|
||||
{#if notice.kind === "success"}
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
{:else}
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
{/if}
|
||||
</svg>
|
||||
<span>{notice.text}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Formulário de Edição -->
|
||||
<form class="space-y-6" onsubmit={(e) => { e.preventDefault(); handleSubmit(); }}>
|
||||
|
||||
`;
|
||||
|
||||
// Extract form from cadastro (from line 294 to 1181)
|
||||
const cadastroLines = cadastro.split('\n');
|
||||
const formLines = cadastroLines.slice(293, 1181); // Get lines 294-1181 (0-indexed)
|
||||
const formContent = formLines.join('\n');
|
||||
|
||||
// Replace "Cadastrar" with "Atualizar" in button
|
||||
const fixedForm = formContent
|
||||
.replace('Cadastrar Funcionário', 'Atualizar Funcionário')
|
||||
.replace('Cadastrando...', 'Atualizando...');
|
||||
|
||||
const finalContent = editContent + fixedForm + '\n </form>\n </main>\n{/if}';
|
||||
|
||||
fs.writeFileSync(editarPath, finalContent, 'utf8');
|
||||
|
||||
console.log(`✓ File created successfully!`);
|
||||
console.log(` Total lines: ${finalContent.split('\n').length}`);
|
||||
console.log(` File saved to: ${editarPath}`);
|
||||
|
||||
Reference in New Issue
Block a user