Aprobación de Agencias
This commit is contained in:
@@ -469,7 +469,8 @@ function aprobar_agencia()
|
|||||||
$usuario_id = $_SESSION['usuario_id'];
|
$usuario_id = $_SESSION['usuario_id'];
|
||||||
|
|
||||||
if (!$id || !is_numeric($id)) {
|
if (!$id || !is_numeric($id)) {
|
||||||
die("❌ ID inválido.");
|
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=invalid_id");
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtener la solicitud
|
// Obtener la solicitud
|
||||||
@@ -478,7 +479,8 @@ function aprobar_agencia()
|
|||||||
$solicitud = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
$solicitud = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||||
|
|
||||||
if (!$solicitud) {
|
if (!$solicitud) {
|
||||||
die("❌ Solicitud no encontrada.");
|
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=invalid_request");
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validar que no haya sido aprobada ya
|
// Validar que no haya sido aprobada ya
|
||||||
@@ -511,6 +513,7 @@ function aprobar_agencia()
|
|||||||
// Insertar en agencias_aduanales
|
// Insertar en agencias_aduanales
|
||||||
$sqlInsert = "INSERT INTO agencias_aduanales
|
$sqlInsert = "INSERT INTO agencias_aduanales
|
||||||
(nombre_agencia, rfc_agencia, direccion, telefono, email, creado_en, creado_por)
|
(nombre_agencia, rfc_agencia, direccion, telefono, email, creado_en, creado_por)
|
||||||
|
OUTPUT INSERTED.id_agencia
|
||||||
VALUES (?, ?, ?, ?, ?, GETDATE(), ?)
|
VALUES (?, ?, ?, ?, ?, GETDATE(), ?)
|
||||||
";
|
";
|
||||||
$stmtInsert = sqlsrv_query($conn, $sqlInsert, [
|
$stmtInsert = sqlsrv_query($conn, $sqlInsert, [
|
||||||
@@ -518,37 +521,38 @@ function aprobar_agencia()
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if (!$stmtInsert) {
|
if (!$stmtInsert) {
|
||||||
die("❌ Error al crear agencia: " . print_r(sqlsrv_errors(), true));
|
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=save_agencia_failed");
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtener ID de la agencia recién creada
|
// Obtener ID de la agencia recién creada
|
||||||
$sqlGetAgenciaId = "SELECT SCOPE_IDENTITY() AS id_agencia";
|
$agenciaIdRow = sqlsrv_fetch_array($stmtInsert, SQLSRV_FETCH_ASSOC);
|
||||||
$stmtGetAgenciaId = sqlsrv_query($conn, $sqlGetAgenciaId);
|
|
||||||
$agenciaIdRow = sqlsrv_fetch_array($stmtGetAgenciaId, SQLSRV_FETCH_ASSOC);
|
|
||||||
$id_agencia = $agenciaIdRow['id_agencia'] ?? null;
|
$id_agencia = $agenciaIdRow['id_agencia'] ?? null;
|
||||||
|
|
||||||
if (!$id_agencia) {
|
if (!$id_agencia) {
|
||||||
die("❌ No se pudo obtener el ID de la agencia recién creada.");
|
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=get_id_failed");
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insertar en usuarios_sistema
|
// Insertar en usuarios_sistema
|
||||||
$sqlInsert2 = "INSERT INTO usuarios_sistema (nombre, email, password_hash, tipo_usuario, activo, creado_en, dos_factores, creado_por)
|
$sqlInsert2 = "INSERT INTO usuarios_sistema (nombre, email, password_hash, tipo_usuario, activo, creado_en, dos_factores, creado_por)
|
||||||
|
OUTPUT INSERTED.id_usuario
|
||||||
VALUES (?, ?, ?, ?, 1, GETDATE(), 0, ?)
|
VALUES (?, ?, ?, ?, 1, GETDATE(), 0, ?)
|
||||||
";
|
";
|
||||||
$stmtInsert2 = sqlsrv_query($conn, $sqlInsert2, [$admin_name_encrypt, $admin_email_encrypt, $password_hash, $tipo, $usuario_id]);
|
$stmtInsert2 = sqlsrv_query($conn, $sqlInsert2, [$admin_name_encrypt, $admin_email_encrypt, $password_hash, $tipo, $usuario_id]);
|
||||||
|
|
||||||
if (!$stmtInsert2) {
|
if (!$stmtInsert2) {
|
||||||
die("❌ Error al crear usuario administrador: " . print_r(sqlsrv_errors(), true));
|
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=error_user");
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtener ID del nuevo usuario
|
// Obtener ID del nuevo usuario
|
||||||
$sqlGetId = "SELECT SCOPE_IDENTITY() AS id_usuario";
|
$idUsuarioRow = sqlsrv_fetch_array($stmtInsert2, SQLSRV_FETCH_ASSOC);
|
||||||
$stmtGetId = sqlsrv_query($conn, $sqlGetId);
|
|
||||||
$idUsuarioRow = sqlsrv_fetch_array($stmtGetId, SQLSRV_FETCH_ASSOC);
|
|
||||||
$id_usuario = $idUsuarioRow['id_usuario'] ?? null;
|
$id_usuario = $idUsuarioRow['id_usuario'] ?? null;
|
||||||
|
|
||||||
if (!$id_usuario) {
|
if (!$id_usuario) {
|
||||||
die("❌ No se pudo obtener el ID del usuario recién creado.");
|
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=error_id");
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualizar agencia con el ID del administrador
|
// Actualizar agencia con el ID del administrador
|
||||||
@@ -556,7 +560,8 @@ function aprobar_agencia()
|
|||||||
$stmtUpdateAgencia = sqlsrv_query($conn, $sqlUpdateAgencia, [$id_usuario, $id_agencia]);
|
$stmtUpdateAgencia = sqlsrv_query($conn, $sqlUpdateAgencia, [$id_usuario, $id_agencia]);
|
||||||
|
|
||||||
if (!$stmtUpdateAgencia) {
|
if (!$stmtUpdateAgencia) {
|
||||||
die("❌ Error al actualizar agencia con administrador: " . print_r(sqlsrv_errors(), true));
|
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=update_failed");
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insertar en informacion_general
|
// Insertar en informacion_general
|
||||||
@@ -564,7 +569,8 @@ function aprobar_agencia()
|
|||||||
$stmtInfo = sqlsrv_query($conn, $sqlInfo, [$id_usuario, $admin_name, $admin_email]);
|
$stmtInfo = sqlsrv_query($conn, $sqlInfo, [$id_usuario, $admin_name, $admin_email]);
|
||||||
|
|
||||||
if (!$stmtInfo) {
|
if (!$stmtInfo) {
|
||||||
die("❌ Error al insertar información general: " . print_r(sqlsrv_errors(), true));
|
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=update_failed");
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualizar solicitud
|
// Actualizar solicitud
|
||||||
@@ -577,7 +583,8 @@ function aprobar_agencia()
|
|||||||
$stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$usuario_id, $id]);
|
$stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$usuario_id, $id]);
|
||||||
|
|
||||||
if (!$stmtUpdate) {
|
if (!$stmtUpdate) {
|
||||||
die("❌ Error al actualizar solicitud: " . print_r(sqlsrv_errors(), true));
|
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=update_request_failed");
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enviar correo a la agencia
|
// Enviar correo a la agencia
|
||||||
@@ -624,7 +631,7 @@ function aprobar_agencia()
|
|||||||
// Registrar en bitácora
|
// Registrar en bitácora
|
||||||
registrar_bitacora_agencia($id_agencia, $nombre, 'CREACION', $usuario_id);
|
registrar_bitacora_agencia($id_agencia, $nombre, 'CREACION', $usuario_id);
|
||||||
|
|
||||||
header("Location: /IMPORTADORES/administrador/agenciasActivas");
|
header("Location: /IMPORTADORES/administrador/agenciasActivas?success=created");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,8 +72,6 @@ function alta()
|
|||||||
FROM agente_agencia aa
|
FROM agente_agencia aa
|
||||||
INNER JOIN usuarios_sistema u
|
INNER JOIN usuarios_sistema u
|
||||||
ON aa.id_agente = u.id_usuario
|
ON aa.id_agente = u.id_usuario
|
||||||
INNER JOIN agencias_aduanales a
|
|
||||||
ON aa.id_agente = a.id_administrador
|
|
||||||
LEFT JOIN usuarios_sistema creador
|
LEFT JOIN usuarios_sistema creador
|
||||||
ON u.creado_por = creador.id_usuario
|
ON u.creado_por = creador.id_usuario
|
||||||
WHERE aa.id_agencia = ?
|
WHERE aa.id_agencia = ?
|
||||||
@@ -108,6 +106,12 @@ function guardarAgente()
|
|||||||
$conn = getConnection();
|
$conn = getConnection();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// === AGREGADO: LOG DE DEPURACIÓN ===
|
||||||
|
error_log("=== INICIO DEBUG guardarAgente ===");
|
||||||
|
error_log("POST data: " . print_r($_POST, true));
|
||||||
|
error_log("SESSION usuario_id: " . $_SESSION['usuario_id']);
|
||||||
|
error_log("SESSION tipo_usuario: " . $_SESSION['tipo_usuario']);
|
||||||
|
|
||||||
if (!sqlsrv_begin_transaction($conn)) {
|
if (!sqlsrv_begin_transaction($conn)) {
|
||||||
error_log("ERROR: No se pudo iniciar la transacción");
|
error_log("ERROR: No se pudo iniciar la transacción");
|
||||||
throw new Exception("Error al iniciar transacción");
|
throw new Exception("Error al iniciar transacción");
|
||||||
@@ -121,13 +125,25 @@ function guardarAgente()
|
|||||||
$password = $_POST['password'] ?? '';
|
$password = $_POST['password'] ?? '';
|
||||||
$tipo = $_POST['tipo_usuario'] ?? '';
|
$tipo = $_POST['tipo_usuario'] ?? '';
|
||||||
|
|
||||||
|
// === AGREGADO: VALIDACIÓN DETALLADA ===
|
||||||
|
error_log("Datos capturados:");
|
||||||
|
error_log("nombre: '$nombre'");
|
||||||
|
error_log("email: '$email'");
|
||||||
|
error_log("password: " . (empty($password) ? 'VACÍO' : 'NO VACÍO'));
|
||||||
|
error_log("tipo: '$tipo'");
|
||||||
|
|
||||||
if (empty($nombre) || empty($email) || empty($password) || empty($tipo)) {
|
if (empty($nombre) || empty($email) || empty($password) || empty($tipo)) {
|
||||||
|
error_log("ERROR: Datos incompletos");
|
||||||
|
error_log("nombre vacío: " . (empty($nombre) ? 'SÍ' : 'NO'));
|
||||||
|
error_log("email vacío: " . (empty($email) ? 'SÍ' : 'NO'));
|
||||||
|
error_log("password vacío: " . (empty($password) ? 'SÍ' : 'NO'));
|
||||||
|
error_log("tipo vacío: " . (empty($tipo) ? 'SÍ' : 'NO'));
|
||||||
header("Location: /IMPORTADORES/agencias/alta?error=invalid_data");
|
header("Location: /IMPORTADORES/agencias/alta?error=invalid_data");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($tipo !== 'agente_aduanal') {
|
if ($tipo !== 'agente_aduanal') {
|
||||||
error_log("DEBUG 5: Tipo de usuario inválido: $tipo");
|
error_log("ERROR: Tipo de usuario inválido: '$tipo'");
|
||||||
header("Location: /IMPORTADORES/agencias/alta?error=invalid_user_type");
|
header("Location: /IMPORTADORES/agencias/alta?error=invalid_user_type");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@@ -137,15 +153,27 @@ function guardarAgente()
|
|||||||
$email_encrypted = encrypt($email);
|
$email_encrypted = encrypt($email);
|
||||||
$password_hash = password_hash($password, PASSWORD_DEFAULT);
|
$password_hash = password_hash($password, PASSWORD_DEFAULT);
|
||||||
|
|
||||||
|
error_log("Datos encriptados exitosamente");
|
||||||
|
|
||||||
// 3. Validar duplicado por email encriptado
|
// 3. Validar duplicado por email encriptado
|
||||||
$sqlCheck = "SELECT COUNT(*) AS total FROM usuarios_sistema WHERE email = ?";
|
$sqlCheck = "SELECT COUNT(*) AS total FROM usuarios_sistema WHERE email = ?";
|
||||||
$stmtCheck = sqlsrv_query($conn, $sqlCheck, [$email_encrypted]);
|
$stmtCheck = sqlsrv_query($conn, $sqlCheck, [$email_encrypted]);
|
||||||
|
|
||||||
|
if ($stmtCheck === false) {
|
||||||
|
error_log("ERROR: Fallo en consulta de duplicado");
|
||||||
|
error_log(print_r(sqlsrv_errors(), true));
|
||||||
|
throw new Exception("Error al verificar duplicado");
|
||||||
|
}
|
||||||
|
|
||||||
$rowCheck = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
|
$rowCheck = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
|
||||||
if ($rowCheck['total'] > 0) {
|
if ($rowCheck['total'] > 0) {
|
||||||
|
error_log("ERROR: Email ya existe");
|
||||||
header("Location: /IMPORTADORES/agencias/alta?error=email_exists");
|
header("Location: /IMPORTADORES/agencias/alta?error=email_exists");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error_log("Validación de duplicado pasada");
|
||||||
|
|
||||||
// 4. Insertar usuario
|
// 4. Insertar usuario
|
||||||
$sqlInsert = "INSERT INTO usuarios_sistema
|
$sqlInsert = "INSERT INTO usuarios_sistema
|
||||||
(nombre, email, password_hash, tipo_usuario, activo, creado_en, dos_factores, creado_por)
|
(nombre, email, password_hash, tipo_usuario, activo, creado_en, dos_factores, creado_por)
|
||||||
@@ -153,10 +181,20 @@ function guardarAgente()
|
|||||||
VALUES (?, ?, ?, ?, 1, GETDATE(), 0, ?)
|
VALUES (?, ?, ?, ?, 1, GETDATE(), 0, ?)
|
||||||
";
|
";
|
||||||
$params = [$nombre_encrypted, $email_encrypted, $password_hash, $tipo, $_SESSION['usuario_id']];
|
$params = [$nombre_encrypted, $email_encrypted, $password_hash, $tipo, $_SESSION['usuario_id']];
|
||||||
|
|
||||||
|
error_log("Parámetros para INSERT:");
|
||||||
|
error_log("nombre_encrypted: " . (empty($nombre_encrypted) ? 'VACÍO' : 'OK'));
|
||||||
|
error_log("email_encrypted: " . (empty($email_encrypted) ? 'VACÍO' : 'OK'));
|
||||||
|
error_log("password_hash: " . (empty($password_hash) ? 'VACÍO' : 'OK'));
|
||||||
|
error_log("tipo: '$tipo'");
|
||||||
|
error_log("creado_por: " . $_SESSION['usuario_id']);
|
||||||
|
|
||||||
$stmtInsert = sqlsrv_query($conn, $sqlInsert, $params);
|
$stmtInsert = sqlsrv_query($conn, $sqlInsert, $params);
|
||||||
|
|
||||||
if ($stmtInsert === false) {
|
if ($stmtInsert === false) {
|
||||||
error_log("ERROR: Fallo al insertar usuario");
|
error_log("ERROR: Fallo al insertar usuario");
|
||||||
|
error_log("SQL: $sqlInsert");
|
||||||
|
error_log("Errores SQL Server:");
|
||||||
error_log(print_r(sqlsrv_errors(), true));
|
error_log(print_r(sqlsrv_errors(), true));
|
||||||
throw new Exception("Error al insertar usuario");
|
throw new Exception("Error al insertar usuario");
|
||||||
}
|
}
|
||||||
@@ -166,41 +204,67 @@ function guardarAgente()
|
|||||||
|
|
||||||
if (!$id_usuario) {
|
if (!$id_usuario) {
|
||||||
error_log("ERROR: No se obtuvo id_usuario tras el insert");
|
error_log("ERROR: No se obtuvo id_usuario tras el insert");
|
||||||
|
error_log("idUsuarioRow: " . print_r($idUsuarioRow, true));
|
||||||
throw new Exception("Error al obtener ID del nuevo usuario");
|
throw new Exception("Error al obtener ID del nuevo usuario");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Obtener la agencia del administrador actual
|
error_log("Usuario insertado exitosamente con ID: $id_usuario");
|
||||||
|
|
||||||
|
// 5. Obtener la agencia del administrador actual
|
||||||
$sqlAgencia = "SELECT id_agencia FROM agencias_aduanales WHERE id_administrador = ?";
|
$sqlAgencia = "SELECT id_agencia FROM agencias_aduanales WHERE id_administrador = ?";
|
||||||
$stmtAgencia = sqlsrv_query($conn, $sqlAgencia, [$_SESSION['usuario_id']]);
|
$stmtAgencia = sqlsrv_query($conn, $sqlAgencia, [$_SESSION['usuario_id']]);
|
||||||
|
|
||||||
|
if ($stmtAgencia === false) {
|
||||||
|
error_log("ERROR: Fallo al consultar agencia");
|
||||||
|
error_log(print_r(sqlsrv_errors(), true));
|
||||||
|
throw new Exception("Error al consultar agencia");
|
||||||
|
}
|
||||||
|
|
||||||
$agenciaRow = sqlsrv_fetch_array($stmtAgencia, SQLSRV_FETCH_ASSOC);
|
$agenciaRow = sqlsrv_fetch_array($stmtAgencia, SQLSRV_FETCH_ASSOC);
|
||||||
$id_agencia = $agenciaRow['id_agencia'] ?? null;
|
$id_agencia = $agenciaRow['id_agencia'] ?? null;
|
||||||
|
|
||||||
if (!$id_agencia) {
|
if (!$id_agencia) {
|
||||||
error_log("ERROR: No se encontró agencia para el admin_agencia con id_usuario=" . $_SESSION['usuario_id']);
|
error_log("ERROR: No se encontró agencia para el admin_agencia con id_usuario=" . $_SESSION['usuario_id']);
|
||||||
|
error_log("agenciaRow: " . print_r($agenciaRow, true));
|
||||||
throw new Exception("No se encontró agencia asociada al administrador");
|
throw new Exception("No se encontró agencia asociada al administrador");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. Crear la relación agente-agencia
|
error_log("Agencia encontrada con ID: $id_agencia");
|
||||||
|
|
||||||
|
// 6. Crear la relación agente-agencia
|
||||||
$sqlRelacion = "INSERT INTO agente_agencia
|
$sqlRelacion = "INSERT INTO agente_agencia
|
||||||
(id_agente, id_agencia, fecha_asignacion, activo, asignado_por)
|
(id_agente, id_agencia, fecha_asignacion, activo, asignado_por)
|
||||||
VALUES (?, ?, GETDATE(), 1, ?)
|
VALUES (?, ?, GETDATE(), 1, ?)
|
||||||
";
|
";
|
||||||
$paramsRelacion = [$id_usuario, $id_agencia, $_SESSION['usuario_id']];
|
$paramsRelacion = [$id_usuario, $id_agencia, $_SESSION['usuario_id']];
|
||||||
|
|
||||||
|
error_log("Parámetros para relación agente-agencia:");
|
||||||
|
error_log("id_agente: $id_usuario");
|
||||||
|
error_log("id_agencia: $id_agencia");
|
||||||
|
error_log("asignado_por: " . $_SESSION['usuario_id']);
|
||||||
|
|
||||||
$stmtRelacion = sqlsrv_query($conn, $sqlRelacion, $paramsRelacion);
|
$stmtRelacion = sqlsrv_query($conn, $sqlRelacion, $paramsRelacion);
|
||||||
|
|
||||||
if ($stmtRelacion === false) {
|
if ($stmtRelacion === false) {
|
||||||
error_log("ERROR: No se pudo insertar la relación agente-agencia");
|
error_log("ERROR: No se pudo insertar la relación agente-agencia");
|
||||||
|
error_log("SQL: $sqlRelacion");
|
||||||
|
error_log("Errores SQL Server:");
|
||||||
error_log(print_r(sqlsrv_errors(), true));
|
error_log(print_r(sqlsrv_errors(), true));
|
||||||
throw new Exception("Error al guardar relación agente-agencia");
|
throw new Exception("Error al guardar relación agente-agencia");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8. CONFIRMAR TRANSACCIÓN ✅
|
error_log("Relación agente-agencia creada exitosamente");
|
||||||
|
|
||||||
|
// 7. CONFIRMAR TRANSACCIÓN ✅
|
||||||
if (!sqlsrv_commit($conn)) {
|
if (!sqlsrv_commit($conn)) {
|
||||||
error_log("ERROR: No se pudo confirmar la transacción");
|
error_log("ERROR: No se pudo confirmar la transacción");
|
||||||
|
error_log(print_r(sqlsrv_errors(), true));
|
||||||
throw new Exception("Error al confirmar transacción");
|
throw new Exception("Error al confirmar transacción");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 9. Enviar correo de bienvenida
|
error_log("Transacción confirmada exitosamente");
|
||||||
|
|
||||||
|
// 8. Enviar correo de bienvenida
|
||||||
if (class_exists('PHPMailer\PHPMailer\PHPMailer')) {
|
if (class_exists('PHPMailer\PHPMailer\PHPMailer')) {
|
||||||
$mail = new PHPMailer(true);
|
$mail = new PHPMailer(true);
|
||||||
try {
|
try {
|
||||||
@@ -253,25 +317,30 @@ function guardarAgente()
|
|||||||
</div>";
|
</div>";
|
||||||
|
|
||||||
$mail->send();
|
$mail->send();
|
||||||
|
error_log("Correo enviado exitosamente");
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("Error al enviar correo: " . $e->getMessage());
|
error_log("Error al enviar correo: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10. Redirigir con mensaje de éxito
|
error_log("=== FIN EXITOSO guardarAgente ===");
|
||||||
|
// 9. Redirigir con mensaje de éxito
|
||||||
header("Location: /IMPORTADORES/agencias/alta?success=created");
|
header("Location: /IMPORTADORES/agencias/alta?success=created");
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("ERROR CAPTURADO: " . $e->getMessage());
|
error_log("ERROR CAPTURADO: " . $e->getMessage());
|
||||||
|
error_log("Stack trace: " . $e->getTraceAsString());
|
||||||
|
|
||||||
if (!sqlsrv_rollback($conn)) {
|
if (!sqlsrv_rollback($conn)) {
|
||||||
error_log("ERROR: No se pudo revertir la transacción");
|
error_log("ERROR: No se pudo revertir la transacción");
|
||||||
|
error_log(print_r(sqlsrv_errors(), true));
|
||||||
} else {
|
} else {
|
||||||
error_log("Transacción revertida exitosamente");
|
error_log("Transacción revertida exitosamente");
|
||||||
}
|
}
|
||||||
|
|
||||||
error_log("=== FIN CON ERROR guardar_agencia ===");
|
error_log("=== FIN CON ERROR guardarAgente ===");
|
||||||
header("Location: /IMPORTADORES/agencias/alta?error=save_failed");
|
header("Location: /IMPORTADORES/agencias/alta?error=save_failed");
|
||||||
exit;
|
exit;
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ function guardar()
|
|||||||
sqlsrv_free_stmt($stmt);
|
sqlsrv_free_stmt($stmt);
|
||||||
sqlsrv_close($conn);
|
sqlsrv_close($conn);
|
||||||
|
|
||||||
header("Location: /IMPORTADORES/patente/lista?success=1");
|
header("Location: /IMPORTADORES/patente/lista?created=ok");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,14 +317,33 @@ function actualizar()
|
|||||||
$curp = trim($_POST['curp'] ?? '');
|
$curp = trim($_POST['curp'] ?? '');
|
||||||
$razon_social = trim($_POST['razon_social'] ?? '');
|
$razon_social = trim($_POST['razon_social'] ?? '');
|
||||||
$id_usuario = $_SESSION['usuario_id'];
|
$id_usuario = $_SESSION['usuario_id'];
|
||||||
|
$tipo_usuario = $_SESSION['tipo_usuario'];
|
||||||
|
|
||||||
// ✅ NUEVO: Obtener la agencia actual del usuario
|
// Obtener id_agencia del usuario actual
|
||||||
$stmt = sqlsrv_query($conn, "SELECT id_agencia FROM dbo.agente_agencia WHERE id_agente = ?", [$id_usuario]);
|
|
||||||
|
|
||||||
$id_agencia = null;
|
$id_agencia = null;
|
||||||
|
if ($tipo_usuario === 'agente_aduanal' || $tipo_usuario === 'admin_agencia') {
|
||||||
|
$stmt = sqlsrv_query($conn, "SELECT id_agencia FROM dbo.agente_agencia WHERE id_agente = ?", [$id_usuario]);
|
||||||
if ($stmt && $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
if ($stmt && $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||||
$id_agencia = $row['id_agencia'];
|
$id_agencia = $row['id_agencia'];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$id_agencia) {
|
||||||
|
die("❌ No se pudo determinar la agencia del usuario.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar que el registro existe y pertenece a la agencia del usuario
|
||||||
|
$sqlVerificar = "SELECT COUNT(*) as count FROM dbo.agentes_aduanales WHERE id_agente = ? AND id_agencia = ?";
|
||||||
|
$stmtVerificar = sqlsrv_query($conn, $sqlVerificar, [$id_agente, $id_agencia]);
|
||||||
|
|
||||||
|
if ($stmtVerificar === false) {
|
||||||
|
die("❌ Error al verificar el registro: " . print_r(sqlsrv_errors(), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
$row = sqlsrv_fetch_array($stmtVerificar, SQLSRV_FETCH_ASSOC);
|
||||||
|
if ($row['count'] == 0) {
|
||||||
|
die("❌ El registro no existe o no tienes permisos para editarlo.");
|
||||||
|
}
|
||||||
|
|
||||||
$mf_nombre = trim($_POST['mf_nombre'] ?? '');
|
$mf_nombre = trim($_POST['mf_nombre'] ?? '');
|
||||||
$mf_paterno = trim($_POST['mf_paterno'] ?? '');
|
$mf_paterno = trim($_POST['mf_paterno'] ?? '');
|
||||||
@@ -351,6 +370,7 @@ function actualizar()
|
|||||||
$vae_final = trim($_POST['vae_final'] ?? '');
|
$vae_final = trim($_POST['vae_final'] ?? '');
|
||||||
$vae_siguiente = trim($_POST['vae_siguiente'] ?? '');
|
$vae_siguiente = trim($_POST['vae_siguiente'] ?? '');
|
||||||
|
|
||||||
|
// Validaciones
|
||||||
if (!$id_agente || empty($aduana) || empty($patente) || empty($agente_aduanal) || empty($rfc) || empty($curp) || empty($razon_social)) {
|
if (!$id_agente || empty($aduana) || empty($patente) || empty($agente_aduanal) || empty($rfc) || empty($curp) || empty($razon_social)) {
|
||||||
die("❌ Datos inválidos o incompletos.");
|
die("❌ Datos inválidos o incompletos.");
|
||||||
}
|
}
|
||||||
@@ -360,19 +380,16 @@ function actualizar()
|
|||||||
if (strlen($rfc) > 13) die("❌ El RFC no puede exceder 13 caracteres.");
|
if (strlen($rfc) > 13) die("❌ El RFC no puede exceder 13 caracteres.");
|
||||||
if (strlen($curp) > 18) die("❌ El CURP no puede exceder 18 caracteres.");
|
if (strlen($curp) > 18) die("❌ El CURP no puede exceder 18 caracteres.");
|
||||||
|
|
||||||
// Validar duplicado (excepto el propio id)
|
// Validar duplicado
|
||||||
$sqlCheck = "SELECT COUNT(*) as count FROM dbo.agentes_aduanales WHERE aduana = ? AND patente = ? AND id_usuario = ? AND id_agente != ?";
|
$sqlCheck = "SELECT COUNT(*) as count FROM dbo.agentes_aduanales WHERE aduana = ? AND patente = ? AND id_agencia = ? AND id_agente != ?";
|
||||||
$stmtCheck = sqlsrv_query($conn, $sqlCheck, [$aduana, $patente, $id_usuario, $id_agente]);
|
$stmtCheck = sqlsrv_query($conn, $sqlCheck, [$aduana, $patente, $id_agencia, $id_agente]);
|
||||||
|
|
||||||
if ($stmtCheck === false) die("❌ Error al verificar duplicados.");
|
if ($stmtCheck === false) die("❌ Error al verificar duplicados.");
|
||||||
|
|
||||||
$row = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
|
$row = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
|
||||||
|
|
||||||
if ($row['count'] > 0) die("❌ Ya existe un agente aduanal con esta combinación de aduana y patente.");
|
if ($row['count'] > 0) die("❌ Ya existe un agente aduanal con esta combinación de aduana y patente.");
|
||||||
|
|
||||||
sqlsrv_free_stmt($stmtCheck);
|
// Convertir valores vacíos a NULL
|
||||||
|
|
||||||
// Convertir valores vacíos a NULL para la base de datos
|
|
||||||
$vp_inicio = empty($vp_inicio) ? null : $vp_inicio;
|
$vp_inicio = empty($vp_inicio) ? null : $vp_inicio;
|
||||||
$vp_final = empty($vp_final) ? null : $vp_final;
|
$vp_final = empty($vp_final) ? null : $vp_final;
|
||||||
$vp_siguiente = empty($vp_siguiente) ? null : $vp_siguiente;
|
$vp_siguiente = empty($vp_siguiente) ? null : $vp_siguiente;
|
||||||
@@ -399,7 +416,7 @@ function actualizar()
|
|||||||
vcc_inicio = ?, vcc_final = ?, vcc_siguiente = ?,
|
vcc_inicio = ?, vcc_final = ?, vcc_siguiente = ?,
|
||||||
vae_inicio = ?, vae_final = ?, vae_siguiente = ?, id_agencia = ?
|
vae_inicio = ?, vae_final = ?, vae_siguiente = ?, id_agencia = ?
|
||||||
WHERE id_agente = ?
|
WHERE id_agente = ?
|
||||||
AND id_usuario = ?
|
AND id_agencia = ?
|
||||||
";
|
";
|
||||||
$params = [
|
$params = [
|
||||||
$aduana, $patente, $agente_aduanal, $rfc, $curp, $razon_social,
|
$aduana, $patente, $agente_aduanal, $rfc, $curp, $razon_social,
|
||||||
@@ -409,11 +426,19 @@ function actualizar()
|
|||||||
$vat_pb_inicio, $vat_pb_final, $vat_pb_siguiente,
|
$vat_pb_inicio, $vat_pb_final, $vat_pb_siguiente,
|
||||||
$vcc_inicio, $vcc_final, $vcc_siguiente,
|
$vcc_inicio, $vcc_final, $vcc_siguiente,
|
||||||
$vae_inicio, $vae_final, $vae_siguiente, $id_agencia,
|
$vae_inicio, $vae_final, $vae_siguiente, $id_agencia,
|
||||||
$id_agente, $id_usuario
|
$id_agente, $id_agencia
|
||||||
];
|
];
|
||||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||||
|
|
||||||
if ($stmt === false) die("❌ Error al actualizar agente aduanal.");
|
if ($stmt === false) {
|
||||||
|
die("❌ Error al actualizar: " . print_r(sqlsrv_errors(), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows_affected = sqlsrv_rows_affected($stmt);
|
||||||
|
|
||||||
|
if ($rows_affected === 0) {
|
||||||
|
die("❌ No se actualizó ningún registro. Verifica los datos.");
|
||||||
|
}
|
||||||
|
|
||||||
sqlsrv_free_stmt($stmt);
|
sqlsrv_free_stmt($stmt);
|
||||||
sqlsrv_close($conn);
|
sqlsrv_close($conn);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
// app/controllers/proveedores.php
|
||||||
require_once __DIR__ . '/../helpers/session.php';
|
require_once __DIR__ . '/../helpers/session.php';
|
||||||
require_once __DIR__ . '/../../config/database.php';
|
require_once __DIR__ . '/../../config/database.php';
|
||||||
// 1) Composer autoload (phpdotenv y demás libs)
|
// 1) Composer autoload (phpdotenv y demás libs)
|
||||||
@@ -32,7 +33,7 @@ function getApiToken(): ?string
|
|||||||
$pass = $_ENV['API_PASS'] ?? '';
|
$pass = $_ENV['API_PASS'] ?? '';
|
||||||
$body = json_encode(['username' => $user, 'password' => $pass]);
|
$body = json_encode(['username' => $user, 'password' => $pass]);
|
||||||
|
|
||||||
error_log("[getApiToken] POST $url → $body");
|
error_log("[getApiToken] POST $url");
|
||||||
|
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
@@ -46,7 +47,7 @@ function getApiToken(): ?string
|
|||||||
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
|
||||||
error_log("[getApiToken] HTTP $http → $resp");
|
error_log("[getApiToken] HTTP $http");
|
||||||
|
|
||||||
if ($http === 200 && ($data = json_decode($resp, true)) && !empty($data['token'])) {
|
if ($http === 200 && ($data = json_decode($resp, true)) && !empty($data['token'])) {
|
||||||
// 3) Guardamos token y tiempo actual
|
// 3) Guardamos token y tiempo actual
|
||||||
@@ -87,47 +88,71 @@ function ajax_lista()
|
|||||||
$token = getApiToken();
|
$token = getApiToken();
|
||||||
if (!$token) {
|
if (!$token) {
|
||||||
error_log('[ajax_lista] Sin token válido');
|
error_log('[ajax_lista] Sin token válido');
|
||||||
// Devolvemos estructura vacía
|
echo json_encode(['data' => [], 'error' => 'No se pudo obtener token de autenticación']);
|
||||||
echo json_encode(['data' => []]);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Construimos la URL de la API
|
// CORRECCIÓN: Usar la misma estructura de URL que en otras funciones
|
||||||
$apiBase = rtrim($_ENV['API_URL'] ?? '', '/');
|
$apiBase = rtrim($_ENV['API_URL'] ?? '', '/');
|
||||||
$url = $apiBase . '/proveedores';
|
$url = $apiBase . '/api/proveedores'; // Cambié para que sea consistente
|
||||||
error_log("[ajax_lista] GET $url");
|
error_log("[ajax_lista] GET $url");
|
||||||
|
|
||||||
// 4) Ejecutamos cURL
|
// 4) Ejecutamos cURL
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_HTTPHEADER => ["Authorization: $token", 'Accept: application/json'],
|
// CORRECCIÓN: Agregar "Bearer" al token
|
||||||
|
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token", 'Accept: application/json'],
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_TIMEOUT => 5,
|
CURLOPT_TIMEOUT => 10, // Aumenté el timeout
|
||||||
]);
|
]);
|
||||||
$resp = curl_exec($ch);
|
$resp = curl_exec($ch);
|
||||||
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$curlError = curl_error($ch);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
|
||||||
error_log("[ajax_lista] HTTP $status → $resp");
|
error_log("[ajax_lista] HTTP $status");
|
||||||
|
|
||||||
|
// MEJORA: Verificar errores de cURL
|
||||||
|
if ($curlError) {
|
||||||
|
error_log("[ajax_lista] cURL Error: $curlError");
|
||||||
|
echo json_encode(['data' => [], 'error' => 'Error de conexión con la API']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MEJORA: Mejor manejo de errores
|
||||||
|
if ($status !== 200) {
|
||||||
|
error_log("[ajax_lista] Error HTTP $status: $resp");
|
||||||
|
echo json_encode(['data' => [], 'error' => "Error HTTP $status"]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$json = json_decode($resp, true);
|
||||||
|
if (!is_array($json)) {
|
||||||
|
error_log("[ajax_lista] Respuesta no es un array válido: $resp");
|
||||||
|
echo json_encode(['data' => [], 'error' => 'Respuesta inválida de la API']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("[ajax_lista] Procesando " . count($json) . " proveedores");
|
||||||
|
|
||||||
// 5) Parseamos y formateamos
|
|
||||||
$dataList = [];
|
$dataList = [];
|
||||||
if ($status === 200 && ($json = json_decode($resp, true)) && is_array($json)) {
|
|
||||||
foreach ($json as $p) {
|
foreach ($json as $p) {
|
||||||
$clave = htmlspecialchars($p['Clave'] ?? '', ENT_QUOTES);
|
$clave = htmlspecialchars($p['Clave'] ?? '', ENT_QUOTES);
|
||||||
|
|
||||||
// Construir dirección
|
// Construir dirección de forma más robusta
|
||||||
$direccion = trim(implode(', ', array_filter([
|
$direccionParts = array_filter([
|
||||||
$p['Calles'] ?? '',
|
$p['Calles'] ?? '',
|
||||||
'Num. Ext: ' . ($p['NumExt'] ?? ''),
|
($p['NumExt'] ?? '') ? 'Num. Ext: ' . $p['NumExt'] : '',
|
||||||
'Num. Int: ' . ($p['NumInt'] ?? ''),
|
($p['NumInt'] ?? '') ? 'Num. Int: ' . $p['NumInt'] : '',
|
||||||
$p['Colonia'] ?? '',
|
$p['Colonia'] ?? '',
|
||||||
$p['Municipio'] ?? '',
|
$p['Municipio'] ?? '',
|
||||||
$p['Ciudad'] ?? '',
|
$p['Ciudad'] ?? '',
|
||||||
'C.P. ' . ($p['CodigoPostal'] ?? ''),
|
($p['CodigoPostal'] ?? '') ? 'C.P. ' . $p['CodigoPostal'] : '',
|
||||||
$p['EntidadFederativa'] ?? '',
|
$p['EntidadFederativa'] ?? '',
|
||||||
$p['Pais'] ?? ''
|
$p['Pais'] ?? ''
|
||||||
])));
|
]);
|
||||||
|
|
||||||
|
$direccion = implode(', ', $direccionParts);
|
||||||
|
|
||||||
$dataList[] = [
|
$dataList[] = [
|
||||||
$clave,
|
$clave,
|
||||||
@@ -135,15 +160,11 @@ function ajax_lista()
|
|||||||
htmlspecialchars($p['RFC'] ?? '', ENT_QUOTES),
|
htmlspecialchars($p['RFC'] ?? '', ENT_QUOTES),
|
||||||
htmlspecialchars($p['Ciudad'] ?? '', ENT_QUOTES),
|
htmlspecialchars($p['Ciudad'] ?? '', ENT_QUOTES),
|
||||||
htmlspecialchars($p['Telefono'] ?? '', ENT_QUOTES),
|
htmlspecialchars($p['Telefono'] ?? '', ENT_QUOTES),
|
||||||
htmlspecialchars($direccion ?? '', ENT_QUOTES),
|
htmlspecialchars($direccion, ENT_QUOTES),
|
||||||
// Acciones
|
|
||||||
"<a href=\"/IMPORTADORES/proveedores/editar?clave=" . rawurlencode($clave) . "\" class=\"btn btn-sm btn-primary\">✏️</a>
|
"<a href=\"/IMPORTADORES/proveedores/editar?clave=" . rawurlencode($clave) . "\" class=\"btn btn-sm btn-primary\">✏️</a>
|
||||||
<button class=\"btn btn-sm btn-danger\" onclick=\"confirmDelete('{$clave}')\">🗑️</button>"
|
<button class=\"btn btn-sm btn-danger\" onclick=\"confirmDelete('{$clave}')\">🗑️</button>"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
error_log('[ajax_lista] Respuesta inválida o status != 200');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6) Devolvemos siempre HTTP 200 con data (posiblemente vacío)
|
// 6) Devolvemos siempre HTTP 200 con data (posiblemente vacío)
|
||||||
echo json_encode(['data' => $dataList]);
|
echo json_encode(['data' => $dataList]);
|
||||||
@@ -161,20 +182,24 @@ function eliminar()
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CORRECCIÓN: Usar la misma URL base y corregir el Authorization header
|
||||||
$url = rtrim($_ENV['API_URL'] ?? '', '/') . '/api/proveedores/' . urlencode($clave);
|
$url = rtrim($_ENV['API_URL'] ?? '', '/') . '/api/proveedores/' . urlencode($clave);
|
||||||
error_log("[eliminar] DELETE $url");
|
error_log("[eliminar] DELETE $url");
|
||||||
|
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_CUSTOMREQUEST => 'DELETE',
|
CURLOPT_CUSTOMREQUEST => 'DELETE',
|
||||||
CURLOPT_HTTPHEADER => ["Authorization: $token",'Accept: application/json'],
|
// CORRECCIÓN: Quitar el espacio extra y agregar Bearer
|
||||||
|
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token", 'Accept: application/json'],
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_TIMEOUT => 5,
|
CURLOPT_TIMEOUT => 5,
|
||||||
]);
|
]);
|
||||||
curl_exec($ch);
|
$resp = curl_exec($ch);
|
||||||
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
|
||||||
|
error_log("[eliminar] HTTP $status: $resp");
|
||||||
|
|
||||||
header('Location: /IMPORTADORES/proveedores?deleted=' . ($status===200||$status===204 ? 'ok':'error'));
|
header('Location: /IMPORTADORES/proveedores?deleted=' . ($status===200||$status===204 ? 'ok':'error'));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ function guardar()
|
|||||||
|
|
||||||
$vehiculo = trim($_POST['vehiculo'] ?? '');
|
$vehiculo = trim($_POST['vehiculo'] ?? '');
|
||||||
$identFiscal = trim($_POST['identificador_fiscal'] ?? '');
|
$identFiscal = trim($_POST['identificador_fiscal'] ?? '');
|
||||||
$idTrans = $_POST['id_transportista'] ?? null;
|
$idTrans = $_POST['transportista_id'] ?? null;
|
||||||
|
|
||||||
if ($vehiculo === '' || $identFiscal === '' || !$idTrans) {
|
if ($vehiculo === '' || $identFiscal === '' || !$idTrans) {
|
||||||
die("❌ Todos los campos son obligatorios.");
|
die("❌ Todos los campos son obligatorios.");
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function guardar()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Redirigir de vuelta a la lista o mostrar mensaje…
|
// Redirigir de vuelta a la lista o mostrar mensaje…
|
||||||
header("Location: /IMPORTADORES/transportistas/lista?success=1");
|
header("Location: /IMPORTADORES/transportistas/lista?created=ok");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ function lista()
|
|||||||
include __DIR__ . '/../../views/transportistas/lista.php';
|
include __DIR__ . '/../../views/transportistas/lista.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Descarga la plantilla CSV para carga masiva **/
|
/** Descarga la plantilla CSV para carga masiva **/
|
||||||
function template()
|
function template()
|
||||||
{
|
{
|
||||||
$file = __DIR__ . '/../../public/downloads/transportistas_template.csv';
|
$file = __DIR__ . '/../../public/downloads/transportistas_template.csv';
|
||||||
|
|||||||
@@ -129,6 +129,16 @@
|
|||||||
</script>
|
</script>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (isset($_GET['success'])): ?>
|
||||||
|
<script>
|
||||||
|
<?php if ($_GET['success'] === 'created'): ?>
|
||||||
|
Swal.fire({ icon: 'success', title: 'Agencia registrada',
|
||||||
|
text: 'La agencia aduanal se ha registrada correctamente y se ha enviado un correo con las credenciales de acceso al administrador.',
|
||||||
|
confirmButtonColor: '#198754' });
|
||||||
|
<?php endif; ?>
|
||||||
|
</script>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (isset($_GET['error'])): ?>
|
<?php if (isset($_GET['error'])): ?>
|
||||||
<script>
|
<script>
|
||||||
<?php if ($_GET['error'] === 'unauthorized'): ?>
|
<?php if ($_GET['error'] === 'unauthorized'): ?>
|
||||||
|
|||||||
@@ -62,58 +62,50 @@
|
|||||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
table.dataTable thead th { background:#343a40; color:#fff; }
|
table.dataTable thead th { background:#343a40; color:#fff; }
|
||||||
/* ========== ANIMACIONES PARA INPUTS ========== */
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
/* 1. Animación al hacer focus */
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
.form-control { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
.form-control:not(.no-animation):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); }
|
||||||
.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); }
|
.form-control:not(.no-animation):not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
|
||||||
/* 2. Animación al escribir */
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
.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 {
|
@keyframes shake {
|
||||||
0%, 100% { transform: translateX(0); }
|
0%, 100% { transform: translateX(0); }
|
||||||
25% { transform: translateX(-5px); }
|
25% { transform: translateX(-5px); }
|
||||||
75% { transform: translateX(5px); }
|
75% { transform: translateX(5px); }
|
||||||
}
|
}
|
||||||
/* 4. Floating labels con animación */
|
/* Floating labels para inputs texto */
|
||||||
.form-floating-custom { position: relative; margin-bottom: 1.5rem; }
|
.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-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-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: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; }
|
.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:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
.input-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
|
|
||||||
@keyframes inputPulse {
|
@keyframes inputPulse {
|
||||||
0% { transform: scale(1); }
|
0% { transform: scale(1); }
|
||||||
50% { transform: scale(1.02); }
|
50% { transform: scale(1.02); }
|
||||||
100% { transform: scale(1); }
|
100% { transform: scale(1); }
|
||||||
}
|
}
|
||||||
/* 6. Gradiente animado en el borde */
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
.input-gradient { position: relative; overflow: hidden; }
|
.input-gradient:not(.no-animation)::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
||||||
.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; }
|
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%; }
|
.input-gradient:not(.no-animation):focus::before { left: 100%; }
|
||||||
/* 7. Efecto de brillo en validación exitosa */
|
.form-control.valid:not(.no-animation) { border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9); animation: successGlow 1s ease-in-out; }
|
||||||
.form-control.valid { border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9); animation: successGlow 1s ease-in-out; }
|
|
||||||
@keyframes successGlow {
|
@keyframes successGlow {
|
||||||
0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
||||||
50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); }
|
50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); }
|
||||||
100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
||||||
}
|
}
|
||||||
/* 8. Typing effect simulation */
|
.input-typing:not(.no-animation) { position: relative; }
|
||||||
.input-typing { position: relative; }
|
.input-typing:not(.no-animation)::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
|
||||||
.input-typing::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
|
.input-typing:not(.no-animation):focus::after { opacity: 1; }
|
||||||
.input-typing:focus::after { opacity: 1; }
|
|
||||||
@keyframes blink {
|
@keyframes blink {
|
||||||
0%, 50% { opacity: 1; }
|
0%, 50% { opacity: 1; }
|
||||||
51%, 100% { opacity: 0; }
|
51%, 100% { opacity: 0; }
|
||||||
}
|
}
|
||||||
/* 9. Efecto de ondas */
|
.input-ripple:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
.input-ripple { position: relative; overflow: hidden; }
|
.input-ripple:not(.no-animation)::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0;
|
||||||
.input-ripple::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0; background: rgba(13, 110, 253, 0.2);
|
background: rgba(13, 110, 253, 0.2); border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; }
|
||||||
border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; }
|
.input-ripple:not(.no-animation):focus::before { width: 300px; height: 300px; }
|
||||||
.input-ripple:focus::before { width: 300px; height: 300px; }
|
/* Animación para los campos del formulario */
|
||||||
/* 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 { 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(1) { animation-delay: 0.1s; }
|
||||||
.form-group-animated:nth-child(2) { animation-delay: 0.2s; }
|
.form-group-animated:nth-child(2) { animation-delay: 0.2s; }
|
||||||
@@ -123,49 +115,45 @@
|
|||||||
.form-group-animated:nth-child(6) { animation-delay: 0.6s; }
|
.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(7) { animation-delay: 0.7s; }
|
||||||
.form-group-animated:nth-child(8) { animation-delay: 0.8s; }
|
.form-group-animated:nth-child(8) { animation-delay: 0.8s; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
/* ========== ANIMACIONES PARA SELECT ========== */
|
/* ========== ANIMACIONES PARA SELECT ========== */
|
||||||
/* 1. Estilos base para select */
|
.form-select { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; cursor: pointer;
|
||||||
.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-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; }
|
background-repeat: no-repeat; background-position: right 0.75rem center; background-size: 16px 12px; padding: 1rem 2.5rem 0.5rem 0.75rem; height: auto; min-height: 3.5rem; }
|
||||||
/* 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);
|
.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"); }
|
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=""]):valid { border-color: #198754; background-color: #f8fff9;
|
||||||
.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"); }
|
||||||
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-select[value=""] { border-color: #dee2e6; background-color: #fff; }
|
||||||
.form-floating-custom .form-select:focus ~ .form-label,
|
/* Floating labels para select */
|
||||||
.form-floating-custom .form-select:not([value=""]) ~ .form-label { top: 0.25rem; font-size: 0.75rem; color: #0d6efd; font-weight: 600; }
|
.form-floating-custom .form-select ~ .form-label { position: absolute; top: 50%; left: 0.75rem; transform: translateY(-50%); pointer-events: none;
|
||||||
/* 5. Efecto de shake en validación para select */
|
transition: all 0.3s ease; color: #6c757d; font-size: 0.875rem; background: white; padding: 0 0.25rem; z-index: 1; opacity: 0; }
|
||||||
|
.form-floating-custom .form-select:focus ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
|
.form-floating-custom .form-select:not([value=""]):valid ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
.form-select.shake { animation: shake 0.5s ease-in-out; }
|
.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; }
|
.select-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
|
||||||
/* 7. Gradiente animado para select */
|
|
||||||
.select-gradient { position: relative; overflow: hidden; }
|
.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::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%; }
|
.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; }
|
.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 { 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"); }
|
.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 { position: relative; overflow: hidden; }
|
||||||
.select-ripple::after { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0;
|
.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; }
|
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; }
|
.select-ripple:focus::after { width: 300px; height: 300px; }
|
||||||
/* 11. Efecto de scale suave */
|
|
||||||
.select-scale { transition: transform 0.2s ease; }
|
.select-scale { transition: transform 0.2s ease; }
|
||||||
.select-scale:hover { transform: scale(1.02); }
|
.select-scale:hover {transform: scale(1.02); }
|
||||||
.select-scale:focus { transform: scale(1.02) translateY(-2px); }
|
.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 { padding: 0.5rem; transition: all 0.2s ease; }
|
||||||
.form-select option:hover { background-color: #f8f9fa; }
|
.form-select option:hover { background-color: #f8f9fa; }
|
||||||
/* 13. Indicador de estado */
|
|
||||||
.select-status { position: relative; }
|
.select-status { position: relative; }
|
||||||
.select-status::after { content: ''; position: absolute; right: 2.5rem; top: 50%; transform: translateY(-50%);
|
.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; }
|
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; }
|
.select-status:invalid::after { background-color: #dc3545; opacity: 1; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
@@ -200,15 +188,15 @@
|
|||||||
<div class="col-md-2 form-group-animated">
|
<div class="col-md-2 form-group-animated">
|
||||||
<div class="form-floating-custom">
|
<div class="form-floating-custom">
|
||||||
<select name="tipo_usuario" id="tipo" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
|
<select name="tipo_usuario" id="tipo" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
|
||||||
<option value=""></option>
|
<option value="">-- Tipo de Usuario --</option>
|
||||||
<option value="super_admin">Administrador General</option>
|
<option value="super_admin">Administrador General</option>
|
||||||
<option value="importador">Importador</option>
|
<option value="importador">Importador</option>
|
||||||
</select>
|
</select>
|
||||||
<label for="tipo" class="form-label">Tipo</label>
|
<label for="tipo" class="form-label">Tipo de Usuario</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-end mt-4">
|
<div class="text-end mt-4 form-group-animated">
|
||||||
<button class="btn btn-success px-4 mt-auto w-auto btn-animated">Registrar</button>
|
<button class="btn btn-success px-4 mt-auto w-auto btn-animated">Registrar</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -286,6 +274,28 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Configurar selects
|
||||||
|
selects.forEach(select => {
|
||||||
|
select.addEventListener('change', function() {
|
||||||
|
updateSelectState(this);
|
||||||
|
});
|
||||||
|
updateSelectState(select);
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateSelectState(select) {
|
||||||
|
select.setAttribute('value', select.value);
|
||||||
|
|
||||||
|
if (select.value && select.value !== '') {
|
||||||
|
select.classList.add('valid');
|
||||||
|
select.classList.remove('invalid');
|
||||||
|
} else {
|
||||||
|
select.classList.remove('valid');
|
||||||
|
if (select.hasAttribute('required') && select.closest('form')?.classList.contains('was-validated')) {
|
||||||
|
select.classList.add('invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Validación del formulario
|
// Validación del formulario
|
||||||
document.getElementById('formAltaUsuarios').addEventListener('submit', function(e) {
|
document.getElementById('formAltaUsuarios').addEventListener('submit', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -297,17 +307,6 @@
|
|||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isValid) {
|
|
||||||
// Aquí puedes agregar tu lógica de envío
|
|
||||||
Swal.fire({
|
|
||||||
icon: 'success',
|
|
||||||
title: '¡Éxito!',
|
|
||||||
text: 'Agencia registrada correctamente',
|
|
||||||
showConfirmButton: false,
|
|
||||||
timer: 1500
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -128,5 +128,29 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<?php if (isset($_GET['error'])): ?>
|
||||||
|
<script>
|
||||||
|
<?php if ($_GET['error'] === 'unauthorized'): ?>
|
||||||
|
Swal.fire({ icon: 'error', title: 'No autorizado', text: 'No tienes permisos para realizar esta acción.', confirmButtonColor: '#dc3545' });
|
||||||
|
<?php elseif ($_GET['error'] === 'error_user'): ?>
|
||||||
|
Swal.fire({ icon: 'error', title: 'Error de creación', text: 'El usuario administrador no se creo correctamente.', confirmButtonColor: '#dc3545' });
|
||||||
|
<?php elseif ($_GET['error'] === 'invalid_id'): ?>
|
||||||
|
Swal.fire({ icon: 'error', title: 'ID inválido', text: 'El identificador del usuario no es válido.', confirmButtonColor: '#dc3545' });
|
||||||
|
<?php elseif ($_GET['error'] === 'get_id_agencia'): ?>
|
||||||
|
Swal.fire({ icon: 'error', title: 'Error de obtención', text: 'El identificador no se pudo obtener correctamente.', confirmButtonColor: '#dc3545' });
|
||||||
|
<?php elseif ($_GET['error'] === 'invalid_request'): ?>
|
||||||
|
Swal.fire({ icon: 'error', title: 'ID de solicitud inválido', text: 'El identificador de la solicitud no es válido.', confirmButtonColor: '#dc3545' });
|
||||||
|
<?php elseif ($_GET['error'] === 'save_agencia_failed'): ?>
|
||||||
|
Swal.fire({ icon: 'error', title: 'Error al guardar agencia', text: 'No se pudo guardar la agencia. Inténtalo nuevamente.', confirmButtonColor: '#dc3545' });
|
||||||
|
<?php elseif ($_GET['error'] === 'update_failed'): ?>
|
||||||
|
Swal.fire({ icon: 'error', title: 'Error al actualizar', text: 'No se pudo actualizar el administrador de la agencia.', confirmButtonColor: '#dc3545' });
|
||||||
|
<?php elseif ($_GET['error'] === 'update_request_failed'): ?>
|
||||||
|
Swal.fire({ icon: 'error', title: 'Error al actualizar', text: 'Error al actualizar la solicitud.', confirmButtonColor: '#dc3545' });
|
||||||
|
<?php elseif ($_GET['error'] === 'get_id_failed'): ?>
|
||||||
|
Swal.fire({ icon: 'error', title: 'Error de obtención', text: 'Error al obtener el id de la agencia recien creada.', confirmButtonColor: '#dc3545' });
|
||||||
|
<?php endif; ?>
|
||||||
|
</script>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -61,6 +61,99 @@
|
|||||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
table.dataTable thead th { background: #343a40; color: #fff; }
|
table.dataTable thead th { background: #343a40; color: #fff; }
|
||||||
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
|
.form-control:not(.no-animation):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); }
|
||||||
|
.form-control:not(.no-animation):not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
|
||||||
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
25% { transform: translateX(-5px); }
|
||||||
|
75% { transform: translateX(5px); }
|
||||||
|
}
|
||||||
|
/* Floating labels para inputs texto */
|
||||||
|
.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; }
|
||||||
|
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
@keyframes inputPulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-gradient:not(.no-animation)::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:not(.no-animation):focus::before { left: 100%; }
|
||||||
|
.form-control.valid:not(.no-animation) { 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); }
|
||||||
|
}
|
||||||
|
.input-typing:not(.no-animation) { position: relative; }
|
||||||
|
.input-typing:not(.no-animation)::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
|
||||||
|
.input-typing:not(.no-animation):focus::after { opacity: 1; }
|
||||||
|
@keyframes blink {
|
||||||
|
0%, 50% { opacity: 1; }
|
||||||
|
51%, 100% { opacity: 0; }
|
||||||
|
}
|
||||||
|
.input-ripple:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-ripple:not(.no-animation)::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:not(.no-animation):focus::before { width: 300px; height: 300px; }
|
||||||
|
/* Animación para los campos del formulario */
|
||||||
|
.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; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
|
/* ========== ANIMACIONES 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; padding: 1rem 2.5rem 0.5rem 0.75rem; height: auto; min-height: 3.5rem; }
|
||||||
|
.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"); }
|
||||||
|
.form-select:not([value=""]):valid { 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"); }
|
||||||
|
.form-select[value=""] { border-color: #dee2e6; background-color: #fff; }
|
||||||
|
/* Floating labels para select */
|
||||||
|
.form-floating-custom .form-select ~ .form-label { position: absolute; top: 50%; left: 0.75rem; transform: translateY(-50%); pointer-events: none;
|
||||||
|
transition: all 0.3s ease; color: #6c757d; font-size: 0.875rem; background: white; padding: 0 0.25rem; z-index: 1; opacity: 0; }
|
||||||
|
.form-floating-custom .form-select:focus ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
|
.form-floating-custom .form-select:not([value=""]):valid ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
|
.form-select.shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
.select-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
.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%; }
|
||||||
|
.form-select.valid { border-color: #198754; background-color: #f8fff9; animation: successGlow 1s ease-in-out; }
|
||||||
|
.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"); }
|
||||||
|
.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; }
|
||||||
|
.select-scale { transition: transform 0.2s ease; }
|
||||||
|
.select-scale:hover {transform: scale(1.02); }
|
||||||
|
.select-scale:focus { transform: scale(1.02) translateY(-2px); }
|
||||||
|
.form-select option { padding: 0.5rem; transition: all 0.2s ease; }
|
||||||
|
.form-select option:hover { background-color: #f8f9fa; }
|
||||||
|
.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>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -70,26 +163,38 @@
|
|||||||
<h3 class="mb-4 animate__animated animate__fadeInDown title_glow">👨✈️ Administración de Agentes</h3>
|
<h3 class="mb-4 animate__animated animate__fadeInDown title_glow">👨✈️ Administración de Agentes</h3>
|
||||||
<!-- FORMULARIO -->
|
<!-- FORMULARIO -->
|
||||||
<div class="card p-4 mb-4 shadow-sm bg-white card-hover position-relative h-auto">
|
<div class="card p-4 mb-4 shadow-sm bg-white card-hover position-relative h-auto">
|
||||||
<form action="/IMPORTADORES/agencias/guardarAgente" method="POST">
|
<form action="/IMPORTADORES/agencias/guardarAgente" method="POST" id="formAltaAgentes">
|
||||||
<h5 class="mb-3">➕ Nuevo Agente</h5>
|
<h5 class="mb-3">➕ Nuevo Agente</h5>
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<input name="nombre" class="form-control" placeholder="Nombre completo" required>
|
<div class="form-floating-custom">
|
||||||
|
<input name="nombre" id="nombre" type="text" class="form-control input-pulse input-gradient" placeholder=" " required>
|
||||||
|
<label for="nombre" class="form-label">Nombre *</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
|
||||||
<input name="email" type="email" class="form-control" placeholder="Correo electrónico" required>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-4 form-group-animated">
|
||||||
<input name="password" type="password" class="form-control" placeholder="Contraseña" required>
|
<div class="form-floating-custom">
|
||||||
|
<input name="email" type="email" id="email" class="form-control input-pulse input-typing" placeholder=" " required>
|
||||||
|
<label for="email" class="form-label">Correo *</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
</div>
|
||||||
<select name="tipo_usuario" class="form-select" required>
|
<div class="col-md-2 form-group-animated">
|
||||||
<option value="">Tipo</option>
|
<div class="form-floating-custom">
|
||||||
|
<input name="password" type="password" id="password" class="form-control input-pulse input-ripple" placeholder=" " required>
|
||||||
|
<label for="password" class="form-label">Contraseña *</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2 form-group-animated">
|
||||||
|
<div class="form-floating-custom">
|
||||||
|
<select name="tipo_usuario" id="tipo" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
|
||||||
|
<option value="">-- Tipo de Usuario --</option>
|
||||||
<option value="agente_aduanal">Agente Aduanal</option>
|
<option value="agente_aduanal">Agente Aduanal</option>
|
||||||
</select>
|
</select>
|
||||||
|
<label for="tipo" class="form-label">Tipo de Usuario</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-end mt-4">
|
</div>
|
||||||
|
<div class="text-end mt-4 form-group-animated">
|
||||||
<button class="btn btn-success px-4 mt-auto w-auto btn-animated">Registrar</button>
|
<button class="btn btn-success px-4 mt-auto w-auto btn-animated">Registrar</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -147,14 +252,112 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Script para manejar las animaciones de validación
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const inputs = document.querySelectorAll('input.form-control, select.form-select');
|
||||||
|
const selects = document.querySelectorAll('select.form-select');
|
||||||
|
|
||||||
|
inputs.forEach(input => {
|
||||||
|
// Validación en tiempo real
|
||||||
|
input.addEventListener('input', function() {
|
||||||
|
if (this.checkValidity()) {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
this.classList.add('valid');
|
||||||
|
} else {
|
||||||
|
this.classList.remove('valid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Efecto shake en campos inválidos
|
||||||
|
input.addEventListener('invalid', function() {
|
||||||
|
this.classList.add('shake');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configurar selects
|
||||||
|
selects.forEach(select => {
|
||||||
|
select.addEventListener('change', function() {
|
||||||
|
updateSelectState(this);
|
||||||
|
});
|
||||||
|
updateSelectState(select);
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateSelectState(select) {
|
||||||
|
select.setAttribute('value', select.value);
|
||||||
|
|
||||||
|
if (select.value && select.value !== '') {
|
||||||
|
select.classList.add('valid');
|
||||||
|
select.classList.remove('invalid');
|
||||||
|
} else {
|
||||||
|
select.classList.remove('valid');
|
||||||
|
if (select.hasAttribute('required') && select.closest('form')?.classList.contains('was-validated')) {
|
||||||
|
select.classList.add('invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UN SOLO EVENT LISTENER PARA EL FORMULARIO
|
||||||
|
document.getElementById('formAltaAgentes').addEventListener('submit', function(e) {
|
||||||
|
console.log('Formulario enviándose...');
|
||||||
|
console.log('Datos del formulario:');
|
||||||
|
const formData = new FormData(this);
|
||||||
|
for (let [key, value] of formData.entries()) {
|
||||||
|
console.log(key + ': ' + value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar que todos los campos requeridos estén llenos
|
||||||
|
const nombre = document.getElementById('nombre').value;
|
||||||
|
const email = document.getElementById('email').value;
|
||||||
|
const password = document.getElementById('password').value;
|
||||||
|
const tipo = document.getElementById('tipo').value;
|
||||||
|
|
||||||
|
if (!nombre || !email || !password || !tipo) {
|
||||||
|
console.error('Faltan campos requeridos');
|
||||||
|
console.log('nombre:', nombre);
|
||||||
|
console.log('email:', email);
|
||||||
|
console.log('password:', password ? 'NO VACÍO' : 'VACÍO');
|
||||||
|
console.log('tipo:', tipo);
|
||||||
|
|
||||||
|
// Mostrar animación de error en campos vacíos
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
e.preventDefault(); // Solo prevenir si hay errores
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tipo !== 'agente_aduanal') {
|
||||||
|
console.error('Tipo de usuario inválido:', tipo);
|
||||||
|
e.preventDefault(); // Solo prevenir si hay errores
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Validación del formulario pasada');
|
||||||
|
|
||||||
|
// Deshabilitar botón de envío para evitar envíos múltiples
|
||||||
|
const submitButton = this.querySelector('button[type="submit"]');
|
||||||
|
if (submitButton) {
|
||||||
|
submitButton.disabled = true;
|
||||||
|
submitButton.innerHTML = 'Enviando...';
|
||||||
|
}
|
||||||
|
|
||||||
|
// NO HACER e.preventDefault() aquí - dejar que el formulario se envíe normalmente
|
||||||
|
// El formulario se enviará automáticamente a la acción especificada
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<?php if (isset($_GET['success'])): ?>
|
<?php if (isset($_GET['success'])): ?>
|
||||||
<script>
|
<script>
|
||||||
<?php if ($_GET['success'] === 'created'): ?>
|
<?php if ($_GET['success'] === 'created'): ?>
|
||||||
Swal.fire({ icon: 'success', title: 'Usuario creado',
|
Swal.fire({ icon: 'success', title: 'Usuario creado', text: 'El usuario se ha creado correctamente y se ha enviado un correo con las credenciales.', confirmButtonColor: '#198754' });
|
||||||
text: 'El usuario se ha creado correctamente y se ha enviado un correo con las credenciales.',
|
|
||||||
confirmButtonColor: '#198754' });
|
|
||||||
<?php elseif ($_GET['success'] === 'status_deactivated'): ?>
|
<?php elseif ($_GET['success'] === 'status_deactivated'): ?>
|
||||||
Swal.fire({ icon: 'success', title: 'Usuario desactivado', text: 'El usuario ha sido desactivado correctamente.', confirmButtonColor: '#198754' });
|
Swal.fire({ icon: 'success', title: 'Usuario desactivado', text: 'El usuario ha sido desactivado correctamente.', confirmButtonColor: '#198754' });
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
@@ -169,8 +169,8 @@
|
|||||||
.form-floating-fecha .form-control:not(:placeholder-shown) ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
.form-floating-fecha .form-control:not(:placeholder-shown) ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
.form-floating-fecha .form-control:focus, .form-floating-fecha .form-control:not(:placeholder-shown) { padding-top: 1.625rem; padding-bottom: 0.625rem; }
|
.form-floating-fecha .form-control:focus, .form-floating-fecha .form-control:not(:placeholder-shown) { padding-top: 1.625rem; padding-bottom: 0.625rem; }
|
||||||
/* ========== ESTILOS PARA CAMPO FOTO (SIN ANIMACIONES) ========== */
|
/* ========== ESTILOS PARA CAMPO FOTO (SIN ANIMACIONES) ========== */
|
||||||
.no-animation, .no-border-style { transition: none !important; border: 1px solid #ccc !important; box-shadow: none !important; background: #fff !important; }
|
.no-animation, .no-border-style { transition: none !important; border: none; box-shadow: none !important; background: #fff !important; }
|
||||||
.no-animation:focus { transform: none !important; border: 1px solid #0d6efd !important; box-shadow: none !important; }
|
.no-animation:focus { transform: none !important; border: none; box-shadow: none !important; }
|
||||||
.no-animation:hover { animation: none !important; }
|
.no-animation:hover { animation: none !important; }
|
||||||
.no-animation::before, .no-animation::after { display: none !important; }
|
.no-animation::before, .no-animation::after { display: none !important; }
|
||||||
</style>
|
</style>
|
||||||
@@ -290,6 +290,7 @@
|
|||||||
const telefonoRegex = /^\d{3}\s\d{7}$/;
|
const telefonoRegex = /^\d{3}\s\d{7}$/;
|
||||||
const emailRegex = /^[a-zA-Z0-9._+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
const emailRegex = /^[a-zA-Z0-9._+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||||
const soloNumerosRegex = /^[0-9]+$/;
|
const soloNumerosRegex = /^[0-9]+$/;
|
||||||
|
const fechaRegex = /^\d{2}\/\d{2}\/\d{4}$/; // formato dd/mm/aaaa
|
||||||
|
|
||||||
// VALIDAR CAMPOS OBLIGATORIOS PRIMERO
|
// VALIDAR CAMPOS OBLIGATORIOS PRIMERO
|
||||||
if (!transportista_id) {
|
if (!transportista_id) {
|
||||||
@@ -320,7 +321,7 @@
|
|||||||
if (!soloNumerosRegex.test(numero_licencia)) {
|
if (!soloNumerosRegex.test(numero_licencia)) {
|
||||||
Swal.fire({ icon: 'error', title: 'Número de Licencia inválido', text: 'El número de licencia solo puede contener números', confirmButtonColor: '#dc3545'
|
Swal.fire({ icon: 'error', title: 'Número de Licencia inválido', text: 'El número de licencia solo puede contener números', confirmButtonColor: '#dc3545'
|
||||||
});
|
});
|
||||||
document.getElementById('Clave').focus();
|
document.getElementById('numero_licencia').focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// VALIDAR CAMPOS OPCIONALES (solo si tienen contenido)
|
// VALIDAR CAMPOS OPCIONALES (solo si tienen contenido)
|
||||||
@@ -336,8 +337,19 @@
|
|||||||
}
|
}
|
||||||
// VALIDAR FECHA DE INGRESO (solo si se proporciona)
|
// VALIDAR FECHA DE INGRESO (solo si se proporciona)
|
||||||
if (fecha_ingreso) {
|
if (fecha_ingreso) {
|
||||||
const fechaIngreso = new Date(fecha_ingreso);
|
// Validar formato primero
|
||||||
|
if (!fechaRegex.test(fecha_ingreso)) {
|
||||||
|
Swal.fire({ icon: 'error', title: 'Formato de fecha inválido', text: 'La fecha debe tener el formato dd/mm/aaaa', confirmButtonColor: '#dc3545' });
|
||||||
|
document.getElementById('fecha_ingreso').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convertir fecha correctamente (dd/mm/aaaa -> mm/dd/aaaa)
|
||||||
|
const [dia, mes, año] = fecha_ingreso.split('/');
|
||||||
|
const fechaIngreso = new Date(año, mes - 1, dia); // mes - 1 porque Date usa 0-11
|
||||||
const fechaActual = new Date();
|
const fechaActual = new Date();
|
||||||
|
fechaActual.setHours(0, 0, 0, 0); // Normalizar a medianoche
|
||||||
|
|
||||||
if (fechaIngreso > fechaActual) {
|
if (fechaIngreso > fechaActual) {
|
||||||
Swal.fire({ icon: 'error', title: 'Fecha inválida', text: 'La fecha de ingreso no puede ser futura.', confirmButtonColor: '#dc3545' });
|
Swal.fire({ icon: 'error', title: 'Fecha inválida', text: 'La fecha de ingreso no puede ser futura.', confirmButtonColor: '#dc3545' });
|
||||||
document.getElementById('fecha_ingreso').focus();
|
document.getElementById('fecha_ingreso').focus();
|
||||||
@@ -415,21 +427,6 @@
|
|||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Si todo es válido, enviar el formulario
|
|
||||||
if (isValid) {
|
|
||||||
// Mostrar indicador de carga
|
|
||||||
const submitBtn = form.querySelector('button[type="submit"]');
|
|
||||||
const originalText = submitBtn.textContent;
|
|
||||||
submitBtn.disabled = true;
|
|
||||||
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Guardando...';
|
|
||||||
|
|
||||||
// Aquí puedes enviar el formulario real
|
|
||||||
form.submit();
|
|
||||||
} else {
|
|
||||||
// Mostrar mensaje de error
|
|
||||||
showNotification('Por favor, complete todos los campos obligatorios correctamente.', 'error');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -465,56 +462,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Validación específica para campos de texto
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
// Validación del número de licencia (solo números y letras)
|
|
||||||
const licenciaInput = document.getElementById('numero_licencia');
|
|
||||||
if (licenciaInput) {
|
|
||||||
licenciaInput.addEventListener('input', function() {
|
|
||||||
this.value = this.value.replace(/[^A-Za-z0-9]/g, '');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validación del teléfono (solo números)
|
|
||||||
const telefonoInput = document.getElementById('telefono');
|
|
||||||
if (telefonoInput) {
|
|
||||||
telefonoInput.addEventListener('input', function() {
|
|
||||||
this.value = this.value.replace(/[^0-9]/g, '');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validación del email en tiempo real
|
|
||||||
const emailInput = document.getElementById('email');
|
|
||||||
if (emailInput) {
|
|
||||||
emailInput.addEventListener('input', function() {
|
|
||||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
||||||
if (this.value && !emailRegex.test(this.value)) {
|
|
||||||
this.setCustomValidity('Por favor, ingrese un email válido');
|
|
||||||
} else {
|
|
||||||
this.setCustomValidity('');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Función para mostrar notificaciones
|
|
||||||
function showNotification(message, type = 'info') {
|
|
||||||
// Crear el elemento de notificación
|
|
||||||
const notification = document.createElement('div');
|
|
||||||
notification.className = `alert alert-${type === 'error' ? 'danger' : type} alert-dismissible fade show position-fixed`;
|
|
||||||
notification.style.cssText = ` top: 20px; right: 20px; z-index: 9999; min-width: 300px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);`;
|
|
||||||
notification.innerHTML = `${message} <button type="button" class="btn-close" data-bs-dismiss="alert"></button>`;
|
|
||||||
|
|
||||||
document.body.appendChild(notification);
|
|
||||||
|
|
||||||
// Auto-remover después de 5 segundos
|
|
||||||
setTimeout(() => {
|
|
||||||
if (notification.parentNode) {
|
|
||||||
notification.remove();
|
|
||||||
}
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inicializar Flatpickr para la fecha
|
// Inicializar Flatpickr para la fecha
|
||||||
flatpickr("#fecha_ingreso", {
|
flatpickr("#fecha_ingreso", {
|
||||||
dateFormat: "d/m/Y",
|
dateFormat: "d/m/Y",
|
||||||
|
|||||||
@@ -14,6 +14,12 @@
|
|||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
<!-- Animate.css para animaciones adicionales -->
|
<!-- Animate.css para animaciones adicionales -->
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
|
||||||
|
<!-- CSS de Flatpickr -->
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
|
||||||
|
<!-- JS de Flatpickr -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
|
||||||
|
<!-- Idioma español -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/es.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
|
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 { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
|
||||||
@@ -58,6 +64,114 @@
|
|||||||
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
.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; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
|
.form-control:not(.no-animation):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); }
|
||||||
|
.form-control:not(.no-animation):not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
|
||||||
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
25% { transform: translateX(-5px); }
|
||||||
|
75% { transform: translateX(5px); }
|
||||||
|
}
|
||||||
|
/* Floating labels para inputs texto */
|
||||||
|
.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; }
|
||||||
|
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
@keyframes inputPulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-gradient:not(.no-animation)::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:not(.no-animation):focus::before { left: 100%; }
|
||||||
|
.form-control.valid:not(.no-animation) { 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); }
|
||||||
|
}
|
||||||
|
.input-typing:not(.no-animation) { position: relative; }
|
||||||
|
.input-typing:not(.no-animation)::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
|
||||||
|
.input-typing:not(.no-animation):focus::after { opacity: 1; }
|
||||||
|
@keyframes blink {
|
||||||
|
0%, 50% { opacity: 1; }
|
||||||
|
51%, 100% { opacity: 0; }
|
||||||
|
}
|
||||||
|
.input-ripple:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-ripple:not(.no-animation)::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:not(.no-animation):focus::before { width: 300px; height: 300px; }
|
||||||
|
/* Animación para los campos del formulario */
|
||||||
|
.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; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
|
/* ========== ANIMACIONES 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; padding: 1rem 2.5rem 0.5rem 0.75rem; height: auto; min-height: 3.5rem; }
|
||||||
|
.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"); }
|
||||||
|
.form-select:not([value=""]):valid { 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"); }
|
||||||
|
.form-select[value=""] { border-color: #dee2e6; background-color: #fff; }
|
||||||
|
/* Floating labels para select */
|
||||||
|
.form-floating-custom .form-select ~ .form-label { position: absolute; top: 50%; left: 0.75rem; transform: translateY(-50%); pointer-events: none;
|
||||||
|
transition: all 0.3s ease; color: #6c757d; font-size: 0.875rem; background: white; padding: 0 0.25rem; z-index: 1; opacity: 0; }
|
||||||
|
.form-floating-custom .form-select:focus ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
|
.form-floating-custom .form-select:not([value=""]):valid ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
|
.form-select.shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
.select-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
.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%; }
|
||||||
|
.form-select.valid { border-color: #198754; background-color: #f8fff9; animation: successGlow 1s ease-in-out; }
|
||||||
|
.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"); }
|
||||||
|
.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; }
|
||||||
|
.select-scale { transition: transform 0.2s ease; }
|
||||||
|
.select-scale:hover {transform: scale(1.02); }
|
||||||
|
.select-scale:focus { transform: scale(1.02) translateY(-2px); }
|
||||||
|
.form-select option { padding: 0.5rem; transition: all 0.2s ease; }
|
||||||
|
.form-select option:hover { background-color: #f8f9fa; }
|
||||||
|
.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; }
|
||||||
|
/* ========== ESTILOS PARA CAMPO FECHA ========== */
|
||||||
|
.form-floating-fecha { position: relative; margin-bottom: 1.5rem; }
|
||||||
|
.form-floating-fecha .form-control { padding: 1rem 0.75rem; transition: all 0.3s ease; border: 2px solid #dee2e6; }
|
||||||
|
.form-floating-fecha .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); }
|
||||||
|
.form-floating-fecha .form-control:not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
|
||||||
|
.form-floating-fecha .form-label { position: absolute; top: 50%; left: 0.75rem; transform: translateY(-50%);pointer-events: none;
|
||||||
|
transition: all 0.3s ease; color: #6c757d; opacity: 0; font-size: 0.875rem; background: white; padding: 0 0.25rem; z-index: 1; }
|
||||||
|
.form-floating-fecha .form-control:focus ~ .form-label,
|
||||||
|
.form-floating-fecha .form-control:not(:placeholder-shown) ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
|
.form-floating-fecha .form-control:focus, .form-floating-fecha .form-control:not(:placeholder-shown) { padding-top: 1.625rem; padding-bottom: 0.625rem; }
|
||||||
|
/* ========== ESTILOS PARA CAMPO FOTO (SIN ANIMACIONES) ========== */
|
||||||
|
.no-animation, .no-border-style { transition: none !important; border: none; box-shadow: none !important; background: #fff !important; }
|
||||||
|
.no-animation:focus { transform: none !important; border: none; box-shadow: none !important; }
|
||||||
|
.no-animation:hover { animation: none !important; }
|
||||||
|
.no-animation::before, .no-animation::after { display: none !important; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -68,10 +182,12 @@
|
|||||||
<form action="/IMPORTADORES/choferes/actualizar" method="POST" enctype="multipart/form-data" id="formEditChoferes">
|
<form action="/IMPORTADORES/choferes/actualizar" method="POST" enctype="multipart/form-data" id="formEditChoferes">
|
||||||
<input type="hidden" name="id_chofer" value="<?= (int)$chofer['id_chofer'] ?>">
|
<input type="hidden" name="id_chofer" value="<?= (int)$chofer['id_chofer'] ?>">
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
<!-- Transportista -->
|
<!-- Transportista -->
|
||||||
<div class="mb-3">
|
<div class="col-md-12 form-group-animated">
|
||||||
<label for="transportista_id" class="form-label">Transportista</label>
|
<label for="transportista_id" class="form-label">Transportista</label>
|
||||||
<select name="transportista_id" id="transportista_id" class="form-select" required>
|
<div class="form-floating-custom">
|
||||||
|
<select name="transportista_id" id="transportista_id" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
|
||||||
<option value="">-- Selecciona un transportista --</option>
|
<option value="">-- Selecciona un transportista --</option>
|
||||||
<?php foreach ($transportistas as $t): ?>
|
<?php foreach ($transportistas as $t): ?>
|
||||||
<option value="<?= $t['id_transportista'] ?>"
|
<option value="<?= $t['id_transportista'] ?>"
|
||||||
@@ -80,65 +196,90 @@
|
|||||||
</option>
|
</option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
|
<label for="transportista_id" class="form-label">Transportista</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<!-- Nombre -->
|
<!-- Nombre -->
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="nombre" class="form-label">Nombre</label>
|
<label for="nombre" class="form-label">Nombre</label>
|
||||||
<input name="nombre" id="nombre" type="text" class="form-control"
|
<div class="form-floating-custom">
|
||||||
|
<input name="nombre" id="nombre" type="text" class="form-control input-pulse input-gradient"
|
||||||
value="<?= htmlspecialchars($chofer['nombre']) ?>" required>
|
value="<?= htmlspecialchars($chofer['nombre']) ?>" required>
|
||||||
|
<label for="nombre" class="form-label">Nombre</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Apellido -->
|
<!-- Apellido -->
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="apellido" class="form-label">Apellido</label>
|
<label for="apellido" class="form-label">Apellido</label>
|
||||||
<input name="apellido" id="apellido" type="text" class="form-control"
|
<div class="form-floating-custom">
|
||||||
|
<input name="apellido" id="apellido" type="text" class="form-control input-pulse input-gradient"
|
||||||
value="<?= htmlspecialchars($chofer['apellido']) ?>" required>
|
value="<?= htmlspecialchars($chofer['apellido']) ?>" required>
|
||||||
|
<label for="apellido" class="form-label">Apellido</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<!-- Licencia -->
|
<!-- Licencia -->
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="numero_licencia" class="form-label">Número de Licencia</label>
|
<label for="numero_licencia" class="form-label">Número de Licencia</label>
|
||||||
<input name="numero_licencia" id="numero_licencia" type="text" maxlength="11" class="form-control"
|
<div class="form-floating-custom">
|
||||||
|
<input name="numero_licencia" id="numero_licencia" type="text" maxlength="11" class="form-control input-pulse input-gradient"
|
||||||
value="<?= htmlspecialchars($chofer['numero_licencia']) ?>" required>
|
value="<?= htmlspecialchars($chofer['numero_licencia']) ?>" required>
|
||||||
|
<label for="numero_licencia" class="form-label">Número de Licencia</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Gafete -->
|
<!-- Gafete -->
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="numero_gafete" class="form-label">Número de Gafete</label>
|
<label for="numero_gafete" class="form-label">Número de Gafete</label>
|
||||||
<input name="numero_gafete" id="numero_gafete" type="text" maxlength="24" class="form-control"
|
<div class="form-floating-custom">
|
||||||
|
<input name="numero_gafete" id="numero_gafete" type="text" maxlength="24" class="form-control input-pulse input-gradient"
|
||||||
value="<?= htmlspecialchars($chofer['numero_gafete']) ?>" required>
|
value="<?= htmlspecialchars($chofer['numero_gafete']) ?>" required>
|
||||||
|
<label for="numero_gafete" class="form-label">Número de Gafete</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Teléfono -->
|
<!-- Teléfono -->
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="telefono" class="form-label">Teléfono</label>
|
<label for="telefono" class="form-label">Teléfono</label>
|
||||||
<input name="telefono" id="telefono" type="tel" maxlength="11" class="form-control"
|
<div class="form-floating-custom">
|
||||||
|
<input name="telefono" id="telefono" type="tel" maxlength="11" class="form-control input-pulse input-gradient"
|
||||||
value="<?= htmlspecialchars($chofer['telefono']) ?>">
|
value="<?= htmlspecialchars($chofer['telefono']) ?>">
|
||||||
|
<label for="telefono" class="form-label">Teléfono</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="email" class="form-label">Email</label>
|
<label for="email" class="form-label">Email</label>
|
||||||
<input name="email" id="email" type="email" class="form-control"
|
<div class="form-floating-custom">
|
||||||
|
<input name="email" id="email" type="email" class="form-control input-pulse input-typing"
|
||||||
value="<?= htmlspecialchars($chofer['email']) ?>">
|
value="<?= htmlspecialchars($chofer['email']) ?>">
|
||||||
|
<label for="email" class="form-label">Email</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Fecha de Ingreso -->
|
<!-- Fecha de Ingreso -->
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="fecha_ingreso" class="form-label">Fecha de Ingreso</label>
|
<label for="fecha_ingreso" class="form-label">Fecha de Ingreso</label>
|
||||||
<input name="fecha_ingreso" id="fecha_ingreso" type="date" class="form-control"
|
<div class="form-floating-custom">
|
||||||
|
<input name="fecha_ingreso" id="fecha_ingreso" type="text" class="form-control input-pulse input-gradient"
|
||||||
value="<?= htmlspecialchars($chofer['fecha_ingreso']) ?>">
|
value="<?= htmlspecialchars($chofer['fecha_ingreso']) ?>">
|
||||||
|
<label for="fecha_ingreso" class="form-label">Fecha de Ingreso</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Cambiar foto -->
|
||||||
|
<div class="col-md-6 form-group-animated">
|
||||||
|
<label for="foto" class="form-label">Nueva Foto</label>
|
||||||
|
<div class="form-floating-custom">
|
||||||
|
<input name="foto" id="foto" type="file" class="form-control no-animation no-border-style" accept="image/*">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Foto actual -->
|
<!-- Foto actual -->
|
||||||
<div class="mb-3">
|
<div class="mb-3 form-group-animated">
|
||||||
<label class="form-label">Foto Actual</label><br>
|
<label class="form-label">Foto Actual</label><br>
|
||||||
<?php if (!empty($chofer['foto_url'])): ?>
|
<?php if (!empty($chofer['foto_url'])): ?>
|
||||||
<img src="<?= htmlspecialchars($chofer['foto_url']) ?>" alt="Foto Chofer" width="100" class="mb-2">
|
<img src="<?= htmlspecialchars($chofer['foto_url']) ?>" alt="Foto Chofer" width="100" class="mb-2">
|
||||||
@@ -147,21 +288,22 @@
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Cambiar foto -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="foto" class="form-label">Nueva Foto</label>
|
|
||||||
<input name="foto" id="foto" type="file" class="form-control" accept="image/*">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Activo -->
|
<!-- Activo -->
|
||||||
<div class="form-check mb-4">
|
<div class="col-md-2 form-group-animated">
|
||||||
|
<div class="form-check">
|
||||||
|
<div class="form-floating-custom">
|
||||||
<input name="status" id="status" type="checkbox" class="form-check-input"
|
<input name="status" id="status" type="checkbox" class="form-check-input"
|
||||||
<?= $chofer['status'] == 1 ? 'checked' : '' ?>>
|
<?= $chofer['status'] == 1 ? 'checked' : '' ?>>
|
||||||
<label for="status" class="form-check-label">Activo</label>
|
<label for="status" class="form-check-label">Activo</label>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-end mt-4 form-group-animated">
|
||||||
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Actualizar</button>
|
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Actualizar</button>
|
||||||
<a href="/IMPORTADORES/choferes/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
<a href="/IMPORTADORES/choferes/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -64,6 +64,51 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
.hide { display: none !important; }
|
.hide { display: none !important; }
|
||||||
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
|
.form-control:not(.no-animation):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); }
|
||||||
|
.form-control:not(.no-animation):not(:placeholder-shown) { /*border-color: #198754; background-color: #f8fff9;*/ }
|
||||||
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
25% { transform: translateX(-5px); }
|
||||||
|
75% { transform: translateX(5px); }
|
||||||
|
}
|
||||||
|
/* Floating labels para inputs texto */
|
||||||
|
.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; }
|
||||||
|
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
@keyframes inputPulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-gradient:not(.no-animation)::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:not(.no-animation):focus::before { left: 100%; }
|
||||||
|
.form-control.valid:not(.no-animation) { /*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); }
|
||||||
|
}
|
||||||
|
/* Animación para los campos del formulario */
|
||||||
|
.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; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -73,15 +118,15 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
|
|
||||||
<!-- Nuevo Estado -->
|
<!-- Nuevo Estado -->
|
||||||
<div class="col-md">
|
<div class="col-md form-group-animated">
|
||||||
<div class="card p-4 bg-white shadow-sm card-hover position-relative h-auto">
|
<div class="card p-4 bg-white shadow-sm card-hover position-relative h-auto">
|
||||||
<form id="estadoForm">
|
<form id="estadoForm">
|
||||||
<h4 class="mb-4 text-dark">➕ Nuevo Estado</h4><br>
|
<h4 class="mb-4 text-dark">➕ Nuevo Estado</h4><br>
|
||||||
<!-- País -->
|
<!-- País -->
|
||||||
<div class="col-md-12">
|
<div class="col-md-12 form-group-animated">
|
||||||
<label for="paisEstado" class="form-label">País *</label>
|
<label for="paisEstado" class="form-label">País *</label>
|
||||||
<select id="paisEstado" name="pais" class="form-select" required>
|
<select id="paisEstado" name="pais" class="form-select" required>
|
||||||
<option value="">Selecciona país</option>
|
<option value="">-- Selecciona un país --</option>
|
||||||
<?php foreach($paises as $p): ?>
|
<?php foreach($paises as $p): ?>
|
||||||
<option value="<?= $p['id_pais'] ?>">
|
<option value="<?= $p['id_pais'] ?>">
|
||||||
<?= htmlspecialchars($p['nombre']) ?>
|
<?= htmlspecialchars($p['nombre']) ?>
|
||||||
@@ -91,12 +136,12 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
</div><br><br><br>
|
</div><br><br><br>
|
||||||
|
|
||||||
<!-- Estado -->
|
<!-- Estado -->
|
||||||
<div class="col-md-12">
|
<div class="col-md-12 form-group-animated">
|
||||||
<label for="entidadEstado" class="form-label">Entidad / Provincia *</label>
|
<label for="entidadEstado" class="form-label">Entidad / Provincia *</label>
|
||||||
<input id="entidadEstado" name="entidad" class="form-control" required>
|
<input id="entidadEstado" name="entidad" class="form-control" required>
|
||||||
</div><br><br>
|
</div><br><br>
|
||||||
|
|
||||||
<div class="col-md-4 d-flex align-items-end">
|
<div class="col-md-4 d-flex align-items-end form-group-animated">
|
||||||
<button type="submit" class="btn btn-success W-100 btn-animated">
|
<button type="submit" class="btn btn-success W-100 btn-animated">
|
||||||
<i class="fas fa-plus"></i> Registrar Estado
|
<i class="fas fa-plus"></i> Registrar Estado
|
||||||
</button>
|
</button>
|
||||||
@@ -108,15 +153,15 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Nueva Ciudad -->
|
<!-- Nueva Ciudad -->
|
||||||
<div class="col-md">
|
<div class="col-md form-group-animated">
|
||||||
<div class="card p-4 bg-white shadow-sm card-hover position-relative h-auto">
|
<div class="card p-4 bg-white shadow-sm card-hover position-relative h-auto">
|
||||||
<form id="ciudadForm" action="/IMPORTADORES/locaciones/guadarCiudad" method="POST" enctype="multipart/form-data">
|
<form id="ciudadForm" action="/IMPORTADORES/locaciones/guadarCiudad" method="POST" enctype="multipart/form-data">
|
||||||
<h4 class="mb-4 text-dark">➕ Nueva Ciudad</h4>
|
<h4 class="mb-4 text-dark">➕ Nueva Ciudad</h4>
|
||||||
<!-- País -->
|
<!-- País -->
|
||||||
<div class="col-md-12">
|
<div class="col-md-12 form-group-animated">
|
||||||
<label for="paisCiudad" class="form-label">País *</label>
|
<label for="paisCiudad" class="form-label">País *</label>
|
||||||
<select id="paisCiudad" name="pais" class="form-select" required>
|
<select id="paisCiudad" name="pais" class="form-select" required>
|
||||||
<option value="">Selecciona país</option>
|
<option value="">-- Selecciona un país --</option>
|
||||||
<?php foreach($paises as $p): ?>
|
<?php foreach($paises as $p): ?>
|
||||||
<option value="<?= $p['id_pais'] ?>">
|
<option value="<?= $p['id_pais'] ?>">
|
||||||
<?= htmlspecialchars($p['nombre']) ?>
|
<?= htmlspecialchars($p['nombre']) ?>
|
||||||
@@ -126,7 +171,7 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
</div><br>
|
</div><br>
|
||||||
|
|
||||||
<!-- Estado -->
|
<!-- Estado -->
|
||||||
<div class="col-md-12">
|
<div class="col-md-12 form-group-animated">
|
||||||
<label for="entidadCiudad" class="form-label">Entidad / Provincia *</label>
|
<label for="entidadCiudad" class="form-label">Entidad / Provincia *</label>
|
||||||
<select id="estadoCiudad" name="entidad" class="form-select" required disabled>
|
<select id="estadoCiudad" name="entidad" class="form-select" required disabled>
|
||||||
<option value="">Primero país…</option>
|
<option value="">Primero país…</option>
|
||||||
@@ -134,12 +179,12 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
</div><br>
|
</div><br>
|
||||||
|
|
||||||
<!-- Ciudad -->
|
<!-- Ciudad -->
|
||||||
<div class="col-md-12">
|
<div class="col-md-12 form-group-animated">
|
||||||
<label for="nombreCiudad" class="form-label">Ciudad *</label>
|
<label for="nombreCiudad" class="form-label">Ciudad *</label>
|
||||||
<input id="nombreCiudad" name="ciudad" class="form-control" required>
|
<input id="nombreCiudad" name="ciudad" class="form-control" required>
|
||||||
</div><br>
|
</div><br>
|
||||||
|
|
||||||
<div class="col-md-4 d-flex align-items-end">
|
<div class="col-md-4 d-flex align-items-end form-group-animated">
|
||||||
<button type="submit" class="btn btn-success W-100 btn-animated">
|
<button type="submit" class="btn btn-success W-100 btn-animated">
|
||||||
<i class="fas fa-plus"></i> Registrar Ciudad
|
<i class="fas fa-plus"></i> Registrar Ciudad
|
||||||
</button>
|
</button>
|
||||||
@@ -161,7 +206,7 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
fetch(`/IMPORTADORES/locaciones/estados?pais=${paisId}`)
|
fetch(`/IMPORTADORES/locaciones/estados?pais=${paisId}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(estados => {
|
.then(estados => {
|
||||||
selectElement.innerHTML = '<option value="">Selecciona estado</option>';
|
selectElement.innerHTML = '<option value="">-- Selecciona un estado --</option>';
|
||||||
estados.forEach(estado => {
|
estados.forEach(estado => {
|
||||||
const option = new Option(estado.nombre, estado.id_estado);
|
const option = new Option(estado.nombre, estado.id_estado);
|
||||||
selectElement.add(option);
|
selectElement.add(option);
|
||||||
@@ -182,7 +227,7 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
if (paisId) {
|
if (paisId) {
|
||||||
cargarEstados(paisId, estadoSelect);
|
cargarEstados(paisId, estadoSelect);
|
||||||
} else {
|
} else {
|
||||||
estadoSelect.innerHTML = '<option value="">Primero selecciona país</option>';
|
estadoSelect.innerHTML = '<option value="">Primero selecciona un país...</option>';
|
||||||
estadoSelect.disabled = true;
|
estadoSelect.disabled = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -200,20 +245,12 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
|
|
||||||
// Validación en frontend
|
// Validación en frontend
|
||||||
if (!paisValue) {
|
if (!paisValue) {
|
||||||
Swal.fire({
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Debe seleccionar un país' });
|
||||||
icon: 'warning',
|
|
||||||
title: 'Campo requerido',
|
|
||||||
text: 'Debe seleccionar un país'
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entidadValue) {
|
if (!entidadValue) {
|
||||||
Swal.fire({
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Debe ingresar el nombre del estado' });
|
||||||
icon: 'warning',
|
|
||||||
title: 'Campo requerido',
|
|
||||||
text: 'Debe ingresar el nombre del estado'
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,29 +278,15 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
Swal.fire({
|
Swal.fire({ icon: 'success', title: '¡Éxito!', text: data.message, timer: 2000, showConfirmButton: false });
|
||||||
icon: 'success',
|
|
||||||
title: '¡Éxito!',
|
|
||||||
text: data.message,
|
|
||||||
timer: 2000,
|
|
||||||
showConfirmButton: false
|
|
||||||
});
|
|
||||||
this.reset();
|
this.reset();
|
||||||
} else {
|
} else {
|
||||||
Swal.fire({
|
Swal.fire({ icon: 'error', title: 'Error', text: data.message });
|
||||||
icon: 'error',
|
|
||||||
title: 'Error',
|
|
||||||
text: data.message
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
Swal.fire({
|
Swal.fire({ icon: 'error', title: 'Error', text: 'Ocurrió un error al procesar la solicitud' });
|
||||||
icon: 'error',
|
|
||||||
title: 'Error',
|
|
||||||
text: 'Ocurrió un error al procesar la solicitud'
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
submitBtn.innerHTML = originalText;
|
submitBtn.innerHTML = originalText;
|
||||||
@@ -289,38 +312,62 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
Swal.fire({
|
Swal.fire({ icon: 'success', title: '¡Éxito!', text: data.message, timer: 2000, showConfirmButton: false });
|
||||||
icon: 'success',
|
|
||||||
title: '¡Éxito!',
|
|
||||||
text: data.message,
|
|
||||||
timer: 2000,
|
|
||||||
showConfirmButton: false
|
|
||||||
});
|
|
||||||
this.reset();
|
this.reset();
|
||||||
// Resetear el select de estados
|
// Resetear el select de estados
|
||||||
document.getElementById('estadoCiudad').innerHTML = '<option value="">Primero selecciona país</option>';
|
document.getElementById('estadoCiudad').innerHTML = '<option value="">Primero selecciona país</option>';
|
||||||
document.getElementById('estadoCiudad').disabled = true;
|
document.getElementById('estadoCiudad').disabled = true;
|
||||||
} else {
|
} else {
|
||||||
Swal.fire({
|
Swal.fire({ icon: 'error', title: 'Error', text: data.message });
|
||||||
icon: 'error',
|
|
||||||
title: 'Error',
|
|
||||||
text: data.message
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
Swal.fire({
|
Swal.fire({ icon: 'error', title: 'Error', text: 'Ocurrió un error al procesar la solicitud' });
|
||||||
icon: 'error',
|
|
||||||
title: 'Error',
|
|
||||||
text: 'Ocurrió un error al procesar la solicitud'
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
submitBtn.innerHTML = originalText;
|
submitBtn.innerHTML = originalText;
|
||||||
submitBtn.disabled = false;
|
submitBtn.disabled = false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Script para manejar las animaciones de validación
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const inputs = document.querySelectorAll('input.form-control');
|
||||||
|
|
||||||
|
inputs.forEach(input => {
|
||||||
|
// Validación en tiempo real
|
||||||
|
input.addEventListener('input', function() {
|
||||||
|
if (this.checkValidity()) {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
this.classList.add('valid');
|
||||||
|
} else {
|
||||||
|
this.classList.remove('valid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Efecto shake en campos inválidos
|
||||||
|
input.addEventListener('invalid', function() {
|
||||||
|
this.classList.add('shake');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Validación del formulario
|
||||||
|
document.getElementById('formAltaPatente').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let isValid = true;
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
if ($esDashboard): ?>
|
if ($esDashboard): ?>
|
||||||
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?>
|
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm">Cerrar Sesión</a>
|
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm ms-2 W-auto btn-animated">Cerrar Sesión</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
if ($esDashboard): ?>
|
if ($esDashboard): ?>
|
||||||
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?>
|
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm">Cerrar Sesión</a>
|
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm ms-2 W-auto btn-animated">Cerrar Sesión</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
if ($esDashboard): ?>
|
if ($esDashboard): ?>
|
||||||
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?>
|
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm">Cerrar Sesión</a>
|
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm ms-2 W-auto btn-animated">Cerrar Sesión</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ function obtenerUrlPermiso($permiso) {
|
|||||||
default => '/IMPORTADORES/importadores/dashboard'
|
default => '/IMPORTADORES/importadores/dashboard'
|
||||||
};
|
};
|
||||||
?>
|
?>
|
||||||
<a href="<?= $urlRegreso ?>" class="btn btn-outline-light btn-sm" style="margin: 0 0 0 25px;">
|
<a href="<?= $urlRegreso ?>" class="btn btn-outline-light btn-sm ms-2 W-auto btn-animated" style="margin: 0 0 0 25px;">
|
||||||
← Panel Principal
|
← Panel Principal
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
if ($esDashboard): ?>
|
if ($esDashboard): ?>
|
||||||
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?>
|
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm">Cerrar Sesión</a>
|
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm ms-2 W-auto btn-animated">Cerrar Sesión</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -89,6 +89,51 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
.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; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
|
.form-control:not(.no-animation):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); }
|
||||||
|
.form-control:not(.no-animation):not(:placeholder-shown) { /*border-color: #198754; background-color: #f8fff9;*/ }
|
||||||
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
25% { transform: translateX(-5px); }
|
||||||
|
75% { transform: translateX(5px); }
|
||||||
|
}
|
||||||
|
/* Floating labels para inputs texto */
|
||||||
|
.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; }
|
||||||
|
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
@keyframes inputPulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-gradient:not(.no-animation)::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:not(.no-animation):focus::before { left: 100%; }
|
||||||
|
.form-control.valid:not(.no-animation) { /*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); }
|
||||||
|
}
|
||||||
|
/* Animación para los campos del formulario */
|
||||||
|
.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; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -119,67 +164,67 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
<!-- Pestaña General -->
|
<!-- Pestaña General -->
|
||||||
<div class="tab-pane fade show active" id="general" role="tabpanel" aria-labelledby="general-tab">
|
<div class="tab-pane fade show active" id="general" role="tabpanel" aria-labelledby="general-tab">
|
||||||
<p style="font-weight: bold;">Datos de la Patente / Aduana</p>
|
<p style="font-weight: bold;">Datos de la Patente / Aduana</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="aduana" class="col-md-2 col-form-label">Aduana</label>
|
<label for="aduana" class="col-md-2 col-form-label">Aduana</label>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3 form-group-animated">
|
||||||
<input name="aduana" id="aduana" type="text" maxlength="3" class="form-control" required>
|
<input name="aduana" id="aduana" type="text" maxlength="3" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<label for="aduana" class="col-md-2 col-form-label">[ Sin Sección ]</label>
|
<label for="aduana" class="col-md-2 col-form-label">[ Sin Sección ]</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="patente" class="col-md-2 col-form-label">Patente</label>
|
<label for="patente" class="col-md-2 col-form-label">Patente</label>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3 form-group-animated">
|
||||||
<input name="patente" id="patente" type="text" maxlength="4" class="form-control" required>
|
<input name="patente" id="patente" type="text" maxlength="4" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="agente_aduanal" class="col-md-2 col-form-label">Agente Aduanal</label>
|
<label for="agente_aduanal" class="col-md-2 col-form-label">Agente Aduanal</label>
|
||||||
<div class="col-md-10">
|
<div class="col-md-10 form-group-animated">
|
||||||
<input name="agente_aduanal" id="agente_aduanal" type="text" class="form-control" required>
|
<input name="agente_aduanal" id="agente_aduanal" type="text" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="rfc" class="col-md-2 col-form-label">RFC</label>
|
<label for="rfc" class="col-md-2 col-form-label">RFC</label>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6 form-group-animated">
|
||||||
<input name="rfc" id="rfc" type="text" maxlength="13" class="form-control" required>
|
<input name="rfc" id="rfc" type="text" maxlength="13" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="curp" class="col-md-2 col-form-label">CURP</label>
|
<label for="curp" class="col-md-2 col-form-label">CURP</label>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6 form-group-animated">
|
||||||
<input name="curp" id="curp" type="text" maxlength="18" class="form-control" required>
|
<input name="curp" id="curp" type="text" maxlength="18" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="razon_social" class="col-md-2 col-form-label">Razón Social</label>
|
<label for="razon_social" class="col-md-2 col-form-label">Razón Social</label>
|
||||||
<div class="col-md-10">
|
<div class="col-md-10 form-group-animated">
|
||||||
<input name="razon_social" id="razon_social" type="text" class="form-control" required>
|
<input name="razon_social" id="razon_social" type="text" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
</div><hr>
|
</div><hr>
|
||||||
|
|
||||||
<div class="col mb-3">
|
<div class="col mb-3 form-group-animated">
|
||||||
<P>Capturar para el llenado de la Manifestación de Valor</P>
|
<P>Capturar para el llenado de la Manifestación de Valor</P>
|
||||||
<p style="font-weight: bold;">Datos del Agente Aduanal:</p>
|
<p style="font-weight: bold;">Datos del Agente Aduanal:</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="mf_nombre" class="col-md-2 col-form-label">Nombre(s)</label>
|
<label for="mf_nombre" class="col-md-2 col-form-label">Nombre(s)</label>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<input name="mf_nombre" id="mf_nombre" type="text" class="form-control">
|
<input name="mf_nombre" id="mf_nombre" type="text" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="mf_paterno" class="col-md-2 col-form-label">Apellido Paterno</label>
|
<label for="mf_paterno" class="col-md-2 col-form-label">Apellido Paterno</label>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9 form-group-animated">
|
||||||
<input name="mf_paterno" id="mf_paterno" type="text" class="form-control">
|
<input name="mf_paterno" id="mf_paterno" type="text" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="mf_materno" class="col-md-2 col-form-label">Apellido Materno</label>
|
<label for="mf_materno" class="col-md-2 col-form-label">Apellido Materno</label>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9 form-group-animated">
|
||||||
<input name="mf_materno" id="mf_materno" type="text" class="form-control">
|
<input name="mf_materno" id="mf_materno" type="text" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -191,107 +236,107 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
<p style="font-weight: bold;">Números de Validación y Folios</p>
|
<p style="font-weight: bold;">Números de Validación y Folios</p>
|
||||||
<!-- Pedimentos -->
|
<!-- Pedimentos -->
|
||||||
<p>Números de Validación para Pedimentos</p>
|
<p>Números de Validación para Pedimentos</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vp_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
<label for="vp_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vp_inicio" id="vp_inicio" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vp_inicio" id="vp_inicio" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vp_final" class="col-md-1 col-form-label">Final:</label>
|
<label for="vp_final" class="col-md-1 col-form-label">Final:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vp_final" id="vp_final" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vp_final" id="vp_final" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vp_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
<label for="vp_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vp_siguiente" id="vp_siguiente" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vp_siguiente" id="vp_siguiente" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
</div><hr>
|
</div><hr>
|
||||||
|
|
||||||
<!-- Pago Electrónico -->
|
<!-- Pago Electrónico -->
|
||||||
<p>Números de Validación para Pago Electrónico</p>
|
<p>Números de Validación para Pago Electrónico</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vpe_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
<label for="vpe_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vpe_inicio" id="vpe_inicio" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vpe_inicio" id="vpe_inicio" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vpe_final" class="col-md-1 col-form-label">Final:</label>
|
<label for="vpe_final" class="col-md-1 col-form-label">Final:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vpe_final" id="vpe_final" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vpe_final" id="vpe_final" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vpe_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
<label for="vpe_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vpe_siguiente" id="vpe_siguiente" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vpe_siguiente" id="vpe_siguiente" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
</div><hr>
|
</div><hr>
|
||||||
|
|
||||||
<!-- Avisos Traslado / Plantas-Bodegas -->
|
<!-- Avisos Traslado / Plantas-Bodegas -->
|
||||||
<p>Números de Validación para Avisos Traslado / Plantas-Bodegas</p>
|
<p>Números de Validación para Avisos Traslado / Plantas-Bodegas</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vat_pb_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
<label for="vat_pb_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vat_pb_inicio" id="vat_pb_inicio" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vat_pb_inicio" id="vat_pb_inicio" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vat_pb_final" class="col-md-1 col-form-label">Final:</label>
|
<label for="vat_pb_final" class="col-md-1 col-form-label">Final:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vat_pb_final" id="vat_pb_final" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vat_pb_final" id="vat_pb_final" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vat_pb_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
<label for="vat_pb_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vat_pb_siguiente" id="vat_pb_siguiente" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vat_pb_siguiente" id="vat_pb_siguiente" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
</div><hr>
|
</div><hr>
|
||||||
|
|
||||||
<!-- Validación y Folio de Cartas Cupo -->
|
<!-- Validación y Folio de Cartas Cupo -->
|
||||||
<p>Números de Validación para Cartas Cupo</p>
|
<p>Números de Validación para Cartas Cupo</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vcc_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
<label for="vcc_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vcc_inicio" id="vcc_inicio" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vcc_inicio" id="vcc_inicio" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vcc_final" class="col-md-1 col-form-label">Final:</label>
|
<label for="vcc_final" class="col-md-1 col-form-label">Final:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vcc_final" id="vcc_final" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vcc_final" id="vcc_final" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vcc_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
<label for="vcc_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vcc_siguiente" id="vcc_siguiente" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vcc_siguiente" id="vcc_siguiente" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
</div><hr>
|
</div><hr>
|
||||||
|
|
||||||
<!-- Avisos Electrónicos -->
|
<!-- Avisos Electrónicos -->
|
||||||
<p>Números de Validación para Avisos Electrónicos</p>
|
<p>Números de Validación para Avisos Electrónicos</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vae_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
<label for="vae_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vae_inicio" id="vae_inicio" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vae_inicio" id="vae_inicio" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vae_final" class="col-md-1 col-form-label">Final:</label>
|
<label for="vae_final" class="col-md-1 col-form-label">Final:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vae_final" id="vae_final" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vae_final" id="vae_final" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vae_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
<label for="vae_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vae_siguiente" id="vae_siguiente" type="text" maxlength="3" class="form-control" value="000">
|
<input name="vae_siguiente" id="vae_siguiente" type="text" maxlength="3" class="form-control" value="000">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="display: flex; justify-content: right;">
|
<div class="text-end mt-4 form-group-animated">
|
||||||
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Registrar</button>
|
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Registrar</button>
|
||||||
<a href="/IMPORTADORES/patente/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
<a href="/IMPORTADORES/patente/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -421,6 +466,43 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
// SI TODAS LAS VALIDACIONES PASAN, ENVIAR EL FORMULARIO
|
// SI TODAS LAS VALIDACIONES PASAN, ENVIAR EL FORMULARIO
|
||||||
this.submit();
|
this.submit();
|
||||||
});
|
});
|
||||||
|
// Script para manejar las animaciones de validación
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const inputs = document.querySelectorAll('input.form-control');
|
||||||
|
|
||||||
|
inputs.forEach(input => {
|
||||||
|
// Validación en tiempo real
|
||||||
|
input.addEventListener('input', function() {
|
||||||
|
if (this.checkValidity()) {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
this.classList.add('valid');
|
||||||
|
} else {
|
||||||
|
this.classList.remove('valid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Efecto shake en campos inválidos
|
||||||
|
input.addEventListener('invalid', function() {
|
||||||
|
this.classList.add('shake');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Validación del formulario
|
||||||
|
document.getElementById('formAltaPatente').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let isValid = true;
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -86,6 +86,51 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
.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; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
|
.form-control:not(.no-animation):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); }
|
||||||
|
.form-control:not(.no-animation):not(:placeholder-shown) { /*border-color: #198754; background-color: #f8fff9;*/ }
|
||||||
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
25% { transform: translateX(-5px); }
|
||||||
|
75% { transform: translateX(5px); }
|
||||||
|
}
|
||||||
|
/* Floating labels para inputs texto */
|
||||||
|
.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; }
|
||||||
|
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
@keyframes inputPulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-gradient:not(.no-animation)::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:not(.no-animation):focus::before { left: 100%; }
|
||||||
|
.form-control.valid:not(.no-animation) { /*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); }
|
||||||
|
}
|
||||||
|
/* Animación para los campos del formulario */
|
||||||
|
.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; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -118,75 +163,75 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
<!-- Pestaña General -->
|
<!-- Pestaña General -->
|
||||||
<div class="tab-pane fade show active" id="general" role="tabpanel" aria-labelledby="general-tab">
|
<div class="tab-pane fade show active" id="general" role="tabpanel" aria-labelledby="general-tab">
|
||||||
<p style="font-weight: bold;">Datos de la Patente / Aduana</p>
|
<p style="font-weight: bold;">Datos de la Patente / Aduana</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="aduana" class="col-md-2 col-form-label">Aduana</label>
|
<label for="aduana" class="col-md-2 col-form-label">Aduana</label>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3 form-group-animated">
|
||||||
<input name="aduana" id="aduana" type="text" maxlength="3" class="form-control"
|
<input name="aduana" id="aduana" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars($agente['aduana'] ?? '') ?>" required>
|
value="<?= htmlspecialchars($agente['aduana'] ?? '') ?>" required>
|
||||||
</div>
|
</div>
|
||||||
<label for="aduana" class="col-md-2 col-form-label">[Sin Sección]</label>
|
<label for="aduana" class="col-md-2 col-form-label">[Sin Sección]</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="patente" class="col-md-2 col-form-label">Patente</label>
|
<label for="patente" class="col-md-2 col-form-label">Patente</label>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3 form-group-animated">
|
||||||
<input name="patente" id="patente" type="text" maxlength="4" class="form-control"
|
<input name="patente" id="patente" type="text" maxlength="4" class="form-control"
|
||||||
value="<?= htmlspecialchars($agente['patente'] ?? '') ?>" required>
|
value="<?= htmlspecialchars($agente['patente'] ?? '') ?>" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="agente_aduanal" class="col-md-2 col-form-label">Agente Aduanal</label>
|
<label for="agente_aduanal" class="col-md-2 col-form-label">Agente Aduanal</label>
|
||||||
<div class="col-md-10">
|
<div class="col-md-10 form-group-animated">
|
||||||
<input name="agente_aduanal" id="agente_aduanal" type="text" class="form-control"
|
<input name="agente_aduanal" id="agente_aduanal" type="text" class="form-control"
|
||||||
value="<?= htmlspecialchars($agente['agente_aduanal'] ?? '') ?>" required>
|
value="<?= htmlspecialchars($agente['agente_aduanal'] ?? '') ?>" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="rfc" class="col-md-2 col-form-label">RFC</label>
|
<label for="rfc" class="col-md-2 col-form-label">RFC</label>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6 form-group-animated">
|
||||||
<input name="rfc" id="rfc" type="text" maxlength="13" class="form-control"
|
<input name="rfc" id="rfc" type="text" maxlength="13" class="form-control"
|
||||||
value="<?= htmlspecialchars($agente['rfc'] ?? '') ?>" required>
|
value="<?= htmlspecialchars($agente['rfc'] ?? '') ?>" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="curp" class="col-md-2 col-form-label">CURP</label>
|
<label for="curp" class="col-md-2 col-form-label">CURP</label>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6 form-group-animated">
|
||||||
<input name="curp" id="curp" type="text" maxlength="18" class="form-control"
|
<input name="curp" id="curp" type="text" maxlength="18" class="form-control"
|
||||||
value="<?= htmlspecialchars($agente['curp'] ?? '') ?>" required>
|
value="<?= htmlspecialchars($agente['curp'] ?? '') ?>" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="razon_social" class="col-md-2 col-form-label">Razón Social</label>
|
<label for="razon_social" class="col-md-2 col-form-label">Razón Social</label>
|
||||||
<div class="col-md-10">
|
<div class="col-md-10 form-group-animated">
|
||||||
<input name="razon_social" id="razon_social" type="text" class="form-control"
|
<input name="razon_social" id="razon_social" type="text" class="form-control"
|
||||||
value="<?= htmlspecialchars($agente['razon_social'] ?? '') ?>" required>
|
value="<?= htmlspecialchars($agente['razon_social'] ?? '') ?>" required>
|
||||||
</div>
|
</div>
|
||||||
</div><hr>
|
</div><hr>
|
||||||
|
|
||||||
<div class="col mb-3">
|
<div class="col mb-3 form-group-animated">
|
||||||
<P>Capturar para el llenado de la Manifestación de Valor</P>
|
<P>Capturar para el llenado de la Manifestación de Valor</P>
|
||||||
<p style="font-weight: bold;">Datos del Agente Aduanal:</p>
|
<p style="font-weight: bold;">Datos del Agente Aduanal:</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="mf_nombre" class="col-md-2 col-form-label">Nombre(s)</label>
|
<label for="mf_nombre" class="col-md-2 col-form-label">Nombre(s)</label>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9 form-group-animated">
|
||||||
<input name="mf_nombre" id="mf_nombre" type="text" class="form-control"
|
<input name="mf_nombre" id="mf_nombre" type="text" class="form-control"
|
||||||
value="<?= htmlspecialchars($agente['mf_nombre'] ?? '') ?>">
|
value="<?= htmlspecialchars($agente['mf_nombre'] ?? '') ?>">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="mf_paterno" class="col-md-2 col-form-label">Apellido Paterno</label>
|
<label for="mf_paterno" class="col-md-2 col-form-label">Apellido Paterno</label>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9 form-group-animated">
|
||||||
<input name="mf_paterno" id="mf_paterno" type="text" class="form-control"
|
<input name="mf_paterno" id="mf_paterno" type="text" class="form-control"
|
||||||
value="<?= htmlspecialchars($agente['mf_paterno'] ?? '') ?>">
|
value="<?= htmlspecialchars($agente['mf_paterno'] ?? '') ?>">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<label for="mf_materno" class="col-md-2 col-form-label">Apellido Materno</label>
|
<label for="mf_materno" class="col-md-2 col-form-label">Apellido Materno</label>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9 form-group-animated">
|
||||||
<input name="mf_materno" id="mf_materno" type="text" class="form-control"
|
<input name="mf_materno" id="mf_materno" type="text" class="form-control"
|
||||||
value="<?= htmlspecialchars($agente['mf_materno'] ?? '') ?>">
|
value="<?= htmlspecialchars($agente['mf_materno'] ?? '') ?>">
|
||||||
</div>
|
</div>
|
||||||
@@ -199,22 +244,22 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
<p style="font-weight: bold;">Números de Validación y Folios</p>
|
<p style="font-weight: bold;">Números de Validación y Folios</p>
|
||||||
<!-- Pedimentos -->
|
<!-- Pedimentos -->
|
||||||
<p>Números de Validación para Pedimentos</p>
|
<p>Números de Validación para Pedimentos</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vp_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
<label for="vp_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vp_inicio" id="vp_inicio" type="text" maxlength="3" class="form-control"
|
<input name="vp_inicio" id="vp_inicio" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vp_inicio'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vp_inicio'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vp_final" class="col-md-1 col-form-label">Final:</label>
|
<label for="vp_final" class="col-md-1 col-form-label">Final:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vp_final" id="vp_final" type="text" maxlength="3" class="form-control"
|
<input name="vp_final" id="vp_final" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vp_final'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vp_final'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vp_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
<label for="vp_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vp_siguiente" id="vp_siguiente" type="text" maxlength="3" class="form-control"
|
<input name="vp_siguiente" id="vp_siguiente" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vp_siguiente'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vp_siguiente'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
@@ -222,22 +267,22 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
|
|
||||||
<!-- Pago Electrónico -->
|
<!-- Pago Electrónico -->
|
||||||
<p>Números de Validación para Pago Electrónico</p>
|
<p>Números de Validación para Pago Electrónico</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vpe_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
<label for="vpe_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vpe_inicio" id="vpe_inicio" type="text" maxlength="3" class="form-control"
|
<input name="vpe_inicio" id="vpe_inicio" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vpe_inicio'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vpe_inicio'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vpe_final" class="col-md-1 col-form-label">Final:</label>
|
<label for="vpe_final" class="col-md-1 col-form-label">Final:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vpe_final" id="vpe_final" type="text" maxlength="3" class="form-control"
|
<input name="vpe_final" id="vpe_final" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vpe_final'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vpe_final'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vpe_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
<label for="vpe_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vpe_siguiente" id="vpe_siguiente" type="text" maxlength="3" class="form-control"
|
<input name="vpe_siguiente" id="vpe_siguiente" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vpe_siguiente'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vpe_siguiente'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
@@ -245,22 +290,22 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
|
|
||||||
<!-- Avisos Traslado / Plantas-Bodegas -->
|
<!-- Avisos Traslado / Plantas-Bodegas -->
|
||||||
<p>Números de Validación para Avisos Traslado / Plantas-Bodegas</p>
|
<p>Números de Validación para Avisos Traslado / Plantas-Bodegas</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vat_pb_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
<label for="vat_pb_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vat_pb_inicio" id="vat_pb_inicio" type="text" maxlength="3" class="form-control"
|
<input name="vat_pb_inicio" id="vat_pb_inicio" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vat_pb_inicio'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vat_pb_inicio'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vat_pb_final" class="col-md-1 col-form-label">Final:</label>
|
<label for="vat_pb_final" class="col-md-1 col-form-label">Final:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vat_pb_final" id="vat_pb_final" type="text" maxlength="3" class="form-control"
|
<input name="vat_pb_final" id="vat_pb_final" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vat_pb_final'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vat_pb_final'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vat_pb_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
<label for="vat_pb_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vat_pb_siguiente" id="vat_pb_siguiente" type="text" maxlength="3" class="form-control"
|
<input name="vat_pb_siguiente" id="vat_pb_siguiente" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vat_pb_siguiente'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vat_pb_siguiente'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
@@ -268,22 +313,22 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
|
|
||||||
<!-- Validación y Folio de Cartas Cupo -->
|
<!-- Validación y Folio de Cartas Cupo -->
|
||||||
<p>Números de Validación para Cartas Cupo</p>
|
<p>Números de Validación para Cartas Cupo</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vcc_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
<label for="vcc_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vcc_inicio" id="vcc_inicio" type="text" maxlength="3" class="form-control"
|
<input name="vcc_inicio" id="vcc_inicio" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vcc_inicio'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vcc_inicio'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vcc_final" class="col-md-1 col-form-label">Final:</label>
|
<label for="vcc_final" class="col-md-1 col-form-label">Final:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vcc_final" id="vcc_final" type="text" maxlength="3" class="form-control"
|
<input name="vcc_final" id="vcc_final" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vcc_final'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vcc_final'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vcc_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
<label for="vcc_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vcc_siguiente" id="vcc_siguiente" type="text" maxlength="3" class="form-control"
|
<input name="vcc_siguiente" id="vcc_siguiente" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vcc_siguiente'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vcc_siguiente'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
@@ -291,22 +336,22 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
|
|
||||||
<!-- Avisos Electrónicos -->
|
<!-- Avisos Electrónicos -->
|
||||||
<p>Números de Validación para Avisos Electrónicos</p>
|
<p>Números de Validación para Avisos Electrónicos</p>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3 form-group-animated">
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vae_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
<label for="vae_inicio" class="col-md-1 col-form-label">Inicio:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vae_inicio" id="vae_inicio" type="text" maxlength="3" class="form-control"
|
<input name="vae_inicio" id="vae_inicio" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vae_inicio'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vae_inicio'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vae_final" class="col-md-1 col-form-label">Final:</label>
|
<label for="vae_final" class="col-md-1 col-form-label">Final:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vae_final" id="vae_final" type="text" maxlength="3" class="form-control"
|
<input name="vae_final" id="vae_final" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vae_final'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vae_final'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<label for="vae_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
<label for="vae_siguiente" class="col-md-1 col-form-label">Siguiente:</label>
|
||||||
<div class="col-md-1">
|
<div class="col-md-1 form-group-animated">
|
||||||
<input name="vae_siguiente" id="vae_siguiente" type="text" maxlength="3" class="form-control"
|
<input name="vae_siguiente" id="vae_siguiente" type="text" maxlength="3" class="form-control"
|
||||||
value="<?= htmlspecialchars(sprintf('%03d', $agente['vae_siguiente'] ?? '')) ?>">
|
value="<?= htmlspecialchars(sprintf('%03d', $agente['vae_siguiente'] ?? '')) ?>">
|
||||||
</div>
|
</div>
|
||||||
@@ -314,7 +359,7 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="display: flex; justify-content: right;">
|
<div class="text-end mt-4 form-group-animated">
|
||||||
<button type="submit" class="btn btn-success">💾 Guardar</button>
|
<button type="submit" class="btn btn-success">💾 Guardar</button>
|
||||||
<a href="/IMPORTADORES/patente/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
<a href="/IMPORTADORES/patente/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -110,8 +110,8 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
<td><?= htmlspecialchars($aa['curp']) ?></td>
|
<td><?= htmlspecialchars($aa['curp']) ?></td>
|
||||||
<td><?= htmlspecialchars($aa['razon_social']) ?></td>
|
<td><?= htmlspecialchars($aa['razon_social']) ?></td>
|
||||||
<td>
|
<td>
|
||||||
<a href="/IMPORTADORES/patente/editar?id=<?= $aa['id_agente'] ?>" class="btn btn-sm btn-primary">✏️</a>
|
<a href="/IMPORTADORES/patente/editar?id=<?= $aa['id_agente'] ?>" class="btn btn-sm btn-primary mt-auto w-auto btn-animated">✏️</a>
|
||||||
<button class="btn btn-sm btn-danger" onclick="confirmDeleteChofer(<?= $aa['id_agente'] ?>)">🗑️</button>
|
<button class="btn btn-sm btn-danger mt-auto w-auto btn-animated" onclick="confirmDeleteChofer(<?= $aa['id_agente'] ?>)">🗑️</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
@@ -147,13 +147,13 @@ if ($tipoUsuario === 'agente_aduanal') {
|
|||||||
});
|
});
|
||||||
|
|
||||||
<?php if(isset($_GET['deleted'])): ?>
|
<?php if(isset($_GET['deleted'])): ?>
|
||||||
Swal.fire('¡Hecho!','Agente eliminado.','success');
|
Swal.fire('¡Hecho!','Patente eliminada.','success');
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if(isset($_GET['created'])): ?>
|
<?php if(isset($_GET['created'])): ?>
|
||||||
Swal.fire('¡Listo!','Agente creado.','success');
|
Swal.fire('¡Listo!','Patente creado.','success');
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if(isset($_GET['updated'])): ?>
|
<?php if(isset($_GET['updated'])): ?>
|
||||||
Swal.fire('¡Listo!','Agente actualizado.','success');
|
Swal.fire('¡Listo!','Patente actualizada.','success');
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -28,8 +28,11 @@
|
|||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<!-- Choices.js CSS -->
|
<!-- Choices.js CSS -->
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"/>
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"/>
|
||||||
<!-- SweetAlert2 -->
|
<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>
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||||
|
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||||||
<!-- Font Awesome -->
|
<!-- Font Awesome -->
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
<!-- Animate.css para animaciones adicionales -->
|
<!-- Animate.css para animaciones adicionales -->
|
||||||
@@ -67,6 +70,51 @@
|
|||||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
.form-label { font-weight: 500; }
|
.form-label { font-weight: 500; }
|
||||||
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
|
.form-control:not(.no-animation):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); }
|
||||||
|
.form-control:not(.no-animation):not(:placeholder-shown) { /*border-color: #198754; background-color: #f8fff9;*/ }
|
||||||
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
25% { transform: translateX(-5px); }
|
||||||
|
75% { transform: translateX(5px); }
|
||||||
|
}
|
||||||
|
/* Floating labels para inputs texto */
|
||||||
|
.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; }
|
||||||
|
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
@keyframes inputPulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-gradient:not(.no-animation)::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:not(.no-animation):focus::before { left: 100%; }
|
||||||
|
.form-control.valid:not(.no-animation) { /*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); }
|
||||||
|
}
|
||||||
|
/* Animación para los campos del formulario */
|
||||||
|
.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; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -87,23 +135,23 @@
|
|||||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">➕ Alta de Producto Frecuente</h4>
|
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">➕ Alta de Producto Frecuente</h4>
|
||||||
<div class="card p-4 shadow-sm bg-white card-hover position-relative h-auto">
|
<div class="card p-4 shadow-sm bg-white card-hover position-relative h-auto">
|
||||||
<form id="altaProductoFrecuenteForm" action="/IMPORTADORES/productos_frecuentes/guardar" method="POST">
|
<form id="altaProductoFrecuenteForm" action="/IMPORTADORES/productos_frecuentes/guardar" method="POST">
|
||||||
<div class="row g-3">
|
<div class="row g-3 form-group-animated">
|
||||||
<!-- Sinónimo, Fracción, NICO -->
|
<!-- Sinónimo, Fracción, NICO -->
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="sinonimo" class="form-label">Sinónimo *</label>
|
<label for="sinonimo" class="form-label">Sinónimo *</label>
|
||||||
<input type="text" id="sinonimo" name="sinonimo" class="form-control" required>
|
<input type="text" id="sinonimo" name="sinonimo" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="fraccion" class="form-label">Fracción *</label>
|
<label for="fraccion" class="form-label">Fracción *</label>
|
||||||
<input type="text" id="fraccion" name="fraccion" class="form-control" required>
|
<input type="text" id="fraccion" name="fraccion" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="nico" class="form-label">NICO *</label>
|
<label for="nico" class="form-label">NICO *</label>
|
||||||
<input type="text" id="nico" name="nico" class="form-control" required>
|
<input type="text" id="nico" name="nico" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Número de Parte / Proveedor -->
|
<!-- Número de Parte / Proveedor -->
|
||||||
<div class="col-md-6">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="numero_parte" class="form-label">Número de Parte</label>
|
<label for="numero_parte" class="form-label">Número de Parte</label>
|
||||||
<input type="text" id="numero_parte" name="numero_parte" class="form-control">
|
<input type="text" id="numero_parte" name="numero_parte" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
@@ -115,7 +163,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Descripción -->
|
<!-- Descripción -->
|
||||||
<div class="col-12">
|
<div class="col-12 form-group-animated">
|
||||||
<label for="descripcion" class="form-label">Descripción</label>
|
<label for="descripcion" class="form-label">Descripción</label>
|
||||||
<textarea id="descripcion" name="descripcion" class="form-control" rows="2"></textarea>
|
<textarea id="descripcion" name="descripcion" class="form-control" rows="2"></textarea>
|
||||||
</div>
|
</div>
|
||||||
@@ -135,7 +183,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<!-- Uso de la Mercancía -->
|
<!-- Uso de la Mercancía -->
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="uso_mercancia" class="form-label">Uso de la Mercancía</label>
|
<label for="uso_mercancia" class="form-label">Uso de la Mercancía</label>
|
||||||
<input type="text" id="uso_mercancia" name="uso_mercancia" class="form-control">
|
<input type="text" id="uso_mercancia" name="uso_mercancia" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
@@ -182,21 +230,20 @@
|
|||||||
<option value="<?= $val ?>"><?= htmlspecialchars($lab) ?></option>
|
<option value="<?= $val ?>"><?= htmlspecialchars($lab) ?></option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="tipo_mercancia" class="form-label">Tipo de Mercancía</label>
|
<label for="tipo_mercancia" class="form-label">Tipo de Mercancía</label>
|
||||||
<input type="text" id="tipo_mercancia" name="tipo_mercancia" class="form-control">
|
<input type="text" id="tipo_mercancia" name="tipo_mercancia" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Checkboxes -->
|
<!-- Checkboxes -->
|
||||||
<div class="col-md-3">
|
<div class="col-md-3 form-group-animated">
|
||||||
<div class="form-check mt-2">
|
<div class="form-check mt-2">
|
||||||
<input class="form-check-input" type="checkbox" id="certificado_origen" name="certificado_origen" value="1">
|
<input class="form-check-input" type="checkbox" id="certificado_origen" name="certificado_origen" value="1">
|
||||||
<label class="form-check-label" for="certificado_origen">Certificado de Origen</label>
|
<label class="form-check-label" for="certificado_origen">Certificado de Origen</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3 form-group-animated">
|
||||||
<div class="form-check mt-2">
|
<div class="form-check mt-2">
|
||||||
<input class="form-check-input" type="checkbox" id="documento_en_original" name="documento_en_original" value="1">
|
<input class="form-check-input" type="checkbox" id="documento_en_original" name="documento_en_original" value="1">
|
||||||
<label class="form-check-label" for="documento_en_original">Documento en Original</label>
|
<label class="form-check-label" for="documento_en_original">Documento en Original</label>
|
||||||
@@ -209,7 +256,7 @@
|
|||||||
<input type="hidden" name="frecuencia_uso" value="1">
|
<input type="hidden" name="frecuencia_uso" value="1">
|
||||||
|
|
||||||
<!-- Botones -->
|
<!-- Botones -->
|
||||||
<div class="col-12 text-end mt-4">
|
<div class="col-12 text-end mt-4 form-group-animated">
|
||||||
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Guardar Producto</button>
|
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Guardar Producto</button>
|
||||||
<a href="/IMPORTADORES/productos_frecuentes" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
<a href="/IMPORTADORES/productos_frecuentes" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -218,10 +265,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- JS -->
|
<!-- Choices.js JS -->
|
||||||
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0/dist/js/select2.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
function fetchJsonOrThrow(url) {
|
function fetchJsonOrThrow(url) {
|
||||||
@@ -269,7 +318,8 @@
|
|||||||
paisData.results.forEach(item => {
|
paisData.results.forEach(item => {
|
||||||
[poSel, pcSel].forEach(sel => {
|
[poSel, pcSel].forEach(sel => {
|
||||||
const o = document.createElement('option');
|
const o = document.createElement('option');
|
||||||
o.value = item.id; o.textContent = item.text;
|
o.value = item.id;
|
||||||
|
o.textContent = item.text;
|
||||||
sel.appendChild(o);
|
sel.appendChild(o);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -284,12 +334,13 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Después de inicializar Choices.js:
|
// Después de inicializar Choices.js:
|
||||||
const prefEl = document.getElementById('preferencia');
|
const prefEl = document.getElementById('preferencia');
|
||||||
const critEl = document.getElementById('criterio_preferencia');
|
const critEl = document.getElementById('criterio_preferencia');
|
||||||
const critChoice = critEl._choices;
|
const critChoice = critEl._choices;
|
||||||
|
|
||||||
function updateCriterio() {
|
if (critChoice) {
|
||||||
|
function updateCriterio() {
|
||||||
if (prefEl.value === 'PROSEC') {
|
if (prefEl.value === 'PROSEC') {
|
||||||
critEl.disabled = false;
|
critEl.disabled = false;
|
||||||
critChoice.enable();
|
critChoice.enable();
|
||||||
@@ -298,11 +349,11 @@ function updateCriterio() {
|
|||||||
critChoice.disable();
|
critChoice.disable();
|
||||||
critEl.disabled = true;
|
critEl.disabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prefEl.addEventListener('change', updateCriterio);
|
|
||||||
updateCriterio();
|
|
||||||
|
|
||||||
|
prefEl.addEventListener('change', updateCriterio);
|
||||||
|
updateCriterio();
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
@@ -315,7 +366,67 @@ updateCriterio();
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Script para manejar las animaciones de validación
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const inputs = document.querySelectorAll('input.form-control, select.form_select');
|
||||||
|
const selects = document.querySelectorAll('select.form_select');
|
||||||
|
|
||||||
|
inputs.forEach(input => {
|
||||||
|
// Validación en tiempo real
|
||||||
|
input.addEventListener('input', function() {
|
||||||
|
if (this.checkValidity()) {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
this.classList.add('valid');
|
||||||
|
} else {
|
||||||
|
this.classList.remove('valid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Efecto shake en campos inválidos
|
||||||
|
input.addEventListener('invalid', function() {
|
||||||
|
this.classList.add('shake');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configurar selects
|
||||||
|
selects.forEach(select => {
|
||||||
|
select.addEventListener('change', function() {
|
||||||
|
updateSelectState(this);
|
||||||
|
});
|
||||||
|
updateSelectState(select);
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateSelectState(select) {
|
||||||
|
select.setAttribute('value', select.value);
|
||||||
|
|
||||||
|
if (select.value && select.value !== '') {
|
||||||
|
select.classList.add('valid');
|
||||||
|
select.classList.remove('invalid');
|
||||||
|
} else {
|
||||||
|
select.classList.remove('valid');
|
||||||
|
if (select.hasAttribute('required') && select.closest('form')?.classList.contains('was-validated')) {
|
||||||
|
select.classList.add('invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validación del formulario
|
||||||
|
document.getElementById('altaProductoFrecuenteForm').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let isValid = true;
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -171,10 +171,10 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function () {
|
||||||
$('#tablaProductosFrecuentes').DataTable({
|
$('#tablaProductosFrecuentes').DataTable({
|
||||||
language: {
|
language: {
|
||||||
url: '//cdn.datatables.net/plug-ins/1.13.4/i18n/es-ES.json'
|
url: 'https://cdn.datatables.net/plug-ins/1.13.4/i18n/es-ES.json'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -51,6 +51,51 @@
|
|||||||
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
.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; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
|
.form-control:not(.no-animation):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); }
|
||||||
|
.form-control:not(.no-animation):not(:placeholder-shown) { /*border-color: #198754; background-color: #f8fff9;*/ }
|
||||||
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
25% { transform: translateX(-5px); }
|
||||||
|
75% { transform: translateX(5px); }
|
||||||
|
}
|
||||||
|
/* Floating labels para inputs texto */
|
||||||
|
.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; }
|
||||||
|
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
@keyframes inputPulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-gradient:not(.no-animation)::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:not(.no-animation):focus::before { left: 100%; }
|
||||||
|
.form-control.valid:not(.no-animation) { /*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); }
|
||||||
|
}
|
||||||
|
/* Animación para los campos del formulario */
|
||||||
|
.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; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -76,48 +121,48 @@
|
|||||||
<div class="card p-4 shadow-sm card-hover position-relative h-auto">
|
<div class="card p-4 shadow-sm card-hover position-relative h-auto">
|
||||||
<form action="/IMPORTADORES/proveedores/guardar" method="POST" enctype="multipart/form-data" id="formAltaProveedores">
|
<form action="/IMPORTADORES/proveedores/guardar" method="POST" enctype="multipart/form-data" id="formAltaProveedores">
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="Clave" class="form-label">Clave *</label>
|
<label for="Clave" class="form-label">Clave *</label>
|
||||||
<input type="text" name="Clave" id="Clave" class="form-control" maxlength="20" required>
|
<input type="text" name="Clave" id="Clave" class="form-control" maxlength="20" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8 form-group-animated">
|
||||||
<label for="Nombre" class="form-label">Nombre *</label>
|
<label for="Nombre" class="form-label">Nombre *</label>
|
||||||
<input type="text" name="Nombre" id="Nombre" class="form-control" required>
|
<input type="text" name="Nombre" id="Nombre" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="RFC" class="form-label">RFC *</label>
|
<label for="RFC" class="form-label">RFC *</label>
|
||||||
<input type="text" name="RFC" id="RFC" class="form-control" maxlength="13" required>
|
<input type="text" name="RFC" id="RFC" class="form-control" maxlength="13" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="Ciudad" class="form-label">Ciudad *</label>
|
<label for="Ciudad" class="form-label">Ciudad *</label>
|
||||||
<input type="text" name="Ciudad" id="Ciudad" class="form-control" required>
|
<input type="text" name="Ciudad" id="Ciudad" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="Telefono" class="form-label">Teléfono</label>
|
<label for="Telefono" class="form-label">Teléfono</label>
|
||||||
<input type="tel" name="Telefono" id="Telefono" maxlength="11" class="form-control">
|
<input type="tel" name="Telefono" id="Telefono" maxlength="11" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="Pais" class="form-label">País</label>
|
<label for="Pais" class="form-label">País</label>
|
||||||
<input type="text" name="Pais" id="Pais" class="form-control">
|
<input type="text" name="Pais" id="Pais" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="EntidadFederativa" class="form-label">Entidad Federativa</label>
|
<label for="EntidadFederativa" class="form-label">Entidad Federativa</label>
|
||||||
<input type="text" name="EntidadFederativa" id="EntidadFederativa" class="form-control">
|
<input type="text" name="EntidadFederativa" id="EntidadFederativa" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="Municipio" class="form-label">Municipio</label>
|
<label for="Municipio" class="form-label">Municipio</label>
|
||||||
<input type="text" name="Municipio" id="Municipio" class="form-control">
|
<input type="text" name="Municipio" id="Municipio" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="Colonia" class="form-label">Colonia</label>
|
<label for="Colonia" class="form-label">Colonia</label>
|
||||||
<input type="text" name="Colonia" id="Colonia" class="form-control">
|
<input type="text" name="Colonia" id="Colonia" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="CodigoPostal" class="form-label">Código Postal</label>
|
<label for="CodigoPostal" class="form-label">Código Postal</label>
|
||||||
<input type="text" name="CodigoPostal" id="CodigoPostal" maxlength="5" class="form-control">
|
<input type="text" name="CodigoPostal" id="CodigoPostal" maxlength="5" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4 text-end">
|
<div class="mt-4 text-end form-group-animated">
|
||||||
<a href="/IMPORTADORES/proveedores" class="btn btn-secondary me-2 mt-auto w-auto btn-animated">Cancelar</a>
|
<a href="/IMPORTADORES/proveedores" class="btn btn-secondary me-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||||||
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Guardar Proveedor</button>
|
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Guardar Proveedor</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -269,6 +314,44 @@
|
|||||||
// SI TODAS LAS VALIDACIONES PASAN, ENVIAR EL FORMULARIO
|
// SI TODAS LAS VALIDACIONES PASAN, ENVIAR EL FORMULARIO
|
||||||
this.submit();
|
this.submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Script para manejar las animaciones de validación
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const inputs = document.querySelectorAll('input.form-control');
|
||||||
|
|
||||||
|
inputs.forEach(input => {
|
||||||
|
// Validación en tiempo real
|
||||||
|
input.addEventListener('input', function() {
|
||||||
|
if (this.checkValidity()) {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
this.classList.add('valid');
|
||||||
|
} else {
|
||||||
|
this.classList.remove('valid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Efecto shake en campos inválidos
|
||||||
|
input.addEventListener('invalid', function() {
|
||||||
|
this.classList.add('shake');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Validación del formulario
|
||||||
|
document.getElementById('formAltaProveedores').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let isValid = true;
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -98,8 +98,12 @@ $dos_factores_estado = obtenerEstadoDosFactores();
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="card shadow-sm p-3">
|
<div class="card shadow-sm p-3">
|
||||||
<h4 class="mb-4 text-dark">Cambiar contraseña</h4>
|
<h4 class="mb-4 text-dark">Cambiar contraseña</h4>
|
||||||
<p>Al actualizar tu contraseña, refuerzas la seguridad de tu cuenta. Te recomendamos usar una combinación de letras, números y símbolos para mayor seguridad.</p><br><br>
|
<p class="text-muted small flex-grow-1 mb-4">Al actualizar tu contraseña, refuerzas la seguridad de tu cuenta. Te recomendamos usar una combinación de letras, números y símbolos para mayor seguridad.</p><br>
|
||||||
<a href="/IMPORTADORES/reset/changePassword" class="btn btn-primary">Cambiar contraseña</a>
|
<form>
|
||||||
|
<button type="button" class="btn btn-primary btn-sm mt-2 w-40 btn-animated" data-bs-toggle="modal" data-bs-target="#modalConfirmarCambio">
|
||||||
|
<i class="fas fa-key"></i>Cambiar contraseña
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -179,8 +179,12 @@ $dos_factores_estado = obtenerEstadoDosFactores();
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="card shadow-sm p-3">
|
<div class="card shadow-sm p-3">
|
||||||
<h4 class="mb-4 text-dark">Cambiar contraseña</h4>
|
<h4 class="mb-4 text-dark">Cambiar contraseña</h4>
|
||||||
<p>Al actualizar tu contraseña, refuerzas la seguridad de tu cuenta. Te recomendamos usar una combinación de letras, números y símbolos para mayor seguridad.</p><br><br>
|
<p class="text-muted small flex-grow-1 mb-4">Al actualizar tu contraseña, refuerzas la seguridad de tu cuenta. Te recomendamos usar una combinación de letras, números y símbolos para mayor seguridad.</p><br>
|
||||||
<a href="/IMPORTADORES/reset/changePassword" class="btn btn-primary">Cambiar contraseña</a>
|
<form>
|
||||||
|
<button type="button" class="btn btn-primary btn-sm mt-2 w-40 btn-animated" data-bs-toggle="modal" data-bs-target="#modalConfirmarCambio">
|
||||||
|
<i class="fas fa-key"></i>Cambiar contraseña
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,80 @@
|
|||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
.hide { display: none !important; }
|
.hide { display: none !important; }
|
||||||
.alert { top: 75px; left: 275px; right: 50px; position: fixed; z-index: 1050; width: calc(100% - 285px); }
|
.alert { top: 75px; left: 275px; right: 50px; position: fixed; z-index: 1050; width: calc(100% - 285px); }
|
||||||
|
.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%; }
|
||||||
|
.form-label { font-weight: 500; }
|
||||||
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
|
.form-control:not(.no-animation):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); }
|
||||||
|
.form-control:not(.no-animation):not(:placeholder-shown) { /*border-color: #198754; background-color: #f8fff9;*/ }
|
||||||
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
25% { transform: translateX(-5px); }
|
||||||
|
75% { transform: translateX(5px); }
|
||||||
|
}
|
||||||
|
/* Floating labels para inputs texto */
|
||||||
|
.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; }
|
||||||
|
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
@keyframes inputPulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-gradient:not(.no-animation)::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:not(.no-animation):focus::before { left: 100%; }
|
||||||
|
.form-control.valid:not(.no-animation) { /*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); }
|
||||||
|
}
|
||||||
|
/* Animación para los campos del formulario */
|
||||||
|
.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; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
|
/* ========== ESTILOS PARA CAMPO FOTO (SIN ANIMACIONES) ========== */
|
||||||
|
.no-animation, .no-border-style { transition: none !important; border: none; box-shadow: none !important; background: #fff !important; }
|
||||||
|
.no-animation:focus { transform: none !important; border: none; box-shadow: none !important; }
|
||||||
|
.no-animation:hover { animation: none !important; }
|
||||||
|
.no-animation::before, .no-animation::after { display: none !important; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -84,11 +158,11 @@
|
|||||||
|
|
||||||
<!-- Sección principal -->
|
<!-- Sección principal -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3 mb-3">
|
<div class="col-md-3 mb-3 form-group-animated">
|
||||||
<label for="numero_factura" class="form-label">Número de Factura</label>
|
<label for="numero_factura" class="form-label">Número de Factura</label>
|
||||||
<input id="numero_factura" name="numero_factura" type="text" class="form-control" required>
|
<input id="numero_factura" name="numero_factura" type="text" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3 mb-3">
|
<div class="col-md-3 mb-3 form-group-animated">
|
||||||
<label for="fecha_factura" class="form-label">Fecha de Factura</label>
|
<label for="fecha_factura" class="form-label">Fecha de Factura</label>
|
||||||
<input id="fecha_factura" name="fecha_factura" type="date" class="form-control" required>
|
<input id="fecha_factura" name="fecha_factura" type="date" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
@@ -156,7 +230,7 @@
|
|||||||
|
|
||||||
<!-- Valor y vinculación -->
|
<!-- Valor y vinculación -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-8 mb-3">
|
<div class="col-md-8 mb-3 form-group-animated">
|
||||||
<label for="valor_factura" class="form-label">Valor Factura</label>
|
<label for="valor_factura" class="form-label">Valor Factura</label>
|
||||||
<input id="valor_factura" name="valor_factura" type="number" step="0.01" min="0" class="form-control" required>
|
<input id="valor_factura" name="valor_factura" type="number" step="0.01" min="0" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
@@ -194,9 +268,9 @@
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 mb-3">
|
<div class="col-md-4 mb-3 form-group-animated">
|
||||||
<label for="foto_solicitud" class="form-label">Foto de la Carga (PIPA)</label>
|
<label for="foto_solicitud" class="form-label">Foto de la Carga (PIPA)</label>
|
||||||
<input id="foto_solicitud" name="foto_solicitud" type="file" class="form-control" accept="image/*">
|
<input id="foto_solicitud" name="foto_solicitud" type="file" class="form-control no-animation no-border-style" accept="image/*">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -221,9 +295,9 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><input name="partidas[0][descripcion]" class="form-control w-auto" required></td>
|
<td><input name="partidas[0][descripcion]" class="form-control w-auto form-group-animated" required></td>
|
||||||
<td><input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control w-auto" min="0" required></td>
|
<td><input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control w-auto form-group-animated" min="0" required></td>
|
||||||
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control w-auto" min="0" required></td>
|
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control w-auto form-group-animated" min="0" required></td>
|
||||||
<td>
|
<td>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable" required>
|
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable" required>
|
||||||
@@ -234,8 +308,8 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida w-auto" min="0" required></td>
|
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida w-auto form-group-animated" min="0" required></td>
|
||||||
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control w-auto" min="0" required></td>
|
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control w-auto form-group-animated" min="0" required></td>
|
||||||
<td>
|
<td>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<select name="partidas[0][tasa_preferencial]" class="form-select searchable" required>
|
<select name="partidas[0][tasa_preferencial]" class="form-select searchable" required>
|
||||||
@@ -248,24 +322,28 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="hide"><input name="partidas[0][precio_unitario]" type="number" class="form-control w-auto"></td>
|
<td class="hide"><input name="partidas[0][precio_unitario]" type="number" class="form-control w-auto form-group-animated"></td>
|
||||||
<td class="hide"><input name="partidas[0][oma_factura]" class="form-control w-auto"></td>
|
<td class="hide"><input name="partidas[0][oma_factura]" class="form-control w-auto form-group-animated"></td>
|
||||||
<td><button type="button" class="btn btn-danger btn-sm remove-row">✖️</button></td>
|
<td><button type="button" class="btn btn-danger btn-sm remove-row mt-auto w-auto btn-animated">✖️</button></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group-animated">
|
||||||
<button type="button" class="btn btn-secondary btn-sm mt-auto w-auto btn-animated" id="add-partida">➕ Agregar partida</button>
|
<button type="button" class="btn btn-secondary btn-sm mt-auto w-auto btn-animated" id="add-partida">➕ Agregar partida</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Activo -->
|
<!-- Activo -->
|
||||||
<div class="form-check mt-4">
|
<div class="form-check mt-4 form-group-animated">
|
||||||
<input id="status" name="status" type="checkbox" class="hide form-check-input" checked>
|
<input id="status" name="status" type="checkbox" class="hide form-check-input" checked>
|
||||||
<label for="status" class="hide form-check-label">Activo</label>
|
<label for="status" class="hide form-check-label">Activo</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Botones finales -->
|
<!-- Botones finales -->
|
||||||
|
<div class="col-12 text-end mt-4 form-group-animated"></div>
|
||||||
<button type="submit" class="btn btn-success mt-3 mt-auto w-auto btn-animated">Guardar</button>
|
<button type="submit" class="btn btn-success mt-3 mt-auto w-auto btn-animated">Guardar</button>
|
||||||
<a href="/IMPORTADORES/solicitud_importacion/lista" class="btn btn-secondary mt-3 ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
<a href="/IMPORTADORES/solicitud_importacion/lista" class="btn btn-secondary mt-3 ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -512,6 +590,67 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Script para manejar las animaciones de validación
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const inputs = document.querySelectorAll('input.form-control, select.form_select');
|
||||||
|
const selects = document.querySelectorAll('select.form_select');
|
||||||
|
|
||||||
|
inputs.forEach(input => {
|
||||||
|
// Validación en tiempo real
|
||||||
|
input.addEventListener('input', function() {
|
||||||
|
if (this.checkValidity()) {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
this.classList.add('valid');
|
||||||
|
} else {
|
||||||
|
this.classList.remove('valid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Efecto shake en campos inválidos
|
||||||
|
input.addEventListener('invalid', function() {
|
||||||
|
this.classList.add('shake');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configurar selects
|
||||||
|
selects.forEach(select => {
|
||||||
|
select.addEventListener('change', function() {
|
||||||
|
updateSelectState(this);
|
||||||
|
});
|
||||||
|
updateSelectState(select);
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateSelectState(select) {
|
||||||
|
select.setAttribute('value', select.value);
|
||||||
|
|
||||||
|
if (select.value && select.value !== '') {
|
||||||
|
select.classList.add('valid');
|
||||||
|
select.classList.remove('invalid');
|
||||||
|
} else {
|
||||||
|
select.classList.remove('valid');
|
||||||
|
if (select.hasAttribute('required') && select.closest('form')?.classList.contains('was-validated')) {
|
||||||
|
select.classList.add('invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validación del formulario
|
||||||
|
document.getElementById('altaProductoFrecuenteForm').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let isValid = true;
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -59,6 +59,80 @@
|
|||||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
.hide { display: none !important; }
|
.hide { display: none !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%; }
|
||||||
|
.form-label { font-weight: 500; }
|
||||||
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
|
.form-control:not(.no-animation):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); }
|
||||||
|
.form-control:not(.no-animation):not(:placeholder-shown) { /*border-color: #198754; background-color: #f8fff9;*/ }
|
||||||
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
25% { transform: translateX(-5px); }
|
||||||
|
75% { transform: translateX(5px); }
|
||||||
|
}
|
||||||
|
/* Floating labels para inputs texto */
|
||||||
|
.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; }
|
||||||
|
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
@keyframes inputPulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-gradient:not(.no-animation)::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:not(.no-animation):focus::before { left: 100%; }
|
||||||
|
.form-control.valid:not(.no-animation) { /*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); }
|
||||||
|
}
|
||||||
|
/* Animación para los campos del formulario */
|
||||||
|
.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; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
|
/* ========== ESTILOS PARA CAMPO FOTO (SIN ANIMACIONES) ========== */
|
||||||
|
.no-animation, .no-border-style { transition: none !important; border: none; box-shadow: none !important; background: #fff !important; }
|
||||||
|
.no-animation:focus { transform: none !important; border: none; box-shadow: none !important; }
|
||||||
|
.no-animation:hover { animation: none !important; }
|
||||||
|
.no-animation::before, .no-animation::after { display: none !important; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -71,12 +145,12 @@
|
|||||||
|
|
||||||
<!-- Datos principales -->
|
<!-- Datos principales -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3 mb-3">
|
<div class="col-md-3 mb-3 form-group-animated">
|
||||||
<label for="numero_factura" class="form-label">Número de Factura</label>
|
<label for="numero_factura" class="form-label">Número de Factura</label>
|
||||||
<input id="numero_factura" name="numero_factura" type="text" class="form-control" required
|
<input id="numero_factura" name="numero_factura" type="text" class="form-control" required
|
||||||
value="<?= htmlspecialchars($factura['numero_factura']) ?>">
|
value="<?= htmlspecialchars($factura['numero_factura']) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3 mb-3">
|
<div class="col-md-3 mb-3 form-group-animated">
|
||||||
<label for="fecha_factura" class="form-label">Fecha de Factura</label>
|
<label for="fecha_factura" class="form-label">Fecha de Factura</label>
|
||||||
<input id="fecha_factura" name="fecha_factura" type="date" class="form-control" required
|
<input id="fecha_factura" name="fecha_factura" type="date" class="form-control" required
|
||||||
value="<?= htmlspecialchars($factura['fecha_factura']) ?>">
|
value="<?= htmlspecialchars($factura['fecha_factura']) ?>">
|
||||||
@@ -150,7 +224,7 @@
|
|||||||
|
|
||||||
<!-- Valor y Vinculación -->
|
<!-- Valor y Vinculación -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-8 mb-3">
|
<div class="col-md-8 mb-3 form-group-animated">
|
||||||
<label for="valor_factura" class="form-label">Valor Factura</label>
|
<label for="valor_factura" class="form-label">Valor Factura</label>
|
||||||
<input id="valor_factura" name="valor_factura" type="number" step="0.01" min="0" class="form-control valor-total" required
|
<input id="valor_factura" name="valor_factura" type="number" step="0.01" min="0" class="form-control valor-total" required
|
||||||
value="<?= htmlspecialchars($factura['valor_factura']) ?>">
|
value="<?= htmlspecialchars($factura['valor_factura']) ?>">
|
||||||
@@ -193,7 +267,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 mb-3">
|
<div class="col-md-4 mb-3">
|
||||||
<label for="foto_solicitud" class="form-label">Foto de la Carga (PIPA)</label>
|
<label for="foto_solicitud" class="form-label">Foto de la Carga (PIPA)</label>
|
||||||
<input id="foto_solicitud" name="foto_solicitud" type="file" class="form-control" accept="image/*">
|
<input id="foto_solicitud" name="foto_solicitud" type="file" class="form-control no-animation no-border-style" accept="image/*">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -219,9 +293,9 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<?php if (!empty($partidas)): foreach($partidas as $i=>$p): ?>
|
<?php if (!empty($partidas)): foreach($partidas as $i=>$p): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><input name="partidas[<?= $i ?>][descripcion]" class="form-control" value="<?= htmlspecialchars($p['descripcion']) ?>"></td>
|
<td><input name="partidas[<?= $i ?>][descripcion]" class="form-control form-group-animated" value="<?= htmlspecialchars($p['descripcion']) ?>"></td>
|
||||||
<td><input name="partidas[<?= $i ?>][cantidad_comercial]" type="number" step="0.0001" min="0" class="form-control" value="<?= htmlspecialchars($p['cantidad_comercial']) ?>"></td>
|
<td><input name="partidas[<?= $i ?>][cantidad_comercial]" type="number" step="0.0001" min="0" class="form-control form-group-animated" value="<?= htmlspecialchars($p['cantidad_comercial']) ?>"></td>
|
||||||
<td><input name="partidas[<?= $i ?>][cantidad_tarifa]" type="number" step="0.0001" min="0" class="form-control" value="<?= htmlspecialchars($p['cantidad_tarifa']) ?>"></td>
|
<td><input name="partidas[<?= $i ?>][cantidad_tarifa]" type="number" step="0.0001" min="0" class="form-control form-group-animated" value="<?= htmlspecialchars($p['cantidad_tarifa']) ?>"></td>
|
||||||
<td>
|
<td>
|
||||||
<select name="partidas[<?= $i ?>][unidad_comercial_id]" class="form-select searchable">
|
<select name="partidas[<?= $i ?>][unidad_comercial_id]" class="form-select searchable">
|
||||||
<option value="">-- Unidad --</option>
|
<option value="">-- Unidad --</option>
|
||||||
@@ -232,8 +306,8 @@
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td><input name="partidas[<?= $i ?>][valor_factura]" type="number" step="0.01" min="0" class="form-control valor-partida" value="<?= htmlspecialchars($p['valor_factura']) ?>"></td>
|
<td><input name="partidas[<?= $i ?>][valor_factura]" type="number" step="0.01" min="0" class="form-control valor-partida form-group-animated" value="<?= htmlspecialchars($p['valor_factura']) ?>"></td>
|
||||||
<td><input name="partidas[<?= $i ?>][peso_bruto]" type="number" step="0.0001" min="0" class="form-control" value="<?= htmlspecialchars($p['peso_bruto']) ?>"></td>
|
<td><input name="partidas[<?= $i ?>][peso_bruto]" type="number" step="0.0001" min="0" class="form-control form-group-animated" value="<?= htmlspecialchars($p['peso_bruto']) ?>"></td>
|
||||||
<td>
|
<td>
|
||||||
<select name="partidas[<?= $i ?>][tasa_preferencial]" class="form-select searchable">
|
<select name="partidas[<?= $i ?>][tasa_preferencial]" class="form-select searchable">
|
||||||
<option value="">-- Selecciona --</option>
|
<option value="">-- Selecciona --</option>
|
||||||
@@ -242,15 +316,15 @@
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td class="hide"><input name="partidas[<?= $i ?>][precio_unitario]" type="number" class="form-control" value="<?= htmlspecialchars($p['precio_unitario'] ?? '') ?>"></td>
|
<td class="hide"><input name="partidas[<?= $i ?>][precio_unitario]" type="number" class="form-control form-group-animated" value="<?= htmlspecialchars($p['precio_unitario'] ?? '') ?>"></td>
|
||||||
<td class="hide"><input name="partidas[<?= $i ?>][oma_factura]" class="form-control" value="<?= htmlspecialchars($p['oma_factura'] ?? '') ?>"></td>
|
<td class="hide"><input name="partidas[<?= $i ?>][oma_factura]" class="form-control form-group-animated" value="<?= htmlspecialchars($p['oma_factura'] ?? '') ?>"></td>
|
||||||
<td><button type="button" class="btn btn-danger btn-sm remove-row">✖️</button></td>
|
<td><button type="button" class="btn btn-danger btn-sm remove-row">✖️</button></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; else: ?>
|
<?php endforeach; else: ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><input name="partidas[0][descripcion]" class="form-control"></td>
|
<td><input name="partidas[0][descripcion]" class="form-control form-group-animated"></td>
|
||||||
<td><input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control" min="0"></td>
|
<td><input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control form-group-animated" min="0"></td>
|
||||||
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control" min="0"></td>
|
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control form-group-animated" min="0"></td>
|
||||||
<td>
|
<td>
|
||||||
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable">
|
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable">
|
||||||
<option value="">-- Unidad --</option>
|
<option value="">-- Unidad --</option>
|
||||||
@@ -259,8 +333,8 @@
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida" min="0"></td>
|
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida form-group-animated" min="0"></td>
|
||||||
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control" min="0"></td>
|
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control form-group-animated" min="0"></td>
|
||||||
<td>
|
<td>
|
||||||
<select name="partidas[0][tasa_preferencial]" class="form-select searchable">
|
<select name="partidas[0][tasa_preferencial]" class="form-select searchable">
|
||||||
<option value="">-- Selecciona --</option>
|
<option value="">-- Selecciona --</option>
|
||||||
@@ -276,16 +350,21 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group-animated">
|
||||||
<button type="button" class="btn btn-secondary btn-sm mb-3 mt-auto w-auto btn-animated" id="add-partida">➕ Agregar partida</button>
|
<button type="button" class="btn btn-secondary btn-sm mb-3 mt-auto w-auto btn-animated" id="add-partida">➕ Agregar partida</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Activo -->
|
<!-- Activo -->
|
||||||
<div class="form-check mb-4">
|
<div class="form-check mb-4 form-group-animated">
|
||||||
<input id="status" value=1 name="status" type="hidden" <?= $factura['status']==1?'checked':'' ?>>
|
<input id="status" value=1 name="status" type="hidden" <?= $factura['status']==1?'checked':'' ?>>
|
||||||
<label for="status" class="hide form-check-label">Activo</label>
|
<label for="status" class="hide form-check-label">Activo</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Botones finales -->
|
||||||
|
<div class="col-12 text-end mt-4 form-group-animated"></div>
|
||||||
<button type="submit" class="btn btn-success mt-auto w-auto btn-animated">Actualizar</button>
|
<button type="submit" class="btn btn-success mt-auto w-auto btn-animated">Actualizar</button>
|
||||||
<a href="/IMPORTADORES/solicitud_importacion/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
<a href="/IMPORTADORES/solicitud_importacion/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -637,6 +716,67 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Script para manejar las animaciones de validación
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const inputs = document.querySelectorAll('input.form-control, select.form_select');
|
||||||
|
const selects = document.querySelectorAll('select.form_select');
|
||||||
|
|
||||||
|
inputs.forEach(input => {
|
||||||
|
// Validación en tiempo real
|
||||||
|
input.addEventListener('input', function() {
|
||||||
|
if (this.checkValidity()) {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
this.classList.add('valid');
|
||||||
|
} else {
|
||||||
|
this.classList.remove('valid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Efecto shake en campos inválidos
|
||||||
|
input.addEventListener('invalid', function() {
|
||||||
|
this.classList.add('shake');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configurar selects
|
||||||
|
selects.forEach(select => {
|
||||||
|
select.addEventListener('change', function() {
|
||||||
|
updateSelectState(this);
|
||||||
|
});
|
||||||
|
updateSelectState(select);
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateSelectState(select) {
|
||||||
|
select.setAttribute('value', select.value);
|
||||||
|
|
||||||
|
if (select.value && select.value !== '') {
|
||||||
|
select.classList.add('valid');
|
||||||
|
select.classList.remove('invalid');
|
||||||
|
} else {
|
||||||
|
select.classList.remove('valid');
|
||||||
|
if (select.hasAttribute('required') && select.closest('form')?.classList.contains('was-validated')) {
|
||||||
|
select.classList.add('invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validación del formulario
|
||||||
|
document.getElementById('altaProductoFrecuenteForm').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let isValid = true;
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -162,8 +162,8 @@
|
|||||||
<!-- Celda de Acciones -->
|
<!-- Celda de Acciones -->
|
||||||
<td>
|
<td>
|
||||||
<a href="/IMPORTADORES/solicitud_importacion/editar?id=<?= $f['id_solicitud'] ?>"
|
<a href="/IMPORTADORES/solicitud_importacion/editar?id=<?= $f['id_solicitud'] ?>"
|
||||||
class="btn btn-sm btn-primary">✏️</a>
|
class="btn btn-sm btn-primary mt-auto w-auto btn-animated">✏️</a>
|
||||||
<button class="btn btn-sm btn-danger"
|
<button class="btn btn-sm btn-danger mt-auto w-auto btn-animated"
|
||||||
onclick="confirmDelete(<?= $f['id_solicitud'] ?>)">🗑️</button>
|
onclick="confirmDelete(<?= $f['id_solicitud'] ?>)">🗑️</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -435,10 +435,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -66,58 +66,50 @@
|
|||||||
.modal-dialog { z-index: 10000 !important; position: relative; }
|
.modal-dialog { z-index: 10000 !important; position: relative; }
|
||||||
/* Opcional: Mejorar la apariencia del overlay */
|
/* Opcional: Mejorar la apariencia del overlay */
|
||||||
.modal-backdrop.show { opacity: 0.5; }
|
.modal-backdrop.show { opacity: 0.5; }
|
||||||
/* ========== ANIMACIONES PARA INPUTS ========== */
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
/* 1. Animación al hacer focus */
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
.form-control { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
.form-control:not(.no-animation):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); }
|
||||||
.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); }
|
.form-control:not(.no-animation):not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
|
||||||
/* 2. Animación al escribir */
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
.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 {
|
@keyframes shake {
|
||||||
0%, 100% { transform: translateX(0); }
|
0%, 100% { transform: translateX(0); }
|
||||||
25% { transform: translateX(-5px); }
|
25% { transform: translateX(-5px); }
|
||||||
75% { transform: translateX(5px); }
|
75% { transform: translateX(5px); }
|
||||||
}
|
}
|
||||||
/* 4. Floating labels con animación */
|
/* Floating labels para inputs texto */
|
||||||
.form-floating-custom { position: relative; margin-bottom: 1.5rem; }
|
.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-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-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: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; }
|
.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:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
.input-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
|
|
||||||
@keyframes inputPulse {
|
@keyframes inputPulse {
|
||||||
0% { transform: scale(1); }
|
0% { transform: scale(1); }
|
||||||
50% { transform: scale(1.02); }
|
50% { transform: scale(1.02); }
|
||||||
100% { transform: scale(1); }
|
100% { transform: scale(1); }
|
||||||
}
|
}
|
||||||
/* 6. Gradiente animado en el borde */
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
.input-gradient { position: relative; overflow: hidden; }
|
.input-gradient:not(.no-animation)::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
||||||
.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; }
|
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%; }
|
.input-gradient:not(.no-animation):focus::before { left: 100%; }
|
||||||
/* 7. Efecto de brillo en validación exitosa */
|
.form-control.valid:not(.no-animation) { border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9); animation: successGlow 1s ease-in-out; }
|
||||||
.form-control.valid { border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9); animation: successGlow 1s ease-in-out; }
|
|
||||||
@keyframes successGlow {
|
@keyframes successGlow {
|
||||||
0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
||||||
50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); }
|
50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); }
|
||||||
100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
||||||
}
|
}
|
||||||
/* 8. Typing effect simulation */
|
.input-typing:not(.no-animation) { position: relative; }
|
||||||
.input-typing { position: relative; }
|
.input-typing:not(.no-animation)::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
|
||||||
.input-typing::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
|
.input-typing:not(.no-animation):focus::after { opacity: 1; }
|
||||||
.input-typing:focus::after { opacity: 1; }
|
|
||||||
@keyframes blink {
|
@keyframes blink {
|
||||||
0%, 50% { opacity: 1; }
|
0%, 50% { opacity: 1; }
|
||||||
51%, 100% { opacity: 0; }
|
51%, 100% { opacity: 0; }
|
||||||
}
|
}
|
||||||
/* 9. Efecto de ondas */
|
.input-ripple:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
.input-ripple { position: relative; overflow: hidden; }
|
.input-ripple:not(.no-animation)::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0;
|
||||||
.input-ripple::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0; background: rgba(13, 110, 253, 0.2);
|
background: rgba(13, 110, 253, 0.2); border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; }
|
||||||
border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; }
|
.input-ripple:not(.no-animation):focus::before { width: 300px; height: 300px; }
|
||||||
.input-ripple:focus::before { width: 300px; height: 300px; }
|
/* Animación para los campos del formulario */
|
||||||
/* 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 { 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(1) { animation-delay: 0.1s; }
|
||||||
.form-group-animated:nth-child(2) { animation-delay: 0.2s; }
|
.form-group-animated:nth-child(2) { animation-delay: 0.2s; }
|
||||||
@@ -127,54 +119,51 @@
|
|||||||
.form-group-animated:nth-child(6) { animation-delay: 0.6s; }
|
.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(7) { animation-delay: 0.7s; }
|
||||||
.form-group-animated:nth-child(8) { animation-delay: 0.8s; }
|
.form-group-animated:nth-child(8) { animation-delay: 0.8s; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
/* ========== ANIMACIONES PARA SELECT ========== */
|
/* ========== ANIMACIONES PARA SELECT ========== */
|
||||||
/* 1. Estilos base para select */
|
.form-select { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; cursor: pointer;
|
||||||
.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-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; }
|
background-repeat: no-repeat; background-position: right 0.75rem center; background-size: 16px 12px; padding: 1rem 2.5rem 0.5rem 0.75rem; height: auto; min-height: 3.5rem; }
|
||||||
/* 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);
|
.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"); }
|
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=""]):valid { border-color: #198754; background-color: #f8fff9;
|
||||||
.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"); }
|
||||||
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-select[value=""] { border-color: #dee2e6; background-color: #fff; }
|
||||||
.form-floating-custom .form-select:focus ~ .form-label,
|
/* Floating labels para select */
|
||||||
.form-floating-custom .form-select:not([value=""]) ~ .form-label { top: 0.25rem; font-size: 0.75rem; color: #0d6efd; font-weight: 600; }
|
.form-floating-custom .form-select ~ .form-label { position: absolute; top: 50%; left: 0.75rem; transform: translateY(-50%); pointer-events: none;
|
||||||
/* 5. Efecto de shake en validación para select */
|
transition: all 0.3s ease; color: #6c757d; font-size: 0.875rem; background: white; padding: 0 0.25rem; z-index: 1; opacity: 0; }
|
||||||
|
.form-floating-custom .form-select:focus ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
|
.form-floating-custom .form-select:not([value=""]):valid ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
.form-select.shake { animation: shake 0.5s ease-in-out; }
|
.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; }
|
.select-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
|
||||||
/* 7. Gradiente animado para select */
|
|
||||||
.select-gradient { position: relative; overflow: hidden; }
|
.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::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%; }
|
.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; }
|
.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 { 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"); }
|
.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 { position: relative; overflow: hidden; }
|
||||||
.select-ripple::after { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0;
|
.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; }
|
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; }
|
.select-ripple:focus::after { width: 300px; height: 300px; }
|
||||||
/* 11. Efecto de scale suave */
|
|
||||||
.select-scale { transition: transform 0.2s ease; }
|
.select-scale { transition: transform 0.2s ease; }
|
||||||
.select-scale:hover { transform: scale(1.02); }
|
.select-scale:hover {transform: scale(1.02); }
|
||||||
.select-scale:focus { transform: scale(1.02) translateY(-2px); }
|
.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 { padding: 0.5rem; transition: all 0.2s ease; }
|
||||||
.form-select option:hover { background-color: #f8f9fa; }
|
.form-select option:hover { background-color: #f8f9fa; }
|
||||||
/* 13. Indicador de estado */
|
|
||||||
.select-status { position: relative; }
|
.select-status { position: relative; }
|
||||||
.select-status::after { content: ''; position: absolute; right: 2.5rem; top: 50%; transform: translateY(-50%);
|
.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; }
|
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; }
|
.select-status:invalid::after { background-color: #dc3545; opacity: 1; }
|
||||||
/* Quitar todo tipo de animación y borde para el campo foto */
|
/* ========== ESTILOS PARA CAMPO FOTO (SIN ANIMACIONES) ========== */
|
||||||
.no-animation,
|
.no-animation, .no-border-style { transition: none !important; border: none; box-shadow: none !important; background: #fff !important; }
|
||||||
.no-border-style { transition: none !important; border: 1px solid #ccc !important; box-shadow: none !important; background: #fff !important; }
|
.no-animation:focus { transform: none !important; border: none; box-shadow: none !important; }
|
||||||
.no-animation:focus { transform: none !important; }
|
.no-animation:hover { animation: none !important; }
|
||||||
|
.no-animation::before, .no-animation::after { display: none !important; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -185,49 +174,51 @@
|
|||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
|
|
||||||
<div class="col-md-6 form-group-animated">
|
<div class="col-md-6 form-group-animated">
|
||||||
|
<label for="" class="form-label">Contenedor *</label>
|
||||||
<div class="form-floating-custom">
|
<div class="form-floating-custom">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<input name="vehiculo" id="vehiculo" class="form-control input-pulse input-gradient" maxlength="20" placeholder=" " required>
|
<input name="vehiculo" id="vehiculo" class="form-control input-pulse input-gradient" maxlength="20" placeholder=" " required>
|
||||||
<label for="vehiculo" class="form-label">Contenedor *</label>
|
<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>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6 form-group-animated">
|
<div class="col-md-6 form-group-animated">
|
||||||
|
<label for="ident_fiscal" class="form-label">Identificación fiscal *</label>
|
||||||
<div class="form-floating-custom">
|
<div class="form-floating-custom">
|
||||||
<div class="d-flex align-items-center">
|
<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>
|
<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>
|
<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>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6 form-group-animated">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label class="form-label">Foto (opcional)</label>
|
<label for="" class="form-label">Transportista</label>
|
||||||
|
<div class="form-floating-custom">
|
||||||
|
<select name="transportista_id" id="transportista_id" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
|
||||||
|
<option value="">-- Selecciona un transportista --</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_id" class="form-label">Transportista</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6 form-group-animated">
|
||||||
|
<label for="foto" class="form-label">Foto (opcional)</label>
|
||||||
<div class="form-floating-custom">
|
<div class="form-floating-custom">
|
||||||
<input type="file" name="foto" id="foto" class="form-control no-animation no-border-style" accept="image/*">
|
<input type="file" name="foto" id="foto" class="form-control no-animation no-border-style" accept="image/*">
|
||||||
</div>
|
</div>
|
||||||
</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 form-group-animated">
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="text-end mt-4">
|
|
||||||
<button type="submit" class="btn btn-success ms-2 mt-auto w-auto btn-animated">Guardar</button>
|
<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>
|
<a href="/IMPORTADORES/transportes/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -272,7 +263,7 @@
|
|||||||
|
|
||||||
const vehiculo = document.getElementById('vehiculo').value.trim();
|
const vehiculo = document.getElementById('vehiculo').value.trim();
|
||||||
const ident_fiscal = document.getElementById('ident_fiscal').value.trim();
|
const ident_fiscal = document.getElementById('ident_fiscal').value.trim();
|
||||||
const transportista = document.getElementById('transportista').value;
|
const transportista_id = document.getElementById('transportista_id').value;
|
||||||
const fotoF = document.getElementById('foto').files[0];
|
const fotoF = document.getElementById('foto').files[0];
|
||||||
|
|
||||||
if (!vehiculo) {
|
if (!vehiculo) {
|
||||||
@@ -294,10 +285,12 @@
|
|||||||
this.submit();
|
this.submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Script para manejar las animaciones de validación
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
const inputs = document.querySelectorAll('.form-control');
|
const inputs = document.querySelectorAll('input.form-control, select.form-select');
|
||||||
|
|
||||||
inputs.forEach(input => {
|
inputs.forEach(input => {
|
||||||
|
// Validación en tiempo real
|
||||||
input.addEventListener('input', function() {
|
input.addEventListener('input', function() {
|
||||||
if (this.checkValidity()) {
|
if (this.checkValidity()) {
|
||||||
this.classList.remove('shake');
|
this.classList.remove('shake');
|
||||||
@@ -307,6 +300,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Efecto shake en campos inválidos
|
||||||
input.addEventListener('invalid', function() {
|
input.addEventListener('invalid', function() {
|
||||||
this.classList.add('shake');
|
this.classList.add('shake');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -314,6 +308,68 @@
|
|||||||
}, 500);
|
}, 500);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Validación del formulario
|
||||||
|
document.getElementById('formTransCrear').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let isValid = true;
|
||||||
|
const form = this;
|
||||||
|
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Si todo es válido, enviar el formulario
|
||||||
|
if (isValid) {
|
||||||
|
// Mostrar indicador de carga
|
||||||
|
const submitBtn = form.querySelector('button[type="submit"]');
|
||||||
|
const originalText = submitBtn.textContent;
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Guardando...';
|
||||||
|
|
||||||
|
// Aquí puedes enviar el formulario real
|
||||||
|
form.submit();
|
||||||
|
} else {
|
||||||
|
// Mostrar mensaje de error
|
||||||
|
showNotification('Por favor, complete todos los campos obligatorios correctamente.', 'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manejo específico para selects
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const selects = document.querySelectorAll('.form-select');
|
||||||
|
|
||||||
|
selects.forEach(select => {
|
||||||
|
// Manejar cambios en el select
|
||||||
|
select.addEventListener('change', function() {
|
||||||
|
updateSelectState(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Estado inicial
|
||||||
|
updateSelectState(select);
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateSelectState(select) {
|
||||||
|
// Actualizar el atributo value para que el CSS pueda detectarlo
|
||||||
|
select.setAttribute('value', select.value);
|
||||||
|
|
||||||
|
// Agregar/quitar clase valid basado en si hay valor seleccionado
|
||||||
|
if (select.value && select.value !== '') {
|
||||||
|
select.classList.add('valid');
|
||||||
|
select.classList.remove('invalid');
|
||||||
|
} else {
|
||||||
|
select.classList.remove('valid');
|
||||||
|
// Solo agregar invalid si el campo es required y se ha intentado enviar
|
||||||
|
if (select.hasAttribute('required') && select.closest('form')?.classList.contains('was-validated')) {
|
||||||
|
select.classList.add('invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,104 @@
|
|||||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
.preview{ width: 40%; }
|
.preview{ width: 40%; }
|
||||||
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
|
.form-control:not(.no-animation):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); }
|
||||||
|
.form-control:not(.no-animation):not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
|
||||||
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
25% { transform: translateX(-5px); }
|
||||||
|
75% { transform: translateX(5px); }
|
||||||
|
}
|
||||||
|
/* Floating labels para inputs texto */
|
||||||
|
.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; }
|
||||||
|
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
@keyframes inputPulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-gradient:not(.no-animation)::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:not(.no-animation):focus::before { left: 100%; }
|
||||||
|
.form-control.valid:not(.no-animation) { 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); }
|
||||||
|
}
|
||||||
|
.input-typing:not(.no-animation) { position: relative; }
|
||||||
|
.input-typing:not(.no-animation)::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
|
||||||
|
.input-typing:not(.no-animation):focus::after { opacity: 1; }
|
||||||
|
@keyframes blink {
|
||||||
|
0%, 50% { opacity: 1; }
|
||||||
|
51%, 100% { opacity: 0; }
|
||||||
|
}
|
||||||
|
.input-ripple:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-ripple:not(.no-animation)::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:not(.no-animation):focus::before { width: 300px; height: 300px; }
|
||||||
|
/* Animación para los campos del formulario */
|
||||||
|
.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; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
|
/* ========== ANIMACIONES 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; padding: 1rem 2.5rem 0.5rem 0.75rem; height: auto; min-height: 3.5rem; }
|
||||||
|
.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"); }
|
||||||
|
.form-select:not([value=""]):valid { 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"); }
|
||||||
|
.form-select[value=""] { border-color: #dee2e6; background-color: #fff; }
|
||||||
|
/* Floating labels para select */
|
||||||
|
.form-floating-custom .form-select ~ .form-label { position: absolute; top: 50%; left: 0.75rem; transform: translateY(-50%); pointer-events: none;
|
||||||
|
transition: all 0.3s ease; color: #6c757d; font-size: 0.875rem; background: white; padding: 0 0.25rem; z-index: 1; opacity: 0; }
|
||||||
|
.form-floating-custom .form-select:focus ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
|
.form-floating-custom .form-select:not([value=""]):valid ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
|
.form-select.shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
.select-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
.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%; }
|
||||||
|
.form-select.valid { border-color: #198754; background-color: #f8fff9; animation: successGlow 1s ease-in-out; }
|
||||||
|
.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"); }
|
||||||
|
.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; }
|
||||||
|
.select-scale { transition: transform 0.2s ease; }
|
||||||
|
.select-scale:hover {transform: scale(1.02); }
|
||||||
|
.select-scale:focus { transform: scale(1.02) translateY(-2px); }
|
||||||
|
.form-select option { padding: 0.5rem; transition: all 0.2s ease; }
|
||||||
|
.form-select option:hover { background-color: #f8f9fa; }
|
||||||
|
.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; }
|
||||||
|
/* ========== ESTILOS PARA CAMPO FOTO (SIN ANIMACIONES) ========== */
|
||||||
|
.no-animation, .no-border-style { transition: none !important; border: none; box-shadow: none !important; background: #fff !important; }
|
||||||
|
.no-animation:focus { transform: none !important; border: none; box-shadow: none !important; }
|
||||||
|
.no-animation:hover { animation: none !important; }
|
||||||
|
.no-animation::before, .no-animation::after { display: none !important; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -69,36 +167,33 @@
|
|||||||
<form id="formTransEdit" action="/IMPORTADORES/transportes/actualizar" method="POST" enctype="multipart/form-data" class="card p-4 shadow-sm card-hover position-relative h-auto">
|
<form id="formTransEdit" action="/IMPORTADORES/transportes/actualizar" method="POST" enctype="multipart/form-data" class="card p-4 shadow-sm card-hover position-relative h-auto">
|
||||||
<input type="hidden" name="id_transporte" value="<?= $t['id_transporte'] ?>">
|
<input type="hidden" name="id_transporte" value="<?= $t['id_transporte'] ?>">
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label class="form-label">Contenedor *</label>
|
<label class="form-label">Contenedor</label>
|
||||||
|
<div class="form-floating-custom">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<input name="vehiculo" id="vehiculo" class="form-control" maxlength="20"
|
<input name="vehiculo" id="vehiculo" class="form-control input-pulse input-gradient" maxlength="20"
|
||||||
value="<?= htmlspecialchars($t['vehiculo']) ?>" required>
|
value="<?= htmlspecialchars($t['vehiculo']) ?>" required>
|
||||||
<button type="button" class="btn btn-outline-secondary ms-2" data-bs-toggle="modal" data-bs-target="#infoContenedor" style="border: none;">ℹ️</button>
|
<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>
|
||||||
<div class="col-md-6">
|
</div>
|
||||||
<label class="form-label">Identificación fiscal *</label>
|
|
||||||
|
<div class="col-md-6 form-group-animated">
|
||||||
|
<label class="form-label">Identificación fiscal</label>
|
||||||
|
<div class="form-floating-custom">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<input name="identificador_fiscal" id="identificador_fiscal" class="form-control" maxlength="20"
|
<input name="identificador_fiscal" id="identificador_fiscal" class="form-control input-pulse input-gradient" maxlength="20"
|
||||||
value="<?= htmlspecialchars($t['identificador_fiscal']) ?>" required>
|
value="<?= htmlspecialchars($t['identificador_fiscal']) ?>" required>
|
||||||
<button type="button" class="btn btn-outline-secondary ms-2" data-bs-toggle="modal" data-bs-target="#infoIdentificacion" style="border: none;">ℹ️</button>
|
<label for="identificador_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>
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label">Foto actual</label><br>
|
|
||||||
<?php if($t['foto_url']): ?>
|
|
||||||
<img src="<?= $t['foto_url'] ?>" class="preview">
|
|
||||||
<?php else: ?>
|
|
||||||
<span class="text-muted">Sin foto</span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label">Reemplazar foto (opcional)</label>
|
<div class="col-md-6 form-group-animated">
|
||||||
<input type="file" name="foto" id="foto" class="form-control" accept="image/*">
|
<label class="form-label">Transportista</label>
|
||||||
</div>
|
<div class="form-floating-custom">
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label">Transportista *</label>
|
|
||||||
<select name="id_transportista" id="transportista" class="form-select" required>
|
<select name="id_transportista" id="transportista" class="form-select" required>
|
||||||
<?php foreach($transportistas as $tr): ?>
|
<?php foreach($transportistas as $tr): ?>
|
||||||
<option value="<?= $tr['id_transportista'] ?>"
|
<option value="<?= $tr['id_transportista'] ?>"
|
||||||
@@ -107,16 +202,37 @@
|
|||||||
</option>
|
</option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
|
<label for="transportista" class="form-label">Transportista</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-end mt-4">
|
<div class="col-md-6"></div>
|
||||||
|
|
||||||
|
<div class="col-md-6 form-group-animated">
|
||||||
|
<label class="form-label">Foto actual</label><br>
|
||||||
|
<div class="form-floating-custom">
|
||||||
|
<?php if($t['foto_url']): ?>
|
||||||
|
<img src="<?= $t['foto_url'] ?>" class="preview">
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="text-muted">Sin foto</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6 form-group-animated">
|
||||||
|
<label class="form-label">Reemplazar foto (opcional)</label>
|
||||||
|
<div class="form-floating-custom">
|
||||||
|
<input type="file" name="foto" id="foto" class="form-control no-animation no-border-style" accept="image/*">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-end mt-4 form-group-animated">
|
||||||
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Actualizar</button>
|
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Actualizar</button>
|
||||||
<a href="/IMPORTADORES/transportes/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
<a href="/IMPORTADORES/transportes/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Modales movidos FUERA del formulario -->
|
|
||||||
<!-- Modal de ayuda - Contenedor -->
|
<!-- Modal de ayuda - Contenedor -->
|
||||||
<div class="modal fade" id="infoContenedor" tabindex="-1" aria-labelledby="infoContenedorLabel" aria-hidden="true">
|
<div class="modal fade" id="infoContenedor" tabindex="-1" aria-labelledby="infoContenedorLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
@@ -176,11 +292,98 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fotoF && fotoF.size > 2 * 1024 * 1024) { // 2 MB
|
if (fotoF && fotoF.size > 2 * 1024 * 1024) { // 2 MB
|
||||||
return Swal.fire({ icon: 'error', title: 'Foto demasiado grande', text: 'La imagen no debe exceder 2 MB.' confirmButtonColor: '#dc3545' });
|
return Swal.fire({ icon: 'error', title: 'Foto demasiado grande', text: 'La imagen no debe exceder 2 MB.', confirmButtonColor: '#dc3545' });
|
||||||
}
|
}
|
||||||
// Si todas las validaciones pasan, el formulario se envía.
|
// Si todas las validaciones pasan, el formulario se envía.
|
||||||
this.submit();
|
this.submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Script para manejar las animaciones de validación
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const inputs = document.querySelectorAll('input.form-control, select.form-select');
|
||||||
|
|
||||||
|
inputs.forEach(input => {
|
||||||
|
// Validación en tiempo real
|
||||||
|
input.addEventListener('input', function() {
|
||||||
|
if (this.checkValidity()) {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
this.classList.add('valid');
|
||||||
|
} else {
|
||||||
|
this.classList.remove('valid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Efecto shake en campos inválidos
|
||||||
|
input.addEventListener('invalid', function() {
|
||||||
|
this.classList.add('shake');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Validación del formulario
|
||||||
|
document.getElementById('formTransEdit').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let isValid = true;
|
||||||
|
const form = this;
|
||||||
|
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Si todo es válido, enviar el formulario
|
||||||
|
if (isValid) {
|
||||||
|
// Mostrar indicador de carga
|
||||||
|
const submitBtn = form.querySelector('button[type="submit"]');
|
||||||
|
const originalText = submitBtn.textContent;
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Guardando...';
|
||||||
|
|
||||||
|
// Aquí puedes enviar el formulario real
|
||||||
|
form.submit();
|
||||||
|
} else {
|
||||||
|
// Mostrar mensaje de error
|
||||||
|
showNotification('Por favor, complete todos los campos obligatorios correctamente.', 'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manejo específico para selects
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const selects = document.querySelectorAll('.form-select');
|
||||||
|
|
||||||
|
selects.forEach(select => {
|
||||||
|
// Manejar cambios en el select
|
||||||
|
select.addEventListener('change', function() {
|
||||||
|
updateSelectState(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Estado inicial
|
||||||
|
updateSelectState(select);
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateSelectState(select) {
|
||||||
|
// Actualizar el atributo value para que el CSS pueda detectarlo
|
||||||
|
select.setAttribute('value', select.value);
|
||||||
|
|
||||||
|
// Agregar/quitar clase valid basado en si hay valor seleccionado
|
||||||
|
if (select.value && select.value !== '') {
|
||||||
|
select.classList.add('valid');
|
||||||
|
select.classList.remove('invalid');
|
||||||
|
} else {
|
||||||
|
select.classList.remove('valid');
|
||||||
|
// Solo agregar invalid si el campo es required y se ha intentado enviar
|
||||||
|
if (select.hasAttribute('required') && select.closest('form')?.classList.contains('was-validated')) {
|
||||||
|
select.classList.add('invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -67,15 +67,19 @@
|
|||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">🚛 Mis Transportes</h4>
|
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">🚛 Mis Transportes</h4>
|
||||||
<a href="/IMPORTADORES/transportes/crear" class="btn btn-success mb-3">➕ Nuevo Transporte</a>
|
<a href="/IMPORTADORES/transportes/crear" class="btn btn-success mb-3 mt-auto w-auto btn-animated">➕ Nuevo Transporte</a>
|
||||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto">
|
<div class="card p-3 shadow-sm card-hover position-relative h-auto">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-striped" id="tabla-transportes">
|
<table class="table table-striped" id="tabla-transportes">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th><th>Contenedor</th><th>Ident. Fiscal</th>
|
<th>#</th>
|
||||||
<th>Foto</th><th>Transportista</th>
|
<th>Contenedor</th>
|
||||||
<th>Alta</th><th>Acciones</th>
|
<th>Identifiación Fiscal</th>
|
||||||
|
<th>Foto</th>
|
||||||
|
<th>Transportista</th>
|
||||||
|
<th>Alta</th>
|
||||||
|
<th>Acciones</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -93,8 +97,8 @@
|
|||||||
<td><?= $t['creado_en']->format('Y-m-d') ?></td>
|
<td><?= $t['creado_en']->format('Y-m-d') ?></td>
|
||||||
<td>
|
<td>
|
||||||
<a href="/IMPORTADORES/transportes/editar?id=<?= $t['id_transporte'] ?>"
|
<a href="/IMPORTADORES/transportes/editar?id=<?= $t['id_transporte'] ?>"
|
||||||
class="btn btn-sm btn-primary">✏️</a>
|
class="btn btn-sm btn-primary mt-auto w-auto btn-animated">✏️</a>
|
||||||
<button class="btn btn-sm btn-danger"
|
<button class="btn btn-sm btn-danger mt-auto w-auto btn-animated"
|
||||||
onclick="confirmDelete(<?= $t['id_transporte'] ?>)">
|
onclick="confirmDelete(<?= $t['id_transporte'] ?>)">
|
||||||
🗑️
|
🗑️
|
||||||
</button>
|
</button>
|
||||||
@@ -132,8 +136,14 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
<?php if(isset($_GET['deleted'])): ?>
|
<?php if (isset($_GET['created']) && $_GET['created']==='ok'): ?>
|
||||||
Swal.fire('¡Hecho!','Transporte eliminado.','success');
|
Swal.fire({ icon: 'success', title: 'Transporte creado', text: 'El transporte se creo correctamente.', confirmButtonColor: '#198754' });
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (isset($_GET['deleted']) && $_GET['deleted']==='ok'): ?>
|
||||||
|
Swal.fire({ icon: 'success', title: 'Transporte eliminado', text: 'Ya no aparecerá en tu lista.', confirmButtonColor: '#198754' });
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (isset($_GET['updated']) && $_GET['updated'] === 'ok'): ?>
|
||||||
|
Swal.fire({ icon: 'success', title: 'Transporte actualizado', text: 'Los datos fueron modificados correctamente.', confirmButtonColor: '#198754' });
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -51,58 +51,50 @@
|
|||||||
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
.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; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
/* ========== ANIMACIONES PARA INPUTS ========== */
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
/* 1. Animación al hacer focus */
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
.form-control { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
.form-control:not(.no-animation):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); }
|
||||||
.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); }
|
.form-control:not(.no-animation):not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
|
||||||
/* 2. Animación al escribir */
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
.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 {
|
@keyframes shake {
|
||||||
0%, 100% { transform: translateX(0); }
|
0%, 100% { transform: translateX(0); }
|
||||||
25% { transform: translateX(-5px); }
|
25% { transform: translateX(-5px); }
|
||||||
75% { transform: translateX(5px); }
|
75% { transform: translateX(5px); }
|
||||||
}
|
}
|
||||||
/* 4. Floating labels con animación */
|
/* Floating labels para inputs texto */
|
||||||
.form-floating-custom { position: relative; margin-bottom: 1.5rem; }
|
.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-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-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: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; }
|
.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:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
.input-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
|
|
||||||
@keyframes inputPulse {
|
@keyframes inputPulse {
|
||||||
0% { transform: scale(1); }
|
0% { transform: scale(1); }
|
||||||
50% { transform: scale(1.02); }
|
50% { transform: scale(1.02); }
|
||||||
100% { transform: scale(1); }
|
100% { transform: scale(1); }
|
||||||
}
|
}
|
||||||
/* 6. Gradiente animado en el borde */
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
.input-gradient { position: relative; overflow: hidden; }
|
.input-gradient:not(.no-animation)::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
||||||
.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; }
|
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%; }
|
.input-gradient:not(.no-animation):focus::before { left: 100%; }
|
||||||
/* 7. Efecto de brillo en validación exitosa */
|
.form-control.valid:not(.no-animation) { border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9); animation: successGlow 1s ease-in-out; }
|
||||||
.form-control.valid { border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9); animation: successGlow 1s ease-in-out; }
|
|
||||||
@keyframes successGlow {
|
@keyframes successGlow {
|
||||||
0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
||||||
50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); }
|
50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); }
|
||||||
100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
||||||
}
|
}
|
||||||
/* 8. Typing effect simulation */
|
.input-typing:not(.no-animation) { position: relative; }
|
||||||
.input-typing { position: relative; }
|
.input-typing:not(.no-animation)::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
|
||||||
.input-typing::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
|
.input-typing:not(.no-animation):focus::after { opacity: 1; }
|
||||||
.input-typing:focus::after { opacity: 1; }
|
|
||||||
@keyframes blink {
|
@keyframes blink {
|
||||||
0%, 50% { opacity: 1; }
|
0%, 50% { opacity: 1; }
|
||||||
51%, 100% { opacity: 0; }
|
51%, 100% { opacity: 0; }
|
||||||
}
|
}
|
||||||
/* 9. Efecto de ondas */
|
.input-ripple:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
.input-ripple { position: relative; overflow: hidden; }
|
.input-ripple:not(.no-animation)::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0;
|
||||||
.input-ripple::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0; background: rgba(13, 110, 253, 0.2);
|
background: rgba(13, 110, 253, 0.2); border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; }
|
||||||
border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; }
|
.input-ripple:not(.no-animation):focus::before { width: 300px; height: 300px; }
|
||||||
.input-ripple:focus::before { width: 300px; height: 300px; }
|
/* Animación para los campos del formulario */
|
||||||
/* 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 { 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(1) { animation-delay: 0.1s; }
|
||||||
.form-group-animated:nth-child(2) { animation-delay: 0.2s; }
|
.form-group-animated:nth-child(2) { animation-delay: 0.2s; }
|
||||||
@@ -112,49 +104,45 @@
|
|||||||
.form-group-animated:nth-child(6) { animation-delay: 0.6s; }
|
.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(7) { animation-delay: 0.7s; }
|
||||||
.form-group-animated:nth-child(8) { animation-delay: 0.8s; }
|
.form-group-animated:nth-child(8) { animation-delay: 0.8s; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
/* ========== ANIMACIONES PARA SELECT ========== */
|
/* ========== ANIMACIONES PARA SELECT ========== */
|
||||||
/* 1. Estilos base para select */
|
.form-select { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; cursor: pointer;
|
||||||
.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-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; }
|
background-repeat: no-repeat; background-position: right 0.75rem center; background-size: 16px 12px; padding: 1rem 2.5rem 0.5rem 0.75rem; height: auto; min-height: 3.5rem; }
|
||||||
/* 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);
|
.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"); }
|
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=""]):valid { border-color: #198754; background-color: #f8fff9;
|
||||||
.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"); }
|
||||||
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-select[value=""] { border-color: #dee2e6; background-color: #fff; }
|
||||||
.form-floating-custom .form-select:focus ~ .form-label,
|
/* Floating labels para select */
|
||||||
.form-floating-custom .form-select:not([value=""]) ~ .form-label { top: 0.25rem; font-size: 0.75rem; color: #0d6efd; font-weight: 600; }
|
.form-floating-custom .form-select ~ .form-label { position: absolute; top: 50%; left: 0.75rem; transform: translateY(-50%); pointer-events: none;
|
||||||
/* 5. Efecto de shake en validación para select */
|
transition: all 0.3s ease; color: #6c757d; font-size: 0.875rem; background: white; padding: 0 0.25rem; z-index: 1; opacity: 0; }
|
||||||
|
.form-floating-custom .form-select:focus ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
|
.form-floating-custom .form-select:not([value=""]):valid ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
.form-select.shake { animation: shake 0.5s ease-in-out; }
|
.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; }
|
.select-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
|
||||||
/* 7. Gradiente animado para select */
|
|
||||||
.select-gradient { position: relative; overflow: hidden; }
|
.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::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%; }
|
.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; }
|
.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 { 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"); }
|
.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 { position: relative; overflow: hidden; }
|
||||||
.select-ripple::after { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0;
|
.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; }
|
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; }
|
.select-ripple:focus::after { width: 300px; height: 300px; }
|
||||||
/* 11. Efecto de scale suave */
|
|
||||||
.select-scale { transition: transform 0.2s ease; }
|
.select-scale { transition: transform 0.2s ease; }
|
||||||
.select-scale:hover { transform: scale(1.02); }
|
.select-scale:hover {transform: scale(1.02); }
|
||||||
.select-scale:focus { transform: scale(1.02) translateY(-2px); }
|
.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 { padding: 0.5rem; transition: all 0.2s ease; }
|
||||||
.form-select option:hover { background-color: #f8f9fa; }
|
.form-select option:hover { background-color: #f8f9fa; }
|
||||||
/* 13. Indicador de estado */
|
|
||||||
.select-status { position: relative; }
|
.select-status { position: relative; }
|
||||||
.select-status::after { content: ''; position: absolute; right: 2.5rem; top: 50%; transform: translateY(-50%);
|
.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; }
|
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; }
|
.select-status:invalid::after { background-color: #dc3545; opacity: 1; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
@@ -222,7 +210,7 @@
|
|||||||
<div class="col-md-4 form-group-animated">
|
<div class="col-md-4 form-group-animated">
|
||||||
<div class="form-floating-custom">
|
<div class="form-floating-custom">
|
||||||
<select id="pais" name="pais" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
|
<select id="pais" name="pais" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
|
||||||
<option value=""></option>
|
<option value="">-- Selecciona un País --</option>
|
||||||
<?php foreach($paises as $p): ?>
|
<?php foreach($paises as $p): ?>
|
||||||
<option value="<?= $p['id_pais'] ?>"><?= htmlspecialchars($p['nombre']) ?></option>
|
<option value="<?= $p['id_pais'] ?>"><?= htmlspecialchars($p['nombre']) ?></option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
@@ -265,15 +253,61 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.getElementById('formAltaTransportista').addEventListener('submit', function(e) {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
e.preventDefault();
|
// Referencias a elementos del DOM
|
||||||
const rfcInput = document.getElementById('rfc');
|
const form = document.getElementById('formAltaTransportista');
|
||||||
const curpInput = document.getElementById('curp');
|
const inputs = document.querySelectorAll('input.form-control, select.form-select');
|
||||||
const telefonoInput = document.getElementById('telefono');
|
const selects = document.querySelectorAll('.form-select');
|
||||||
|
|
||||||
const rfc = rfcInput.value.trim().toUpperCase();
|
// Configurar validación en tiempo real para inputs
|
||||||
const curp = curpInput.value.trim();
|
inputs.forEach(input => {
|
||||||
const telefono = telefonoInput.value.trim();
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configurar selects
|
||||||
|
selects.forEach(select => {
|
||||||
|
select.addEventListener('change', function() {
|
||||||
|
updateSelectState(this);
|
||||||
|
});
|
||||||
|
updateSelectState(select);
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateSelectState(select) {
|
||||||
|
select.setAttribute('value', select.value);
|
||||||
|
|
||||||
|
if (select.value && select.value !== '') {
|
||||||
|
select.classList.add('valid');
|
||||||
|
select.classList.remove('invalid');
|
||||||
|
} else {
|
||||||
|
select.classList.remove('valid');
|
||||||
|
if (select.hasAttribute('required') && select.closest('form')?.classList.contains('was-validated')) {
|
||||||
|
select.classList.add('invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event listener para el formulario
|
||||||
|
if (form) {
|
||||||
|
form.addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const rfc = document.getElementById('rfc').value.trim().toUpperCase();
|
||||||
|
const curp = document.getElementById('curp').value.trim();
|
||||||
|
const telefono = document.getElementById('telefono').value.trim();
|
||||||
const clave = document.getElementById('clave').value.trim();
|
const clave = document.getElementById('clave').value.trim();
|
||||||
const nombre = document.getElementById('nombre').value.trim();
|
const nombre = document.getElementById('nombre').value.trim();
|
||||||
const caat = document.getElementById('caat').value.trim();
|
const caat = document.getElementById('caat').value.trim();
|
||||||
@@ -322,7 +356,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!telefonoRegex.test(telefono)) {
|
if (!telefonoRegex.test(telefono)) {
|
||||||
Swal.fire({ icon: 'error', title: 'Teléfono inválido', text: 'Debe tener 10 dígitos en el formato: 3 dígitos (LADA), espacio, y 7 dígitos (ej. 123 4567890).', onfirmButtonColor:'#dc3545'});
|
Swal.fire({ icon: 'error', title: 'Teléfono inválido', text: 'Debe tener 10 dígitos en el formato: 3 dígitos (LADA), espacio, y 7 dígitos (ej. 123 4567890).', confirmButtonColor:'#dc3545'});
|
||||||
document.getElementById('telefono').focus();
|
document.getElementById('telefono').focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -356,99 +390,17 @@
|
|||||||
document.getElementById('domicilio').focus();
|
document.getElementById('domicilio').focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
document.getElementById('rfc').value = rfc;
|
|
||||||
document.getElementById('curp').value = curp;
|
// Actualizar valores procesados
|
||||||
|
const rfcElement = document.getElementById('rfc');
|
||||||
|
const curpElement = document.getElementById('curp');
|
||||||
|
if (rfcElement) rfcElement.value = rfc;
|
||||||
|
if (curpElement) curpElement.value = curp;
|
||||||
|
|
||||||
|
// Si todas las validaciones son correctas: Enviar el formulario
|
||||||
this.submit();
|
this.submit();
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('pais').addEventListener('change', e => {
|
|
||||||
const pid = e.target.value;
|
|
||||||
const estadoSelect = document.getElementById('entidad');
|
|
||||||
const ciudadSelect = document.getElementById('ciudad');
|
|
||||||
estadoSelect.innerHTML = '<option value="">Cargando…</option>';
|
|
||||||
estadoSelect.disabled = true;
|
|
||||||
ciudadSelect.innerHTML = '<option value="">Primero estado…</option>';
|
|
||||||
ciudadSelect.disabled = true;
|
|
||||||
if (!pid) { estadoSelect.innerHTML = '<option value="">Primero país…</option>'; return; }
|
|
||||||
fetch(`/IMPORTADORES/transportistas/estados?pais=${pid}`)
|
|
||||||
.then(r => { if (!r.ok) throw new Error('Error al cargar estados'); return r.json(); })
|
|
||||||
.then(list => {
|
|
||||||
estadoSelect.innerHTML = '<option value=""></option>';
|
|
||||||
list.forEach(st => estadoSelect.add(new Option(st.nombre, st.id_estado)));
|
|
||||||
estadoSelect.disabled = false;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
estadoSelect.innerHTML = '<option value="">Error al cargar</option>';
|
|
||||||
Swal.fire({ icon:'error',title:'Error',text:'No se pudieron cargar los estados',confirmButtonColor:'#dc3545'});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('entidad').addEventListener('change', e => {
|
|
||||||
const eid = e.target.value;
|
|
||||||
const ciudadSelect = document.getElementById('ciudad');
|
|
||||||
ciudadSelect.innerHTML = '<option value="">Cargando…</option>';
|
|
||||||
ciudadSelect.disabled = true;
|
|
||||||
if (!eid) { ciudadSelect.innerHTML = '<option value="">Primero estado…</option>'; return; }
|
|
||||||
fetch(`/IMPORTADORES/transportistas/ciudades?estado=${eid}`)
|
|
||||||
.then(r => { if (!r.ok) throw new Error('Error al cargar ciudades'); return r.json(); })
|
|
||||||
.then(list => {
|
|
||||||
ciudadSelect.innerHTML = '<option value=""></option>';
|
|
||||||
list.forEach(ct => ciudadSelect.add(new Option(ct.nombre, ct.id_ciudad)));
|
|
||||||
ciudadSelect.disabled = false;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
ciudadSelect.innerHTML = '<option value="">Error al cargar</option>';
|
|
||||||
Swal.fire({ icon:'error',title:'Error',text:'No se pudieron cargar las ciudades',confirmButtonColor:'#dc3545'});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Switch Persona Moral
|
|
||||||
document.getElementById('personaMoralSwitch').addEventListener('change', function() {
|
|
||||||
const checked = this.checked;
|
|
||||||
const label = document.getElementById('labelNombre');
|
|
||||||
const curp = document.getElementById('curp');
|
|
||||||
const hidden = document.getElementById('es_persona_moral');
|
|
||||||
if (checked) {
|
|
||||||
label.textContent = 'Razón Social *';
|
|
||||||
curp.value = '';
|
|
||||||
curp.disabled = true;
|
|
||||||
curp.removeAttribute('required');
|
|
||||||
hidden.value = '1';
|
|
||||||
} else {
|
|
||||||
label.textContent = 'Nombre *';
|
|
||||||
curp.disabled = false;
|
|
||||||
curp.setAttribute('required', 'required');
|
|
||||||
hidden.value = '0';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Script para manejar las animaciones de validación
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const inputs = document.querySelectorAll('input.form-control, select.form_select');
|
|
||||||
|
|
||||||
inputs.forEach(input => {
|
|
||||||
// Validación en tiempo real
|
|
||||||
input.addEventListener('input', function() {
|
|
||||||
if (this.checkValidity()) {
|
|
||||||
this.classList.remove('shake');
|
|
||||||
this.classList.add('valid');
|
|
||||||
} else {
|
|
||||||
this.classList.remove('valid');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Efecto shake en campos inválidos
|
|
||||||
input.addEventListener('invalid', function() {
|
|
||||||
this.classList.add('shake');
|
|
||||||
setTimeout(() => {
|
|
||||||
this.classList.remove('shake');
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Validación del formulario
|
|
||||||
document.getElementById('formAltaAgencias').addEventListener('submit', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
|
// Validar campos
|
||||||
let isValid = true;
|
let isValid = true;
|
||||||
inputs.forEach(input => {
|
inputs.forEach(input => {
|
||||||
if (!input.checkValidity()) {
|
if (!input.checkValidity()) {
|
||||||
@@ -456,16 +408,76 @@
|
|||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (isValid) {
|
document.getElementById('pais').addEventListener('change', e => {
|
||||||
// Aquí puedes agregar tu lógica de envío
|
const pid = e.target.value;
|
||||||
Swal.fire({
|
const estadoSelect = document.getElementById('entidad');
|
||||||
icon: 'success',
|
const ciudadSelect = document.getElementById('ciudad');
|
||||||
title: '¡Éxito!',
|
|
||||||
text: 'Agencia registrada correctamente',
|
estadoSelect.innerHTML = '<option value="">Cargando…</option>';
|
||||||
showConfirmButton: false,
|
estadoSelect.disabled = true;
|
||||||
timer: 1500
|
ciudadSelect.innerHTML = '<option value="">Primero estado…</option>';
|
||||||
|
ciudadSelect.disabled = true;
|
||||||
|
|
||||||
|
if (!pid) { estadoSelect.innerHTML = '<option value="">Primero país…</option>'; return; }
|
||||||
|
fetch(`/IMPORTADORES/transportistas/estados?pais=${pid}`)
|
||||||
|
.then(r => { if (!r.ok) throw new Error('Error al cargar estados'); return r.json(); })
|
||||||
|
.then(list => {
|
||||||
|
estadoSelect.innerHTML = '<option value="">-- Selecciona un Estado --</option>';
|
||||||
|
list.forEach(st => estadoSelect.add(new Option(st.nombre, st.id_estado)));
|
||||||
|
estadoSelect.disabled = false;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
estadoSelect.innerHTML = '<option value="">Error al cargar</option>';
|
||||||
|
Swal.fire({ icon:'error', title:'Error', text:'No se pudieron cargar los estados', confirmButtonColor:'#dc3545'});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('entidad').addEventListener('change', e => {
|
||||||
|
const eid = e.target.value;
|
||||||
|
const ciudadSelect = document.getElementById('ciudad');
|
||||||
|
|
||||||
|
ciudadSelect.innerHTML = '<option value="">Cargando…</option>';
|
||||||
|
ciudadSelect.disabled = true;
|
||||||
|
|
||||||
|
if (!eid) { ciudadSelect.innerHTML = '<option value="">Primero estado…</option>'; return; }
|
||||||
|
fetch(`/IMPORTADORES/transportistas/ciudades?estado=${eid}`)
|
||||||
|
.then(r => { if (!r.ok) throw new Error('Error al cargar ciudades'); return r.json(); })
|
||||||
|
.then(list => {
|
||||||
|
ciudadSelect.innerHTML = '<option value="">-- Seleciona una ciudad --</option>';
|
||||||
|
list.forEach(ct => ciudadSelect.add(new Option(ct.nombre, ct.id_ciudad)));
|
||||||
|
ciudadSelect.disabled = false;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
ciudadSelect.innerHTML = '<option value="">Error al cargar</option>';
|
||||||
|
Swal.fire({ icon:'error', title:'Error', text:'No se pudieron cargar las ciudades', confirmButtonColor:'#dc3545'});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Switch Persona Moral
|
||||||
|
document.getElementById('personaMoralSwitch')?.addEventListener('change', function() {
|
||||||
|
const checked = this.checked;
|
||||||
|
const label = document.getElementById('labelNombre');
|
||||||
|
const curp = document.getElementById('curp');
|
||||||
|
const hidden = document.getElementById('es_persona_moral');
|
||||||
|
|
||||||
|
if (label) {
|
||||||
|
label.textContent = checked ? 'Razón Social *' : 'Nombre *';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curp && hidden) {
|
||||||
|
if (checked) {
|
||||||
|
curp.value = '';
|
||||||
|
curp.disabled = true;
|
||||||
|
curp.removeAttribute('required');
|
||||||
|
hidden.value = '1';
|
||||||
|
} else {
|
||||||
|
curp.disabled = false;
|
||||||
|
curp.setAttribute('required', 'required');
|
||||||
|
hidden.value = '0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -58,6 +58,99 @@
|
|||||||
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
.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; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
|
.form-control:not(.no-animation):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); }
|
||||||
|
.form-control:not(.no-animation):not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
|
||||||
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
25% { transform: translateX(-5px); }
|
||||||
|
75% { transform: translateX(5px); }
|
||||||
|
}
|
||||||
|
/* Floating labels para inputs texto */
|
||||||
|
.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; }
|
||||||
|
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
@keyframes inputPulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-gradient:not(.no-animation)::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:not(.no-animation):focus::before { left: 100%; }
|
||||||
|
.form-control.valid:not(.no-animation) { 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); }
|
||||||
|
}
|
||||||
|
.input-typing:not(.no-animation) { position: relative; }
|
||||||
|
.input-typing:not(.no-animation)::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
|
||||||
|
.input-typing:not(.no-animation):focus::after { opacity: 1; }
|
||||||
|
@keyframes blink {
|
||||||
|
0%, 50% { opacity: 1; }
|
||||||
|
51%, 100% { opacity: 0; }
|
||||||
|
}
|
||||||
|
.input-ripple:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-ripple:not(.no-animation)::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:not(.no-animation):focus::before { width: 300px; height: 300px; }
|
||||||
|
/* Animación para los campos del formulario */
|
||||||
|
.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; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
|
/* ========== ANIMACIONES 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; padding: 1rem 2.5rem 0.5rem 0.75rem; height: auto; min-height: 3.5rem; }
|
||||||
|
.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"); }
|
||||||
|
.form-select:not([value=""]):valid { 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"); }
|
||||||
|
.form-select[value=""] { border-color: #dee2e6; background-color: #fff; }
|
||||||
|
/* Floating labels para select */
|
||||||
|
.form-floating-custom .form-select ~ .form-label { position: absolute; top: 50%; left: 0.75rem; transform: translateY(-50%); pointer-events: none;
|
||||||
|
transition: all 0.3s ease; color: #6c757d; font-size: 0.875rem; background: white; padding: 0 0.25rem; z-index: 1; opacity: 0; }
|
||||||
|
.form-floating-custom .form-select:focus ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
|
.form-floating-custom .form-select:not([value=""]):valid ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
|
||||||
|
.form-select.shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
.select-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
.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%; }
|
||||||
|
.form-select.valid { border-color: #198754; background-color: #f8fff9; animation: successGlow 1s ease-in-out; }
|
||||||
|
.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"); }
|
||||||
|
.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; }
|
||||||
|
.select-scale { transition: transform 0.2s ease; }
|
||||||
|
.select-scale:hover {transform: scale(1.02); }
|
||||||
|
.select-scale:focus { transform: scale(1.02) translateY(-2px); }
|
||||||
|
.form-select option { padding: 0.5rem; transition: all 0.2s ease; }
|
||||||
|
.form-select option:hover { background-color: #f8f9fa; }
|
||||||
|
.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>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -67,41 +160,58 @@
|
|||||||
<form action="/IMPORTADORES/transportistas/actualizar" method="POST" class="card p-4 shadow-sm card-hover position-relative h-auto" id="formEditTransportista">
|
<form action="/IMPORTADORES/transportistas/actualizar" method="POST" class="card p-4 shadow-sm card-hover position-relative h-auto" id="formEditTransportista">
|
||||||
<input type="hidden" name="id_transportista" value="<?= $t['id_transportista'] ?>">
|
<input type="hidden" name="id_transportista" value="<?= $t['id_transportista'] ?>">
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label class="form-label">Clave</label>
|
<div class="form-floating-custom">
|
||||||
<input name="clave" value="<?= htmlspecialchars($t['clave_identificador']) ?>"
|
<input name="clave" value="<?= htmlspecialchars($t['clave_identificador']) ?>"
|
||||||
id="clave" class="form-control" maxlength="8" required>
|
id="clave" class="form-control input-pulse input-gradient" maxlength="8" required>
|
||||||
|
<label for="clave" class="form-label">Clave</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
|
||||||
<label class="form-label">Nombre</label>
|
|
||||||
<input name="nombre" value="<?= htmlspecialchars($t['nombre']) ?>"
|
|
||||||
id="nombre" class="form-control" required>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<label class="form-label">RFC</label>
|
|
||||||
<input name="rfc" value="<?= htmlspecialchars($t['rfc']) ?>"
|
|
||||||
id="rfc" class="form-control" maxlength="13" required>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<label class="form-label">CURP</label>
|
|
||||||
<input name="curp" value="<?= htmlspecialchars($t['curp']) ?>"
|
|
||||||
id="curp" class="form-control" maxlength="18">
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<label class="form-label">Teléfono</label>
|
|
||||||
<input name="telefono" value="<?= htmlspecialchars($t['telefono']) ?>"
|
|
||||||
id="telefono" class="form-control" maxlength="11" required>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<label class="form-label">Código caat</label>
|
|
||||||
<input name="caat" value="<?= htmlspecialchars($t['caat']) ?>"
|
|
||||||
id="caat" class="form-control" maxlength="20" required>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label class="form-label">País</label>
|
<div class="form-floating-custom">
|
||||||
<select id="pais" name="pais" class="form-select" required>
|
<input name="nombre" value="<?= htmlspecialchars($t['nombre']) ?>"
|
||||||
<option value="">Selecciona país</option>
|
id="nombre" class="form-control input-pulse input-gradient" required>
|
||||||
|
<label for="nombre" class="form-label">Nombre</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4 form-group-animated">
|
||||||
|
<div class="form-floating-custom">
|
||||||
|
<input name="rfc" value="<?= htmlspecialchars($t['rfc']) ?>"
|
||||||
|
id="rfc" class="form-control input-pulse input-gradient" maxlength="13" required>
|
||||||
|
<label for="rfc" class="form-label">RFC</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4 form-group-animated">
|
||||||
|
<div class="form-floating-custom">
|
||||||
|
<input name="curp" value="<?= htmlspecialchars($t['curp']) ?>"
|
||||||
|
id="curp" class="form-control input-pulse input-gradient" maxlength="18">
|
||||||
|
<label for="curp" class="form-label">CURP</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4 form-group-animated">
|
||||||
|
<div class="form-floating-custom">
|
||||||
|
<input name="telefono" value="<?= htmlspecialchars($t['telefono']) ?>"
|
||||||
|
id="telefono" class="form-control input-pulse input-gradient" maxlength="11" required>
|
||||||
|
<label for="telefono" class="form-label">Teléfono</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4 form-group-animated">
|
||||||
|
<div class="form-floating-custom">
|
||||||
|
<input name="caat" value="<?= htmlspecialchars($t['caat']) ?>"
|
||||||
|
id="caat" class="form-control input-pulse input-gradient" maxlength="20" required>
|
||||||
|
<label for="caat" class="form-label">Código caat</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4 form-group-animated">
|
||||||
|
<div class="form-floating-custom">
|
||||||
|
<select id="pais" name="pais" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
|
||||||
|
<option value="">-- Selecciona un País --</option>
|
||||||
<?php foreach($paises as $p): ?>
|
<?php foreach($paises as $p): ?>
|
||||||
<option value="<?= $p['id_pais'] ?>"
|
<option value="<?= $p['id_pais'] ?>"
|
||||||
<?= $p['id_pais']==$t['pais']?'selected':'' ?>>
|
<?= $p['id_pais']==$t['pais']?'selected':'' ?>>
|
||||||
@@ -109,11 +219,14 @@
|
|||||||
</option>
|
</option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
|
<label for="pais" class="form-label">País</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
</div>
|
||||||
<label class="form-label">Estado</label>
|
|
||||||
<select id="entidad" name="entidad" class="form-select" required>
|
<div class="col-md-4 form-group-animated">
|
||||||
<option value="">Selecciona estado</option>
|
<div class="form-floating-custom">
|
||||||
|
<select id="entidad" name="entidad" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
|
||||||
|
<option value="">-- Selecciona un Estado --</option>
|
||||||
<?php foreach($estados as $e): ?>
|
<?php foreach($estados as $e): ?>
|
||||||
<option value="<?= $e['id_estado'] ?>"
|
<option value="<?= $e['id_estado'] ?>"
|
||||||
<?= $e['id_estado']==$t['entidad_federativa']?'selected':'' ?>>
|
<?= $e['id_estado']==$t['entidad_federativa']?'selected':'' ?>>
|
||||||
@@ -121,11 +234,14 @@
|
|||||||
</option>
|
</option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
|
<label for="entidad" class="form-label">Entidad</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
</div>
|
||||||
<label class="form-label">Ciudad</label>
|
|
||||||
<select id="ciudad" name="ciudad" class="form-select" required>
|
<div class="col-md-4 form-group-animated">
|
||||||
<option value="">Selecciona ciudad</option>
|
<div class="form-floating-custom">
|
||||||
|
<select id="ciudad" name="ciudad" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
|
||||||
|
<option value="">-- Selecciona una Ciudad --</option>
|
||||||
<?php foreach($ciudades as $c): ?>
|
<?php foreach($ciudades as $c): ?>
|
||||||
<option value="<?= $c['id_ciudad'] ?>"
|
<option value="<?= $c['id_ciudad'] ?>"
|
||||||
<?= $c['id_ciudad']==$t['ciudad']?'selected':'' ?>>
|
<?= $c['id_ciudad']==$t['ciudad']?'selected':'' ?>>
|
||||||
@@ -133,14 +249,19 @@
|
|||||||
</option>
|
</option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
|
<label for="ciudad" class="form-label">Ciudad</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-12">
|
<div class="col-md-12 form-group-animated">
|
||||||
<label class="form-label">Domicilio Completo</label>
|
<div class="form-floating-custom">
|
||||||
<textarea name="domicilio" id="domicilio" class="form-control" rows="3" required><?= htmlspecialchars($t['domicilio']) ?></textarea>
|
<textarea name="domicilio" id="domicilio" class="form-control input-pulse input-gradient" rows="1" required><?= htmlspecialchars($t['domicilio']) ?></textarea>
|
||||||
|
<label for="domicilio" class="form-label">Domicilio Completo</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-end mt-4">
|
</div>
|
||||||
|
|
||||||
|
<div class="text-end mt-4 form-group-animated">
|
||||||
<button class="btn btn-success px-4 mt-auto w-auto btn-animated">💾 Guardar Cambios</button>
|
<button class="btn btn-success px-4 mt-auto w-auto btn-animated">💾 Guardar Cambios</button>
|
||||||
<a href="/IMPORTADORES/transportistas/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
<a href="/IMPORTADORES/transportistas/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -151,13 +272,9 @@
|
|||||||
document.getElementById('formEditTransportista').addEventListener('submit', function(e) {
|
document.getElementById('formEditTransportista').addEventListener('submit', function(e) {
|
||||||
e.preventDefault(); // Prevenir envío por defecto
|
e.preventDefault(); // Prevenir envío por defecto
|
||||||
|
|
||||||
const rfcInput = document.getElementById('rfc');
|
const rfc = document.getElementById('rfc').value.trim().toUpperCase();
|
||||||
const curpInput = document.getElementById('curp');
|
const curp = document.getElementById('curp').value.trim();
|
||||||
const telefonoInput = document.getElementById('telefono');
|
const telefono = document.getElementById('telefono').value.trim();
|
||||||
|
|
||||||
const rfc = rfcInput.value.trim().toUpperCase();
|
|
||||||
const curp = curpInput.value.trim();
|
|
||||||
const telefono = telefonoInput.value.trim();
|
|
||||||
const clave = document.getElementById('clave').value.trim();
|
const clave = document.getElementById('clave').value.trim();
|
||||||
const nombre = document.getElementById('nombre').value.trim();
|
const nombre = document.getElementById('nombre').value.trim();
|
||||||
const caat = document.getElementById('caat').value.trim();
|
const caat = document.getElementById('caat').value.trim();
|
||||||
@@ -248,8 +365,16 @@
|
|||||||
document.getElementById('rfc').value = rfc;
|
document.getElementById('rfc').value = rfc;
|
||||||
document.getElementById('curp').value = curp;
|
document.getElementById('curp').value = curp;
|
||||||
|
|
||||||
// Enviar el formulario
|
// Si todas las validaciones son correctas: Enviar el formulario
|
||||||
this.submit();
|
this.submit();
|
||||||
|
// Validar campos
|
||||||
|
let isValid = true;
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Funcionalidad de selects en cascada
|
// Funcionalidad de selects en cascada
|
||||||
@@ -277,7 +402,7 @@
|
|||||||
return r.json();
|
return r.json();
|
||||||
})
|
})
|
||||||
.then(list => {
|
.then(list => {
|
||||||
estadoSelect.innerHTML = '<option value="">Selecciona estado</option>';
|
estadoSelect.innerHTML = '<option value="">-- Selecciona un Estado --</option>';
|
||||||
list.forEach(st => {
|
list.forEach(st => {
|
||||||
const option = new Option(st.nombre, st.id_estado);
|
const option = new Option(st.nombre, st.id_estado);
|
||||||
estadoSelect.add(option);
|
estadoSelect.add(option);
|
||||||
@@ -287,12 +412,7 @@
|
|||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
estadoSelect.innerHTML = '<option value="">Error al cargar</option>';
|
estadoSelect.innerHTML = '<option value="">Error al cargar</option>';
|
||||||
Swal.fire({
|
Swal.fire({ icon: 'error', title: 'Error', text: 'No se pudieron cargar los estados', confirmButtonColor: '#dc3545' });
|
||||||
icon: 'error',
|
|
||||||
title: 'Error',
|
|
||||||
text: 'No se pudieron cargar los estados',
|
|
||||||
confirmButtonColor: '#dc3545'
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -316,7 +436,7 @@
|
|||||||
return r.json();
|
return r.json();
|
||||||
})
|
})
|
||||||
.then(list => {
|
.then(list => {
|
||||||
ciudadSelect.innerHTML = '<option value="">Selecciona ciudad</option>';
|
ciudadSelect.innerHTML = '<option value="">-- Selecciona una Ciudad --</option>';
|
||||||
list.forEach(ct => {
|
list.forEach(ct => {
|
||||||
const option = new Option(ct.nombre, ct.id_ciudad);
|
const option = new Option(ct.nombre, ct.id_ciudad);
|
||||||
ciudadSelect.add(option);
|
ciudadSelect.add(option);
|
||||||
@@ -326,13 +446,186 @@
|
|||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
ciudadSelect.innerHTML = '<option value="">Error al cargar</option>';
|
ciudadSelect.innerHTML = '<option value="">Error al cargar</option>';
|
||||||
Swal.fire({
|
Swal.fire({ icon: 'error', title: 'Error', text: 'No se pudieron cargar las ciudades', confirmButtonColor: '#dc3545' });
|
||||||
icon: 'error',
|
|
||||||
title: 'Error',
|
|
||||||
text: 'No se pudieron cargar las ciudades',
|
|
||||||
confirmButtonColor: '#dc3545'
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Script para manejar las animaciones de validación
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const inputs = document.querySelectorAll('input.form-control, select.form-select');
|
||||||
|
|
||||||
|
inputs.forEach(input => {
|
||||||
|
// Validación en tiempo real
|
||||||
|
input.addEventListener('input', function() {
|
||||||
|
if (this.checkValidity()) {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
this.classList.add('valid');
|
||||||
|
} else {
|
||||||
|
this.classList.remove('valid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Efecto shake en campos inválidos
|
||||||
|
input.addEventListener('invalid', function() {
|
||||||
|
this.classList.add('shake');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Validación del formulario
|
||||||
|
document.getElementById('formEditTransportista').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let isValid = true;
|
||||||
|
const form = this;
|
||||||
|
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Si todo es válido, enviar el formulario
|
||||||
|
if (isValid) {
|
||||||
|
// Mostrar indicador de carga
|
||||||
|
const submitBtn = form.querySelector('button[type="submit"]');
|
||||||
|
const originalText = submitBtn.textContent;
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Guardando...';
|
||||||
|
|
||||||
|
// Aquí puedes enviar el formulario real
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manejo específico para selects
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const selects = document.querySelectorAll('.form-select');
|
||||||
|
|
||||||
|
selects.forEach(select => {
|
||||||
|
// Manejar cambios en el select
|
||||||
|
select.addEventListener('change', function() {
|
||||||
|
updateSelectState(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Estado inicial
|
||||||
|
updateSelectState(select);
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateSelectState(select) {
|
||||||
|
// Actualizar el atributo value para que el CSS pueda detectarlo
|
||||||
|
select.setAttribute('value', select.value);
|
||||||
|
|
||||||
|
// Agregar/quitar clase valid basado en si hay valor seleccionado
|
||||||
|
if (select.value && select.value !== '') {
|
||||||
|
select.classList.add('valid');
|
||||||
|
select.classList.remove('invalid');
|
||||||
|
} else {
|
||||||
|
select.classList.remove('valid');
|
||||||
|
// Solo agregar invalid si el campo es required y se ha intentado enviar
|
||||||
|
if (select.hasAttribute('required') && select.closest('form')?.classList.contains('was-validated')) {
|
||||||
|
select.classList.add('invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const paisSelect = document.getElementById('pais');
|
||||||
|
const estadoSelect = document.getElementById('entidad');
|
||||||
|
const ciudadSelect = document.getElementById('ciudad');
|
||||||
|
|
||||||
|
if (!paisSelect || !estadoSelect || !ciudadSelect) return;
|
||||||
|
|
||||||
|
// ✅ Remueve clases de animación/validación
|
||||||
|
function cleanVisualState(select) {
|
||||||
|
select.classList.remove('valid', 'invalid', 'shake', 'loading');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Reset de select con mensaje personalizado
|
||||||
|
function resetSelect(select, message, disabled = true) {
|
||||||
|
if (!select) return;
|
||||||
|
select.innerHTML = `<option value="">${message}</option>`;
|
||||||
|
select.disabled = disabled;
|
||||||
|
cleanVisualState(select);
|
||||||
|
updateSelectState(select);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Actualiza el estado visual según el valor
|
||||||
|
function updateSelectState(select) {
|
||||||
|
select.setAttribute('value', select.value);
|
||||||
|
if (select.value) {
|
||||||
|
select.classList.add('valid');
|
||||||
|
select.classList.remove('invalid');
|
||||||
|
} else {
|
||||||
|
select.classList.remove('valid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Listener para cambiar país
|
||||||
|
paisSelect.addEventListener('change', function () {
|
||||||
|
const pid = this.value;
|
||||||
|
|
||||||
|
resetSelect(estadoSelect, pid ? 'Cargando estados…' : 'Primero selecciona un país…');
|
||||||
|
resetSelect(ciudadSelect, 'Primero selecciona un estado…');
|
||||||
|
|
||||||
|
if (!pid) return;
|
||||||
|
|
||||||
|
// Lógica real de carga
|
||||||
|
fetch(`/IMPORTADORES/transportistas/estados?pais=${pid}`)
|
||||||
|
.then(r => r.ok ? r.json() : Promise.reject('Error al cargar'))
|
||||||
|
.then(data => {
|
||||||
|
estadoSelect.innerHTML = '<option value="">-- Selecciona un Estado --</option>';
|
||||||
|
data.forEach(e => {
|
||||||
|
const o = new Option(e.nombre, e.id_estado);
|
||||||
|
estadoSelect.add(o);
|
||||||
|
});
|
||||||
|
estadoSelect.disabled = false;
|
||||||
|
updateSelectState(estadoSelect);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
resetSelect(estadoSelect, 'Error al cargar estados');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ✅ Listener para cambiar estado
|
||||||
|
estadoSelect.addEventListener('change', function () {
|
||||||
|
const eid = this.value;
|
||||||
|
resetSelect(ciudadSelect, eid ? 'Cargando ciudades…' : 'Primero selecciona un estado…');
|
||||||
|
|
||||||
|
if (!eid) return;
|
||||||
|
|
||||||
|
fetch(`/IMPORTADORES/transportistas/ciudades?estado=${eid}`)
|
||||||
|
.then(r => r.ok ? r.json() : Promise.reject('Error al cargar'))
|
||||||
|
.then(data => {
|
||||||
|
ciudadSelect.innerHTML = '<option value="">-- Selecciona una Ciudad --</option>';
|
||||||
|
data.forEach(c => {
|
||||||
|
const o = new Option(c.nombre, c.id_ciudad);
|
||||||
|
ciudadSelect.add(o);
|
||||||
|
});
|
||||||
|
ciudadSelect.disabled = false;
|
||||||
|
updateSelectState(ciudadSelect);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
resetSelect(ciudadSelect, 'Error al cargar ciudades');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ✅ Actualizar ciudad visual
|
||||||
|
ciudadSelect.addEventListener('change', function () {
|
||||||
|
updateSelectState(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ✅ Aplicar estado visual inicial
|
||||||
|
[paisSelect, estadoSelect, ciudadSelect].forEach(select => {
|
||||||
|
updateSelectState(select);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -64,8 +64,8 @@
|
|||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">🚚 Mis Transportistas</h4>
|
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">🚚 Mis Transportistas</h4>
|
||||||
<a href="/IMPORTADORES/transportistas/alta" class="btn btn-success mb-3 card-hover position-relative h-auto mt-auto w-auto btn-animated">➕ Nuevo Transportista</a>
|
<a href="/IMPORTADORES/transportistas/alta" class="btn btn-success mb-3 mt-auto w-auto btn-animated">➕ Nuevo Transportista</a>
|
||||||
<div class="card p-3 shadow-sm">
|
<div class="card p-3 shadow-sm card-hover position-relative h-auto">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table id="transportistas-table" class="display nowrap" style="width:100%">
|
<table id="transportistas-table" class="display nowrap" style="width:100%">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -145,6 +145,9 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<?php if (isset($_GET['created']) && $_GET['created']==='ok'): ?>
|
||||||
|
Swal.fire({ icon: 'success', title: 'Transportista creado', text: 'El transportista se creo correctamente.', confirmButtonColor: '#198754' });
|
||||||
|
<?php endif; ?>
|
||||||
// Mostrar alert de “borrado” al volver de la acción
|
// Mostrar alert de “borrado” al volver de la acción
|
||||||
<?php if (isset($_GET['deleted']) && $_GET['deleted']==='ok'): ?>
|
<?php if (isset($_GET['deleted']) && $_GET['deleted']==='ok'): ?>
|
||||||
Swal.fire({ icon: 'success', title: 'Transportista eliminado', text: 'Ya no aparecerá en tu lista.', confirmButtonColor: '#198754' });
|
Swal.fire({ icon: 'success', title: 'Transportista eliminado', text: 'Ya no aparecerá en tu lista.', confirmButtonColor: '#198754' });
|
||||||
|
|||||||
Reference in New Issue
Block a user