Vista información general

This commit is contained in:
2025-05-19 12:18:02 -06:00
parent 35b18f5808
commit 8b1e3a2810
7 changed files with 384 additions and 103 deletions

View File

@@ -1,5 +1,4 @@
<?php <?php
session_start(); session_start();
require_once __DIR__ . '/../../vendor/autoload.php'; require_once __DIR__ . '/../../vendor/autoload.php';
@@ -9,13 +8,11 @@ require_once __DIR__ . '/../helpers/crypto.php';
require_once __DIR__ . '/../helpers/bitacoras.php'; require_once __DIR__ . '/../helpers/bitacoras.php';
require_once __DIR__ . '/../helpers/env.php'; require_once __DIR__ . '/../helpers/env.php';
use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception; use PHPMailer\PHPMailer\Exception;
loadEnv(); loadEnv();
function dashboard() { function dashboard() {
if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'agente_aduanal') { if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'agente_aduanal') {
header("Location: /IMPORTADORES/login"); header("Location: /IMPORTADORES/login");
@@ -31,8 +28,6 @@ function dashboard() {
include __DIR__ . '/../../views/agentes/dashboard.php'; include __DIR__ . '/../../views/agentes/dashboard.php';
} }
function importadores_activos() { function importadores_activos() {
if (!($_SESSION['usuario_id'] ?? false) || $_SESSION['tipo_usuario'] !== 'agente_aduanal') { if (!($_SESSION['usuario_id'] ?? false) || $_SESSION['tipo_usuario'] !== 'agente_aduanal') {
header('Location: /IMPORTADORES/login'); header('Location: /IMPORTADORES/login');
@@ -55,7 +50,6 @@ function importadores_activos() {
include __DIR__ . '/../../views/agentes/importadores_activos.php'; include __DIR__ . '/../../views/agentes/importadores_activos.php';
} }
function solicitudes_pendientes() { function solicitudes_pendientes() {
if (!($_SESSION['usuario_id'] ?? false) || $_SESSION['tipo_usuario'] !== 'agente_aduanal') { if (!($_SESSION['usuario_id'] ?? false) || $_SESSION['tipo_usuario'] !== 'agente_aduanal') {
header('Location: /IMPORTADORES/login'); header('Location: /IMPORTADORES/login');
@@ -79,12 +73,8 @@ function solicitudes_pendientes() {
include __DIR__ . '/../../views/agentes/solicitudes_pendientes.php'; include __DIR__ . '/../../views/agentes/solicitudes_pendientes.php';
} }
function aprobar_solicitud() function aprobar_solicitud()
{ {
$conn = getConnection(); $conn = getConnection();
$id = $_GET['id'] ?? null; $id = $_GET['id'] ?? null;
@@ -185,7 +175,6 @@ function aprobar_solicitud()
exit; exit;
} }
function activos() { function activos() {
if (!($_SESSION['usuario_id'] ?? false)) { if (!($_SESSION['usuario_id'] ?? false)) {
@@ -214,7 +203,6 @@ function activos() {
include __DIR__ . '/../../views/agentes/importadores_activos.php'; include __DIR__ . '/../../views/agentes/importadores_activos.php';
} }
function toggle_estado() { function toggle_estado() {
@@ -253,5 +241,3 @@ function toggle_estado() {
header("Location: /IMPORTADORES/agentes/activos"); header("Location: /IMPORTADORES/agentes/activos");
exit; exit;
} }

View File

@@ -5,9 +5,34 @@ require_once __DIR__ . '/../helpers/crypto.php';
function index() function index()
{ {
$conn = getConnection();
$id_usuario = $_SESSION['usuario_id'] ?? null;
if (!$id_usuario) {
die("ID de usuario no disponible en la sesión.");
}
$sql = "SELECT * FROM informacion_general WHERE id_usuario = ?";
$params = [$id_usuario];
$stmt = sqlsrv_query($conn, $sql, $params);
if ($stmt === false) {
die(print_r(sqlsrv_errors(), true));
}
$datos = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
include __DIR__ . '/../../views/configuracion/dashboard_configuracion.php'; include __DIR__ . '/../../views/configuracion/dashboard_configuracion.php';
} }
function editar()
{
include __DIR__ . '/../../views/configuracion/editar.php';
}
function automatizaciones() function automatizaciones()
{ {
include __DIR__ . '/../../views/configuracion/automatizaciones.php'; include __DIR__ . '/../../views/configuracion/automatizaciones.php';

View File

@@ -32,9 +32,10 @@ function validar()
$emailEncrypted = encrypt($email); $emailEncrypted = encrypt($email);
// Obtenemos el usuario
$sql = "SELECT id_usuario, nombre, email, password_hash, tipo_usuario, activo $sql = "SELECT id_usuario, nombre, email, password_hash, tipo_usuario, activo
FROM usuarios_sistema FROM usuarios_sistema WHERE email = ?";
WHERE email = ?";
$stmt = sqlsrv_query($conn, $sql, [$emailEncrypted]); $stmt = sqlsrv_query($conn, $sql, [$emailEncrypted]);
if ($stmt && $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { if ($stmt && $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
@@ -54,6 +55,38 @@ function validar()
registrarBitacora($conn, $row['id_usuario'], $email, $ip, 1, 'Login exitoso'); registrarBitacora($conn, $row['id_usuario'], $email, $ip, 1, 'Login exitoso');
// Buscar RFC y teléfono desde solicitudes_importadores
$sqlSolicitudes = "SELECT rfc, phone FROM solicitudes_importadores WHERE email = ?";
$stmtSolicitudes = sqlsrv_query($conn, $sqlSolicitudes, [$email]);
if ($stmtSolicitudes && $solRow = sqlsrv_fetch_array($stmtSolicitudes, SQLSRV_FETCH_ASSOC)) {
// Desencriptar RFC
$rfc = strtoupper(decrypt(trim($solRow['rfc'])));
// Validar teléfono (ej. 123 4567890)
$telefono = trim($solRow['phone']);
if (!preg_match('/^\d{3}\s\d{7}$/', $telefono)) {
$telefono = null; // o puedes dejarlo como ''
}
}
$nombreUsuario = decrypt($row['nombre']);
$sqlCheck = "SELECT COUNT(*) AS total FROM informacion_general WHERE id_usuario = ?";
$stmtCheck = sqlsrv_query($conn, $sqlCheck, [$row['id_usuario']]);
$checkRow = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
if ($checkRow['total'] == 0) {
$sqlInsert = "INSERT INTO informacion_general (id_usuario, nombre, rfc, telefono, correo)
VALUES (?, ?, ?, ?, ?)";
$paramsInsert = [$row['id_usuario'], $nombreUsuario, $rfc, $telefono, $email];
sqlsrv_query($conn, $sqlInsert, $paramsInsert);
} else {
$sqlUpdate = "UPDATE informacion_general SET rfc = ?, telefono = ? WHERE id_usuario = ?";
$paramsUpdate = [$rfc, $telefono, $row['id_usuario']];
sqlsrv_query($conn, $sqlUpdate, $paramsUpdate);
}
// Redirección por rol // Redirección por rol
if ($row['tipo_usuario'] === 'importador') { if ($row['tipo_usuario'] === 'importador') {
header('Location: /IMPORTADORES/importadores/dashboard'); header('Location: /IMPORTADORES/importadores/dashboard');

View File

@@ -1,27 +1,20 @@
<?php <?php
require_once __DIR__ . '/../../vendor/autoload.php'; require_once __DIR__ . '/../../vendor/autoload.php';
use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception; use PHPMailer\PHPMailer\Exception;
require_once __DIR__ . '/../../config/database.php'; require_once __DIR__ . '/../../config/database.php';
function index() { function index() {
include __DIR__ . '/../../views/registro/form.php'; include __DIR__ . '/../../views/registro/form.php';
} }
require_once __DIR__ . '/../helpers/crypto.php'; require_once __DIR__ . '/../helpers/crypto.php';
require_once __DIR__ . '/../helpers/env.php'; require_once __DIR__ . '/../helpers/env.php';
loadEnv(); loadEnv();
function enviar() { function enviar() {
// Validar reCAPTCHA // Validar reCAPTCHA
$captchaResponse = $_POST['g-recaptcha-response'] ?? ''; $captchaResponse = $_POST['g-recaptcha-response'] ?? '';
@@ -82,7 +75,6 @@ function enviar() {
die("❌ Archivo inválido. Solo se permiten PDFs."); die("❌ Archivo inválido. Solo se permiten PDFs.");
} }
// Guardar archivo // Guardar archivo
$nombreArchivo = uniqid() . '_' . basename($archivo['name']); $nombreArchivo = uniqid() . '_' . basename($archivo['name']);
$rutaDestino = __DIR__ . '/../../storage/opiniones/' . $nombreArchivo; $rutaDestino = __DIR__ . '/../../storage/opiniones/' . $nombreArchivo;
@@ -100,7 +92,6 @@ function enviar() {
die(print_r(sqlsrv_errors(), true)); die(print_r(sqlsrv_errors(), true));
} }
$mail = new PHPMailer(true); $mail = new PHPMailer(true);
try { try {
@@ -123,6 +114,7 @@ try {
$mail->Subject = 'Confirmación de solicitud de registro | SIIH'; $mail->Subject = 'Confirmación de solicitud de registro | SIIH';
$fechaRegistro = date('d/m/Y H:i'); $fechaRegistro = date('d/m/Y H:i');
// Consulta configuración institucional // Consulta configuración institucional
$sqlConf = "SELECT TOP 1 * FROM configuracion_sistema"; $sqlConf = "SELECT TOP 1 * FROM configuracion_sistema";
$stmtConf = sqlsrv_query($conn, $sqlConf); $stmtConf = sqlsrv_query($conn, $sqlConf);
@@ -170,7 +162,5 @@ try {
error_log("Error al enviar correo: {$mail->ErrorInfo}"); error_log("Error al enviar correo: {$mail->ErrorInfo}");
} }
include __DIR__ . '/../../views/registro/gracias.php'; include __DIR__ . '/../../views/registro/gracias.php';
} }

23
informacion_general.txt Normal file
View File

@@ -0,0 +1,23 @@
CREATE TABLE informacion_general (
id_info INT PRIMARY KEY IDENTITY,
id_usuario INT,
clave VARCHAR(100),
tipo_identificador VARCHAR(100),
nombre NVARCHAR(255),
rfc NVARCHAR(13),
curp VARCHAR(18),
calle NVARCHAR(255),
num_exterior VARCHAR(20),
num_interior VARCHAR(20),
ciudad NVARCHAR(100),
colonia NVARCHAR(100),
pais NVARCHAR(100),
codigo_postal VARCHAR(10),
municipio NVARCHAR(100),
estado NVARCHAR(100),
telefono VARCHAR(50),
fax VARCHAR(50),
correo NVARCHAR(100),
observaciones TEXT,
FOREIGN KEY (id_usuario) REFERENCES usuarios_sistema(id_usuario)
);

View File

@@ -1,6 +1,7 @@
<?php <?php
include __DIR__ . '/../partials/sidebar_configuracion.php'; include __DIR__ . '/../partials/sidebar_configuracion.php';
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="es"> <html lang="es">
<head> <head>
@@ -86,132 +87,134 @@ include __DIR__ . '/../partials/sidebar_configuracion.php';
<div class="row mb-2"> <div class="row mb-2">
<label class="col-md-2 col-form-label">Clave:</label> <label class="col-md-2 col-form-label">Clave:</label>
<div class="col-md-3"> <div class="col-md-3">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['clave'] ?? '') ?>" readonly>
</div> </div>
<div class="col-md-1"></div> <div class="col-md-1"></div>
<label class="col-md-2 col-form-label">Tipo de identificador:</label> <label class="col-md-2 col-form-label">Tipo de identificador:</label>
<div class="col-md-4"> <div class="col-md-4">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['tipo_identificador'] ?? '') ?>" readonly>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label class="col-md-2 col-form-label">Nombre:</label> <label class="col-md-2 col-form-label">Nombre:</label>
<div class="col-md-10"> <div class="col-md-10">
<input type="text" class="form-control"> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['nombre'] ?? '') ?>" readonly>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label class="col-md-2 col-form-label">RFC:</label> <label class="col-md-2 col-form-label">RFC:</label>
<div class="col-md-3"> <div class="col-md-3">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['rfc'] ?? '') ?>" readonly>
</div> </div>
<div class="col-md-1"></div> <div class="col-md-1"></div>
<label class="col-md-1 col-form-label">CURP:</label> <label class="col-md-1 col-form-label">CURP:</label>
<div class="col-md-5"> <div class="col-md-5">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['curp'] ?? '') ?>" readonly>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label class="col-md-2 col-form-label">Calle:</label> <label class="col-md-2 col-form-label">Calle:</label>
<div class="col-md-10"> <div class="col-md-10">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['calle'] ?? '') ?>" readonly>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label class="col-md-2 col-form-label">Núm. Exterior:</label> <label class="col-md-2 col-form-label">Núm. Exterior:</label>
<div class="col-md-2"> <div class="col-md-2">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['num_exterior'] ?? '') ?>" readonly>
</div> </div>
<div class="col-md-4"></div> <div class="col-md-4"></div>
<label class="col-md-2 col-form-label">Núm. Interior:</label> <label class="col-md-2 col-form-label">Núm. Interior:</label>
<div class="col-md-2"> <div class="col-md-2">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['num_interior'] ?? '') ?>" readonly>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label class="col-md-2 col-form-label">Ciudad / Localidad:</label> <label class="col-md-2 col-form-label">Ciudad / Localidad:</label>
<div class="col-md-3"> <div class="col-md-3">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['ciudad'] ?? '') ?>" readonly>
</div> </div>
<div class="col-md-1"></div> <div class="col-md-1"></div>
<label class="col-md-1 col-form-label">Colonia:</label> <label class="col-md-1 col-form-label">Colonia:</label>
<div class="col-md-5"> <div class="col-md-5">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['colonia'] ?? '') ?>" readonly>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label class="col-md-2 col-form-label">País:</label> <label class="col-md-2 col-form-label">País:</label>
<div class="col-md-3"> <div class="col-md-3">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['pais'] ?? '') ?>" readonly>
</div> </div>
<div class="col-md-3"></div> <div class="col-md-3"></div>
<label class="col-md-2 col-form-label">Código Postal:</label> <label class="col-md-2 col-form-label">Código Postal:</label>
<div class="col-md-2"> <div class="col-md-2">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['codigo_postal'] ?? '') ?>" readonly>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label class="col-md-2 col-form-label">Municipio:</label> <label class="col-md-2 col-form-label">Municipio:</label>
<div class="col-md-4"> <div class="col-md-4">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['municipio'] ?? '') ?>" readonly>
</div> </div>
<div class="col-md-1"></div> <div class="col-md-1"></div>
<label class="col-md-1 col-form-label">Estado:</label> <label class="col-md-1 col-form-label">Estado:</label>
<div class="col-md-4"> <div class="col-md-4">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['estado'] ?? '') ?>" readonly>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label class="col-md-2 col-form-label">Teléfonos:</label> <label class="col-md-2 col-form-label">Teléfono:</label>
<div class="col-md-5"> <div class="col-md-5">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['telefono'] ?? '') ?>" readonly>
</div> </div>
<div class="col-md-1"></div> <div class="col-md-1"></div>
<label class="col-md-1 col-form-label">Fax:</label> <label class="col-md-1 col-form-label">Fax:</label>
<div class="col-md-3"> <div class="col-md-3">
<input type="text" class="form-control" value="" readonly> <input type="text" class="form-control" value="<?= htmlspecialchars($datos['fax'] ?? '') ?>" readonly>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label class="col-md-2 col-form-label">Correo:</label> <label class="col-md-2 col-form-label">Correo:</label>
<div class="col-md-10"> <div class="col-md-10">
<input type="email" class="form-control" value="" readonly> <input type="email" class="form-control" value="<?= htmlspecialchars($datos['correo'] ?? '') ?>" readonly>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label class="col-md-2 col-form-label">Observaciones:</label> <label class="col-md-2 col-form-label">Observaciones:</label>
<div class="col-md-10"> <div class="col-md-10">
<textarea class="form-control" rows="3" readonly></textarea> <textarea class="form-control" rows="3" readonly><?= htmlspecialchars($datos['observaciones'] ?? '') ?></textarea>
</div> </div>
</div> </div>
<div style="display: flex; justify-content: right;">
<a href="/IMPORTADORES/configuracion/editar" class="btn btn-success mb-3">✏️ Editar Información</a>
</div>
</form> </form>
</div> </div>
</div> </div>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,221 @@
<?php
include __DIR__ . '/../partials/sidebar_configuracion.php';
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Dashboard | Configuración</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<style>
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; /* Alineado con la altura de la navbar */
z-index: 1040; /* Asegura que esté por encima del contenido */
}
.sidebar .nav-link {
font-weight: bold;
color: white;
transition: all 0.3s ease;
}
.sidebar .nav-link:hover,
.sidebar .nav-link.active {
background-color: #495057;
color: #fff;
}
.content {
margin-top: 56px; /* Ajusta debajo de navbar */
padding: 40px 20px;
position: relative;
z-index: 1;
background-color: #f4f6f9; /* Asegura fondo uniforme */
transition: margin-left 0.3s ease;
}
.navbar {
position: fixed;
top: 0;
width: 100%;
z-index: 1050;
}
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
@media (min-width: 768px) {
.content {
margin-left: 250px; /* Ancho del sidebar */
}
}
/* En móviles, sin margen lateral */
@media (max-width: 767.98px) {
.content {
margin-left: 0;
}
.sidebar .nav-link {
font-weight: normal;
color: #343a40;
background-color: transparent;
}
.sidebar .nav-link:hover,
.sidebar .nav-link.active {
background-color: #e9ecef;
color: #212529;
}
}
.card {
border-radius: 12px;
}
label {font-weight: bold;}
</style>
</head>
<body>
<div class="content">
<h4 class="mb-4">✏️ Editar Información</h4>
<div class="card shadow-sm p-4 mb-4 bg-white">
<form>
<div class="row mb-2">
<label class="col-md-2 col-form-label">Clave:</label>
<div class="col-md-3">
<input type="text" class="form-control" value="">
</div>
<div class="col-md-1"></div>
<label class="col-md-2 col-form-label">Tipo de identificador:</label>
<div class="col-md-4">
<input type="text" class="form-control" value="">
</div>
</div>
<div class="row mb-3">
<label class="col-md-2 col-form-label">Nombre:</label>
<div class="col-md-10">
<input type="text" class="form-control" value="">
</div>
</div>
<div class="row mb-3">
<label class="col-md-2 col-form-label">RFC:</label>
<div class="col-md-3">
<input type="text" class="form-control" value="">
</div>
<div class="col-md-1"></div>
<label class="col-md-1 col-form-label">CURP:</label>
<div class="col-md-5">
<input type="text" class="form-control" value="" readonly>
</div>
</div>
<div class="row mb-3">
<label class="col-md-2 col-form-label">Calle:</label>
<div class="col-md-10">
<input type="text" class="form-control" value="">
</div>
</div>
<div class="row mb-3">
<label class="col-md-2 col-form-label">Núm. Exterior:</label>
<div class="col-md-2">
<input type="text" class="form-control" value="">
</div>
<div class="col-md-4"></div>
<label class="col-md-2 col-form-label">Núm. Interior:</label>
<div class="col-md-2">
<input type="text" class="form-control" value="">
</div>
</div>
<div class="row mb-3">
<label class="col-md-2 col-form-label">Ciudad / Localidad:</label>
<div class="col-md-3">
<input type="text" class="form-control" value="">
</div>
<div class="col-md-1"></div>
<label class="col-md-1 col-form-label">Colonia:</label>
<div class="col-md-5">
<input type="text" class="form-control" value="">
</div>
</div>
<div class="row mb-3">
<label class="col-md-2 col-form-label">País:</label>
<div class="col-md-3">
<input type="text" class="form-control" value="">
</div>
<div class="col-md-3"></div>
<label class="col-md-2 col-form-label">Código Postal:</label>
<div class="col-md-2">
<input type="text" class="form-control" value="">
</div>
</div>
<div class="row mb-3">
<label class="col-md-2 col-form-label">Municipio:</label>
<div class="col-md-4">
<input type="text" class="form-control" value="">
</div>
<div class="col-md-1"></div>
<label class="col-md-1 col-form-label">Estado:</label>
<div class="col-md-4">
<input type="text" class="form-control" value="">
</div>
</div>
<div class="row mb-3">
<label class="col-md-2 col-form-label">Teléfono:</label>
<div class="col-md-5">
<input type="text" class="form-control" value="">
</div>
<div class="col-md-1"></div>
<label class="col-md-1 col-form-label">Fax:</label>
<div class="col-md-3">
<input type="text" class="form-control" value="">
</div>
</div>
<div class="row mb-3">
<label class="col-md-2 col-form-label">Correo:</label>
<div class="col-md-10">
<input type="email" class="form-control" value="">
</div>
</div>
<div class="row mb-3">
<label class="col-md-2 col-form-label">Observaciones:</label>
<div class="col-md-10">
<textarea class="form-control" rows="3"></textarea>
</div>
</div>
<div style="display: flex; justify-content: right;">
<button type="submit" class="btn btn-primary">💾 Guardar Cambios</button>
</div>
</form>
</div>
</div>
</body>
</html>