Spaces:
Running
Running
| document.addEventListener('DOMContentLoaded', function() { | |
| // Variables de estado | |
| let parkingSlots = []; | |
| let totalSlots = 20; | |
| let availableSlots = 20; | |
| // Elementos del DOM | |
| const parkingSlotsInput = document.getElementById('parking-slots'); | |
| const updateLayoutBtn = document.getElementById('update-layout'); | |
| const monthlyFixedBtn = document.getElementById('monthly-fixed-btn'); | |
| const monthlyRotatingBtn = document.getElementById('monthly-rotating-btn'); | |
| const hourlyBtn = document.getElementById('hourly-btn'); | |
| const exitPlateInput = document.getElementById('exit-plate'); | |
| const processExitBtn = document.getElementById('process-exit'); | |
| const modal = document.getElementById('modal'); | |
| const modalTitle = document.getElementById('modal-title'); | |
| const modalContent = document.getElementById('modal-content'); | |
| const modalCancel = document.getElementById('modal-cancel'); | |
| const modalConfirm = document.getElementById('modal-confirm'); | |
| const availableSlotsSpan = document.getElementById('available-slots'); | |
| const totalSlotsSpan = document.getElementById('total-slots'); | |
| const parkingGrid = document.querySelector('parking-grid'); | |
| // Inicializar la cuadrícula de estacionamiento | |
| function initializeParking() { | |
| totalSlots = parseInt(parkingSlotsInput.value); | |
| availableSlots = totalSlots; | |
| parkingSlots = Array(totalSlots).fill(null); | |
| updateCounters(); | |
| parkingGrid.setAttribute('slots', totalSlots); | |
| } | |
| // Actualizar contadores | |
| function updateCounters() { | |
| availableSlotsSpan.textContent = availableSlots; | |
| totalSlotsSpan.textContent = totalSlots; | |
| } | |
| // Mostrar modal | |
| function showModal(title, content, confirmCallback) { | |
| modalTitle.textContent = title; | |
| modalContent.innerHTML = content; | |
| modal.classList.remove('hidden'); | |
| modal.classList.add('flex'); | |
| // Configurar el botón de confirmación | |
| modalConfirm.onclick = function() { | |
| if (confirmCallback) confirmCallback(); | |
| hideModal(); | |
| }; | |
| } | |
| // Ocultar modal | |
| function hideModal() { | |
| modal.classList.add('hidden'); | |
| modal.classList.remove('flex'); | |
| } | |
| // Procesar ingreso de vehículo | |
| function processVehicleEntry(type) { | |
| if (availableSlots <= 0) { | |
| showModal('Estacionamiento lleno', '<p class="text-red-600">No hay plazas disponibles en este momento.</p>'); | |
| return; | |
| } | |
| let title, content; | |
| switch(type) { | |
| case 'monthly-fixed': | |
| title = 'Ingreso mensual fijo'; | |
| content = ` | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Número de placa</label> | |
| <input type="text" id="plate-number" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Ej: ABC123"> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Número de plaza asignada</label> | |
| <input type="number" id="assigned-slot" min="1" max="${totalSlots}" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| </div> | |
| </div> | |
| `; | |
| break; | |
| case 'monthly-rotating': | |
| title = 'Ingreso mensual rotativo'; | |
| content = ` | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Número de placa</label> | |
| <input type="text" id="plate-number" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Ej: ABC123"> | |
| </div> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="key-deposit" class="mr-2"> | |
| <label class="text-sm font-medium text-gray-700">El cliente dejó las llaves</label> | |
| </div> | |
| </div> | |
| `; | |
| break; | |
| case 'hourly': | |
| title = 'Ingreso por hora'; | |
| content = ` | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Número de placa</label> | |
| <input type="text" id="plate-number" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Ej: ABC123"> | |
| </div> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="key-deposit" class="mr-2" checked> | |
| <label class="text-sm font-medium text-gray-700">El cliente dejó las llaves</label> | |
| </div> | |
| </div> | |
| `; | |
| break; | |
| } | |
| showModal(title, content, function() { | |
| const plateNumber = document.getElementById('plate-number').value.trim(); | |
| if (!plateNumber) { | |
| alert('Por favor ingrese el número de placa'); | |
| return; | |
| } | |
| let assignedSlot; | |
| if (type === 'monthly-fixed') { | |
| assignedSlot = parseInt(document.getElementById('assigned-slot').value) - 1; | |
| if (isNaN(assignedSlot) || assignedSlot < 0 || assignedSlot >= totalSlots) { | |
| alert('Por favor ingrese un número de plaza válido'); | |
| return; | |
| } | |
| if (parkingSlots[assignedSlot] !== null) { | |
| alert('Esta plaza ya está ocupada'); | |
| return; | |
| } | |
| } else { | |
| // Encontrar la primera plaza disponible | |
| assignedSlot = parkingSlots.findIndex(slot => slot === null); | |
| if (assignedSlot === -1) { | |
| alert('No hay plazas disponibles'); | |
| return; | |
| } | |
| } | |
| const keyDeposit = type !== 'monthly-fixed' ? document.getElementById('key-deposit').checked : false; | |
| parkingSlots[assignedSlot] = { | |
| type: type, | |
| plateNumber: plateNumber, | |
| entryTime: new Date(), | |
| keyDeposit: keyDeposit, | |
| assignedSlot: type === 'monthly-fixed' ? assignedSlot : null | |
| }; | |
| availableSlots--; | |
| updateCounters(); | |
| parkingGrid.setAttribute('slots-data', JSON.stringify(parkingSlots)); | |
| let message = `Vehículo registrado exitosamente en plaza ${assignedSlot + 1}`; | |
| if (type === 'hourly') { | |
| message += '<br><br><strong class="text-blue-600">Ticket generado:</strong> ' + generateTicketNumber(); | |
| } | |
| showModal('Registro exitoso', `<p>${message}</p>`); | |
| }); | |
| } | |
| // Generar número de ticket | |
| function generateTicketNumber() { | |
| return 'T-' + Date.now().toString().slice(-6); | |
| } | |
| // Procesar salida de vehículo | |
| function processExit() { | |
| const plateNumber = exitPlateInput.value.trim(); | |
| if (!plateNumber) { | |
| alert('Por favor ingrese el número de placa'); | |
| return; | |
| } | |
| const slotIndex = parkingSlots.findIndex(slot => slot && slot.plateNumber === plateNumber); | |
| if (slotIndex === -1) { | |
| showModal('Vehículo no encontrado', '<p class="text-red-600">No se encontró un vehículo con esa placa en el estacionamiento.</p>'); | |
| return; | |
| } | |
| const vehicle = parkingSlots[slotIndex]; | |
| let content = ` | |
| <div class="space-y-3"> | |
| <p><strong>Tipo:</strong> ${getVehicleTypeName(vehicle.type)}</p> | |
| <p><strong>Placa:</strong> ${vehicle.plateNumber}</p> | |
| <p><strong>Plaza:</strong> ${slotIndex + 1}</p> | |
| <p><strong>Hora de entrada:</strong> ${vehicle.entryTime.toLocaleTimeString()}</p> | |
| `; | |
| if (vehicle.type === 'hourly') { | |
| const exitTime = new Date(); | |
| const duration = Math.ceil((exitTime - vehicle.entryTime) / (1000 * 60 * 60)); // Horas | |
| const rate = 5; // $5 por hora | |
| const total = duration * rate; | |
| content += ` | |
| <p><strong>Tiempo estacionado:</strong> ~${duration} hora(s)</p> | |
| <p><strong>Tarifa:</strong> $${rate} por hora</p> | |
| <p class="font-bold text-lg">Total a pagar: $${total}</p> | |
| <div class="mt-4"> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Método de pago</label> | |
| <select id="payment-method" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <option value="cash">Efectivo</option> | |
| <option value="card">Tarjeta</option> | |
| <option value="transfer">Transferencia</option> | |
| </select> | |
| </div> | |
| `; | |
| } | |
| if (vehicle.keyDeposit) { | |
| content += ` | |
| <div class="mt-3 flex items-center"> | |
| <input type="checkbox" id="return-key" class="mr-2" checked> | |
| <label class="text-sm font-medium text-gray-700">Llaves devueltas al cliente</label> | |
| </div> | |
| `; | |
| } | |
| content += `</div>`; | |
| showModal('Procesar salida', content, function() { | |
| if (vehicle.type === 'hourly') { | |
| const paymentMethod = document.getElementById('payment-method').value; | |
| // Aquí podrías registrar el pago en tu sistema | |
| } | |
| if (vehicle.keyDeposit) { | |
| const keyReturned = document.getElementById('return-key').checked; | |
| if (!keyReturned) { | |
| alert('¡Atención! Las llaves no fueron devueltas al cliente'); | |
| // Podrías registrar esto como una alerta | |
| } | |
| } | |
| // Liberar la plaza | |
| parkingSlots[slotIndex] = null; | |
| availableSlots++; | |
| updateCounters(); | |
| parkingGrid.setAttribute('slots-data', JSON.stringify(parkingSlots)); | |
| exitPlateInput.value = ''; | |
| showModal('Salida registrada', '<p class="text-green-600">La salida del vehículo ha sido registrada exitosamente.</p>'); | |
| }); | |
| } | |
| // Obtener nombre del tipo de vehículo | |
| function getVehicleTypeName(type) { | |
| switch(type) { | |
| case 'monthly-fixed': return 'Mensual con plaza fija'; | |
| case 'monthly-rotating': return 'Mensual rotativo'; | |
| case 'hourly': return 'Por hora'; | |
| default: return type; | |
| } | |
| } | |
| // Event listeners | |
| updateLayoutBtn.addEventListener('click', initializeParking); | |
| monthlyFixedBtn.addEventListener('click', () => processVehicleEntry('monthly-fixed')); | |
| monthlyRotatingBtn.addEventListener('click', () => processVehicleEntry('monthly-rotating')); | |
| hourlyBtn.addEventListener('click', () => processVehicleEntry('hourly')); | |
| processExitBtn.addEventListener('click', processExit); | |
| modalCancel.addEventListener('click', hideModal); | |
| // Permitir procesar salida con Enter | |
| exitPlateInput.addEventListener('keypress', function(e) { | |
| if (e.key === 'Enter') { | |
| processExit(); | |
| } | |
| }); | |
| // Inicializar la aplicación | |
| initializeParking(); | |
| }); |