Files
MVE/views/transportes/crear.php
2025-07-08 09:05:48 -06:00

317 lines
18 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title> Nuevo Transporte</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<!-- Animate.css para animaciones adicionales -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
<style>
table.dataTable thead th { background:#343a40; color:#fff; }
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
.sidebar .nav-link { font-weight: bold; color: white; transition: all 0.3s ease; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }
.navbar { position: fixed; top: 0; width: 100%; z-index: 1050; }
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
@media (min-width: 768px) { .content { margin-left: 250px; /* Ancho del sidebar */ } }
/* En móviles, sin margen lateral */
@media (max-width: 767.98px) {
.content { margin-left: 0;}
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
}
.card { border-radius: 12px; }
/* Animaciones personalizadas */
.card-hover { transition: all 0.3s ease; cursor: pointer; }
.card-hover:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; }
.btn-pulse { animation: pulse 2s infinite; }
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.fade-in-up { animation: fadeInUp 0.8s ease-out; }
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
/* Responsive animations */
@media (max-width: 768px) { .card-hover:hover { transform: translateY(-4px) scale(1.01); } }
/* Efecto de glow para elementos activos */
.btn.active { box-shadow: 0 0 20px rgba(var(--bs-primary-rgb), 0.5); }
/* Animación para el título */
.title-glow { text-shadow: 0 0 10px rgba(0, 123, 255, 0.3); }
/* Efecto para botones */
.btn-animated { transition: all 0.3s ease; position: relative; overflow: hidden; }
.btn-animated:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); }
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
.btn-animated:hover::before { left: 100%; }
/* Forzar z-index más alto para modales anidados */
.modal { z-index: 9999 !important; }
.modal-backdrop { z-index: 9998 !important; }
/* Asegurar que el contenido del modal esté por encima */
.modal-dialog { z-index: 10000 !important; position: relative; }
/* Opcional: Mejorar la apariencia del overlay */
.modal-backdrop.show { opacity: 0.5; }
/* ========== ANIMACIONES PARA INPUTS ========== */
/* 1. Animación al hacer focus */
.form-control { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
.form-control:focus { border-color: #0d6efd; box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25), 0 0 20px rgba(13, 110, 253, 0.3); transform: translateY(-2px); }
/* 2. Animación al escribir */
.form-control:not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
/* 3. Efecto de shake en validación */
.form-control.shake { animation: shake 0.5s ease-in-out; }
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
/* 4. Floating labels con animación */
.form-floating-custom { position: relative; margin-bottom: 1.5rem; }
.form-floating-custom .form-control { padding: 1rem 0.75rem 0.5rem 0.75rem; height: auto; }
.form-floating-custom .form-label { position: absolute; top: 0.75rem; left: 0.75rem; transition: all 0.3s ease; pointer-events: none; color: #6c757d; z-index: 2; }
.form-floating-custom .form-control:focus ~ .form-label,
.form-floating-custom .form-control:not(:placeholder-shown) ~ .form-label { top: 0.25rem; font-size: 0.75rem; color: #0d6efd; font-weight: 600; }
/* 5. Efecto de pulso en hover */
.input-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
@keyframes inputPulse {
0% { transform: scale(1); }
50% { transform: scale(1.02); }
100% { transform: scale(1); }
}
/* 6. Gradiente animado en el borde */
.input-gradient { position: relative; overflow: hidden; }
.input-gradient::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
background: linear-gradient(90deg, transparent, rgba(13, 110, 253, 0.3), transparent); transition: left 0.5s; pointer-events: none; z-index: 1; }
.input-gradient:focus::before { left: 100%; }
/* 7. Efecto de brillo en validación exitosa */
.form-control.valid { border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9); animation: successGlow 1s ease-in-out; }
@keyframes successGlow {
0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); }
100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
}
/* 8. Typing effect simulation */
.input-typing { position: relative; }
.input-typing::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
.input-typing:focus::after { opacity: 1; }
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
/* 9. Efecto de ondas */
.input-ripple { position: relative; overflow: hidden; }
.input-ripple::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0; background: rgba(13, 110, 253, 0.2);
border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; }
.input-ripple:focus::before { width: 300px; height: 300px; }
/* 10. Slide-up animation para los campos */
.form-group-animated { opacity: 0; transform: translateY(20px); animation: slideUp 0.6s ease-out forwards; }
.form-group-animated:nth-child(1) { animation-delay: 0.1s; }
.form-group-animated:nth-child(2) { animation-delay: 0.2s; }
.form-group-animated:nth-child(3) { animation-delay: 0.3s; }
.form-group-animated:nth-child(4) { animation-delay: 0.4s; }
.form-group-animated:nth-child(5) { animation-delay: 0.5s; }
.form-group-animated:nth-child(6) { animation-delay: 0.6s; }
.form-group-animated:nth-child(7) { animation-delay: 0.7s; }
.form-group-animated:nth-child(8) { animation-delay: 0.8s; }
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
/* ========== ANIMACIONES PARA SELECT ========== */
/* 1. Estilos base para select */
.form-select {transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; cursor: pointer;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m1 6 7 7 7-7'/%3e%3c/svg%3e");
background-repeat: no-repeat; background-position: right 0.75rem center; background-size: 16px 12px; }
/* 2. Animación al hacer focus */
.form-select:focus { border-color: #0d6efd; box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25), 0 0 20px rgba(13, 110, 253, 0.3); transform: translateY(-2px);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%230d6efd' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m1 6 7 7 7-7'/%3e%3c/svg%3e"); }
/* 3. Animación cuando tiene valor seleccionado */
.form-select:not([value=""]):not(:invalid) { border-color: #198754; background-color: #f8fff9;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23198754' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m1 6 7 7 7-7'/%3e%3c/svg%3e"); padding: 1rem 2.5rem 0.5rem 0.75rem; height: auto; min-height: 3.5rem; }
.form-floating-custom .form-select:focus ~ .form-label,
.form-floating-custom .form-select:not([value=""]) ~ .form-label { top: 0.25rem; font-size: 0.75rem; color: #0d6efd; font-weight: 600; }
/* 5. Efecto de shake en validación para select */
.form-select.shake { animation: shake 0.5s ease-in-out; }
/* 6. Efecto de pulso en hover para select */
.select-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
/* 7. Gradiente animado para select */
.select-gradient { position: relative; overflow: hidden; }
.select-gradient::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(13, 110, 253, 0.3), transparent); transition: left 0.5s; pointer-events: none; z-index: 1; }
.select-gradient:focus::before { left: 100%; }
/* 8. Efecto de brillo en validación exitosa para select */
.form-select.valid { border-color: #198754; background-color: #f8fff9; animation: successGlow 1s ease-in-out; }
/* 9. Efecto de rotación de la flecha al abrir */
.select-arrow-rotate { transition: all 0.3s ease; }
.select-arrow-rotate:focus { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%230d6efd' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m1 10 7-7 7 7'/%3e%3c/svg%3e"); }
/* 10. Efecto de ondas para select */
.select-ripple { position: relative; overflow: hidden; }
.select-ripple::after { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0;
background: rgba(13, 110, 253, 0.2); border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; }
.select-ripple:focus::after { width: 300px; height: 300px; }
/* 11. Efecto de scale suave */
.select-scale { transition: transform 0.2s ease; }
.select-scale:hover { transform: scale(1.02); }
.select-scale:focus { transform: scale(1.02) translateY(-2px); }
/* 12. Personalización de opciones (limitado en algunos navegadores) */
.form-select option { padding: 0.5rem; transition: all 0.2s ease; }
.form-select option:hover { background-color: #f8f9fa; }
/* 13. Indicador de estado */
.select-status { position: relative; }
.select-status::after { content: ''; position: absolute; right: 2.5rem; top: 50%; transform: translateY(-50%);
width: 8px; height: 8px; border-radius: 50%; background-color: #dc3545; opacity: 0; transition: opacity 0.3s ease; } .select-status.valid::after { background-color: #198754; opacity: 1; }
.select-status:invalid::after { background-color: #dc3545; opacity: 1; }
</style>
</head>
<body>
<div class="content">
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow"> Nuevo Transporte</h4>
<form id="formTransCrear" action="/IMPORTADORES/transportes/guardar" method="POST" enctype="multipart/form-data" class="card p-4 shadow-sm card-hover position-relative h-auto">
<div class="row g-3">
<div class="col-md-6 form-group-animated">
<div class="form-floating-custom">
<div class="d-flex align-items-center">
<input name="vehiculo" id="vehiculo" class="form-control input-pulse input-gradient" maxlength="20" placeholder=" " required>
<label for="vehiculo" class="form-label">Contenedor *</label>
<button type="button" class="btn btn-white ms-2" data-bs-toggle="modal" data-bs-target="#infoContenedor" style="border: none;"></button>
</div>
</div>
</div>
<div class="col-md-6 form-group-animated">
<div class="form-floating-custom">
<div class="d-flex align-items-center">
<input name="identificador_fiscal" id="ident_fiscal" class="form-control input-pulse input-gradient" maxlength="20" placeholder=" " required>
<label for="ident_fiscal" class="form-label">Identificación fiscal *</label>
<button type="button" class="btn btn-white ms-2" data-bs-toggle="modal" data-bs-target="#infoIdentificacion" style="border: none;"></button>
</div>
</div>
</div>
<div class="col-md-6 form-group-animated">
<label class="form-label">Foto (opcional)</label>
<div class="form-floating-custom">
<input type="file" name="foto" id="foto" class="form-control" accept="image/*">
</div>
</div>
<div class="col-md-6 form-group-animated">
<label for="" class="form-label">Transportista</label>
<div class="form-floating-custom">
<select name="id_transportista" id="transportista" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
<option value=""></option>
<?php foreach($transportistas as $tr): ?>
<option value="<?= $tr['id_transportista'] ?>">
<?= htmlspecialchars(($tr['clave_identificador'] . ' - ' . $tr['nombre'] . ' - ' . $tr['ciudad_nombre'] . ' - ' . $tr['domicilio'])) ?>
</option>
<?php endforeach; ?>
</select>
<label for="trasportista" class="form-label">Transportista</label>
</div>
</div>
</div>
<div class="text-end mt-4">
<button type="submit" class="btn btn-success ms-2 mt-auto w-auto btn-animated">Guardar</button>
<a href="/IMPORTADORES/transportes/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
</div>
</form>
</div>
<!-- Modal de ayuda - Contenedor -->
<div class="modal fade" id="infoContenedor" tabindex="-1" aria-labelledby="infoContenedorLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="infoContenedorLabel">Info - Contenedor</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
</div>
<div class="modal-body">
<strong>• Número económico del vehículo.</strong>
</div>
</div>
</div>
</div>
<!-- Modal de ayuda - Identificación Fiscal -->
<div class="modal fade" id="infoIdentificacion" tabindex="-1" aria-labelledby="infoIdentificacionLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="infoIdentificacionLabel">Info - Identificación Fiscal</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
</div>
<div class="modal-body">
• Si el medio de transporte es <strong>vehículo terrestre</strong>, se anotarán las <strong>placas de circulación</strong> del mismo.<br><br>
• Si el medio de transporte es <strong>ferrocarril</strong>, se anotará el <strong>número de furgón o plataforma</strong>.<br><br>
• Si el medio de transporte es <strong>marítimo</strong>, se anotará el <strong>nombre de la embarcación</strong>.
</div>
</div>
</div>
</div>
<script>
document.getElementById('formTransCrear').addEventListener('submit', function(e) {
e.preventDefault();
const vehiculo = document.getElementById('vehiculo').value.trim();
const ident_fiscal = document.getElementById('ident_fiscal').value.trim();
const transportista = document.getElementById('transportista').value;
const fotoF = document.getElementById('foto').files[0];
if (!vehiculo) {
Swal.fire({ icon: 'warning', title: 'Contenedor requerido', text: 'Por favor ingresa el número económico del vehículo.', confirmButtonColor: '#dc3545' });
return document.getElementById('vehiculo').focus();
}
if (!ident_fiscal) {
Swal.fire({ icon: 'warning', title: 'Identificación fiscal requerida', text: 'Por favor ingresa la identificación fiscal.', confirmButtonColor: '#dc3545' });
return document.getElementById('ident_fiscal').focus();
}
if (!transportista) {
Swal.fire({ icon: 'warning', title: 'Transportista no seleccionado', text: 'Debes elegir un transportista.', confirmButtonColor: '#dc3545' });
return document.getElementById('transportista').focus();
}
if (fotoF && fotoF.size > 2 * 1024 * 1024) {
return Swal.fire({ icon: 'error', title: 'Foto demasiado grande', text: 'La imagen no debe exceder 2 MB.', confirmButtonColor: '#dc3545' });
}
this.submit();
});
document.addEventListener('DOMContentLoaded', function() {
const inputs = document.querySelectorAll('.form-control');
inputs.forEach(input => {
input.addEventListener('input', function() {
if (this.checkValidity()) {
this.classList.remove('shake');
this.classList.add('valid');
} else {
this.classList.remove('valid');
}
});
input.addEventListener('invalid', function() {
this.classList.add('shake');
setTimeout(() => {
this.classList.remove('shake');
}, 500);
});
});
});
</script>
</body>
</html>