1ra Versión
This commit is contained in:
@@ -0,0 +1,291 @@
|
||||
let gastosActuales = {};
|
||||
let columnasGastos = []; // Columnas dinámicas de gastos
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
cargarEstructuraGastos();
|
||||
setupFormListeners();
|
||||
});
|
||||
|
||||
function setupFormListeners() {
|
||||
// Formulario para agregar nuevo tipo de gasto
|
||||
const formAgregarTipo = document.getElementById('form-agregar-tipo-gasto');
|
||||
if (formAgregarTipo) {
|
||||
formAgregarTipo.addEventListener('submit', handleAgregarTipoGasto);
|
||||
}
|
||||
}
|
||||
|
||||
// ========== CARGAR ESTRUCTURA DINÁMICA ==========
|
||||
|
||||
async function cargarEstructuraGastos() {
|
||||
try {
|
||||
const response = await fetch('../php/Obtener_Gastos.php');
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
columnasGastos = data.columnas || [];
|
||||
gastosActuales = data.gasto || {};
|
||||
|
||||
construirFormularioDinamico();
|
||||
} else {
|
||||
console.log('No hay gastos registrados:', data.message);
|
||||
columnasGastos = [];
|
||||
construirFormularioDinamico();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error al cargar gastos:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// ========== CONSTRUIR FORMULARIO DINÁMICO ==========
|
||||
|
||||
function construirFormularioDinamico() {
|
||||
// Solo mostrar tabla de gastos
|
||||
mostrarTablaGastos();
|
||||
}
|
||||
|
||||
// ========== AGREGAR NUEVO TIPO DE GASTO ==========
|
||||
|
||||
async function handleAgregarTipoGasto(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const nombre = document.getElementById('nombre-nuevo-gasto').value.trim();
|
||||
const monto = parseFloat(document.getElementById('monto-nuevo-gasto').value);
|
||||
|
||||
if (!nombre || monto < 0) {
|
||||
alert('Por favor completa los datos correctamente');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validar nombre (solo letras y espacios)
|
||||
if (!/^[a-zA-Z\s]+$/.test(nombre)) {
|
||||
alert('El nombre del gasto solo puede contener letras y espacios');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('../php/Registrar_Gastos.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nuevo_gasto: nombre,
|
||||
monto: monto
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
alert('Nuevo tipo de gasto agregado correctamente');
|
||||
document.getElementById('form-agregar-tipo-gasto').reset();
|
||||
cargarEstructuraGastos();
|
||||
} else {
|
||||
alert('Error al agregar gasto: ' + data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
alert('Error de conexión');
|
||||
}
|
||||
}
|
||||
|
||||
// ========== MOSTRAR TABLA DE GASTOS ==========
|
||||
|
||||
function mostrarTablaGastos() {
|
||||
const tabla = document.getElementById('tabla-gastos');
|
||||
if (!tabla) return;
|
||||
|
||||
const tbody = tabla.querySelector('tbody');
|
||||
tbody.innerHTML = '';
|
||||
|
||||
if (columnasGastos.length === 0) {
|
||||
const tr = document.createElement('tr');
|
||||
const td = document.createElement('td');
|
||||
td.colSpan = 3;
|
||||
td.textContent = 'No hay gastos configurados';
|
||||
td.style.textAlign = 'center';
|
||||
td.style.color = '#999';
|
||||
tr.appendChild(td);
|
||||
tbody.appendChild(tr);
|
||||
return;
|
||||
}
|
||||
|
||||
columnasGastos.forEach(columna => {
|
||||
const tr = document.createElement('tr');
|
||||
const monto = gastosActuales[columna] || 0;
|
||||
const descripcionFormato = columna.charAt(0).toUpperCase() + columna.slice(1);
|
||||
|
||||
// Descripción
|
||||
const tdDesc = document.createElement('td');
|
||||
tdDesc.textContent = descripcionFormato;
|
||||
tr.appendChild(tdDesc);
|
||||
|
||||
// Monto
|
||||
const tdMonto = document.createElement('td');
|
||||
tdMonto.textContent = `$${parseFloat(monto).toFixed(2)}`;
|
||||
tr.appendChild(tdMonto);
|
||||
|
||||
// Acciones
|
||||
const tdAcciones = document.createElement('td');
|
||||
tdAcciones.style.display = 'flex';
|
||||
tdAcciones.style.gap = '10px';
|
||||
|
||||
// Botón Editar
|
||||
const btnEditar = document.createElement('button');
|
||||
btnEditar.type = 'button';
|
||||
btnEditar.className = 'btn-editar-gasto';
|
||||
btnEditar.textContent = 'Editar';
|
||||
btnEditar.addEventListener('click', () => activarEdicionGasto(btnEditar, columna));
|
||||
tdAcciones.appendChild(btnEditar);
|
||||
|
||||
// Botón Eliminar
|
||||
const btnEliminar = document.createElement('button');
|
||||
btnEliminar.type = 'button';
|
||||
btnEliminar.className = 'btn-eliminar-gasto';
|
||||
btnEliminar.textContent = 'Eliminar';
|
||||
btnEliminar.addEventListener('click', () => abrirModalEliminar(columna));
|
||||
tdAcciones.appendChild(btnEliminar);
|
||||
|
||||
tr.appendChild(tdAcciones);
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
}
|
||||
|
||||
// ========== EDITAR GASTO ==========
|
||||
|
||||
function activarEdicionGasto(btnEditar, columnaActual) {
|
||||
const fila = btnEditar.closest('tr');
|
||||
const celdas = fila.querySelectorAll('td');
|
||||
const descripcionActual = celdas[0].textContent;
|
||||
const montoActual = parseFloat(celdas[1].textContent.replace('$', ''));
|
||||
|
||||
// Convertir descripción a input
|
||||
celdas[0].innerHTML = `<input type="text" value="${columnaActual}" class="input-descripcion-gasto">`;
|
||||
|
||||
// Convertir monto a input
|
||||
celdas[1].innerHTML = `<input type="number" value="${montoActual}" step="0.01" min="0" class="input-monto-gasto">`;
|
||||
|
||||
// Crear botones Guardar y Cancelar
|
||||
const btnGuardar = document.createElement('button');
|
||||
btnGuardar.type = 'button';
|
||||
btnGuardar.textContent = 'Guardar';
|
||||
btnGuardar.className = 'btn-guardar';
|
||||
btnGuardar.addEventListener('click', () => guardarEdicionGasto(fila, columnaActual, montoActual, descripcionActual));
|
||||
|
||||
const btnCancelar = document.createElement('button');
|
||||
btnCancelar.type = 'button';
|
||||
btnCancelar.textContent = 'Cancelar';
|
||||
btnCancelar.className = 'btn-cancelar';
|
||||
btnCancelar.addEventListener('click', () => cancelarEdicionGasto(fila, columnaActual, montoActual, descripcionActual));
|
||||
|
||||
// Reemplazar botones en la celda de acciones
|
||||
celdas[2].innerHTML = '';
|
||||
celdas[2].appendChild(btnGuardar);
|
||||
celdas[2].appendChild(btnCancelar);
|
||||
}
|
||||
|
||||
function cancelarEdicionGasto(fila, columnaActual, montoActual, descripcionActual) {
|
||||
const celdas = fila.querySelectorAll('td');
|
||||
|
||||
// Restaurar descripción
|
||||
celdas[0].textContent = descripcionActual;
|
||||
|
||||
// Restaurar monto
|
||||
celdas[1].textContent = `$${parseFloat(montoActual).toFixed(2)}`;
|
||||
|
||||
// Restaurar botones Editar y Eliminar
|
||||
const btnEditar = document.createElement('button');
|
||||
btnEditar.type = 'button';
|
||||
btnEditar.className = 'btn-editar-gasto';
|
||||
btnEditar.textContent = 'Editar';
|
||||
btnEditar.addEventListener('click', () => activarEdicionGasto(btnEditar, columnaActual));
|
||||
|
||||
const btnEliminar = document.createElement('button');
|
||||
btnEliminar.type = 'button';
|
||||
btnEliminar.className = 'btn-eliminar-gasto';
|
||||
btnEliminar.textContent = 'Eliminar';
|
||||
btnEliminar.addEventListener('click', () => abrirModalEliminar(columnaActual));
|
||||
|
||||
celdas[2].innerHTML = '';
|
||||
celdas[2].appendChild(btnEditar);
|
||||
celdas[2].appendChild(btnEliminar);
|
||||
}
|
||||
|
||||
async function guardarEdicionGasto(fila, columnaActual, montoActual, descripcionActual) {
|
||||
const nuevoNombre = fila.querySelector('.input-descripcion-gasto').value.trim();
|
||||
const nuevoMonto = parseFloat(fila.querySelector('.input-monto-gasto').value);
|
||||
|
||||
if (!nuevoNombre) {
|
||||
alert('El nombre no puede estar vacío');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNaN(nuevoMonto) || nuevoMonto < 0) {
|
||||
alert('El monto debe ser un número válido y mayor o igual a 0');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('../php/Editar_Gasto.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
columna_actual: columnaActual,
|
||||
columna_nueva: nuevoNombre,
|
||||
monto: nuevoMonto
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
alert('Gasto editado correctamente');
|
||||
cargarEstructuraGastos();
|
||||
} else {
|
||||
alert('Error al editar gasto: ' + data.message);
|
||||
cancelarEdicionGasto(fila, columnaActual, montoActual, descripcionActual);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
alert('Error de conexión');
|
||||
cancelarEdicionGasto(fila, columnaActual, montoActual, descripcionActual);
|
||||
}
|
||||
}
|
||||
|
||||
// ========== ELIMINAR GASTO ==========
|
||||
|
||||
function abrirModalEliminar(columna) {
|
||||
const confirmar = confirm(`¿Deseas eliminar el gasto "${columna}"? Esta acción no se puede deshacer.`);
|
||||
|
||||
if (confirmar) {
|
||||
eliminarGasto(columna);
|
||||
}
|
||||
}
|
||||
|
||||
async function eliminarGasto(columna) {
|
||||
try {
|
||||
const response = await fetch('../php/Eliminar_Gasto.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
columna: columna
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
alert('Gasto eliminado correctamente');
|
||||
cargarEstructuraGastos();
|
||||
} else {
|
||||
alert('Error al eliminar gasto: ' + data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
alert('Error de conexión');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user