parkflow-pro / script.js
Randux's picture
crea una app para control de estacionamiento, debe ajustarse al tamaño del estacionamiento es decir la cantidad de plazas disponibles o puestos debe ser configurable. debe trabajar con 3 modelos 🅿️ Diagrama de Proceso para Estacionamiento Inteligente
ba33f5d verified
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();
});