Tabla empleados
sql
Copy
CREATE TABLE empleados (
id INT AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(100) NOT NULL,
departamento VARCHAR(100) NOT NULL,
cargo VARCHAR(100) NOT NULL,
estatus ENUM('activo', 'inactivo') DEFAULT 'activo'
);
Tabla horarios
sql
Copy
CREATE TABLE horarios (
id INT AUTO_INCREMENT PRIMARY KEY,
empleado_id INT,
hora_entrada TIME NOT NULL,
hora_salida TIME NOT NULL,
FOREIGN KEY (empleado_id) REFERENCES empleados(id)
);
Tabla asistencia
sql
Copy
CREATE TABLE asistencia (
id INT AUTO_INCREMENT PRIMARY KEY,
empleado_id INT,
fecha DATE NOT NULL,
hora_entrada TIME,
hora_salida TIME,
estatus ENUM('asistio', 'tarde', 'falto') DEFAULT 'falto',
FOREIGN KEY (empleado_id) REFERENCES empleados(id)
);
Crea un archivo includes/[Link] para manejar la conexión a la base de datos:
php
Copy
<?php
$host = 'localhost';
$dbname = 'asistencia_empleados';
$user = 'root';
$pass = '';
try {
$conn = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo "Error de conexión: " . $e->getMessage();
}
?>
Crea un archivo [Link] para el menú principal:
php
Copy
<?php include 'includes/[Link]'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Asistencia de Empleados</title>
<link href="[Link]
rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="text-center my-4">Sistema de Asistencia</h1>
<nav class="nav justify-content-center">
<a href="[Link]" class="nav-link">Administración</a>
<a href="modulos/[Link]" class="nav-link">Registrar Asistencia</a>
<a href="modulos/[Link]" class="nav-link">Reportes</a>
</nav>
</div>
</body>
</html>
Crea un archivo [Link] para el menú principal:
php
Copy
<?php include 'includes/[Link]'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Asistencia de Empleados</title>
<link href="[Link]
rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="text-center my-4">Sistema de Asistencia</h1>
<nav class="nav justify-content-center">
<a href="[Link]" class="nav-link">Administración</a>
<a href="modulos/[Link]" class="nav-link">Registrar Asistencia</a>
<a href="modulos/[Link]" class="nav-link">Reportes</a>
</nav>
</div>
</body>
</html>
Crea un archivo [Link] para el área administrativa:
php
Copy
<?php include 'includes/[Link]'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Administración</title>
<link href="[Link]
rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="text-center my-4">Administración</h1>
<div class="row">
<div class="col-md-4">
<a href="modulos/listado_personal.php" class="btn btn-primary w-100 mb-
3">Listado de Personal</a>
</div>
<div class="col-md-4">
<a href="modulos/[Link]" class="btn btn-primary w-100 mb-
3">Horarios</a>
</div>
<div class="col-md-4">
<a href="modulos/[Link]" class="btn btn-primary w-100 mb-
3">Asistencia</a>
</div>
</div>
</div>
</body>
</html>
Listado de Personal (modulos/listado_personal.php)
php
Copy
<?php include '../includes/[Link]'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Listado de Personal</title>
<link href="[Link]
rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="text-center my-4">Listado de Personal</h1>
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Nombre</th>
<th>Departamento</th>
<th>Cargo</th>
<th>Estatus</th>
</tr>
</thead>
<tbody>
<?php
$stmt = $conn->query("SELECT * FROM empleados");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "<tr>
<td>{$row['id']}</td>
<td>{$row['nombre']}</td>
<td>{$row['departamento']}</td>
<td>{$row['cargo']}</td>
<td>{$row['estatus']}</td>
</tr>";
}
?>
</tbody>
</table>
</div>
</body>
</html>
Código para modulos/[Link]:
php
Copy
<?php include '../includes/[Link]'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Registrar Asistencia</title>
<link href="[Link]
rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="text-center my-4">Registrar Asistencia</h1>
<form method="POST" action="">
<div class="mb-3">
<label for="empleado_id" class="form-label">Empleado</label>
<select class="form-select" id="empleado_id" name="empleado_id" required>
<?php
$stmt = $conn->query("SELECT id, nombre FROM empleados WHERE estatus =
'activo'");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "<option value='{$row['id']}'>{$row['nombre']}</option>";
}
?>
</select>
</div>
<div class="mb-3">
<label for="hora_entrada" class="form-label">Hora de Entrada</label>
<input type="time" class="form-control" id="hora_entrada"
name="hora_entrada" required>
</div>
<button type="submit" class="btn btn-primary" name="registrar">Registrar
Asistencia</button>
</form>
<?php
if (isset($_POST['registrar'])) {
$empleado_id = $_POST['empleado_id'];
$hora_entrada = $_POST['hora_entrada'];
$fecha = date('Y-m-d');
// Obtener la hora de entrada esperada
$stmt = $conn->prepare("SELECT hora_entrada FROM horarios WHERE empleado_id
= ?");
$stmt->execute([$empleado_id]);
$horario = $stmt->fetch(PDO::FETCH_ASSOC);
if ($horario) {
$hora_esperada = $horario['hora_entrada'];
$estatus = 'asistio';
// Comparar horas
if ($hora_entrada > $hora_esperada) {
$estatus = 'tarde';
} elseif ($hora_entrada < $hora_esperada) {
$estatus = 'temprano';
}
// Registrar asistencia
$stmt = $conn->prepare("INSERT INTO asistencia (empleado_id, fecha,
hora_entrada, estatus) VALUES (?, ?, ?, ?)");
$stmt->execute([$empleado_id, $fecha, $hora_entrada, $estatus]);
echo "<div class='alert alert-success mt-3'>Asistencia registrada:
{$estatus}</div>";
} else {
echo "<div class='alert alert-danger mt-3'>No se encontró un horario para este
empleado.</div>";
}
}
?>
</div>
</body>
</html>
Código para modulos/[Link]:
php
Copy
<?php include '../includes/[Link]'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reportes de Asistencia</title>
<link href="[Link]
rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="text-center my-4">Reportes de Asistencia</h1>
<form method="POST" action="">
<div class="mb-3">
<label for="fecha" class="form-label">Seleccionar Fecha</label>
<input type="date" class="form-control" id="fecha" name="fecha" required>
</div>
<button type="submit" class="btn btn-primary" name="generar">Generar
Reporte</button>
</form>
<?php
if (isset($_POST['generar'])) {
$fecha = $_POST['fecha'];
// Obtener la lista de empleados
$stmt = $conn->query("SELECT id, nombre FROM empleados WHERE estatus =
'activo'");
$empleados = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo "<h2 class='mt-4'>Reporte del {$fecha}</h2>";
echo "<table class='table table-bordered'>
<thead>
<tr>
<th>Empleado</th>
<th>Estatus</th>
</tr>
</thead>
<tbody>";
foreach ($empleados as $empleado) {
$empleado_id = $empleado['id'];
$nombre = $empleado['nombre'];
// Verificar asistencia
$stmt = $conn->prepare("SELECT estatus FROM asistencia WHERE empleado_id =
? AND fecha = ?");
$stmt->execute([$empleado_id, $fecha]);
$asistencia = $stmt->fetch(PDO::FETCH_ASSOC);
$estatus = $asistencia ? $asistencia['estatus'] : 'falto';
echo "<tr>
<td>{$nombre}</td>
<td>{$estatus}</td>
</tr>";
}
echo "</tbody></table>";
}
?>
</div>
</body>
</html>
Código para [Link]:
php
Copy
<?php
session_start();
include 'includes/[Link]';
if (isset($_POST['login'])) {
$usuario = $_POST['usuario'];
$contrasena = $_POST['contrasena'];
// Verificar credenciales (usuario: admin, contraseña: admin123)
if ($usuario === 'admin' && $contrasena === 'admin123') {
$_SESSION['admin'] = true;
header('Location: [Link]');
exit();
} else {
echo "<div class='alert alert-danger'>Credenciales incorrectas.</div>";
}
}
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<link href="[Link]
rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="text-center my-4">Login</h1>
<form method="POST" action="">
<div class="mb-3">
<label for="usuario" class="form-label">Usuario</label>
<input type="text" class="form-control" id="usuario" name="usuario" required>
</div>
<div class="mb-3">
<label for="contrasena" class="form-label">Contraseña</label>
<input type="password" class="form-control" id="contrasena"
name="contrasena" required>
</div>
<button type="submit" class="btn btn-primary" name="login">Iniciar
Sesión</button>
</form>
</div>
</body>
</html>
Proteger el Área Administrativa ([Link]):
php
Copy
<?php
session_start();
if (!isset($_SESSION['admin'])) {
header('Location: [Link]');
exit();
}
include 'includes/[Link]';
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Administración</title>
<link href="[Link]
rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="text-center my-4">Administración</h1>
<div class="row">
<div class="col-md-4">
<a href="modulos/listado_personal.php" class="btn btn-primary w-100 mb-
3">Listado de Personal</a>
</div>
<div class="col-md-4">
<a href="modulos/[Link]" class="btn btn-primary w-100 mb-
3">Horarios</a>
</div>
<div class="col-md-4">
<a href="modulos/[Link]" class="btn btn-primary w-100 mb-
3">Asistencia</a>
</div>
</div>
<a href="[Link]" class="btn btn-danger mt-3">Cerrar Sesión</a>
</div>
</body>
</html>
Cerrar Sesión ([Link]):
php
Copy
<?php
session_start();
session_destroy();
header('Location: [Link]');
exit();
?>
En cada archivo HTML, incluye los estilos de Bootstrap y el archivo [Link]:
html
Copy
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Título de la Página</title>
<link href="[Link]
rel="stylesheet">
<link href="../css/[Link]" rel="stylesheet">
</head>
<body>
<!-- Contenido de la página -->
</body>
</html>
Run HTML
2. Mejoras en el Formulario de Asistencia
Agregaremos validaciones en tiempo real usando JavaScript.
Código Actualizado para modulos/[Link]:
php
Copy
<?php include '../includes/[Link]'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Registrar Asistencia</title>
<link href="[Link]
rel="stylesheet">
<link href="../css/[Link]" rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="text-center my-4">Registrar Asistencia</h1>
<form method="POST" action="" onsubmit="return validarFormulario()">
<div class="mb-3">
<label for="empleado_id" class="form-label">Empleado</label>
<select class="form-select" id="empleado_id" name="empleado_id" required>
<?php
$stmt = $conn->query("SELECT id, nombre FROM empleados WHERE estatus =
'activo'");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "<option value='{$row['id']}'>{$row['nombre']}</option>";
}
?>
</select>
</div>
<div class="mb-3">
<label for="hora_entrada" class="form-label">Hora de Entrada</label>
<input type="time" class="form-control" id="hora_entrada"
name="hora_entrada" required>
</div>
<button type="submit" class="btn btn-primary" name="registrar">Registrar
Asistencia</button>
</form>
<?php
if (isset($_POST['registrar'])) {
$empleado_id = $_POST['empleado_id'];
$hora_entrada = $_POST['hora_entrada'];
$fecha = date('Y-m-d');
// Obtener la hora de entrada esperada
$stmt = $conn->prepare("SELECT hora_entrada FROM horarios WHERE empleado_id
= ?");
$stmt->execute([$empleado_id]);
$horario = $stmt->fetch(PDO::FETCH_ASSOC);
if ($horario) {
$hora_esperada = $horario['hora_entrada'];
$estatus = 'asistio';
// Comparar horas
if ($hora_entrada > $hora_esperada) {
$estatus = 'tarde';
} elseif ($hora_entrada < $hora_esperada) {
$estatus = 'temprano';
}
// Registrar asistencia
$stmt = $conn->prepare("INSERT INTO asistencia (empleado_id, fecha,
hora_entrada, estatus) VALUES (?, ?, ?, ?)");
$stmt->execute([$empleado_id, $fecha, $hora_entrada, $estatus]);
echo "<div class='alert alert-success mt-3'>Asistencia registrada:
{$estatus}</div>";
} else {
echo "<div class='alert alert-danger mt-3'>No se encontró un horario para este
empleado.</div>";
}
}
?>
</div>
<script>
function validarFormulario() {
const horaEntrada = [Link]('hora_entrada').value;
if (!horaEntrada) {
alert('Por favor, ingresa la hora de entrada.');
return false;
}
return true;
}
</script>
</body>
</html>
3. Mejoras en el Reporte de Asistencia
Agregaremos un filtro por fecha y un botón para descargar el reporte en
formato CSV.
Código Actualizado para modulos/[Link]:
php
Copy
<?php include '../includes/[Link]'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reportes de Asistencia</title>
<link href="[Link]
rel="stylesheet">
<link href="../css/[Link]" rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="text-center my-4">Reportes de Asistencia</h1>
<form method="POST" action="">
<div class="mb-3">
<label for="fecha" class="form-label">Seleccionar Fecha</label>
<input type="date" class="form-control" id="fecha" name="fecha" required>
</div>
<button type="submit" class="btn btn-primary" name="generar">Generar
Reporte</button>
<button type="submit" class="btn btn-success" name="descargar">Descargar
CSV</button>
</form>
<?php
if (isset($_POST['generar']) || isset($_POST['descargar'])) {
$fecha = $_POST['fecha'];
// Obtener la lista de empleados
$stmt = $conn->query("SELECT id, nombre FROM empleados WHERE estatus =
'activo'");
$empleados = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (isset($_POST['descargar'])) {
// Generar archivo CSV
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="reporte_asistencia_' . $fecha
. '.csv"');
$output = fopen('php://output', 'w');
fputcsv($output, ['Empleado', 'Estatus']);
foreach ($empleados as $empleado) {
$empleado_id = $empleado['id'];
$nombre = $empleado['nombre'];
// Verificar asistencia
$stmt = $conn->prepare("SELECT estatus FROM asistencia WHERE
empleado_id = ? AND fecha = ?");
$stmt->execute([$empleado_id, $fecha]);
$asistencia = $stmt->fetch(PDO::FETCH_ASSOC);
$estatus = $asistencia ? $asistencia['estatus'] : 'falto';
fputcsv($output, [$nombre, $estatus]);
}
fclose($output);
exit();
}
echo "<h2 class='mt-4'>Reporte del {$fecha}</h2>";
echo "<table class='table table-bordered'>
<thead>
<tr>
<th>Empleado</th>
<th>Estatus</th>
</tr>
</thead>
<tbody>";
foreach ($empleados as $empleado) {
$empleado_id = $empleado['id'];
$nombre = $empleado['nombre'];
// Verificar asistencia
$stmt = $conn->prepare("SELECT estatus FROM asistencia WHERE empleado_id =
? AND fecha = ?");
$stmt->execute([$empleado_id, $fecha]);
$asistencia = $stmt->fetch(PDO::FETCH_ASSOC);
$estatus = $asistencia ? $asistencia['estatus'] : 'falto';
echo "<tr>
<td>{$nombre}</td>
<td>{$estatus}</td>
</tr>";
}
echo "</tbody></table>";
}
?>
</div>
</body>
</html>
4. Mejoras en el Login
Agregaremos un diseño moderno al formulario de login.
Código Actualizado para [Link]:
php
Copy
<?php
session_start();
include 'includes/[Link]';
if (isset($_POST['login'])) {
$usuario = $_POST['usuario'];
$contrasena = $_POST['contrasena'];
// Verificar credenciales (usuario: admin, contraseña: admin123)
if ($usuario === 'admin' && $contrasena === 'admin123') {
$_SESSION['admin'] = true;
header('Location: [Link]');
exit();
} else {
echo "<div class='alert alert-danger'>Credenciales incorrectas.</div>";
}
}
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<link href="[Link]
rel="stylesheet">
<link href="css/[Link]" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card mt-5">
<div class="card-body">
<h1 class="text-center">Login</h1>
<form method="POST" action="">
<div class="mb-3">
<label for="usuario" class="form-label">Usuario</label>
<input type="text" class="form-control" id="usuario" name="usuario"
required>
</div>
<div class="mb-3">
<label for="contrasena" class="form-label">Contraseña</label>
<input type="password" class="form-control" id="contrasena"
name="contrasena" required>
</div>
<button type="submit" class="btn btn-primary w-100"
name="login">Iniciar Sesión</button>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>