Auto commit: 2025-11-24T23:41:00.323Z
This commit is contained in:
parent
fc7141b6a0
commit
786ed30042
2
api.php
2
api.php
@ -27,7 +27,7 @@ try {
|
|||||||
case 'get_current_locations':
|
case 'get_current_locations':
|
||||||
default:
|
default:
|
||||||
$stmt = $pdo->query(
|
$stmt = $pdo->query(
|
||||||
"SELECT t.matricula, t.modelo, lt.latitud, lt.longitud, lt.ultima_actualizacion " .
|
"SELECT t.id, t.matricula, t.modelo, lt.latitud, lt.longitud, lt.ultima_actualizacion " .
|
||||||
"FROM localizacion_taxis lt " .
|
"FROM localizacion_taxis lt " .
|
||||||
"JOIN taxis t ON lt.id_taxi = t.id " .
|
"JOIN taxis t ON lt.id_taxi = t.id " .
|
||||||
"ORDER BY lt.ultima_actualizacion DESC"
|
"ORDER BY lt.ultima_actualizacion DESC"
|
||||||
|
|||||||
298
citas.php
298
citas.php
@ -2,167 +2,253 @@
|
|||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
require_once 'header.php';
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
$message_type = '';
|
||||||
|
|
||||||
|
// --- DB Schema and Data Fetching ---
|
||||||
try {
|
try {
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
|
||||||
// Create table if it doesn't exist
|
// Add id_conductor to citas table
|
||||||
$pdo->exec("CREATE TABLE IF NOT EXISTS citas (
|
$pdo->exec("CREATE TABLE IF NOT EXISTS citas (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
fecha DATE NOT NULL,
|
title VARCHAR(255) NOT NULL,
|
||||||
hora TIME NOT NULL,
|
start_event DATETIME NOT NULL,
|
||||||
|
end_event DATETIME NOT NULL,
|
||||||
id_departamento INT NOT NULL,
|
id_departamento INT NOT NULL,
|
||||||
|
id_conductor INT,
|
||||||
lugar VARCHAR(255),
|
lugar VARCHAR(255),
|
||||||
usuarios TEXT,
|
usuarios TEXT,
|
||||||
estado VARCHAR(50) DEFAULT 'Pendiente',
|
estado VARCHAR(50) DEFAULT 'Pendiente',
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
FOREIGN KEY (id_departamento) REFERENCES departamentos(id)
|
FOREIGN KEY (id_departamento) REFERENCES departamentos(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (id_conductor) REFERENCES taxis(id) ON DELETE SET NULL
|
||||||
)");
|
)");
|
||||||
|
|
||||||
|
// Check if id_conductor column exists and add it if not
|
||||||
|
$stmt = $pdo->query("SHOW COLUMNS FROM citas LIKE 'id_conductor'");
|
||||||
|
if ($stmt->rowCount() == 0) {
|
||||||
|
$pdo->exec("ALTER TABLE citas ADD COLUMN id_conductor INT NULL AFTER id_departamento, ADD FOREIGN KEY (id_conductor) REFERENCES taxis(id) ON DELETE SET NULL;");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Fetch departments and conductors
|
||||||
|
$departamentos = $pdo->query("SELECT id, nombre FROM departamentos ORDER BY nombre")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
$conductores = $pdo->query("SELECT id, matricula FROM taxis ORDER BY matricula")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Get selected filters
|
||||||
|
$selected_depto_id = $_GET['id_departamento'] ?? null;
|
||||||
|
$selected_conductor_id = $_GET['id_conductor'] ?? null;
|
||||||
|
|
||||||
// Handle form submission
|
// Handle form submission
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_cita'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_cita'])) {
|
||||||
|
$title = $_POST['title'];
|
||||||
$fecha = $_POST['fecha'];
|
$fecha = $_POST['fecha'];
|
||||||
$hora = $_POST['hora'];
|
$hora_inicio = $_POST['hora_inicio'];
|
||||||
|
$hora_fin = $_POST['hora_fin'];
|
||||||
$id_departamento = $_POST['id_departamento'];
|
$id_departamento = $_POST['id_departamento'];
|
||||||
|
$id_conductor = $_POST['id_conductor'] ?: null;
|
||||||
$lugar = trim($_POST['lugar']);
|
$lugar = trim($_POST['lugar']);
|
||||||
$usuarios = trim($_POST['usuarios']);
|
$usuarios = trim($_POST['usuarios']);
|
||||||
$estado = $_POST['estado'];
|
$estado = $_POST['estado'];
|
||||||
|
|
||||||
if (!empty($fecha) && !empty($hora) && !empty($id_departamento)) {
|
if (!empty($title) && !empty($fecha) && !empty($hora_inicio) && !empty($hora_fin) && !empty($id_departamento)) {
|
||||||
$stmt = $pdo->prepare("INSERT INTO citas (fecha, hora, id_departamento, lugar, usuarios, estado) VALUES (?, ?, ?, ?, ?, ?)");
|
$start_event = $fecha . ' ' . $hora_inicio;
|
||||||
$stmt->execute([$fecha, $hora, $id_departamento, $lugar, $usuarios, $estado]);
|
$end_event = $fecha . ' ' . $hora_fin;
|
||||||
echo '<div class="alert alert-success" role="alert">Cita añadida con éxito.</div>';
|
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO citas (title, start_event, end_event, id_departamento, id_conductor, lugar, usuarios, estado) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||||
|
$stmt->execute([$title, $start_event, $end_event, $id_departamento, $id_conductor, $lugar, $usuarios, $estado]);
|
||||||
|
$message = '<div class="alert alert-success">Cita añadida con éxito.</div>';
|
||||||
} else {
|
} else {
|
||||||
echo '<div class="alert alert-danger" role="alert">Fecha, hora y departamento son obligatorios.</div>';
|
$message = '<div class="alert alert-danger">Título, fecha, horas y departamento son obligatorios.</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch all departments for dropdown
|
// Fetch citas for the calendar and list
|
||||||
$departamentos_stmt = $pdo->query("SELECT id, nombre FROM departamentos ORDER BY nombre");
|
$events = [];
|
||||||
$departamentos = $departamentos_stmt->fetchAll(PDO::FETCH_ASSOC);
|
$citas_list = [];
|
||||||
|
|
||||||
|
$sql = "SELECT c.id, c.title, c.start_event as start, c.end_event as end, c.estado, c.lugar, c.usuarios, c.created_at, t.matricula as conductor_nombre
|
||||||
|
FROM citas c
|
||||||
|
LEFT JOIN taxis t ON c.id_conductor = t.id
|
||||||
|
WHERE 1=1";
|
||||||
|
$params = [];
|
||||||
|
if ($selected_depto_id) {
|
||||||
|
$sql .= " AND c.id_departamento = ?";
|
||||||
|
$params[] = $selected_depto_id;
|
||||||
|
}
|
||||||
|
if ($selected_conductor_id) {
|
||||||
|
$sql .= " AND c.id_conductor = ?";
|
||||||
|
$params[] = $selected_conductor_id;
|
||||||
|
}
|
||||||
|
$sql .= " ORDER BY c.start_event DESC";
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute($params);
|
||||||
|
$citas_list = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
// Fetch all citas
|
// Format for FullCalendar
|
||||||
$stmt = $pdo->query("SELECT c.id, c.fecha, c.hora, dep.nombre as departamento_nombre, c.lugar, c.usuarios, c.estado, c.created_at
|
foreach($citas_list as $cita) {
|
||||||
FROM citas c
|
$events[] = [
|
||||||
JOIN departamentos dep ON c.id_departamento = dep.id
|
'title' => $cita['title'],
|
||||||
ORDER BY c.fecha DESC, c.hora DESC");
|
'start' => $cita['start'],
|
||||||
$citas = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
'end' => $cita['end'],
|
||||||
|
'extendedProps' => [
|
||||||
|
'estado' => $cita['estado'],
|
||||||
|
'conductor' => $cita['conductor_nombre'] ?? 'N/A'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
die("Error de base de datos: " . $e->getMessage());
|
$message = "Error de base de datos: " . $e->getMessage();
|
||||||
|
$message_type = 'danger';
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
<!-- FullCalendar CSS -->
|
||||||
|
<link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css' rel='stylesheet' />
|
||||||
|
|
||||||
<div class="container-fluid px-4">
|
<div class="container-fluid px-4">
|
||||||
<h1 class="mt-4">Citas</h1>
|
<h1 class="mt-4">Calendario de Citas</h1>
|
||||||
<ol class="breadcrumb mb-4">
|
<ol class="breadcrumb mb-4">
|
||||||
<li class="breadcrumb-item"><a href="index.php">Dashboard</a></li>
|
<li class="breadcrumb-item"><a href="index.php">Dashboard</a></li>
|
||||||
<li class="breadcrumb-item active">Citas</li>
|
<li class="breadcrumb-item active">Citas</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
<?php if ($message): ?>
|
||||||
|
<div class="alert alert-info alert-dismissible fade show" role="alert">
|
||||||
|
<?php echo $message; ?><button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header"><i class="fas fa-filter me-1"></i>Filtros</div>
|
||||||
<i class="fas fa-table me-1"></i>
|
|
||||||
Añadir Nueva Cita
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form action="citas.php" method="POST">
|
<form action="citas.php" method="GET" id="filter-form">
|
||||||
<div class="row mb-3">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="form-floating mb-3">
|
<select class="form-select" name="id_departamento" onchange="this.form.submit()">
|
||||||
<input class="form-control" id="inputFecha" type="date" name="fecha" required />
|
<option value="">Seleccione un departamento</option>
|
||||||
<label for="inputFecha">Fecha</label>
|
<?php foreach ($departamentos as $depto): ?>
|
||||||
</div>
|
<option value="<?php echo $depto['id']; ?>" <?php echo ($depto['id'] == $selected_depto_id) ? 'selected' : ''; ?>><?php echo htmlspecialchars($depto['nombre']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="form-floating mb-3">
|
<select class="form-select" name="id_conductor" onchange="this.form.submit()">
|
||||||
<input class="form-control" id="inputHora" type="time" name="hora" required />
|
<option value="">Todos los conductores</option>
|
||||||
<label for="inputHora">Hora</label>
|
<?php foreach ($conductores as $conductor): ?>
|
||||||
</div>
|
<option value="<?php echo $conductor['id']; ?>" <?php echo ($conductor['id'] == $selected_conductor_id) ? 'selected' : ''; ?>><?php echo htmlspecialchars($conductor['matricula']); ?></option>
|
||||||
</div>
|
<?php endforeach; ?>
|
||||||
</div>
|
</select>
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="form-floating mb-3">
|
|
||||||
<select class="form-select" id="selectDepartamento" name="id_departamento" required>
|
|
||||||
<option value="">Seleccione un departamento</option>
|
|
||||||
<?php foreach ($departamentos as $departamento): ?>
|
|
||||||
<option value="<?php echo $departamento['id']; ?>"><?php echo htmlspecialchars($departamento['nombre']); ?></option>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</select>
|
|
||||||
<label for="selectDepartamento">Departamento</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="form-floating mb-3">
|
|
||||||
<input class="form-control" id="inputLugar" type="text" name="lugar" placeholder="Lugar" />
|
|
||||||
<label for="inputLugar">Lugar (Lat, Lon)</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-floating mb-3">
|
|
||||||
<textarea class="form-control" id="inputUsuarios" name="usuarios" placeholder="Usuarios" style="height: 100px;"></textarea>
|
|
||||||
<label for="inputUsuarios">Usuarios</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-floating mb-3">
|
|
||||||
<select class="form-select" id="selectEstado" name="estado">
|
|
||||||
<option value="Pendiente">Pendiente</option>
|
|
||||||
<option value="Confirmada">Confirmada</option>
|
|
||||||
<option value="Cancelada">Cancelada</option>
|
|
||||||
</select>
|
|
||||||
<label for="selectEstado">Estado</label>
|
|
||||||
</div>
|
|
||||||
<div class="mt-4 mb-0">
|
|
||||||
<div class="d-grid">
|
|
||||||
<button type="submit" name="add_cita" class="btn btn-primary btn-block">Añadir Cita</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card mb-4">
|
<?php if ($selected_depto_id || $selected_conductor_id): ?>
|
||||||
<div class="card-header">
|
<div class="card mb-4">
|
||||||
<i class="fas fa-table me-1"></i>
|
<div class="card-body">
|
||||||
Lista de Citas
|
<div id='calendar'></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
|
||||||
<table id="datatablesSimple" class="table table-striped">
|
<div class="card mb-4">
|
||||||
<thead>
|
<div class="card-header"><i class="fas fa-list me-1"></i>Listado de Citas</div>
|
||||||
<tr>
|
<div class="card-body">
|
||||||
<th>ID</th>
|
<table class="table">
|
||||||
<th>Fecha y Hora</th>
|
<thead><tr><th>Título</th><th>Conductor</th><th>Inicio</th><th>Fin</th><th>Estado</th><th>Lugar</th><th>Usuarios</th></tr></thead>
|
||||||
<th>Departamento</th>
|
<tbody>
|
||||||
<th>Lugar</th>
|
<?php if(empty($citas_list)): ?>
|
||||||
<th>Usuarios</th>
|
<tr><td colspan="7" class="text-center">No hay citas para los filtros seleccionados.</td></tr>
|
||||||
<th>Estado</th>
|
<?php else: foreach($citas_list as $cita): ?>
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<?php if (!empty($citas)):
|
|
||||||
foreach ($citas as $cita):
|
|
||||||
?>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><?php echo htmlspecialchars($cita['id']); ?></td>
|
<td><?php echo htmlspecialchars($cita['title']); ?></td>
|
||||||
<td><?php echo htmlspecialchars($cita['fecha'] . ' ' . $cita['hora']); ?></td>
|
<td><?php echo htmlspecialchars($cita['conductor_nombre'] ?? 'N/A'); ?></td>
|
||||||
<td><?php echo htmlspecialchars($cita['departamento_nombre']); ?></td>
|
<td><?php echo date('d/m/Y H:i', strtotime($cita['start'])); ?></td>
|
||||||
|
<td><?php echo date('d/m/Y H:i', strtotime($cita['end'])); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($cita['estado']); ?></td>
|
||||||
<td><?php echo htmlspecialchars($cita['lugar']); ?></td>
|
<td><?php echo htmlspecialchars($cita['lugar']); ?></td>
|
||||||
<td><?php echo htmlspecialchars($cita['usuarios']); ?></td>
|
<td><?php echo htmlspecialchars($cita['usuarios']); ?></td>
|
||||||
<td><?php echo htmlspecialchars($cita['estado']); ?></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<?php
|
<?php endforeach; endif; ?>
|
||||||
endforeach;
|
</tbody>
|
||||||
else:
|
</table>
|
||||||
?>
|
</div>
|
||||||
<tr>
|
</div>
|
||||||
<td colspan="6" class="text-center">No hay citas registradas.</td>
|
<?php else: ?>
|
||||||
</tr>
|
<div class="alert alert-info">Por favor, seleccione un departamento o conductor para ver el calendario y las citas.</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</tbody>
|
|
||||||
</table>
|
<div class="card mb-4">
|
||||||
|
<div class="card-header"><i class="fas fa-plus me-1"></i>Añadir Nueva Cita</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form action="citas.php?<?php echo http_build_query($_GET); ?>" method="POST">
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input class="form-control" type="text" name="title" placeholder="Título" required />
|
||||||
|
<label>Título de la cita</label>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-4"><div class="form-floating"><input class="form-control" type="date" name="fecha" required /><label>Fecha</label></div></div>
|
||||||
|
<div class="col-md-4"><div class="form-floating"><input class="form-control" type="time" name="hora_inicio" required /><label>Hora Inicio</label></div></div>
|
||||||
|
<div class="col-md-4"><div class="form-floating"><input class="form-control" type="time" name="hora_fin" required /><label>Hora Fin</label></div></div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-6"><div class="form-floating"><select class="form-select" name="id_departamento" required>
|
||||||
|
<option value="">Seleccione departamento</option>
|
||||||
|
<?php foreach ($departamentos as $depto): ?>
|
||||||
|
<option value="<?php echo $depto['id']; ?>" <?php echo ($depto['id'] == $selected_depto_id) ? 'selected' : ''; ?>><?php echo htmlspecialchars($depto['nombre']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select><label>Departamento</label></div></div>
|
||||||
|
<div class="col-md-6"><div class="form-floating"><select class="form-select" name="id_conductor">
|
||||||
|
<option value="">Seleccione un conductor (Opcional)</option>
|
||||||
|
<?php foreach ($conductores as $conductor): ?>
|
||||||
|
<option value="<?php echo $conductor['id']; ?>" <?php echo ($conductor['id'] == $selected_conductor_id) ? 'selected' : ''; ?>><?php echo htmlspecialchars($conductor['matricula']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select><label>Conductor</label></div></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input class="form-control" type="text" name="lugar" placeholder="Lugar" />
|
||||||
|
<label>Lugar</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<textarea class="form-control" name="usuarios" placeholder="Usuarios" style="height: 80px;"></textarea>
|
||||||
|
<label>Usuarios</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3"><select class="form-select" name="estado">
|
||||||
|
<option value="Pendiente">Pendiente</option>
|
||||||
|
<option value="Confirmada">Confirmada</option>
|
||||||
|
<option value="Cancelada">Cancelada</option>
|
||||||
|
</select><label>Estado</label></div>
|
||||||
|
<div class="d-grid"><button type="submit" name="add_cita" class="btn btn-primary">Añadir Cita</button></div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- FullCalendar JS -->
|
||||||
|
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.js'></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
<?php if ($selected_depto_id || $selected_conductor_id): ?>
|
||||||
|
var calendarEl = document.getElementById('calendar');
|
||||||
|
var calendar = new FullCalendar.Calendar(calendarEl, {
|
||||||
|
initialView: 'dayGridMonth',
|
||||||
|
locale: 'es',
|
||||||
|
headerToolbar: {
|
||||||
|
left: 'prev,next today',
|
||||||
|
center: 'title',
|
||||||
|
right: 'dayGridMonth,timeGridWeek,timeGridDay'
|
||||||
|
},
|
||||||
|
events: <?php echo json_encode($events); ?>
|
||||||
|
});
|
||||||
|
calendar.render();
|
||||||
|
<?php endif; ?>
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
require_once 'footer.php';
|
require_once 'footer.php';
|
||||||
?>
|
?>
|
||||||
227
consultas.php
227
consultas.php
@ -2,53 +2,82 @@
|
|||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
require_once 'header.php';
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
$message_type = '';
|
||||||
|
|
||||||
|
// --- DB Schema and Data Fetching ---
|
||||||
try {
|
try {
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
|
||||||
// Create table if it doesn't exist
|
// Create/update consultas table
|
||||||
$pdo->exec("CREATE TABLE IF NOT EXISTS consultas (
|
$pdo->exec("CREATE TABLE IF NOT EXISTS consultas (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
id_taxista INT NOT NULL,
|
id_conductor INT NOT NULL,
|
||||||
id_departamento INT NOT NULL,
|
id_departamento INT NOT NULL,
|
||||||
|
asunto VARCHAR(255) NOT NULL,
|
||||||
resultado TEXT,
|
resultado TEXT,
|
||||||
|
status VARCHAR(50) DEFAULT 'Pendiente',
|
||||||
fecha_consulta TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
fecha_consulta TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
FOREIGN KEY (id_taxista) REFERENCES drivers(id),
|
FOREIGN KEY (id_conductor) REFERENCES taxis(id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (id_departamento) REFERENCES departamentos(id)
|
FOREIGN KEY (id_departamento) REFERENCES departamentos(id) ON DELETE CASCADE
|
||||||
)");
|
)");
|
||||||
|
|
||||||
|
// Fetch departments for dropdowns
|
||||||
|
$departamentos = $pdo->query("SELECT id, nombre FROM departamentos ORDER BY nombre")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Fetch taxis/conductores for dropdowns
|
||||||
|
$conductores = $pdo->query("SELECT id, matricula FROM taxis ORDER BY matricula")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Get selected department for filtering
|
||||||
|
$selected_depto_id = $_GET['id_departamento'] ?? null;
|
||||||
|
|
||||||
// Handle form submission
|
// Handle form submission
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_consulta'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_consulta'])) {
|
||||||
$id_taxista = $_POST['id_taxista'];
|
$id_conductor = $_POST['id_conductor'];
|
||||||
$id_departamento = $_POST['id_departamento'];
|
$id_departamento = $_POST['id_departamento'];
|
||||||
|
$asunto = trim($_POST['asunto']);
|
||||||
$resultado = trim($_POST['resultado']);
|
$resultado = trim($_POST['resultado']);
|
||||||
|
$status = $_POST['status'];
|
||||||
|
|
||||||
if (!empty($id_taxista) && !empty($id_departamento)) {
|
if (!empty($id_conductor) && !empty($id_departamento) && !empty($asunto)) {
|
||||||
$stmt = $pdo->prepare("INSERT INTO consultas (id_taxista, id_departamento, resultado) VALUES (?, ?, ?)");
|
$stmt = $pdo->prepare("INSERT INTO consultas (id_conductor, id_departamento, asunto, resultado, status) VALUES (?, ?, ?, ?, ?)");
|
||||||
$stmt->execute([$id_taxista, $id_departamento, $resultado]);
|
$stmt->execute([$id_conductor, $id_departamento, $asunto, $resultado, $status]);
|
||||||
echo '<div class="alert alert-success" role="alert">Consulta añadida con éxito.</div>';
|
$message = '<div class="alert alert-success">Consulta añadida con éxito.</div>';
|
||||||
} else {
|
} else {
|
||||||
echo '<div class="alert alert-danger" role="alert">Taxista y departamento son obligatorios.</div>';
|
$message = '<div class="alert alert-danger">Conductor, departamento y asunto son obligatorios.</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch all drivers for dropdown
|
// Fetch consultations
|
||||||
$drivers_stmt = $pdo->query("SELECT id, name FROM drivers ORDER BY name");
|
$filter_status = $_GET['status'] ?? null;
|
||||||
$drivers = $drivers_stmt->fetchAll(PDO::FETCH_ASSOC);
|
$sql = "SELECT c.id, t.matricula as conductor_nombre, dep.nombre as departamento_nombre, c.asunto, c.resultado, c.status, c.fecha_consulta
|
||||||
|
FROM consultas c
|
||||||
|
JOIN taxis t ON c.id_conductor = t.id
|
||||||
|
JOIN departamentos dep ON c.id_departamento = dep.id";
|
||||||
|
|
||||||
|
$conditions = [];
|
||||||
|
$params = [];
|
||||||
|
if ($filter_status) {
|
||||||
|
$conditions[] = "c.status = :status";
|
||||||
|
$params[':status'] = $filter_status;
|
||||||
|
}
|
||||||
|
if ($selected_depto_id) {
|
||||||
|
$conditions[] = "c.id_departamento = :id_departamento";
|
||||||
|
$params[':id_departamento'] = $selected_depto_id;
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch all departments for dropdown
|
if (count($conditions) > 0) {
|
||||||
$departamentos_stmt = $pdo->query("SELECT id, nombre FROM departamentos ORDER BY nombre");
|
$sql .= " WHERE " . implode(' AND ', $conditions);
|
||||||
$departamentos = $departamentos_stmt->fetchAll(PDO::FETCH_ASSOC);
|
}
|
||||||
|
|
||||||
// Fetch all consultas
|
$sql .= " ORDER BY c.fecha_consulta DESC";
|
||||||
$stmt = $pdo->query("SELECT c.id, d.name as taxista_nombre, dep.nombre as departamento_nombre, c.resultado, c.fecha_consulta
|
$stmt = $pdo->prepare($sql);
|
||||||
FROM consultas c
|
$stmt->execute($params);
|
||||||
JOIN drivers d ON c.id_taxista = d.id
|
|
||||||
JOIN departamentos dep ON c.id_departamento = dep.id
|
|
||||||
ORDER BY c.fecha_consulta DESC");
|
|
||||||
$consultas = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$consultas = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
die("Error de base de datos: " . $e->getMessage());
|
$message = "Error de base de datos: " . $e->getMessage();
|
||||||
|
$message_type = 'danger';
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
@ -59,85 +88,101 @@ try {
|
|||||||
<li class="breadcrumb-item active">Consultas</li>
|
<li class="breadcrumb-item active">Consultas</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
<?php if ($message): ?>
|
||||||
|
<div class="alert alert-<?php echo $message_type ? $message_type : 'info'; ?> alert-dismissible fade show" role="alert">
|
||||||
|
<?php echo $message; ?><button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header"><i class="fas fa-filter me-1"></i>Filtro por Departamento</div>
|
||||||
<i class="fas fa-table me-1"></i>
|
|
||||||
Añadir Nueva Consulta
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form action="consultas.php" method="POST">
|
<form action="consultas.php" method="GET" id="depto-select-form">
|
||||||
<div class="row mb-3">
|
<div class="input-group">
|
||||||
<div class="col-md-6">
|
<select class="form-select" name="id_departamento" onchange="this.form.submit()">
|
||||||
<div class="form-floating mb-3">
|
<option value="">Todos los departamentos</option>
|
||||||
<select class="form-select" id="selectTaxista" name="id_taxista" required>
|
<?php foreach ($departamentos as $depto): ?>
|
||||||
<option value="">Seleccione un taxista</option>
|
<option value="<?php echo $depto['id']; ?>" <?php echo ($depto['id'] == $selected_depto_id) ? 'selected' : ''; ?>><?php echo htmlspecialchars($depto['nombre']); ?></option>
|
||||||
<?php foreach ($drivers as $driver): ?>
|
<?php endforeach; ?>
|
||||||
<option value="<?php echo $driver['id']; ?>"><?php echo htmlspecialchars($driver['name']); ?></option>
|
</select>
|
||||||
<?php endforeach; ?>
|
<?php if($filter_status): ?>
|
||||||
</select>
|
<input type="hidden" name="status" value="<?php echo htmlspecialchars($filter_status); ?>" />
|
||||||
<label for="selectTaxista">Taxista</label>
|
<?php endif; ?>
|
||||||
</div>
|
<a href="consultas.php" class="btn btn-outline-secondary">Limpiar</a>
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="form-floating mb-3">
|
|
||||||
<select class="form-select" id="selectDepartamento" name="id_departamento" required>
|
|
||||||
<option value="">Seleccione un departamento</option>
|
|
||||||
<?php foreach ($departamentos as $departamento): ?>
|
|
||||||
<option value="<?php echo $departamento['id']; ?>"><?php echo htmlspecialchars($departamento['nombre']); ?></option>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</select>
|
|
||||||
<label for="selectDepartamento">Departamento</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-floating mb-3">
|
|
||||||
<textarea class="form-control" id="inputResultado" name="resultado" placeholder="Resultado de la consulta" style="height: 100px;"></textarea>
|
|
||||||
<label for="inputResultado">Resultado</label>
|
|
||||||
</div>
|
|
||||||
<div class="mt-4 mb-0">
|
|
||||||
<div class="d-grid">
|
|
||||||
<button type="submit" name="add_consulta" class="btn btn-primary btn-block">Añadir Consulta</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header"><i class="fas fa-plus me-1"></i>Añadir Nueva Consulta</div>
|
||||||
<i class="fas fa-table me-1"></i>
|
|
||||||
Lista de Consultas
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<table id="datatablesSimple" class="table table-striped">
|
<form action="consultas.php" method="POST">
|
||||||
<thead>
|
<div class="form-floating mb-3">
|
||||||
<tr>
|
<input class="form-control" id="inputAsunto" type="text" name="asunto" placeholder="Asunto" required />
|
||||||
<th>ID</th>
|
<label for="inputAsunto">Asunto</label>
|
||||||
<th>Taxista</th>
|
</div>
|
||||||
<th>Departamento</th>
|
<div class="row mb-3">
|
||||||
<th>Resultado</th>
|
<div class="col-md-6">
|
||||||
<th>Fecha</th>
|
<div class="form-floating mb-3">
|
||||||
</tr>
|
<select class="form-select" name="id_conductor" required>
|
||||||
</thead>
|
<option value="">Seleccione un conductor</option>
|
||||||
|
<?php foreach ($conductores as $conductor): ?>
|
||||||
|
<option value="<?php echo $conductor['id']; ?>"><?php echo htmlspecialchars($conductor['matricula']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<label>Conductor</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<select class="form-select" name="id_departamento" required>
|
||||||
|
<option value="">Seleccione un departamento</option>
|
||||||
|
<?php foreach ($departamentos as $depto): ?>
|
||||||
|
<option value="<?php echo $depto['id']; ?>"><?php echo htmlspecialchars($depto['nombre']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<label>Departamento</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<textarea class="form-control" name="resultado" placeholder="Resultado" style="height: 100px;"></textarea>
|
||||||
|
<label>Resultado</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<select class="form-select" name="status">
|
||||||
|
<option value="Pendiente">Pendiente</option>
|
||||||
|
<option value="En Progreso">En Progreso</option>
|
||||||
|
<option value="Resuelta">Resuelta</option>
|
||||||
|
</select>
|
||||||
|
<label>Estado</label>
|
||||||
|
</div>
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" name="add_consulta" class="btn btn-primary">Añadir Consulta</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header"><i class="fas fa-table me-1"></i>Lista de Consultas</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead><tr><th>Conductor</th><th>Departamento</th><th>Asunto</th><th>Resultado</th><th>Estado</th><th>Fecha</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php if (!empty($consultas)):
|
<?php if (empty($consultas)): ?>
|
||||||
foreach ($consultas as $consulta):
|
<tr><td colspan="6" class="text-center">No hay consultas.</td></tr>
|
||||||
?>
|
<?php else: foreach ($consultas as $consulta): ?>
|
||||||
<tr>
|
|
||||||
<td><?php echo htmlspecialchars($consulta['id']); ?></td>
|
|
||||||
<td><?php echo htmlspecialchars($consulta['taxista_nombre']); ?></td>
|
|
||||||
<td><?php echo htmlspecialchars($consulta['departamento_nombre']); ?></td>
|
|
||||||
<td><?php echo htmlspecialchars($consulta['resultado']); ?></td>
|
|
||||||
<td><?php echo htmlspecialchars($consulta['fecha_consulta']); ?></td>
|
|
||||||
</tr>
|
|
||||||
<?php
|
|
||||||
endforeach;
|
|
||||||
else:
|
|
||||||
?>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="5" class="text-center">No hay consultas registradas.</td>
|
<td><?php echo htmlspecialchars($consulta['conductor_nombre']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($consulta['departamento_nombre']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($consulta['asunto']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($consulta['resultado']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($consulta['status']); ?></td>
|
||||||
|
<td><?php echo date("d/m/Y H:i", strtotime($consulta['fecha_consulta'])); ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endif; ?>
|
<?php endforeach; endif; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,114 +1,160 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
require_once 'header.php';
|
|
||||||
|
|
||||||
|
// --- DB Schema and Logic ---
|
||||||
try {
|
try {
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
// Create departments table
|
||||||
// Create table if it doesn't exist
|
|
||||||
$pdo->exec("CREATE TABLE IF NOT EXISTS departamentos (
|
$pdo->exec("CREATE TABLE IF NOT EXISTS departamentos (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
nombre VARCHAR(255) NOT NULL,
|
nombre VARCHAR(255) NOT NULL UNIQUE
|
||||||
color VARCHAR(7) DEFAULT '#FFFFFF',
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
||||||
)");
|
|
||||||
|
|
||||||
// Handle form submission
|
$message = '';
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_department'])) {
|
// Handle POST requests
|
||||||
$nombre = trim($_POST['nombre']);
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$color = trim($_POST['color']);
|
// Add new
|
||||||
|
if (isset($_POST['add_departamento'])) {
|
||||||
if (!empty($nombre)) {
|
$nombre = trim($_POST['nombre']);
|
||||||
$stmt = $pdo->prepare("INSERT INTO departamentos (nombre, color) VALUES (?, ?)");
|
if (!empty($nombre)) {
|
||||||
$stmt->execute([$nombre, $color]);
|
$stmt = $pdo->prepare("INSERT INTO departamentos (nombre) VALUES (?)");
|
||||||
echo '<div class="alert alert-success" role="alert">Departamento añadido con éxito.</div>';
|
$stmt->execute([$nombre]);
|
||||||
} else {
|
$message = '<div class="alert alert-success">Departamento añadido.</div>';
|
||||||
echo '<div class="alert alert-danger" role="alert">El nombre del departamento es obligatorio.</div>';
|
} else {
|
||||||
|
$message = '<div class="alert alert-danger">El nombre no puede estar vacío.</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update
|
||||||
|
elseif (isset($_POST['update_departamento'])) {
|
||||||
|
$id = $_POST['id'];
|
||||||
|
$nombre = trim($_POST['nombre']);
|
||||||
|
if (!empty($nombre)) {
|
||||||
|
$stmt = $pdo->prepare("UPDATE departamentos SET nombre = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$nombre, $id]);
|
||||||
|
$message = '<div class="alert alert-success">Departamento actualizado.</div>';
|
||||||
|
} else {
|
||||||
|
$message = '<div class="alert alert-danger">El nombre no puede estar vacío.</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Delete
|
||||||
|
elseif (isset($_POST['delete_departamento'])) {
|
||||||
|
$id = $_POST['id'];
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM departamentos WHERE id = ?");
|
||||||
|
$stmt->execute([$id]);
|
||||||
|
$message = '<div class="alert alert-warning">Departamento eliminado.</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch all departments
|
// Fetch all departments
|
||||||
$stmt = $pdo->query("SELECT id, nombre, color, created_at FROM departamentos ORDER BY created_at DESC");
|
$departamentos = $pdo->query("SELECT * FROM departamentos ORDER BY nombre")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
$departamentos = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
die("Error de base de datos: " . $e->getMessage());
|
die("DB ERROR: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
include 'header.php';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="container-fluid px-4">
|
<div class="container-fluid px-4">
|
||||||
<h1 class="mt-4">Departamentos</h1>
|
<h1 class="mt-4">Gestión de Departamentos</h1>
|
||||||
<ol class="breadcrumb mb-4">
|
<ol class="breadcrumb mb-4">
|
||||||
<li class="breadcrumb-item"><a href="index.php">Dashboard</a></li>
|
<li class="breadcrumb-item"><a href="index.php">Dashboard</a></li>
|
||||||
<li class="breadcrumb-item active">Departamentos</li>
|
<li class="breadcrumb-item active">Departamentos</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<div class="card mb-4">
|
<?php echo $message; ?>
|
||||||
<div class="card-header">
|
|
||||||
<i class="fas fa-table me-1"></i>
|
|
||||||
Añadir Nuevo Departamento
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<form action="departamentos.php" method="POST">
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="form-floating mb-3 mb-md-0">
|
|
||||||
<input class="form-control" id="inputNombre" type="text" name="nombre" placeholder="Nombre del departamento" required />
|
|
||||||
<label for="inputNombre">Nombre del departamento</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="form-floating">
|
|
||||||
<input class="form-control" id="inputColor" type="color" name="color" value="#FFFFFF" />
|
|
||||||
<label for="inputColor">Color</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mt-4 mb-0">
|
|
||||||
<div class="d-grid">
|
|
||||||
<button type="submit" name="add_department" class="btn btn-primary btn-block">Añadir Departamento</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card mb-4">
|
<div class="row">
|
||||||
<div class="card-header">
|
<!-- Add Department Form -->
|
||||||
<i class="fas fa-table me-1"></i>
|
<div class="col-xl-4">
|
||||||
Lista de Departamentos
|
<div class="card mb-4">
|
||||||
|
<div class="card-header">
|
||||||
|
<i class="fas fa-plus me-1"></i>
|
||||||
|
Añadir Nuevo Departamento
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form action="departamentos.php" method="POST">
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input class="form-control" id="inputNombre" type="text" name="nombre" placeholder="Nombre del departamento" required />
|
||||||
|
<label for="inputNombre">Nombre del Departamento</label>
|
||||||
|
</div>
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" name="add_departamento" class="btn btn-primary">Añadir</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
|
||||||
<table id="datatablesSimple" class="table table-striped">
|
<!-- Departments List -->
|
||||||
<thead>
|
<div class="col-xl-8">
|
||||||
<tr>
|
<div class="card mb-4">
|
||||||
<th>ID</th>
|
<div class="card-header">
|
||||||
<th>Nombre</th>
|
<i class="fas fa-building me-1"></i>
|
||||||
<th>Color</th>
|
Listado de Departamentos
|
||||||
<th>Fecha de Creación</th>
|
</div>
|
||||||
</tr>
|
<div class="card-body">
|
||||||
</thead>
|
<div class="table-responsive">
|
||||||
<tbody>
|
<table class="table table-hover">
|
||||||
<?php if (!empty($departamentos)): ?>
|
<thead>
|
||||||
<?php foreach ($departamentos as $departamento): ?>
|
<tr>
|
||||||
<tr>
|
<th>Nombre</th>
|
||||||
<td><?php echo htmlspecialchars($departamento['id']); ?></td>
|
<th class="text-end">Acciones</th>
|
||||||
<td><?php echo htmlspecialchars($departamento['nombre']); ?></td>
|
</tr>
|
||||||
<td style="background-color: <?php echo htmlspecialchars($departamento['color']); ?>;"><?php echo htmlspecialchars($departamento['color']); ?></td>
|
</thead>
|
||||||
<td><?php echo htmlspecialchars($departamento['created_at']); ?></td>
|
<tbody>
|
||||||
</tr>
|
<?php if (empty($departamentos)): ?>
|
||||||
<?php endforeach; ?>
|
<tr><td colspan="2" class="text-center">No hay departamentos.</td></tr>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<tr>
|
<?php foreach ($departamentos as $depto): ?>
|
||||||
<td colspan="4" class="text-center">No hay departamentos registrados.</td>
|
<tr>
|
||||||
</tr>
|
<td><?php echo htmlspecialchars($depto['nombre']); ?></td>
|
||||||
<?php endif; ?>
|
<td class="text-end">
|
||||||
</tbody>
|
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#editModal-<?php echo $depto['id']; ?>">
|
||||||
</table>
|
<i class="bi bi-pencil"></i> Editar
|
||||||
|
</button>
|
||||||
|
<form action="departamentos.php" method="POST" class="d-inline" onsubmit="return confirm('¿Estás seguro de que quieres eliminar este departamento?');">
|
||||||
|
<input type="hidden" name="id" value="<?php echo $depto['id']; ?>">
|
||||||
|
<button type="submit" name="delete_departamento" class="btn btn-sm btn-outline-danger">
|
||||||
|
<i class="bi bi-trash"></i> Eliminar
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Edit Modal -->
|
||||||
|
<div class="modal fade" id="editModal-<?php echo $depto['id']; ?>" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Editar Departamento</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<form action="departamentos.php" method="POST">
|
||||||
|
<div class="modal-body">
|
||||||
|
<input type="hidden" name="id" value="<?php echo $depto['id']; ?>">
|
||||||
|
<div class="form-floating">
|
||||||
|
<input type="text" class="form-control" name="nombre" value="<?php echo htmlspecialchars($depto['nombre']); ?>" required>
|
||||||
|
<label>Nombre</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
|
||||||
|
<button type="submit" name="update_departamento" class="btn btn-primary">Guardar Cambios</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php
|
<?php include 'footer.php'; ?>
|
||||||
require_once 'footer.php';
|
|
||||||
?>
|
|
||||||
219
documents.php
219
documents.php
@ -4,61 +4,125 @@ require_once 'db/config.php';
|
|||||||
// --- DB Schema Setup ---
|
// --- DB Schema Setup ---
|
||||||
try {
|
try {
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
// Create documents table
|
// Create documents table with new fields
|
||||||
$pdo->exec("CREATE TABLE IF NOT EXISTS documents (
|
$pdo->exec("CREATE TABLE IF NOT EXISTS documents (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
id_conductor INT,
|
||||||
|
tipo_documento VARCHAR(255),
|
||||||
title VARCHAR(255) NOT NULL,
|
title VARCHAR(255) NOT NULL,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
file_name VARCHAR(255) NOT NULL,
|
file_name VARCHAR(255) NOT NULL,
|
||||||
file_path VARCHAR(255) NOT NULL,
|
file_path VARCHAR(255) NOT NULL,
|
||||||
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (id_conductor) REFERENCES taxis(id) ON DELETE SET NULL
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
|
||||||
|
|
||||||
|
// Add columns if they don't exist (for existing tables)
|
||||||
|
$check_columns = $pdo->query("SHOW COLUMNS FROM documents LIKE 'id_conductor'");
|
||||||
|
if ($check_columns->rowCount() == 0) {
|
||||||
|
$pdo->exec("ALTER TABLE documents ADD COLUMN id_conductor INT, ADD FOREIGN KEY (id_conductor) REFERENCES taxis(id) ON DELETE SET NULL;");
|
||||||
|
}
|
||||||
|
$check_columns = $pdo->query("SHOW COLUMNS FROM documents LIKE 'tipo_documento'");
|
||||||
|
if ($check_columns->rowCount() == 0) {
|
||||||
|
$pdo->exec("ALTER TABLE documents ADD COLUMN tipo_documento VARCHAR(255);");
|
||||||
|
}
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
die("DB ERROR: " . $e->getMessage());
|
die("DB ERROR: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- File Upload Logic ---
|
// --- File Upload & Update Logic ---
|
||||||
$upload_dir = 'uploads/';
|
$upload_dir = 'uploads/';
|
||||||
$message = '';
|
$message = '';
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['document'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
if (!is_dir($upload_dir)) {
|
$pdo = db();
|
||||||
mkdir($upload_dir, 0755, true);
|
// Handle Update
|
||||||
|
if (isset($_POST['update_document'])) {
|
||||||
|
$id = $_POST['document_id'];
|
||||||
|
$title = $_POST['title'];
|
||||||
|
$description = $_POST['description'];
|
||||||
|
$id_conductor = $_POST['id_conductor'];
|
||||||
|
$tipo_documento = $_POST['tipo_documento'];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("UPDATE documents SET title = ?, description = ?, id_conductor = ?, tipo_documento = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$title, $description, $id_conductor, $tipo_documento, $id]);
|
||||||
|
$message = '<div class="alert alert-success">Documento actualizado con éxito.</div>';
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error al actualizar: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// Handle Upload
|
||||||
|
elseif (isset($_FILES['document'])) {
|
||||||
|
if (!is_dir($upload_dir)) {
|
||||||
|
mkdir($upload_dir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
$title = $_POST['title'] ?? 'Sin Título';
|
$title = $_POST['title'] ?? 'Sin Título';
|
||||||
$description = $_POST['description'] ?? '';
|
$description = $_POST['description'] ?? '';
|
||||||
$file_name = basename($_FILES['document']['name']);
|
$id_conductor = $_POST['id_conductor'] ?? null;
|
||||||
$file_tmp = $_FILES['document']['tmp_name'];
|
$tipo_documento = $_POST['tipo_documento'] ?? '';
|
||||||
$file_error = $_FILES['document']['error'];
|
$file_name = basename($_FILES['document']['name']);
|
||||||
|
$file_tmp = $_FILES['document']['tmp_name'];
|
||||||
|
$file_error = $_FILES['document']['error'];
|
||||||
|
|
||||||
if ($file_error === UPLOAD_ERR_OK) {
|
if ($file_error === UPLOAD_ERR_OK) {
|
||||||
$safe_file_name = uniqid() . '-' . preg_replace("/[^a-zA-Z0-9._-]/", "", $file_name);
|
$safe_file_name = uniqid() . '-' . preg_replace("/[^a-zA-Z0-9._-]/", "", $file_name);
|
||||||
$file_path = $upload_dir . $safe_file_name;
|
$file_path = $upload_dir . $safe_file_name;
|
||||||
|
|
||||||
if (move_uploaded_file($file_tmp, $file_path)) {
|
if (move_uploaded_file($file_tmp, $file_path)) {
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("INSERT INTO documents (title, description, file_name, file_path) VALUES (?, ?, ?, ?)");
|
$stmt = $pdo->prepare("INSERT INTO documents (title, description, id_conductor, tipo_documento, file_name, file_path) VALUES (?, ?, ?, ?, ?, ?)");
|
||||||
$stmt->execute([$title, $description, $file_name, $file_path]);
|
$stmt->execute([$title, $description, $id_conductor, $tipo_documento, $file_name, $file_path]);
|
||||||
$message = '<div class="alert alert-success">Documento subido con éxito.</div>';
|
$message = '<div class="alert alert-success">Documento subido con éxito.</div>';
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
$message = '<div class="alert alert-danger">Error al guardar en la base de datos: ' . $e->getMessage() . '</div>';
|
$message = '<div class="alert alert-danger">Error al guardar en la base de datos: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message = '<div class="alert alert-danger">Error al mover el fichero subido.</div>';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$message = '<div class="alert alert-danger">Error al mover el fichero subido.</div>';
|
$message = '<div class="alert alert-danger">Error en la subida del fichero: ' . $file_error . '</div>';
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$message = '<div class="alert alert-danger">Error en la subida del fichero: ' . $file_error . '</div>';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Fetch Documents ---
|
// --- Fetch Data ---
|
||||||
$documents = [];
|
$documents = [];
|
||||||
|
$conductores = [];
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->query("SELECT id, title, description, file_name, file_path, uploaded_at FROM documents ORDER BY uploaded_at DESC");
|
$pdo = db();
|
||||||
|
|
||||||
|
// Fetch drivers (taxis)
|
||||||
|
$conductores = $pdo->query("SELECT id, matricula, modelo FROM taxis ORDER BY matricula")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Fetch documents with driver info
|
||||||
|
$sort_column = $_GET['sort'] ?? 'uploaded_at';
|
||||||
|
$sort_order = $_GET['order'] ?? 'DESC';
|
||||||
|
$valid_columns = ['title', 'tipo_documento', 'conductor', 'uploaded_at'];
|
||||||
|
if (!in_array($sort_column, $valid_columns)) {
|
||||||
|
$sort_column = 'uploaded_at';
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "SELECT d.id, d.title, d.description, d.file_name, d.file_path, d.uploaded_at, d.tipo_documento, t.matricula as conductor, d.id_conductor
|
||||||
|
FROM documents d
|
||||||
|
LEFT JOIN taxis t ON d.id_conductor = t.id
|
||||||
|
ORDER BY $sort_column $sort_order";
|
||||||
|
|
||||||
|
$stmt = $pdo->query($sql);
|
||||||
$documents = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$documents = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
$message .= '<div class="alert alert-danger">Error al obtener los documentos: ' . $e->getMessage() . '</div>';
|
$message .= '<div class="alert alert-danger">Error al obtener los datos: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_sort_link($column, $display) {
|
||||||
|
$sort_column = $_GET['sort'] ?? 'uploaded_at';
|
||||||
|
$sort_order = $_GET['order'] ?? 'DESC';
|
||||||
|
$order = ($sort_column == $column && $sort_order == 'ASC') ? 'DESC' : 'ASC';
|
||||||
|
$icon = $sort_column == $column ? ($sort_order == 'ASC' ? 'bi-sort-up' : 'bi-sort-down') : 'bi-arrow-down-up-square';
|
||||||
|
return '<a href="?sort=' . $column . '&order=' . $order . '">' . $display . ' <i class="bi '.$icon.'"></i></a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
include 'header.php';
|
include 'header.php';
|
||||||
@ -79,29 +143,42 @@ include 'header.php';
|
|||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
<thead class="table-light">
|
<thead class="table-light">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Título</th>
|
<th><?php echo get_sort_link('title', 'Título'); ?></th>
|
||||||
<th>Descripción</th>
|
<th>Descripción</th>
|
||||||
|
<th><?php echo get_sort_link('tipo_documento', 'Tipo'); ?></th>
|
||||||
|
<th><?php echo get_sort_link('conductor', 'Conductor'); ?></th>
|
||||||
<th>Fichero</th>
|
<th>Fichero</th>
|
||||||
<th>Fecha de Subida</th>
|
<th><?php echo get_sort_link('uploaded_at', 'Fecha de Subida'); ?></th>
|
||||||
<th>Acciones</th>
|
<th>Acciones</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php if (empty($documents)): ?>
|
<?php if (empty($documents)): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="5" class="text-center">No hay documentos todavía.</td>
|
<td colspan="7" class="text-center">No hay documentos todavía.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?php foreach ($documents as $doc): ?>
|
<?php foreach ($documents as $doc): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?php echo htmlspecialchars($doc['title']); ?></td>
|
<td><?php echo htmlspecialchars($doc['title']); ?></td>
|
||||||
<td><?php echo htmlspecialchars($doc['description']); ?></td>
|
<td><?php echo htmlspecialchars($doc['description']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($doc['tipo_documento']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($doc['conductor'] ?? 'N/A'); ?></td>
|
||||||
<td><?php echo htmlspecialchars($doc['file_name']); ?></td>
|
<td><?php echo htmlspecialchars($doc['file_name']); ?></td>
|
||||||
<td><?php echo date("d/m/Y H:i", strtotime($doc['uploaded_at'])); ?></td>
|
<td><?php echo date("d/m/Y H:i", strtotime($doc['uploaded_at'])); ?></td>
|
||||||
<td>
|
<td>
|
||||||
<a href="<?php echo htmlspecialchars($doc['file_path']); ?>" class="btn btn-sm btn-outline-primary" download>
|
<a href="<?php echo htmlspecialchars($doc['file_path']); ?>" class="btn btn-sm btn-outline-primary" download>
|
||||||
<i class="bi bi-download"></i> Descargar
|
<i class="bi bi-download"></i>
|
||||||
</a>
|
</a>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary edit-btn"
|
||||||
|
data-id="<?php echo $doc['id']; ?>"
|
||||||
|
data-title="<?php echo htmlspecialchars($doc['title']); ?>"
|
||||||
|
data-description="<?php echo htmlspecialchars($doc['description']); ?>"
|
||||||
|
data-id-conductor="<?php echo $doc['id_conductor']; ?>"
|
||||||
|
data-tipo-documento="<?php echo htmlspecialchars($doc['tipo_documento']); ?>"
|
||||||
|
data-bs-toggle="modal" data-bs-target="#editModal">
|
||||||
|
<i class="bi bi-pencil"></i>
|
||||||
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
@ -123,12 +200,25 @@ include 'header.php';
|
|||||||
<form action="documents.php" method="post" enctype="multipart/form-data">
|
<form action="documents.php" method="post" enctype="multipart/form-data">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="title" class="form-label">Título del Documento</label>
|
<label for="title" class="form-label">Título</label>
|
||||||
<input type="text" class="form-control" id="title" name="title" required>
|
<input type="text" class="form-control" id="title" name="title" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="description" class="form-label">Descripción (Opcional)</label>
|
<label for="description" class="form-label">Descripción</label>
|
||||||
<textarea class="form-control" id="description" name="description" rows="3"></textarea>
|
<textarea class="form-control" id="description" name="description" rows="2"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="id_conductor_upload" class="form-label">Conductor</label>
|
||||||
|
<select class="form-select" id="id_conductor_upload" name="id_conductor">
|
||||||
|
<option value="">Sin asignar</option>
|
||||||
|
<?php foreach ($conductores as $conductor): ?>
|
||||||
|
<option value="<?php echo $conductor['id']; ?>"><?php echo htmlspecialchars($conductor['matricula']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="tipo_documento" class="form-label">Tipo de Documento</label>
|
||||||
|
<input type="text" class="form-control" id="tipo_documento" name="tipo_documento" placeholder="Ej: ITV, Seguro, DNI...">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="document" class="form-label">Seleccionar Fichero</label>
|
<label for="document" class="form-label">Seleccionar Fichero</label>
|
||||||
@ -144,4 +234,63 @@ include 'header.php';
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php include 'footer.php'; ?>
|
<!-- Edit Modal -->
|
||||||
|
<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="editModalLabel">Editar Documento</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<form action="documents.php" method="post">
|
||||||
|
<input type="hidden" name="update_document" value="1">
|
||||||
|
<input type="hidden" id="edit_document_id" name="document_id">
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="edit_title" class="form-label">Título</label>
|
||||||
|
<input type="text" class="form-control" id="edit_title" name="title" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="edit_description" class="form-label">Descripción</label>
|
||||||
|
<textarea class="form-control" id="edit_description" name="description" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="edit_id_conductor" class="form-label">Conductor</label>
|
||||||
|
<select class="form-select" id="edit_id_conductor" name="id_conductor">
|
||||||
|
<option value="">Sin asignar</option>
|
||||||
|
<?php foreach ($conductores as $conductor): ?>
|
||||||
|
<option value="<?php echo $conductor['id']; ?>"><?php echo htmlspecialchars($conductor['matricula']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="edit_tipo_documento" class="form-label">Tipo de Documento</label>
|
||||||
|
<input type="text" class="form-control" id="edit_tipo_documento" name="tipo_documento">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Guardar Cambios</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const editModal = document.getElementById('editModal');
|
||||||
|
editModal.addEventListener('show.bs.modal', function (event) {
|
||||||
|
const button = event.relatedTarget;
|
||||||
|
const modal = this;
|
||||||
|
|
||||||
|
modal.querySelector('#edit_document_id').value = button.dataset.id;
|
||||||
|
modal.querySelector('#edit_title').value = button.dataset.title;
|
||||||
|
modal.querySelector('#edit_description').value = button.dataset.description;
|
||||||
|
modal.querySelector('#edit_id_conductor').value = button.dataset.idConductor;
|
||||||
|
modal.querySelector('#edit_tipo_documento').value = button.dataset.tipoDocumento;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php include 'footer.php'; ?>
|
||||||
194
drivers.php
194
drivers.php
@ -1,146 +1,136 @@
|
|||||||
<?php
|
<?php
|
||||||
ini_set('display_errors', 1);
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
|
|
||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
require_once 'header.php';
|
require_once 'header.php';
|
||||||
|
|
||||||
$message = '';
|
$message = '';
|
||||||
$message_type = '';
|
$message_type = '';
|
||||||
|
|
||||||
// DDL to create table
|
// --- DB Schema and Data Fetching ---
|
||||||
try {
|
try {
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
$pdo->exec("CREATE TABLE IF NOT EXISTS drivers (
|
// Add department FK to taxis table
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
$check_column = $pdo->query("SHOW COLUMNS FROM taxis LIKE 'id_departamento'");
|
||||||
name VARCHAR(100) NOT NULL,
|
if ($check_column->rowCount() == 0) {
|
||||||
license_number VARCHAR(50) NOT NULL,
|
$pdo->exec("ALTER TABLE taxis ADD COLUMN id_departamento INT, ADD FOREIGN KEY (id_departamento) REFERENCES departamentos(id) ON DELETE SET NULL;");
|
||||||
phone VARCHAR(20) NOT NULL,
|
}
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
||||||
);");
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
// die("DB error: " . $e->getMessage()); // Avoid dying on production
|
|
||||||
$message = 'Error de conexión con la base de datos.';
|
|
||||||
$message_type = 'danger';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle POST request to add a new driver
|
// Handle POST requests
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_driver'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$name = trim($_POST['name']);
|
// Add new taxi
|
||||||
$license_number = trim($_POST['license_number']);
|
if (isset($_POST['add_taxi'])) {
|
||||||
$phone = trim($_POST['phone']);
|
$matricula = trim($_POST['matricula']);
|
||||||
|
$modelo = trim($_POST['modelo']);
|
||||||
|
$id_departamento = $_POST['id_departamento'] ?: null;
|
||||||
|
|
||||||
if (!empty($name) && !empty($license_number) && !empty($phone)) {
|
if (!empty($matricula)) {
|
||||||
try {
|
$sql = "INSERT INTO taxis (matricula, modelo, id_departamento) VALUES (?, ?, ?)";
|
||||||
$sql = "INSERT INTO drivers (name, license_number, phone) VALUES (:name, :license_number, :phone)";
|
$pdo->prepare($sql)->execute([$matricula, $modelo, $id_departamento]);
|
||||||
$stmt = $pdo->prepare($sql);
|
$message = 'Taxi/Conductor añadido exitosamente.';
|
||||||
$stmt->execute([
|
$message_type = 'success';
|
||||||
':name' => $name,
|
} else {
|
||||||
':license_number' => $license_number,
|
$message = 'La matrícula es obligatoria.';
|
||||||
':phone' => $phone
|
$message_type = 'warning';
|
||||||
]);
|
}
|
||||||
$message = 'Conductor añadido exitosamente.';
|
|
||||||
$message_type = 'success';
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
$message = 'Error al añadir conductor: ' . $e->getMessage();
|
|
||||||
$message_type = 'danger';
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$message = 'Por favor, complete todos los campos.';
|
|
||||||
$message_type = 'warning';
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch all drivers
|
// Fetch departments for dropdown
|
||||||
$drivers = [];
|
$departamentos = $pdo->query("SELECT id, nombre FROM departamentos ORDER BY nombre")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
if(isset($pdo)) {
|
|
||||||
try {
|
// Fetch all taxis with department info
|
||||||
$stmt = $pdo->query("SELECT id, name, license_number, phone, created_at FROM drivers ORDER BY id DESC");
|
$taxis = $pdo->query(
|
||||||
$drivers = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
"SELECT t.*, d.nombre as departamento_nombre
|
||||||
} catch (PDOException $e) {
|
FROM taxis t
|
||||||
$message = 'Error al obtener los conductores: ' . $e->getMessage();
|
LEFT JOIN departamentos d ON t.id_departamento = d.id
|
||||||
$message_type = 'danger';
|
ORDER BY t.matricula ASC"
|
||||||
}
|
)->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = 'Error de base de datos: ' . $e->getMessage();
|
||||||
|
$message_type = 'danger';
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="container-fluid px-4">
|
||||||
<h1 class="h2">Gestión de Conductores</h1>
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addDriverModal">
|
<h1 class="h2">Gestión de Taxis/Conductores</h1>
|
||||||
<i class="bi bi-plus-circle"></i> Añadir Conductor
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addTaxiModal">
|
||||||
</button>
|
<i class="bi bi-plus-circle"></i> Añadir Taxi/Conductor
|
||||||
</div>
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php if ($message): ?>
|
<?php if ($message): ?>
|
||||||
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show" role="alert">
|
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show" role="alert">
|
||||||
<?php echo htmlspecialchars($message); ?>
|
<?php echo htmlspecialchars($message); ?>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
<thead class="table-light">
|
<thead class="table-light">
|
||||||
<tr>
|
|
||||||
<th scope="col">ID</th>
|
|
||||||
<th scope="col">Nombre</th>
|
|
||||||
<th scope="col">Nº Licencia</th>
|
|
||||||
<th scope="col">Teléfono</th>
|
|
||||||
<th scope="col">Fecha de Registro</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<?php if (empty($drivers)): ?>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="5" class="text-center">No hay conductores registrados.</td>
|
<th>Matrícula</th>
|
||||||
|
<th>Modelo</th>
|
||||||
|
<th>Departamento</th>
|
||||||
|
<th>Fecha de Registro</th>
|
||||||
</tr>
|
</tr>
|
||||||
<?php else: ?>
|
</thead>
|
||||||
<?php foreach ($drivers as $driver): ?>
|
<tbody>
|
||||||
<tr>
|
<?php if (empty($taxis)): ?>
|
||||||
<td><?php echo htmlspecialchars($driver['id']); ?></td>
|
<tr><td colspan="4" class="text-center">No hay taxis registrados.</td></tr>
|
||||||
<td><?php echo htmlspecialchars($driver['name']); ?></td>
|
<?php else: ?>
|
||||||
<td><?php echo htmlspecialchars($driver['license_number']); ?></td>
|
<?php foreach ($taxis as $taxi): ?>
|
||||||
<td><?php echo htmlspecialchars($driver['phone']); ?></td>
|
<tr>
|
||||||
<td><?php echo htmlspecialchars(date("d/m/Y H:i", strtotime($driver['created_at']))); ?></td>
|
<td><?php echo htmlspecialchars($taxi['matricula']); ?></td>
|
||||||
</tr>
|
<td><?php echo htmlspecialchars($taxi['modelo']); ?></td>
|
||||||
<?php endforeach; ?>
|
<td><?php echo htmlspecialchars($taxi['departamento_nombre'] ?? 'N/A'); ?></td>
|
||||||
<?php endif; ?>
|
<td><?php echo date("d/m/Y H:i", strtotime($taxi['created_at'])); ?></td>
|
||||||
</tbody>
|
</tr>
|
||||||
</table>
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Modal -->
|
<!-- Add Taxi Modal -->
|
||||||
<div class="modal fade" id="addDriverModal" tabindex="-1" aria-labelledby="addDriverModalLabel" aria-hidden="true">
|
<div class="modal fade" id="addTaxiModal" tabindex="-1" aria-labelledby="addTaxiModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<form action="drivers.php" method="POST">
|
<form action="drivers.php" method="POST">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="addDriverModalLabel">Añadir Nuevo Conductor</h5>
|
<h5 class="modal-title" id="addTaxiModalLabel">Añadir Nuevo Taxi/Conductor</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<input type="hidden" name="add_driver" value="1">
|
<input type="hidden" name="add_taxi" value="1">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="name" class="form-label">Nombre Completo</label>
|
<label for="matricula" class="form-label">Matrícula</label>
|
||||||
<input type="text" class="form-control" id="name" name="name" required>
|
<input type="text" class="form-control" id="matricula" name="matricula" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="license_number" class="form-label">Número de Licencia</label>
|
<label for="modelo" class="form-label">Modelo</label>
|
||||||
<input type="text" class="form-control" id="license_number" name="license_number" required>
|
<input type="text" class="form-control" id="modelo" name="modelo">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="phone" class="form-label">Teléfono</label>
|
<label for="id_departamento" class="form-label">Departamento</label>
|
||||||
<input type="tel" class="form-control" id="phone" name="phone" required>
|
<select class="form-select" id="id_departamento" name="id_departamento">
|
||||||
|
<option value="">Sin asignar</option>
|
||||||
|
<?php foreach ($departamentos as $depto): ?>
|
||||||
|
<option value="<?php echo $depto['id']; ?>"><?php echo htmlspecialchars($depto['nombre']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
|
||||||
<button type="submit" class="btn btn-primary">Guardar Conductor</button>
|
<button type="submit" class="btn btn-primary">Guardar</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -149,4 +139,4 @@ if(isset($pdo)) {
|
|||||||
|
|
||||||
<?php
|
<?php
|
||||||
require_once 'footer.php';
|
require_once 'footer.php';
|
||||||
?>
|
?>
|
||||||
175
horarios.php
Normal file
175
horarios.php
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
<?php
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
$message_type = '';
|
||||||
|
|
||||||
|
// --- DB Schema and Data Fetching ---
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
// Add department FK to appointment_slots table
|
||||||
|
$pdo->exec("CREATE TABLE IF NOT EXISTS appointment_slots (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
id_departamento INT NOT NULL,
|
||||||
|
day_of_week TINYINT NOT NULL, -- 1 for Monday, 7 for Sunday
|
||||||
|
start_time TIME NOT NULL,
|
||||||
|
end_time TIME NOT NULL,
|
||||||
|
is_active BOOLEAN DEFAULT true,
|
||||||
|
UNIQUE KEY (id_departamento, day_of_week, start_time, end_time),
|
||||||
|
FOREIGN KEY (id_departamento) REFERENCES departamentos(id) ON DELETE CASCADE
|
||||||
|
);");
|
||||||
|
|
||||||
|
// Fetch departments
|
||||||
|
$departamentos = $pdo->query("SELECT id, nombre FROM departamentos ORDER BY nombre")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Get selected department (from GET param or first available)
|
||||||
|
$selected_depto_id = $_GET['id_departamento'] ?? ($departamentos[0]['id'] ?? null);
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = 'Error de conexión con la base de datos: ' . $e->getMessage();
|
||||||
|
$message_type = 'danger';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle POST request to update slots
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($pdo) && isset($_POST['id_departamento'])) {
|
||||||
|
$id_departamento_post = $_POST['id_departamento'];
|
||||||
|
try {
|
||||||
|
// Deactivate all existing slots for the specific department first
|
||||||
|
$stmt_deactivate = $pdo->prepare("UPDATE appointment_slots SET is_active = false WHERE id_departamento = ?");
|
||||||
|
$stmt_deactivate->execute([$id_departamento_post]);
|
||||||
|
|
||||||
|
if (isset($_POST['slots'])) {
|
||||||
|
$slots = $_POST['slots'];
|
||||||
|
$stmt_upsert = $pdo->prepare(
|
||||||
|
"INSERT INTO appointment_slots (id_departamento, day_of_week, start_time, end_time, is_active)
|
||||||
|
VALUES (:id_departamento, :day_of_week, :start_time, :end_time, true)
|
||||||
|
ON DUPLICATE KEY UPDATE is_active = true"
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($slots as $day => $times) {
|
||||||
|
foreach ($times as $time_range => $on) {
|
||||||
|
list($start_time, $end_time) = explode('-', $time_range);
|
||||||
|
$stmt_upsert->execute([
|
||||||
|
':id_departamento' => $id_departamento_post,
|
||||||
|
':day_of_week' => $day,
|
||||||
|
':start_time' => $start_time,
|
||||||
|
':end_time' => $end_time
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$message = 'Horarios actualizados correctamente para el departamento seleccionado.';
|
||||||
|
$message_type = 'success';
|
||||||
|
$selected_depto_id = $id_departamento_post; // Keep the current department selected
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = 'Error al actualizar los horarios: ' . $e->getMessage();
|
||||||
|
$message_type = 'danger';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch current active slots for the selected department
|
||||||
|
$active_slots = [];
|
||||||
|
if (isset($pdo) && $selected_depto_id) {
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT day_of_week, start_time, end_time FROM appointment_slots WHERE is_active = true AND id_departamento = ? ORDER BY day_of_week, start_time");
|
||||||
|
$stmt->execute([$selected_depto_id]);
|
||||||
|
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$active_slots[$row['day_of_week']][date('H:i', strtotime($row['start_time'])) . '-' . date('H:i', strtotime($row['end_time']))] = true;
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = 'Error al obtener los horarios: ' . $e->getMessage();
|
||||||
|
$message_type = 'danger';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$days_of_week = [1 => 'Lunes', 2 => 'Martes', 3 => 'Miércoles', 4 => 'Jueves', 5 => 'Viernes', 6 => 'Sábado', 7 => 'Domingo'];
|
||||||
|
$time_ranges = [];
|
||||||
|
for ($h = 8; $h < 20; $h++) {
|
||||||
|
$start = str_pad($h, 2, '0', STR_PAD_LEFT) . ':00';
|
||||||
|
$end = str_pad($h + 1, 2, '0', STR_PAD_LEFT) . ':00';
|
||||||
|
$time_ranges[] = $start . '-' . $end;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.schedule-grid { display: grid; grid-template-columns: 120px repeat(<?php echo count($time_ranges); ?>, 1fr); gap: 5px; overflow-x: auto; }
|
||||||
|
.grid-header, .day-label, .slot-checkbox { padding: 10px; text-align: center; background-color: #f8f9fa; font-size: 0.8rem; white-space: nowrap; }
|
||||||
|
.day-label { font-weight: bold; position: sticky; left: 0; z-index: 1; }
|
||||||
|
.slot-checkbox { background-color: #fff; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid px-4">
|
||||||
|
<h1 class="mt-4">Gestión de Horarios para Citas</h1>
|
||||||
|
<ol class="breadcrumb mb-4">
|
||||||
|
<li class="breadcrumb-item"><a href="index.php">Dashboard</a></li>
|
||||||
|
<li class="breadcrumb-item active">Horarios</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<?php if ($message): ?>
|
||||||
|
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show" role="alert">
|
||||||
|
<?php echo htmlspecialchars($message); ?><button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header">
|
||||||
|
<i class="fas fa-calendar-alt me-1"></i>
|
||||||
|
Seleccionar Departamento
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form action="horarios.php" method="GET" id="depto-select-form">
|
||||||
|
<div class="input-group">
|
||||||
|
<select class="form-select" name="id_departamento" onchange="document.getElementById('depto-select-form').submit();">
|
||||||
|
<option value="">Seleccione un departamento</option>
|
||||||
|
<?php foreach ($departamentos as $depto): ?>
|
||||||
|
<option value="<?php echo $depto['id']; ?>" <?php echo ($depto['id'] == $selected_depto_id) ? 'selected' : ''; ?>><?php echo htmlspecialchars($depto['nombre']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($selected_depto_id): ?>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Marque los bloques de tiempo disponibles</h5>
|
||||||
|
<p class="card-text">Seleccione las franjas horarias disponibles para el departamento seleccionado. Los cambios guardados se aplicarán solo a este departamento.</p>
|
||||||
|
<form action="horarios.php?id_departamento=<?php echo $selected_depto_id; ?>" method="POST">
|
||||||
|
<input type="hidden" name="id_departamento" value="<?php echo $selected_depto_id; ?>">
|
||||||
|
<div class="schedule-grid mb-3">
|
||||||
|
<div class="grid-header day-label">Día</div>
|
||||||
|
<?php foreach ($time_ranges as $range): ?>
|
||||||
|
<div class="grid-header"><?php echo str_replace('-', ' - ', $range); ?></div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<?php foreach ($days_of_week as $day_num => $day_name): ?>
|
||||||
|
<div class="day-label"><?php echo $day_name; ?></div>
|
||||||
|
<?php foreach ($time_ranges as $range): ?>
|
||||||
|
<div class="slot-checkbox">
|
||||||
|
<input class="form--input" type="checkbox"
|
||||||
|
name="slots[<?php echo $day_num; ?>][<?php echo $range; ?>]"
|
||||||
|
<?php echo isset($active_slots[$day_num][$range]) ? 'checked' : ''; ?>>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<div class="text-end">
|
||||||
|
<button type="submit" class="btn btn-primary">Guardar Horarios</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="alert alert-info">Por favor, seleccione un departamento para ver y gestionar sus horarios.</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
require_once 'footer.php';
|
||||||
|
?>
|
||||||
204
index.php
204
index.php
@ -1,38 +1,188 @@
|
|||||||
<?php
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
require_once 'header.php';
|
require_once 'header.php';
|
||||||
|
|
||||||
|
// Fetch data for selectors
|
||||||
|
$conductores = [];
|
||||||
|
$departamentos = [];
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$conductores = $pdo->query("SELECT id, matricula, nombre FROM taxis ORDER BY nombre ASC")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
$departamentos = $pdo->query("SELECT id, nombre FROM departamentos ORDER BY nombre ASC")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// Silently fail, selectors will be empty
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="px-4 py-5 my-5 text-center">
|
<style>
|
||||||
<h1 class="display-5 fw-bold">Bienvenido a <?php echo htmlspecialchars(getenv('PROJECT_NAME') ?: 'Taxi HRM'); ?></h1>
|
.dashboard-container {
|
||||||
<div class="col-lg-6 mx-auto">
|
display: grid;
|
||||||
<p class="lead mb-4"><?php echo htmlspecialchars(getenv('PROJECT_DESCRIPTION') ?: 'Una solución completa para la gestión de su negocio de taxis.'); ?></p>
|
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||||
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center">
|
gap: 2rem;
|
||||||
<a href="drivers.php" class="btn btn-primary btn-lg px-4 gap-3">Gestionar Conductores</a>
|
padding-top: 1rem;
|
||||||
<button type="button" class="btn btn-outline-secondary btn-lg px-4">Ver Reportes</button>
|
}
|
||||||
|
.role-card {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
|
||||||
|
padding: 2rem;
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
}
|
||||||
|
.role-card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 8px 20px rgba(0,0,0,0.12);
|
||||||
|
}
|
||||||
|
.role-card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.role-card-header i {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
color: #0d6efd;
|
||||||
|
}
|
||||||
|
.role-card-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #343a40;
|
||||||
|
}
|
||||||
|
.role-card .form-select {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.action-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.action-list li a {
|
||||||
|
display: block;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #495057;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: background-color 0.2s ease, color 0.2s ease;
|
||||||
|
}
|
||||||
|
.action-list li a:hover {
|
||||||
|
background-color: #e9ecef;
|
||||||
|
color: #0d6efd;
|
||||||
|
}
|
||||||
|
.action-list li a i {
|
||||||
|
margin-right: 0.75rem;
|
||||||
|
width: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.hidden-list {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container-fluid px-4">
|
||||||
|
<h1 class="mt-4">Dashboard Interactivo</h1>
|
||||||
|
<ol class="breadcrumb mb-4">
|
||||||
|
<li class="breadcrumb-item active">Seleccione un rol para empezar</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<div class="dashboard-container">
|
||||||
|
<!-- Administrador Card -->
|
||||||
|
<div class="role-card" id="admin-card">
|
||||||
|
<div class="role-card-header">
|
||||||
|
<i class="bi bi-shield-lock-fill"></i>
|
||||||
|
<h3>Administrador</h3>
|
||||||
|
</div>
|
||||||
|
<ul class="action-list">
|
||||||
|
<li><a href="drivers.php"><i class="bi bi-people-fill"></i>Conductores y Taxis</a></li>
|
||||||
|
<li><a href="departamentos.php"><i class="bi bi-building"></i>Departamentos</a></li>
|
||||||
|
<li><a href="documents.php"><i class="bi bi-file-earmark-text"></i>Documentos</a></li>
|
||||||
|
<li><a href="citas.php"><i class="bi bi-calendar-check"></i>Citas</a></li>
|
||||||
|
<li><a href="consultas.php"><i class="bi bi-question-circle"></i>Consultas</a></li>
|
||||||
|
<li><a href="horarios.php"><i class="bi bi-clock"></i>Horarios de Citas</a></li>
|
||||||
|
<li><a href="localizacion.php"><i class="bi bi-pin-map-fill"></i>Localizaciones de Taxis</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Conductor Card -->
|
||||||
|
<div class="role-card" id="conductor-card">
|
||||||
|
<div class="role-card-header">
|
||||||
|
<i class="bi bi-person-badge-fill"></i>
|
||||||
|
<h3>Conductor</h3>
|
||||||
|
</div>
|
||||||
|
<select class="form-select" id="conductor-selector">
|
||||||
|
<option value="">Seleccione un conductor...</option>
|
||||||
|
<?php foreach ($conductores as $conductor): ?>
|
||||||
|
<option value="<?php echo $conductor['id']; ?>"><?php echo htmlspecialchars($conductor['nombre'] . ' (' . $conductor['matricula'] . ')'); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<ul class="action-list hidden-list" id="conductor-actions">
|
||||||
|
<li><a href="#" data-url="drivers.php?action=edit&id="><i class="bi bi-person-lines-fill"></i>Mi Información</a></li>
|
||||||
|
<li><a href="#" data-url="documents.php?id_conductor="><i class="bi bi-file-earmark-text"></i>Mis Documentos</a></li>
|
||||||
|
<li><a href="#" data-url="citas.php?id_conductor="><i class="bi bi-calendar-check"></i>Mis Citas</a></li>
|
||||||
|
<li><a href="#" data-url="consultas.php?id_conductor="><i class="bi bi-question-circle"></i>Mis Consultas</a></li>
|
||||||
|
<li><a href="#" data-url="localizacion.php?action=show_history&id_taxi="><i class="bi bi-clock-history"></i>Mi Historial de Ubicaciones</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Departamento Card -->
|
||||||
|
<div class="role-card" id="departamento-card">
|
||||||
|
<div class="role-card-header">
|
||||||
|
<i class="bi bi-diagram-3-fill"></i>
|
||||||
|
<h3>Departamento</h3>
|
||||||
|
</div>
|
||||||
|
<select class="form-select" id="departamento-selector">
|
||||||
|
<option value="">Seleccione un departamento...</option>
|
||||||
|
<?php foreach ($departamentos as $depto): ?>
|
||||||
|
<option value="<?php echo $depto['id']; ?>"><?php echo htmlspecialchars($depto['nombre']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<ul class="action-list hidden-list" id="departamento-actions">
|
||||||
|
<li><a href="#" data-url="departamentos.php?action=edit&id="><i class="bi bi-pencil-square"></i>Ver/Editar Departamento</a></li>
|
||||||
|
<li><a href="#" data-url="citas.php?id_departamento="><i class="bi bi-calendar-check"></i>Citas del Departamento</a></li>
|
||||||
|
<li><a href="#" data-url="consultas.php?id_departamento="><i class="bi bi-question-circle"></i>Consultas del Departamento</a></li>
|
||||||
|
<li><a href="#" data-url="horarios.php?id_departamento="><i class="bi bi-clock"></i>Horarios del Departamento</a></li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<script>
|
||||||
<div class="col-md-6">
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
<div class="card">
|
const conductorSelector = document.getElementById('conductor-selector');
|
||||||
<div class="card-body">
|
const conductorActions = document.getElementById('conductor-actions');
|
||||||
<h5 class="card-title"><i class="bi bi-person-badge"></i> Conductores</h5>
|
const departamentoSelector = document.getElementById('departamento-selector');
|
||||||
<p class="card-text">Administre el personal de conducción, incluyendo sus perfiles, licencias y documentación.</p>
|
const departamentoActions = document.getElementById('departamento-actions');
|
||||||
<a href="drivers.php" class="btn btn-primary">Ir a Conductores</a>
|
|
||||||
</div>
|
conductorSelector.addEventListener('change', function() {
|
||||||
</div>
|
const conductorId = this.value;
|
||||||
</div>
|
if (conductorId) {
|
||||||
<div class="col-md-6">
|
conductorActions.classList.remove('hidden-list');
|
||||||
<div class="card">
|
conductorActions.querySelectorAll('a').forEach(link => {
|
||||||
<div class="card-body">
|
const baseUrl = link.getAttribute('data-url');
|
||||||
<h5 class="card-title"><i class="bi bi-geo-alt-fill"></i> Mapa en Tiempo Real</h5>
|
link.href = baseUrl + conductorId;
|
||||||
<p class="card-text">Visualice la ubicación de toda su flota en tiempo real para una gestión eficiente. (Próximamente)</p>
|
});
|
||||||
<a href="#" class="btn btn-secondary disabled">Ir al Mapa</a>
|
} else {
|
||||||
</div>
|
conductorActions.classList.add('hidden-list');
|
||||||
</div>
|
}
|
||||||
</div>
|
});
|
||||||
</div>
|
|
||||||
|
departamentoSelector.addEventListener('change', function() {
|
||||||
|
const deptoId = this.value;
|
||||||
|
if (deptoId) {
|
||||||
|
departamentoActions.classList.remove('hidden-list');
|
||||||
|
departamentoActions.querySelectorAll('a').forEach(link => {
|
||||||
|
const baseUrl = link.getAttribute('data-url');
|
||||||
|
link.href = baseUrl + deptoId;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
departamentoActions.classList.add('hidden-list');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
require_once 'footer.php';
|
require_once 'footer.php';
|
||||||
|
|||||||
@ -43,30 +43,21 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle form submission
|
// Handle form submission for historical location
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_localizacion'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_localizacion_historica'])) {
|
||||||
$id_taxi = $_POST['id_taxi'];
|
$id_taxi = $_POST['id_taxi'];
|
||||||
$latitud = $_POST['latitud'];
|
$latitud = $_POST['latitud'];
|
||||||
$longitud = $_POST['longitud'];
|
$longitud = $_POST['longitud'];
|
||||||
|
$fecha_registro = $_POST['fecha_registro'];
|
||||||
|
|
||||||
if (!empty($id_taxi) && is_numeric($latitud) && is_numeric($longitud)) {
|
if (!empty($id_taxi) && is_numeric($latitud) && is_numeric($longitud) && !empty($fecha_registro)) {
|
||||||
$pdo->beginTransaction();
|
|
||||||
try {
|
try {
|
||||||
// Upsert (Update or Insert) the last known location
|
// Insert into history with specific timestamp
|
||||||
$stmt_upsert = $pdo->prepare(
|
$stmt_history = $pdo->prepare("INSERT INTO localizacion_historico (id_taxi, latitud, longitud, fecha_registro) VALUES (?, ?, ?, ?)");
|
||||||
"INSERT INTO localizacion_taxis (id_taxi, latitud, longitud) VALUES (?, ?, ?) " .
|
$stmt_history->execute([$id_taxi, $latitud, $longitud, $fecha_registro]);
|
||||||
"ON DUPLICATE KEY UPDATE latitud = VALUES(latitud), longitud = VALUES(longitud)"
|
|
||||||
);
|
|
||||||
$stmt_upsert->execute([$id_taxi, $latitud, $longitud]);
|
|
||||||
|
|
||||||
// Insert into history
|
|
||||||
$stmt_history = $pdo->prepare("INSERT INTO localizacion_historico (id_taxi, latitud, longitud) VALUES (?, ?, ?)");
|
|
||||||
$stmt_history->execute([$id_taxi, $latitud, $longitud]);
|
|
||||||
|
|
||||||
$pdo->commit();
|
echo '<div class="alert alert-success" role="alert">Ubicación histórica añadida con éxito.</div>';
|
||||||
echo '<div class="alert alert-success" role="alert">Localización actualizada con éxito.</div>';
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$pdo->rollBack();
|
|
||||||
echo '<div class="alert alert-danger" role="alert">Error al guardar los datos: '. $e->getMessage() .'</div>';
|
echo '<div class="alert alert-danger" role="alert">Error al guardar los datos: '. $e->getMessage() .'</div>';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -136,11 +127,12 @@ try {
|
|||||||
<div class="col-xl-6">
|
<div class="col-xl-6">
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<i class="fas fa-taxi me-1"></i>
|
<i class="fas fa-plus me-1"></i>
|
||||||
Añadir o Actualizar Localización
|
Añadir Ubicación Histórica
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form action="localizacion.php" method="POST">
|
<form action="localizacion.php" method="POST">
|
||||||
|
<p class="small text-muted">Haz clic en un taxi del mapa para rellenar los datos o haz clic en el mapa para obtener coordenadas.</p>
|
||||||
<div class="form-floating mb-3">
|
<div class="form-floating mb-3">
|
||||||
<select class="form-select" id="selectTaxi" name="id_taxi" required>
|
<select class="form-select" id="selectTaxi" name="id_taxi" required>
|
||||||
<option value="">Seleccione un taxi</option>
|
<option value="">Seleccione un taxi</option>
|
||||||
@ -164,9 +156,13 @@ try {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input class="form-control" id="inputFecha" type="datetime-local" name="fecha_registro" required />
|
||||||
|
<label for="inputFecha">Fecha y Hora</label>
|
||||||
|
</div>
|
||||||
<div class="mt-4 mb-0">
|
<div class="mt-4 mb-0">
|
||||||
<div class="d-grid">
|
<div class="d-grid">
|
||||||
<button type="submit" name="add_localizacion" class="btn btn-primary btn-block">Actualizar Localización</button>
|
<button type="submit" name="add_localizacion_historica" class="btn btn-primary btn-block">Añadir a Historial</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -241,18 +237,31 @@ try {
|
|||||||
const lat = parseFloat(taxi.latitud);
|
const lat = parseFloat(taxi.latitud);
|
||||||
const lon = parseFloat(taxi.longitud);
|
const lon = parseFloat(taxi.longitud);
|
||||||
const matricula = taxi.matricula;
|
const matricula = taxi.matricula;
|
||||||
|
const taxiId = taxi.id; // Asegúrate de que la API devuelve el ID del taxi
|
||||||
|
|
||||||
if (!isNaN(lat) && !isNaN(lon)) {
|
if (!isNaN(lat) && !isNaN(lon)) {
|
||||||
const popupContent = `<b>Taxi:</b> ${matricula}<br><b>Modelo:</b> ${taxi.modelo || 'N/A'}<br><b>Última vez:</b> ${taxi.ultima_actualizacion}`;
|
const popupContent = `<b>Taxi:</b> ${matricula}<br><b>Modelo:</b> ${taxi.modelo || 'N/A'}<br><b>Última vez:</b> ${taxi.ultima_actualizacion}`;
|
||||||
const latLng = [lat, lon];
|
const latLng = [lat, lon];
|
||||||
|
|
||||||
|
let marker;
|
||||||
if (markers[matricula]) {
|
if (markers[matricula]) {
|
||||||
markers[matricula].setLatLng(latLng).setPopupContent(popupContent);
|
marker = markers[matricula].setLatLng(latLng).setPopupContent(popupContent);
|
||||||
} else {
|
} else {
|
||||||
markers[matricula] = L.marker(latLng, { icon: taxiIcon }).addTo(map)
|
marker = L.marker(latLng, { icon: taxiIcon }).addTo(map)
|
||||||
.bindPopup(popupContent);
|
.bindPopup(popupContent);
|
||||||
|
markers[matricula] = marker;
|
||||||
}
|
}
|
||||||
// Extender los límites para el auto-zoom
|
|
||||||
|
marker.off('click').on('click', () => {
|
||||||
|
document.getElementById('selectTaxi').value = taxiId;
|
||||||
|
document.getElementById('inputLatitud').value = lat.toFixed(8);
|
||||||
|
document.getElementById('inputLongitud').value = lon.toFixed(8);
|
||||||
|
document.getElementById('inputFecha').value = new Date().toISOString().slice(0, 16);
|
||||||
|
|
||||||
|
// Scroll to the form for better UX
|
||||||
|
document.getElementById('selectTaxi').focus();
|
||||||
|
});
|
||||||
|
|
||||||
bounds.extend(latLng);
|
bounds.extend(latLng);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -271,6 +280,15 @@ try {
|
|||||||
// Carga inicial
|
// Carga inicial
|
||||||
updateMap();
|
updateMap();
|
||||||
|
|
||||||
|
// Set current date and time for the historical form
|
||||||
|
document.getElementById('inputFecha').value = new Date().toISOString().slice(0, 16);
|
||||||
|
|
||||||
|
// Get coordinates on map click
|
||||||
|
map.on('click', function(e) {
|
||||||
|
document.getElementById('inputLatitud').value = e.latlng.lat.toFixed(8);
|
||||||
|
document.getElementById('inputLongitud').value = e.latlng.lng.toFixed(8);
|
||||||
|
});
|
||||||
|
|
||||||
// Lógica para el historial de rutas
|
// Lógica para el historial de rutas
|
||||||
let routePolyline = null;
|
let routePolyline = null;
|
||||||
document.getElementById('history-form').addEventListener('submit', function(e) {
|
document.getElementById('history-form').addEventListener('submit', function(e) {
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user