Relatórios Dinâmicos

Formulário Dinâmico

Formulário

?
(ID: campo-relatorio)
`; } else { this.frmGroups.innerHTML = this.groups.map(grupo => `

${this.escapeHtml(grupo.name)}

${(grupo.inputs || []).map(input => this.criarElementoInput(input)).join('')}
`).join(''); this.adicionarEventListenersGrupos(); } } criarElementoInput(input) { if (input.tipo === 'text') { return `
ID: ${input.id} | Tipo: ${input.tipo}
`; } else if (input.tipo === 'radio') { const radioOptions = input.options.map((option, index) => { const rotulo = typeof option === 'object' ? option.rotulo : option; const texto = typeof option === 'object' ? option.texto : option; const valor = typeof option === 'object' ? texto : option; return `
`}).join(''); return `
${radioOptions}
ID: ${input.id} | Tipo: ${input.tipo}
`; } else if (input.tipo === 'tratamento') { const radioOptions = input.options.map((option, index) => `
`).join(''); return `
${radioOptions}
ID: ${input.id} | Tipo: ${input.tipo} | Opções fixas: ele, ela
`; } return ''; } adicionarEventListenersGrupos() { // Botões editar grupo document.querySelectorAll('.edit-group').forEach(btn => { btn.addEventListener('click', () => { const groupId = btn.dataset.groupId; this.openGroupModal(groupId); }); }); // Botões excluir grupo document.querySelectorAll('.delete-group').forEach(btn => { btn.addEventListener('click', () => { const groupId = btn.dataset.groupId; this.excluirGrupo(groupId); }); }); // Botões adicionar campo texto document.querySelectorAll('.add-input-btn').forEach(btn => { btn.addEventListener('click', () => { const groupId = btn.dataset.groupId; this.openInputModal(groupId); }); }); // Botões adicionar campo radio document.querySelectorAll('.add-radio-btn').forEach(btn => { btn.addEventListener('click', () => { const groupId = btn.dataset.groupId; this.openRadioModal(groupId); }); }); // Botões adicionar campo tratamento document.querySelectorAll('.add-tratamento-btn').forEach(btn => { btn.addEventListener('click', () => { const groupId = btn.dataset.groupId; this.openTratamentoModal(groupId); }); }); // Botões editar inputs document.querySelectorAll('.edit-input-btn').forEach(btn => { btn.addEventListener('click', () => { const inputId = btn.dataset.inputId; const groupId = btn.closest('.frm-group').dataset.groupId; this.openEditInputModal(groupId, inputId); }); }); // Botões editar radio document.querySelectorAll('.edit-radio-btn').forEach(btn => { btn.addEventListener('click', () => { const inputId = btn.dataset.inputId; const groupId = btn.closest('.frm-group').dataset.groupId; this.openEditRadioModal(groupId, inputId); }); }); // Botões editar tratamento document.querySelectorAll('.edit-tratamento-btn').forEach(btn => { btn.addEventListener('click', () => { const inputId = btn.dataset.inputId; const groupId = btn.closest('.frm-group').dataset.groupId; this.openEditTratamentoModal(groupId, inputId); }); }); // Botões remover inputs document.querySelectorAll('.btn-remove-input').forEach(btn => { btn.addEventListener('click', () => { const inputId = btn.dataset.inputId; const groupId = btn.closest('.frm-group').dataset.groupId; this.excluirInput(groupId, inputId); }); }); // Eventos para inputs de texto (salvar em blur, tab, enter) document.querySelectorAll('.custom-input').forEach(input => { input.addEventListener('blur', () => { const inputId = input.dataset.inputId; const groupId = input.closest('.frm-group').dataset.groupId; this.atualizarValorInput(groupId, inputId, input.value); }); input.addEventListener('keydown', (e) => { if (e.key === 'Tab' || e.key === 'Enter') { const inputId = input.dataset.inputId; const groupId = input.closest('.frm-group').dataset.groupId; this.atualizarValorInput(groupId, inputId, input.value); } }); }); // Eventos para radio buttons document.querySelectorAll('.radio-option').forEach(radio => { radio.addEventListener('change', () => { if (radio.checked) { const inputId = radio.dataset.inputId; const groupId = radio.closest('.frm-group').dataset.groupId; this.atualizarValorRadio(groupId, inputId, radio.value); } }); }); } excluirGrupo(groupId) { if (confirm('Tem certeza que deseja excluir este grupo? Todos os campos serão perdidos.')) { this.groups = this.groups.filter(g => g.id !== groupId); // USAR apenas estrutura para não alterar o código this.atualizarEstruturaFormulario(); this.renderizarGrupos(); this.showNotification('Grupo excluído com sucesso!'); } } excluirInput(groupId, inputId) { if (confirm('Tem certeza que deseja excluir este campo?')) { const grupo = this.groups.find(g => g.id === groupId); grupo.inputs = grupo.inputs.filter(i => i.id !== inputId); // USAR apenas estrutura para não alterar o código this.atualizarEstruturaFormulario(); this.renderizarGrupos(); this.showNotification('Campo excluído com sucesso!'); } } atualizarValorInput(groupId, inputId, valor) { const grupo = this.groups.find(g => g.id === groupId); const input = grupo.inputs.find(i => i.id === inputId); if (input) { input.value = valor; // USAR apenas estrutura para não alterar o código this.atualizarEstruturaFormulario(); } } atualizarValorRadio(groupId, inputId, valor) { const grupo = this.groups.find(g => g.id === groupId); const input = grupo.inputs.find(i => i.id === inputId); if (input) { input.selected = valor; // USAR apenas estrutura para não alterar o código this.atualizarEstruturaFormulario(); } } showNotification(message, isError = false) { this.notification.textContent = message; this.notification.className = 'notification'; if (isError) { this.notification.classList.add('error'); } this.notification.classList.add('show'); setTimeout(() => { this.notification.classList.remove('show'); }, 3000); } escapeHtml(unsafe) { if (!unsafe) return ''; return unsafe .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } atualizarPreviewInputId() { const label = this.inputLabel.value.trim(); if (label) { const idPadronizado = this.rotuloPadronizado(label); this.inputIdPreview.textContent = `ID gerado: campo-${idPadronizado}`; } else { this.inputIdPreview.textContent = 'ID gerado: '; } } atualizarPreviewRadioId() { const label = this.radioLabel.value.trim(); if (label) { const idPadronizado = this.rotuloPadronizado(label); this.radioIdPreview.textContent = `ID gerado: campo-radio-${idPadronizado}`; } else { this.radioIdPreview.textContent = 'ID gerado: '; } } atualizarPreviewTratamentoId() { const label = this.tratamentoLabel.value.trim(); if (label) { const idPadronizado = this.rotuloPadronizado(label); this.tratamentoIdPreview.textContent = `ID gerado: campo-tratamento-${idPadronizado}`; } else { this.tratamentoIdPreview.textContent = 'ID gerado: '; } } // MÉTODO NOVO FORMULÁRIO - CORRIGIDO (AGORA LIMPA TAMBÉM O CAMPO-RELATORIO) novoFormulario() { if (confirm('Deseja criar um novo formulário? Todos os dados não salvos serão perdidos.')) { // Resetar título this.projectTitle.textContent = 'Formulário'; // Resetar grupos this.groups = []; // CORREÇÃO: Resetar código - placeholder vazio e valor vazio this.campoCodigo.value = ''; this.campoCodigo.placeholder = ''; // CORREÇÃO COMPLETA: Resetar relatório - limpar o conteúdo e resetar altura if (this.campoRelatorio) { this.campoRelatorio.value = ''; this.campoRelatorio.placeholder = 'Bom dia João Silva.'; this.campoRelatorio.style.height = '200px'; // resetar altura padrão this.campoRelatorio.style.display = 'block'; // mostrar textarea novamente // Remover container HTML se existir const htmlContainer = document.getElementById('relatorio-html-container'); if (htmlContainer) { htmlContainer.remove(); } // Parar observer se existir if (this.relatorioObserver) { this.relatorioObserver.disconnect(); this.relatorioObserver = null; } } // CORREÇÃO: Resetar formulário no localStorage com código vazio this.formulario = { nome: 'Formulário', grupos: [], codigo: '', // Código vazio dataCriacao: new Date().toISOString(), dataAtualizacao: new Date().toISOString() }; localStorage.setItem('formulario', JSON.stringify(this.formulario)); // Re-renderizar interface this.renderizarGrupos(); this.showNotification('Novo formulário criado com sucesso!'); console.log('Formulário resetado para estado padrão:', this.formulario); } } salvarBackup() { // Primeiro atualiza o formulário com os dados atuais this.atualizarFormularioCompleto(); // Obter o nome do projeto para sugerir como nome do arquivo const nomeProjeto = this.projectTitle.textContent || 'formulario'; // Criar nome do arquivo padronizado const nomeArquivo = `${this.rotuloPadronizado(nomeProjeto)}.json`; // Criar o blob com o conteúdo do formulário const dados = JSON.stringify(this.formulario, null, 2); const blob = new Blob([dados], { type: 'application/json' }); // Criar URL temporária para download const url = URL.createObjectURL(blob); // Criar elemento de link para download const link = document.createElement('a'); link.href = url; link.download = nomeArquivo; // Adicionar ao DOM, clicar e remover document.body.appendChild(link); link.click(); document.body.removeChild(link); // Liberar a URL URL.revokeObjectURL(url); this.showNotification(`Formulário salvo como: ${nomeArquivo}`); console.log('Formulário salvo como arquivo:', nomeArquivo, this.formulario); } abrirBackup() { this.fileInput.click(); } // MÉTODO PARA VALIDAR ESTRUTURA DO FORMULÁRIO validarEstruturaFormulario(formulario) { if (!formulario || typeof formulario !== 'object') { return false; } // Verificar propriedades básicas const propriedadesRequeridas = ['nome', 'grupos', 'codigo']; for (const prop of propriedadesRequeridas) { if (!formulario.hasOwnProperty(prop)) { return false; } } // Validar que grupos é um array if (!Array.isArray(formulario.grupos)) { return false; } return true; } // MÉTODO PARA ATUALIZAR INTERFACE APÓS CARREGAR FORMULÁRIO atualizarInterfaceComFormularioCarregado() { // Atualizar título do projeto if (this.formulario.nome) { this.projectTitle.textContent = this.formulario.nome; } // Atualizar grupos if (this.formulario.grupos) { this.groups = this.formulario.grupos; } else { this.groups = []; } // Atualizar código if (this.formulario.codigo && this.campoCodigo) { this.campoCodigo.value = this.formulario.codigo; } else { this.campoCodigo.value = ''; } // Re-renderizar grupos this.renderizarGrupos(); console.log('Interface atualizada com formulário carregado'); } // MÉTODO CARREGAR ARQUIVO - CORRIGIDO E FUNCIONAL carregarArquivo(e) { const file = e.target.files[0]; if (!file) return; // Verificar se é um arquivo JSON if (!file.name.endsWith('.json')) { this.showNotification('Por favor, selecione um arquivo JSON.', true); this.fileInput.value = ''; // Limpar seleção return; } const reader = new FileReader(); reader.onload = (event) => { try { const conteudo = event.target.result; const formularioCarregado = JSON.parse(conteudo); // Validar estrutura básica do arquivo if (!formularioCarregado || typeof formularioCarregado !== 'object') { throw new Error('Arquivo JSON inválido'); } // Verificar estrutura mínima esperada if (!this.validarEstruturaFormulario(formularioCarregado)) { throw new Error('Estrutura do arquivo inválida. Deve conter: nome, grupos (array) e codigo'); } // Confirmar substituição com o usuário if (confirm('Deseja carregar este formulário? Todos os dados atuais serão substituídos.')) { // Sobrescrever o formulário no localStorage this.formulario = formularioCarregado; localStorage.setItem('formulario', JSON.stringify(this.formulario)); // Atualizar a interface this.atualizarInterfaceComFormularioCarregado(); this.showNotification('Formulário carregado com sucesso!'); console.log('Formulário carregado:', this.formulario); } } catch (error) { console.error('Erro ao carregar arquivo:', error); this.showNotification(`Erro ao carregar arquivo: ${error.message}`, true); } finally { // Limpar o input de arquivo para permitir recarregar o mesmo arquivo this.fileInput.value = ''; } }; reader.onerror = () => { this.showNotification('Erro ao ler o arquivo.', true); this.fileInput.value = ''; // Limpar seleção }; reader.readAsText(file); } } // Inicializar a aplicação quando o DOM estiver carregado document.addEventListener('DOMContentLoaded', function() { console.log('DOM carregado - inicializando FormularioDinamico'); window.formularioApp = new FormularioDinamico(); });