diff --git a/controllers/graficos.php b/controllers/graficos.php index c59fe56..f7600b6 100644 --- a/controllers/graficos.php +++ b/controllers/graficos.php @@ -5,66 +5,58 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $input = json_decode(file_get_contents('php://input'), true); $tipoConsulta = $input['tipoConsulta'] ?? ''; - $filtros = [ - 'id_rango_edad' => $input['id_rango_edad'] ?? null, - 'id_genero' => $input['id_genero'] ?? null, - 'id_examen' => $input['id_examen'] ?? null, - 'fechaInicio' => $input['fechaInicio'] ?? null, - 'fechaFin' => $input['fechaFin'] ?? null, - ]; + $graficos = new Graficos(); - $graficos = new Graficos(); + // Casos especiales para tarjetas de promedio + if ( + $tipoConsulta === "Femenino" || + $tipoConsulta === "Masculino" || + $tipoConsulta === "Prefiero no decirlo" + ) { + $cantidad = $graficos->obtenerCantidadPorGenero($tipoConsulta); + echo json_encode(["cantidad" => $cantidad]); + exit; + } - switch ($tipoConsulta) { - case 'Femenino': - $cantidad = $graficos->obtenerGeneroFemenino($filtros); - break; - case 'Masculino': - $cantidad = $graficos->obtenerGeneroMasculino($filtros); - break; - case 'Prefiero no decirlo': - $cantidad = $graficos->obtenerGeneroNoDefinido($filtros); - break; - case 'Menor de 18 años': - $cantidad = $graficos->obtenerEdadMenor18($filtros); - break; - case '18 a 24 años': - $cantidad = $graficos->obtenerEdad1824($filtros); - break; - case '25 a 34 años': - $cantidad = $graficos->obtenerEdad2434($filtros); - break; - case '35 a 44 años': - $cantidad = $graficos->obtenerEdad3544($filtros); - break; - case '45 a 54 años': - $cantidad = $graficos->obtenerEdad4554($filtros); - break; - case '55 a 64 años': - $cantidad = $graficos->obtenerEdad5564($filtros); - break; - case '65 años o más': - $cantidad = $graficos->obtenerEdad65oMas($filtros); - break; - case 'Estados': - $cantidad = $graficos->obtenerEstados($filtros); - echo json_encode($cantidad); - exit; - case 'Examenes': - $cantidad = $graficos->obtenerExamenes($filtros); - echo json_encode($cantidad); - exit; - case 'Fechas': - $fechaInicio = $input['fechaInicio'] ?? ''; - $fechaFin = $input['fechaFin'] ?? ''; - $cantidad = $graficos->obtenerFecha($fechaInicio, $fechaFin); - echo json_encode($cantidad); - exit; - default: - $cantidad = 0; + // Solo un filtro a la vez + $filtros = []; + if (!empty($input['id_rango_edad'])) $filtros['id_rango_edad'] = $input['id_rango_edad']; + else if (!empty($input['id_genero'])) $filtros['id_genero'] = $input['id_genero']; + else if (!empty($input['id_examen'])) $filtros['id_examen'] = $input['id_examen']; + else if (!empty($input['fechaInicio']) && !empty($input['fechaFin'])) { + $filtros['fechaInicio'] = $input['fechaInicio']; + $filtros['fechaFin'] = $input['fechaFin']; } - echo json_encode(['cantidad' => $cantidad]); + switch ($tipoConsulta) { + case 'Generos': + $cantidad = $graficos->obtenerGeneros($filtros); + echo json_encode($cantidad); + exit; + case 'Edades': + $cantidad = $graficos->obtenerEdades($filtros); + echo json_encode($cantidad); + exit; + case 'Estados': + $cantidad = $graficos->obtenerEstados($filtros); + echo json_encode($cantidad); + exit; + case 'Examenes': + $cantidad = $graficos->obtenerExamenes($filtros); + echo json_encode($cantidad); + exit; + case 'Fechas': + $cantidad = $graficos->obtenerFechas($filtros); + echo json_encode($cantidad); + exit; + case 'ResumenGenero': // NUEVO + $cantidad = $graficos->obtenerResumenGenero($filtros); + echo json_encode($cantidad); + exit; + default: + echo json_encode([]); + exit; + } } class Graficos{ @@ -76,378 +68,116 @@ class Graficos{ $this->db = $this->Database->getInstance(); } - public function obtenerGeneroFemenino($filtros = []) { - $sql = "SELECT COUNT(*) AS Femenino FROM candidato WHERE id_genero = 2"; - $params = []; - $types = ""; - if (!empty($filtros['id_rango_edad']) && $filtros['id_rango_edad'] !== "NULL") { - $sql .= " AND id_rango_edad = ?"; - $params[] = $filtros['id_rango_edad']; - $types .= "i"; - } - if (!empty($filtros['id_examen']) && $filtros['id_examen'] !== "NULL") { - $sql .= " AND id_examen = ?"; - $params[] = $filtros['id_examen']; - $types .= "i"; - } - if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { - $sql .= " AND DATE(fecha_entrada) >= ? AND DATE(fecha_salida) <= ?"; - $params[] = $filtros['fechaInicio']; - $params[] = $filtros['fechaFin']; - $types .= "ss"; + // NUEVO: Para tarjetas de promedio + public function obtenerCantidadPorGenero($genero) { + $sql = "SELECT COUNT(*) as cantidad + FROM candidato c + INNER JOIN genero g ON c.id_genero = g.id_genero + WHERE g.descripcion = ?"; + $query = $this->db->prepare($sql); + $query->bind_param("s", $genero); + $query->execute(); + $resultado = $query->get_result(); + $row = $resultado->fetch_assoc(); + $query->close(); + return intval($row['cantidad']); } - $query = $this->db->prepare($sql); - if ($params) { - $query->bind_param($types, ...$params); - } - $query->execute(); - $resultado = $query->get_result(); - $output = "0"; - if ($resultado->num_rows > 0) { - $data = $resultado->fetch_assoc(); - $output = $data['Femenino']; - } - $query->close(); - return $output; -} - -public function obtenerGeneroMasculino($filtros = []) { - $sql = "SELECT COUNT(*) AS Masculino FROM candidato WHERE id_genero = 1"; - $params = []; - $types = ""; - - if (!empty($filtros['id_rango_edad']) && $filtros['id_rango_edad'] !== "NULL") { - $sql .= " AND id_rango_edad = ?"; - $params[] = $filtros['id_rango_edad']; - $types .= "i"; - } - if (!empty($filtros['id_examen']) && $filtros['id_examen'] !== "NULL") { - $sql .= " AND id_examen = ?"; - $params[] = $filtros['id_examen']; - $types .= "i"; - } - if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { - $sql .= " AND DATE(fecha_entrada) >= ? AND DATE(fecha_salida) <= ?"; - $params[] = $filtros['fechaInicio']; - $params[] = $filtros['fechaFin']; - $types .= "ss"; - } - - $query = $this->db->prepare($sql); - if ($params) { - $query->bind_param($types, ...$params); - } - $query->execute(); - $resultado = $query->get_result(); - $output = "0"; - if ($resultado->num_rows > 0) { - $data = $resultado->fetch_assoc(); - $output = $data['Masculino']; - } - $query->close(); - return $output; -} - -public function obtenerGeneroNoDefinido($filtros = []) { - $sql = "SELECT COUNT(*) AS NoDefinido FROM candidato WHERE id_genero = 3"; - $params = []; - $types = ""; - - if (!empty($filtros['id_rango_edad']) && $filtros['id_rango_edad'] !== "NULL") { - $sql .= " AND id_rango_edad = ?"; - $params[] = $filtros['id_rango_edad']; - $types .= "i"; - } - if (!empty($filtros['id_examen']) && $filtros['id_examen'] !== "NULL") { - $sql .= " AND id_examen = ?"; - $params[] = $filtros['id_examen']; - $types .= "i"; - } - if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { - $sql .= " AND DATE(fecha_entrada) >= ? AND DATE(fecha_salida) <= ?"; - $params[] = $filtros['fechaInicio']; - $params[] = $filtros['fechaFin']; - $types .= "ss"; - } - - $query = $this->db->prepare($sql); - if ($params) { - $query->bind_param($types, ...$params); - } - $query->execute(); - $resultado = $query->get_result(); - $output = "0"; - if ($resultado->num_rows > 0) { - $data = $resultado->fetch_assoc(); - $output = $data['NoDefinido']; - } - $query->close(); - return $output; -} - -public function obtenerEdadMenor18($filtros = []) { - $sql = "SELECT COUNT(*) AS menorEdad FROM candidato WHERE id_rango_edad = 1"; - $params = []; - $types = ""; - - if (!empty($filtros['id_examen']) && $filtros['id_examen'] !== "NULL") { - $sql .= " AND id_examen = ?"; - $params[] = $filtros['id_examen']; - $types .= "i"; - } - if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { - $sql .= " AND DATE(fecha_entrada) >= ? AND DATE(fecha_salida) <= ?"; - $params[] = $filtros['fechaInicio']; - $params[] = $filtros['fechaFin']; - $types .= "ss"; - } - - $query = $this->db->prepare($sql); - if ($params) { - $query->bind_param($types, ...$params); - } - $query->execute(); - $resultado = $query->get_result(); - $output = "0"; - if ($resultado->num_rows > 0) { - $data = $resultado->fetch_assoc(); - $output = $data['menorEdad']; - } - $query->close(); - return $output; -} - -public function obtenerEdad1824($filtros = []) { - $sql = "SELECT COUNT(*) AS edad1824 FROM candidato WHERE id_rango_edad = 2"; - $params = []; - $types = ""; - - if (!empty($filtros['id_examen']) && $filtros['id_examen'] !== "NULL") { - $sql .= " AND id_examen = ?"; - $params[] = $filtros['id_examen']; - $types .= "i"; - } - if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { - $sql .= " AND DATE(fecha_entrada) >= ? AND DATE(fecha_salida) <= ?"; - $params[] = $filtros['fechaInicio']; - $params[] = $filtros['fechaFin']; - $types .= "ss"; - } - - $query = $this->db->prepare($sql); - if ($params) { - $query->bind_param($types, ...$params); - } - $query->execute(); - $resultado = $query->get_result(); - $output = "0"; - if ($resultado->num_rows > 0) { - $data = $resultado->fetch_assoc(); - $output = $data['edad1824']; - } - $query->close(); - return $output; -} - -public function obtenerEdad2434($filtros = []) { - $sql = "SELECT COUNT(*) AS edad2434 FROM candidato WHERE id_rango_edad = 3"; - $params = []; - $types = ""; - - if (!empty($filtros['id_examen']) && $filtros['id_examen'] !== "NULL") { - $sql .= " AND id_examen = ?"; - $params[] = $filtros['id_examen']; - $types .= "i"; - } - if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { - $sql .= " AND DATE(fecha_entrada) >= ? AND DATE(fecha_salida) <= ?"; - $params[] = $filtros['fechaInicio']; - $params[] = $filtros['fechaFin']; - $types .= "ss"; - } - - $query = $this->db->prepare($sql); - if ($params) { - $query->bind_param($types, ...$params); - } - $query->execute(); - $resultado = $query->get_result(); - $output = "0"; - if ($resultado->num_rows > 0) { - $data = $resultado->fetch_assoc(); - $output = $data['edad2434']; - } - $query->close(); - return $output; -} - -public function obtenerEdad3544($filtros = []) { - $sql = "SELECT COUNT(*) AS edad3544 FROM candidato WHERE id_rango_edad = 4"; - $params = []; - $types = ""; - - if (!empty($filtros['id_examen']) && $filtros['id_examen'] !== "NULL") { - $sql .= " AND id_examen = ?"; - $params[] = $filtros['id_examen']; - $types .= "i"; - } - if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { - $sql .= " AND DATE(fecha_entrada) >= ? AND DATE(fecha_salida) <= ?"; - $params[] = $filtros['fechaInicio']; - $params[] = $filtros['fechaFin']; - $types .= "ss"; - } - - $query = $this->db->prepare($sql); - if ($params) { - $query->bind_param($types, ...$params); - } - $query->execute(); - $resultado = $query->get_result(); - $output = "0"; - if ($resultado->num_rows > 0) { - $data = $resultado->fetch_assoc(); - $output = $data['edad3544']; - } - $query->close(); - return $output; -} - -public function obtenerEdad4554($filtros = []) { - $sql = "SELECT COUNT(*) AS edad4554 FROM candidato WHERE id_rango_edad = 5"; - $params = []; - $types = ""; - - if (!empty($filtros['id_examen']) && $filtros['id_examen'] !== "NULL") { - $sql .= " AND id_examen = ?"; - $params[] = $filtros['id_examen']; - $types .= "i"; - } - if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { - $sql .= " AND DATE(fecha_entrada) >= ? AND DATE(fecha_salida) <= ?"; - $params[] = $filtros['fechaInicio']; - $params[] = $filtros['fechaFin']; - $types .= "ss"; - } - - $query = $this->db->prepare($sql); - if ($params) { - $query->bind_param($types, ...$params); - } - $query->execute(); - $resultado = $query->get_result(); - $output = "0"; - if ($resultado->num_rows > 0) { - $data = $resultado->fetch_assoc(); - $output = $data['edad4554']; - } - $query->close(); - return $output; -} - -public function obtenerEdad5564($filtros = []) { - $sql = "SELECT COUNT(*) AS edad5564 FROM candidato WHERE id_rango_edad = 6"; - $params = []; - $types = ""; - - if (!empty($filtros['id_examen']) && $filtros['id_examen'] !== "NULL") { - $sql .= " AND id_examen = ?"; - $params[] = $filtros['id_examen']; - $types .= "i"; - } - if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { - $sql .= " AND DATE(fecha_entrada) >= ? AND DATE(fecha_salida) <= ?"; - $params[] = $filtros['fechaInicio']; - $params[] = $filtros['fechaFin']; - $types .= "ss"; - } - - $query = $this->db->prepare($sql); - if ($params) { - $query->bind_param($types, ...$params); - } - $query->execute(); - $resultado = $query->get_result(); - $output = "0"; - if ($resultado->num_rows > 0) { - $data = $resultado->fetch_assoc(); - $output = $data['edad5564']; - } - $query->close(); - return $output; -} - -public function obtenerEdad65oMas($filtros = []) { - $sql = "SELECT COUNT(*) AS edad65oMas FROM candidato WHERE id_rango_edad = 7"; - $params = []; - $types = ""; - - if (!empty($filtros['id_examen']) && $filtros['id_examen'] !== "NULL") { - $sql .= " AND id_examen = ?"; - $params[] = $filtros['id_examen']; - $types .= "i"; - } - if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { - $sql .= " AND DATE(fecha_entrada) >= ? AND DATE(fecha_salida) <= ?"; - $params[] = $filtros['fechaInicio']; - $params[] = $filtros['fechaFin']; - $types .= "ss"; - } - - $query = $this->db->prepare($sql); - if ($params) { - $query->bind_param($types, ...$params); - } - $query->execute(); - $resultado = $query->get_result(); - $output = "0"; - if ($resultado->num_rows > 0) { - $data = $resultado->fetch_assoc(); - $output = $data['edad65oMas']; - } - $query->close(); - return $output; -} - -public function obtenerEstados($filtros = []) { - $sql = "SELECT estados.nombre AS estado, COUNT(*) AS cantidad - FROM candidato - INNER JOIN info_candidatos ON candidato.id_candidato = info_candidatos.id_candidato - INNER JOIN estados ON info_candidatos.id_estado = estados.id + // Gráfico de Géneros + public function obtenerGeneros($filtros = []) { + $sql = "SELECT g.descripcion AS genero, COUNT(*) AS cantidad + FROM candidato c + INNER JOIN genero g ON c.id_genero = g.id_genero WHERE 1=1"; $params = []; $types = ""; - if (!empty($filtros['id_rango_edad']) && $filtros['id_rango_edad'] !== "NULL") { - $sql .= " AND candidato.id_rango_edad = ?"; - $params[] = $filtros['id_rango_edad']; - $types .= "i"; - } - if (!empty($filtros['id_genero']) && $filtros['id_genero'] !== "NULL") { - $sql .= " AND candidato.id_genero = ?"; + if (!empty($filtros['id_genero'])) { + $sql .= " AND c.id_genero = ?"; $params[] = $filtros['id_genero']; $types .= "i"; } - if (!empty($filtros['id_examen']) && $filtros['id_examen'] !== "NULL") { - $sql .= " AND candidato.id_examen = ?"; - $params[] = $filtros['id_examen']; - $types .= "i"; - } if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { - $sql .= " AND DATE(candidato.fecha_entrada) >= ? AND DATE(candidato.fecha_salida) <= ?"; + $sql .= " AND DATE(c.fecha_entrada) >= ? AND DATE(c.fecha_entrada) <= ?"; $params[] = $filtros['fechaInicio']; $params[] = $filtros['fechaFin']; $types .= "ss"; } - - $sql .= " GROUP BY estados.nombre ORDER BY estados.nombre"; + $sql .= " GROUP BY g.descripcion ORDER BY g.descripcion"; $query = $this->db->prepare($sql); - if ($params) { - $query->bind_param($types, ...$params); + if ($params) $query->bind_param($types, ...$params); + $query->execute(); + $resultado = $query->get_result(); + + $generos = []; + while ($data = $resultado->fetch_assoc()) { + $generos[] = $data; } + $query->close(); + return $generos; + } + + // Gráfico de Edades + public function obtenerEdades($filtros = []) { + $sql = "SELECT r.descripcion AS rango_edad, COUNT(*) AS cantidad + FROM candidato c + INNER JOIN rango_edad r ON c.id_rango_edad = r.id_rango_edad + WHERE 1=1"; + $params = []; + $types = ""; + + if (!empty($filtros['id_rango_edad'])) { + $sql .= " AND c.id_rango_edad = ?"; + $params[] = $filtros['id_rango_edad']; + $types .= "i"; + } + if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { + $sql .= " AND DATE(c.fecha_entrada) >= ? AND DATE(c.fecha_entrada) <= ?"; + $params[] = $filtros['fechaInicio']; + $params[] = $filtros['fechaFin']; + $types .= "ss"; + } + $sql .= " GROUP BY r.descripcion ORDER BY r.id_rango_edad"; + + $query = $this->db->prepare($sql); + if ($params) $query->bind_param($types, ...$params); + $query->execute(); + $resultado = $query->get_result(); + + $edades = []; + while ($data = $resultado->fetch_assoc()) { + $edades[] = $data; + } + $query->close(); + return $edades; + } + + // Gráfico de Estados + public function obtenerEstados($filtros = []) { + $sql = "SELECT e.nombre AS estado, COUNT(*) AS cantidad + FROM info_candidatos i + INNER JOIN estados e ON i.id_estado = e.id + WHERE 1=1"; + $params = []; + $types = ""; + + if (!empty($filtros['id_estado'])) { + $sql .= " AND i.id_estado = ?"; + $params[] = $filtros['id_estado']; + $types .= "i"; + } + if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { + $sql .= " AND DATE(i.fecha_entrada) >= ? AND DATE(i.fecha_entrada) <= ?"; + $params[] = $filtros['fechaInicio']; + $params[] = $filtros['fechaFin']; + $types .= "ss"; + } + $sql .= " GROUP BY e.nombre ORDER BY e.nombre"; + + $query = $this->db->prepare($sql); + if ($params) $query->bind_param($types, ...$params); $query->execute(); $resultado = $query->get_result(); @@ -457,44 +187,32 @@ public function obtenerEstados($filtros = []) { } $query->close(); return $estados; -} + } -public function obtenerExamenes($filtros = []) { - $sql = "SELECT examen.nombre_examen AS examen, COUNT(*) AS cantidad - FROM candidato - LEFT JOIN examen ON candidato.id_examen = examen.id_examen + // Gráfico de Exámenes + public function obtenerExamenes($filtros = []) { + $sql = "SELECT ex.nombre_examen AS examen, COUNT(*) AS cantidad + FROM candidato c + INNER JOIN examen ex ON c.id_examen = ex.id_examen WHERE 1=1"; $params = []; $types = ""; - if (!empty($filtros['id_rango_edad']) && $filtros['id_rango_edad'] !== "NULL") { - $sql .= " AND candidato.id_rango_edad = ?"; - $params[] = $filtros['id_rango_edad']; - $types .= "i"; - } - if (!empty($filtros['id_genero']) && $filtros['id_genero'] !== "NULL") { - $sql .= " AND candidato.id_genero = ?"; - $params[] = $filtros['id_genero']; - $types .= "i"; - } - if (!empty($filtros['id_examen']) && $filtros['id_examen'] !== "NULL") { - $sql .= " AND candidato.id_examen = ?"; + if (!empty($filtros['id_examen'])) { + $sql .= " AND c.id_examen = ?"; $params[] = $filtros['id_examen']; $types .= "i"; } if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { - $sql .= " AND DATE(candidato.fecha_entrada) >= ? AND DATE(candidato.fecha_salida) <= ?"; + $sql .= " AND DATE(c.fecha_entrada) >= ? AND DATE(c.fecha_entrada) <= ?"; $params[] = $filtros['fechaInicio']; $params[] = $filtros['fechaFin']; $types .= "ss"; } - - $sql .= " GROUP BY examen.nombre_examen ORDER BY examen.nombre_examen"; + $sql .= " GROUP BY ex.nombre_examen ORDER BY ex.nombre_examen"; $query = $this->db->prepare($sql); - if ($params) { - $query->bind_param($types, ...$params); - } + if ($params) $query->bind_param($types, ...$params); $query->execute(); $resultado = $query->get_result(); @@ -504,22 +222,69 @@ public function obtenerExamenes($filtros = []) { } $query->close(); return $examenes; + } -} - -public function obtenerFecha($fechaInicio, $fechaFin) { + // Gráfico de Fechas + public function obtenerFechas($filtros = []) { $sql = "SELECT COUNT(*) AS cantidad FROM candidato - WHERE DATE(fecha_entrada) >= ? AND DATE(fecha_entrada) <= ?"; + WHERE 1=1"; + $params = []; + $types = ""; + + if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { + $sql .= " AND DATE(fecha_entrada) >= ? AND DATE(fecha_entrada) <= ?"; + $params[] = $filtros['fechaInicio']; + $params[] = $filtros['fechaFin']; + $types .= "ss"; + } + $query = $this->db->prepare($sql); - $query->bind_param("ss", $fechaInicio, $fechaFin); + if ($params) $query->bind_param($types, ...$params); $query->execute(); $resultado = $query->get_result(); - $data = $resultado->fetch_assoc(); + $fechas = []; + while ($data = $resultado->fetch_assoc()) { + $fechas[] = $data; + } $query->close(); - // Devuelve un array con un solo objeto para mantener compatibilidad con el frontend - return [ [ 'cantidad' => $data['cantidad'], 'fechaInicio' => $fechaInicio, 'fechaFin' => $fechaFin ] ]; -} + return $fechas; + } + + public function obtenerResumenGenero($filtros = []) { + $sql = "SELECT g.descripcion AS genero, COUNT(*) AS cantidad + FROM candidato c + INNER JOIN genero g ON c.id_genero = g.id_genero + WHERE 1=1"; + $params = []; + $types = ""; + + if (!empty($filtros['id_genero'])) { + $sql .= " AND c.id_genero = ?"; + $params[] = $filtros['id_genero']; + $types .= "i"; + } + if (!empty($filtros['fechaInicio']) && !empty($filtros['fechaFin'])) { + $sql .= " AND DATE(c.fecha_entrada) >= ? AND DATE(c.fecha_entrada) <= ?"; + $params[] = $filtros['fechaInicio']; + $params[] = $filtros['fechaFin']; + $types .= "ss"; + } + $sql .= " GROUP BY g.descripcion ORDER BY g.descripcion"; + + $query = $this->db->prepare($sql); + if ($params) $query->bind_param($types, ...$params); + $query->execute(); + $resultado = $query->get_result(); + + $generos = []; + while ($data = $resultado->fetch_assoc()) { + $generos[] = $data; + } + $query->close(); + return $generos; + } + } ?> \ No newline at end of file diff --git a/js/funcionesGraficos.js b/js/funcionesGraficos.js index 9afe06a..7718338 100644 --- a/js/funcionesGraficos.js +++ b/js/funcionesGraficos.js @@ -76,76 +76,89 @@ async function recuperarCantidadFecha(tipoConsulta, filtros = {}) { } } -async function obtenerDatosEdades(filtros = {}) { - const edad1 = await recuperarCantidadEdad("Menor de 18 años", filtros); - const edad2 = await recuperarCantidadEdad("18 a 24 años", filtros); - const edad3 = await recuperarCantidadEdad("25 a 34 años", filtros); - const edad4 = await recuperarCantidadEdad("35 a 44 años", filtros); - const edad5 = await recuperarCantidadEdad("45 a 54 años", filtros); - const edad6 = await recuperarCantidadEdad("55 a 64 años", filtros); - const edad7 = await recuperarCantidadEdad("65 años o más", filtros); - return [edad1, edad2, edad3, edad4, edad5, edad6, edad7]; +let filtroActivo = null; // Puede ser 'id_rango_edad', 'id_genero', 'id_examen', 'fechas' o null + +function getFiltrosSeleccionados() { + const id_rango_edad = document.getElementById('id_rango_edad')?.value || "NULL"; + const id_genero = document.getElementById('id_genero')?.value || "NULL"; + const id_examen = document.getElementById('id_examen')?.value || "NULL"; + const fechaInicio = document.getElementById('date1')?.value || ""; + const fechaFin = document.getElementById('date2')?.value || ""; + + if (filtroActivo === 'id_rango_edad' && id_rango_edad !== "NULL") { + return { id_rango_edad }; + } + if (filtroActivo === 'id_genero' && id_genero !== "NULL") { + return { id_genero }; + } + if (filtroActivo === 'id_examen' && id_examen !== "NULL") { + return { id_examen }; + } + if (filtroActivo === 'fechas' && fechaInicio && fechaFin) { + return { fechaInicio, fechaFin }; + } + return {}; // Sin filtros +} + +function setFiltroActivo(tipo) { + filtroActivo = tipo; +} +function getFiltroActivo() { + return filtroActivo; } async function obtenerDatosGeneros(filtros = {}) { - const femenino = await recuperarCantidadGenero("Femenino", filtros); - const masculino = await recuperarCantidadGenero("Masculino", filtros); - const noDefinido = await recuperarCantidadGenero("Prefiero no decirlo", filtros); - return [femenino, masculino, noDefinido]; + const response = await fetch("../controllers/graficos.php", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ tipoConsulta: "Generos", ...filtros }), + }); + return await response.json(); +} + +async function obtenerDatosEdades(filtros = {}) { + const response = await fetch("../controllers/graficos.php", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ tipoConsulta: "Edades", ...filtros }), + }); + return await response.json(); } async function obtenerDatosEstados(filtros = {}) { - try { - const estados = await recuperarCantidadEstado("Estados", filtros); - if (!Array.isArray(estados)) { - console.error("Error: 'estados' no es un array. Verifica la respuesta del backend"); - return []; - } - const estadosValidos = estados.filter(estado => estado.estado && estado.cantidad !== undefined); - return estadosValidos; - } catch (error) { - console.error("Error al obtener datos de estados:", error); - return []; - } + const response = await fetch("../controllers/graficos.php", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ tipoConsulta: "Estados", ...filtros }), + }); + return await response.json(); } async function obtenerDatosExamenes(filtros = {}) { - try { - const examenes = await recuperarCantidadExamen("Examenes", filtros); - if (!Array.isArray(examenes)) { - console.error("Error: 'examenes' no es un array. Verifica la respuesta del backend"); - return []; - } - const examenesValidos = examenes.filter(examen => examen.examen && examen.cantidad !== undefined); - return examenesValidos; - } catch (error) { - console.error("Error al obtener datos de examenes:", error); - return []; - } + const response = await fetch("../controllers/graficos.php", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ tipoConsulta: "Examenes", ...filtros }), + }); + return await response.json(); } async function obtenerDatosFechas(filtros = {}) { - try { - const fechas = await recuperarCantidadFecha("Fechas", filtros); - if (!Array.isArray(fechas) || !fechas.length) { - return []; - } - // Solo un objeto con la cantidad total - return fechas; - } catch (error) { - console.error("Error al obtener datos de fechas:", error); - return []; - } + const response = await fetch("../controllers/graficos.php", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ tipoConsulta: "Fechas", ...filtros }), + }); + return await response.json(); } -function getFiltrosSeleccionados() { - return { - id_rango_edad: document.getElementById('id_rango_edad')?.value || "NULL", - id_genero: document.getElementById('id_genero')?.value || "NULL", - id_examen: document.getElementById('id_examen')?.value || "NULL", - fechaInicio: document.getElementById('date1')?.value || "", - fechaFin: document.getElementById('date2')?.value || "" - }; +async function obtenerResumenGenero(filtros = {}) { + const response = await fetch("../controllers/graficos.php", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ tipoConsulta: "ResumenGenero", ...filtros }), + }); + return await response.json(); } export { @@ -154,5 +167,8 @@ export { obtenerDatosEstados, obtenerDatosExamenes, obtenerDatosFechas, - getFiltrosSeleccionados + getFiltrosSeleccionados, + setFiltroActivo, + getFiltroActivo, + obtenerResumenGenero // <-- Exporta la nueva función }; \ No newline at end of file diff --git a/js/inicio.js b/js/inicio.js index 863f2b6..a492b1e 100644 --- a/js/inicio.js +++ b/js/inicio.js @@ -133,27 +133,30 @@ allMenu.forEach(item => { window.addEventListener('click', function (e) { - if(e.target !== imgProfile) { - if(e.target !== dropdownProfile) { - if(dropdownProfile.classList.contains('show')) { - dropdownProfile.classList.remove('show'); - } - } - } + if (profile) { + const imgProfile = profile.querySelector('img'); + const dropdownProfile = profile.querySelector('.profile-link'); + if (imgProfile && dropdownProfile) { + if (e.target !== imgProfile && e.target !== dropdownProfile) { + if (dropdownProfile.classList.contains('show')) { + dropdownProfile.classList.remove('show'); + } + } + } + } - allMenu.forEach(item=> { - const icon = item.querySelector('.icon'); - const menuLink = item.querySelector('.menu-link'); - - if(e.target !== icon) { - if(e.target !== menuLink) { - if (menuLink.classList.contains('show')) { - menuLink.classList.remove('show') - } - } - } - }) -}) + allMenu.forEach(item => { + const icon = item.querySelector('.icon'); + const menuLink = item.querySelector('.menu-link'); + if (icon && menuLink) { + if (e.target !== icon && e.target !== menuLink) { + if (menuLink.classList.contains('show')) { + menuLink.classList.remove('show'); + } + } + } + }); +}); @@ -166,27 +169,122 @@ allProgress.forEach(item=> { item.style.setProperty('--value', item.dataset.value) }) + import { obtenerDatosGeneros, obtenerDatosEdades, obtenerDatosEstados, obtenerDatosExamenes, obtenerDatosFechas, - getFiltrosSeleccionados + getFiltrosSeleccionados, + setFiltroActivo, + getFiltroActivo, + obtenerResumenGenero } from './funcionesGraficos.js'; -// Variables globales para los graficos let chartGenero = null; let chartEdad = null; let chartEstado = null; let chartExamen = null; let chartFecha = null; - -// Controla si el filtro de fecha está activo let filtroFechaActivo = false; +function deshabilitarFiltros(excepto = null) { + const combos = ['id_rango_edad', 'id_genero', 'id_examen']; + combos.forEach(id => { + const el = document.getElementById(id); + if (el) el.disabled = (excepto !== id); + }); + const date1 = document.getElementById('date1'); + const date2 = document.getElementById('date2'); + const btnBuscar = document.getElementById('buscar'); + if (date1) date1.disabled = (excepto !== 'fechas'); + if (date2) date2.disabled = (excepto !== 'fechas'); + if (btnBuscar) btnBuscar.disabled = (excepto !== 'fechas'); +} + +function habilitarTodosFiltros() { + ['id_rango_edad', 'id_genero', 'id_examen'].forEach(id => { + const el = document.getElementById(id); + if (el) el.disabled = false; + }); + const date1 = document.getElementById('date1'); + const date2 = document.getElementById('date2'); + const btnBuscar = document.getElementById('buscar'); + if (date1) date1.disabled = false; + if (date2) date2.disabled = false; + if (btnBuscar) btnBuscar.disabled = false; +} + +async function inicializarGrafico(filtros) { + const datos = await obtenerDatosGeneros(filtros); + const series = datos.map(d => d.cantidad); + const categories = datos.map(d => d.genero); + const options = { + series: [{ name: 'Cantidad', data: series }], + chart: { height: 350, type: 'bar' }, + plotOptions: { bar: { horizontal: false, columnWidth: '55%', borderRadius: 5 } }, + dataLabels: { enabled: true }, + xaxis: { categories }, + tooltip: { y: { formatter: val => val + " personas" } } + }; + if (chartGenero) chartGenero.destroy(); + chartGenero = new ApexCharts(document.querySelector("#chart"), options); + chartGenero.render(); +} + +async function inicializarGrafico2(filtros) { + const datos = await obtenerDatosEdades(filtros); + const series = datos.map(d => d.cantidad); + const categories = datos.map(d => d.rango_edad); + const options2 = { + series: [{ name: 'Cantidad', data: series }], + chart: { height: 350, type: 'bar' }, + plotOptions: { bar: { horizontal: false, columnWidth: '55%', borderRadius: 5 } }, + dataLabels: { enabled: true }, + xaxis: { categories }, + tooltip: { y: { formatter: val => val + " personas" } } + }; + if (chartEdad) chartEdad.destroy(); + chartEdad = new ApexCharts(document.querySelector("#chart2"), options2); + chartEdad.render(); +} + +async function inicializarGrafico3(filtros) { + const datos = await obtenerDatosEstados(filtros); + const series = datos.map(d => d.cantidad); + const categories = datos.map(d => d.estado); + const options3 = { + series: [{ name: 'Cantidad', data: series }], + chart: { height: 350, type: 'bar' }, + plotOptions: { bar: { horizontal: false, columnWidth: '55%', borderRadius: 5 } }, + dataLabels: { enabled: true }, + xaxis: { categories }, + tooltip: { y: { formatter: val => val + " personas" } } + }; + if (chartEstado) chartEstado.destroy(); + chartEstado = new ApexCharts(document.querySelector("#chart3"), options3); + chartEstado.render(); +} + +async function inicializarGrafico4(filtros) { + const datos = await obtenerDatosExamenes(filtros); + const series = datos.map(d => d.cantidad); + const categories = datos.map(d => d.examen); + const options4 = { + series: [{ name: 'Cantidad', data: series }], + chart: { height: 350, type: 'bar' }, + plotOptions: { bar: { horizontal: false, columnWidth: '55%', borderRadius: 5 } }, + dataLabels: { enabled: true }, + xaxis: { categories }, + tooltip: { y: { formatter: val => val + " examenes" } } + }; + if (chartExamen) chartExamen.destroy(); + chartExamen = new ApexCharts(document.querySelector("#chart4"), options4); + chartExamen.render(); +} + async function inicializarGraficoFecha(filtros) { - // Solo dibujar si ambas fechas están presentes y el filtro está activo if (!filtroFechaActivo || !filtros.fechaInicio || !filtros.fechaFin) { if (chartFecha) { chartFecha.destroy(); @@ -194,129 +292,30 @@ async function inicializarGraficoFecha(filtros) { } return; } - - const fechas = await obtenerDatosFechas(filtros); - - if (!fechas.length) { + const datos = await obtenerDatosFechas(filtros); + if (!datos.length) { if (chartFecha) { chartFecha.destroy(); chartFecha = null; } return; } - - // Solo un valor total - const cantidad = fechas[0].cantidad; - const label = `Del ${fechas[0].fechaInicio} al ${fechas[0].fechaFin}`; - + const cantidad = datos[0].cantidad; + const label = `Del ${filtros.fechaInicio} al ${filtros.fechaFin}`; const options = { - series: [{ - name: 'Candidatos', - data: [cantidad] - }], + series: [{ name: 'Candidatos', data: [cantidad] }], chart: { height: 350, type: 'bar' }, xaxis: { categories: [label] }, dataLabels: { enabled: true }, tooltip: { y: { formatter: val => val + " candidatos" } } }; - if (chartFecha) chartFecha.destroy(); chartFecha = new ApexCharts(document.querySelector("#chart5"), options); chartFecha.render(); } -async function inicializarGrafico(filtros) { - const [femenino, masculino, noDefinido] = await obtenerDatosGeneros(filtros); - - const options = { - series: [ - { name: 'Femenino', data: [femenino] }, - { name: 'Masculino', data: [masculino] }, - { name: 'Prefiero no decirlo', data: [noDefinido] }, - ], - chart: { height: 350, type: 'bar' }, - plotOptions: { bar: { horizontal: false, columnWidth: '55%', borderRadius: 5 } }, - dataLabels: { enabled: false }, - xaxis: { categories: ['Géneros'] }, - tooltip: { y: { formatter: val => val + " personas" } } - }; - - if (chartGenero) chartGenero.destroy(); - chartGenero = new ApexCharts(document.querySelector("#chart"), options); - chartGenero.render(); -} - -async function inicializarGrafico2(filtros) { - const [edad1, edad2, edad3, edad4, edad5, edad6, edad7] = await obtenerDatosEdades(filtros); - - const options2 = { - series: [ - { name: 'Menor de 18 años', data: [edad1] }, - { name: '18 a 24 años', data: [edad2] }, - { name: '25 a 34 años', data: [edad3] }, - { name: '35 a 44 años', data: [edad4] }, - { name: '45 a 54 años', data: [edad5] }, - { name: '55 a 64 años', data: [edad6] }, - { name: '65 años o más', data: [edad7] }, - ], - chart: { height: 350, type: 'bar' }, - plotOptions: { bar: { horizontal: false, columnWidth: '55%', borderRadius: 5 } }, - dataLabels: { enabled: false }, - xaxis: { categories: ['Edades'] }, - tooltip: { y: { formatter: val => val + " Años" } } - }; - - if (chartEdad) chartEdad.destroy(); - chartEdad = new ApexCharts(document.querySelector("#chart2"), options2); - chartEdad.render(); -} - -async function inicializarGrafico3(filtros) { - const estados = await obtenerDatosEstados(filtros); - - const seriesData = estados.map(estado => ({ - name: estado.estado, - data: [estado.cantidad] - })); - - const options3 = { - series: seriesData, - chart: { height: 350, type: 'bar' }, - plotOptions: { bar: { horizontal: false, columnWidth: '55%', borderRadius: 5 } }, - dataLabels: { enabled: false }, - xaxis: { categories: estados.map(estado => estado.estado) }, - tooltip: { y: { formatter: val => val + " personas" } } - }; - - if (chartEstado) chartEstado.destroy(); - chartEstado = new ApexCharts(document.querySelector("#chart3"), options3); - chartEstado.render(); -} - -async function inicializarGrafico4(filtros) { - const examenes = await obtenerDatosExamenes(filtros); - - const seriesData = examenes.map(examen => ({ - name: examen.examen, - data: [examen.cantidad] - })); - - const options4 = { - series: seriesData, - chart: { height: 350, type: 'bar' }, - plotOptions: { bar: { horizontal: false, columnWidth: '55%', borderRadius: 5 } }, - dataLabels: { enabled: false }, - xaxis: { categories: examenes.map(examen => examen.examen) }, - tooltip: { y: { formatter: val => val + " examenes" } } - }; - - if (chartExamen) chartExamen.destroy(); - chartExamen = new ApexCharts(document.querySelector("#chart4"), options4); - chartExamen.render(); -} - +// ----------- AQUÍ VA LA FUNCIÓN PRINCIPAL DE ACTUALIZACIÓN ----------- async function actualizarTodosLosGraficos() { - // Si el filtro de fecha está activo, se pasan las fechas, si no, se limpian let filtros = getFiltrosSeleccionados(); if (!filtroFechaActivo) { filtros.fechaInicio = ""; @@ -328,41 +327,114 @@ async function actualizarTodosLosGraficos() { await inicializarGrafico4(filtros); await inicializarGraficoFecha(filtros); } +// --------------------------------------------------------------------- + +async function actualizarTarjetasGenero() { + const filtros = getFiltrosSeleccionados(); + const resumen = await obtenerResumenGenero(filtros); + // Limpia las tarjetas + document.getElementById('card-masculino').textContent = '0'; + document.getElementById('card-femenino').textContent = '0'; + document.getElementById('card-prefiero').textContent = '0'; + // Actualiza según los datos + resumen.forEach(item => { + if (item.genero === 'Masculino') { + document.getElementById('card-masculino').textContent = item.cantidad; + } else if (item.genero === 'Femenino') { + document.getElementById('card-femenino').textContent = item.cantidad; + } else if (item.genero === 'Prefiero no decir') { + document.getElementById('card-prefiero').textContent = item.cantidad; + } + }); +} document.addEventListener('DOMContentLoaded', () => { - // Agrega eventos a los combos si existen + // Solo un filtro a la vez ['id_rango_edad', 'id_genero', 'id_examen'].forEach(id => { const el = document.getElementById(id); if (el) { - el.addEventListener('change', actualizarTodosLosGraficos); + el.addEventListener('change', () => { + if (el.value !== "NULL") { + setFiltroActivo(id); + filtroFechaActivo = false; + // Limpiar y deshabilitar los otros filtros + ['id_rango_edad', 'id_genero', 'id_examen'].forEach(oid => { + if (oid !== id) { + const oel = document.getElementById(oid); + if (oel) oel.value = "NULL"; + } + }); + // Limpiar fechas + const date1 = document.getElementById('date1'); + const date2 = document.getElementById('date2'); + if (date1) date1.value = ''; + if (date2) date2.value = ''; + deshabilitarFiltros(id); + actualizarTodosLosGraficos(); + } else { + setFiltroActivo(null); + filtroFechaActivo = false; + habilitarTodosFiltros(); + actualizarTodosLosGraficos(); + } + }); } }); - // Botón buscar para fechas const btnBuscar = document.getElementById('buscar'); if (btnBuscar) { btnBuscar.addEventListener('click', () => { const date1 = document.getElementById('date1')?.value; const date2 = document.getElementById('date2')?.value; - filtroFechaActivo = !!(date1 && date2); + if (date1 && date2) { + setFiltroActivo('fechas'); + filtroFechaActivo = true; + // Limpiar y deshabilitar combos + ['id_rango_edad', 'id_genero', 'id_examen'].forEach(id => { + const el = document.getElementById(id); + if (el) el.value = "NULL"; + }); + deshabilitarFiltros('fechas'); + } else { + filtroFechaActivo = false; + setFiltroActivo(null); + habilitarTodosFiltros(); + } actualizarTodosLosGraficos(); }); } - // Botón limpiar para quitar filtro de fecha + function limpiarTodo() { + ['id_rango_edad', 'id_genero', 'id_examen'].forEach(id => { + const el = document.getElementById(id); + if (el) { + el.value = "NULL"; + el.disabled = false; + } + }); + const date1 = document.getElementById('date1'); + const date2 = document.getElementById('date2'); + const btnBuscar = document.getElementById('buscar'); + if (date1) { date1.value = ''; date1.disabled = false; } + if (date2) { date2.value = ''; date2.disabled = false; } + if (btnBuscar) btnBuscar.disabled = false; + filtroFechaActivo = false; + setFiltroActivo(null); + actualizarTodosLosGraficos(); + } + const btnLimpiar = document.getElementById('limpiar'); if (btnLimpiar) { - btnLimpiar.addEventListener('click', () => { - const date1 = document.getElementById('date1'); - const date2 = document.getElementById('date2'); - if (date1) date1.value = ''; - if (date2) date2.value = ''; - filtroFechaActivo = false; - actualizarTodosLosGraficos(); - }); + btnLimpiar.addEventListener('click', limpiarTodo); + } + + const btnLimpiar2 = document.getElementById('limpiar2'); + if (btnLimpiar2) { + btnLimpiar2.addEventListener('click', limpiarTodo); } - // SIEMPRE inicializa los gráficos al cargar la página filtroFechaActivo = false; + setFiltroActivo(null); + habilitarTodosFiltros(); actualizarTodosLosGraficos(); }); \ No newline at end of file diff --git a/js/tarjetasPromedio.js b/js/tarjetasPromedio.js index ff7e93d..e27fbe5 100644 --- a/js/tarjetasPromedio.js +++ b/js/tarjetasPromedio.js @@ -45,14 +45,13 @@ async function obtenerPromedioPorGenero() { // Función para actualizar las tarjetas en el DOM function actualizarTarjetas(promF, promM, promND) { - // Multiplicamos por 100 para mostrar el promedio como número decimal simple. - // Aquí simplemente mostramos el promedio como número decimal con 2 decimales + const femenino = document.querySelector("#card-femenino h2"); + const masculino = document.querySelector("#card-masculino h2"); + const prefiero = document.querySelector("#card-prefiero h2"); - document.querySelector("#card-femenino h2").textContent = promF.toFixed(2)+ "%";; - document.querySelector("#card-masculino h2").textContent = promM.toFixed(2) + "%";; - document.querySelector("#card-nodefinido h2").textContent = promND.toFixed(2) + "%";; - - + if (femenino) femenino.textContent = (promF * 100).toFixed(2) + "%"; + if (masculino) masculino.textContent = (promM * 100).toFixed(2) + "%"; + if (prefiero) prefiero.textContent = (promND * 100).toFixed(2) + "%"; } // Ejecutar cuando el DOM esté listo diff --git a/views/inicio.html b/views/inicio.html index d32856a..dc94357 100644 --- a/views/inicio.html +++ b/views/inicio.html @@ -1,291 +1,267 @@ - - - - - - AdminSite + + + + + AdminSite - - - - +
+ - -
- - - +
+

Dashboard

+ - -
-

Dashboard

- +
+
+
+ +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ +

Fecha

+

Ingresa una fecha de inicio:

+
+ +

Ingresa una fecha de final:

+ +
+ + +
+
+
+

Resultado de registros en el rango de fecha ingresado

+ +
+
+
+
+
+
+
- -
-
-
- -
+
+
+

Promedio de géneros:

+
+
+
+
+ +
+

0

+

Femenino

+
+
+
+
+
+
+
+ +
+

0

+

Masculino

+
+
+
+
+
+
+
+ +
+

0

+

Prefiero no decirlo

+
+
+
+
+
+
- -
- -
- - -
+
+
+
+

Generos

+ +
+
+
+
+
+
+
+

Edades

+ +
+
+
+
+
+
+
+

Estados

+ +
+
+
+
+
+
+
+

Examenes

+ +
+
+
+
+
+
+
+
- -
- - -
- -
- - -
- - -

Fecha

-

Ingresa una fecha de inicio:

-
- -

Ingresa una fecha de final:

- -
- - -
-
-
-

Resultado de registros en el rango de fecha ingresado

- -
-
-
-
-
- - -
-
-

Promedio de géneros:

-
-
-
-
- -
-

0

-

Femenino

-
-
-
-
- -
-
-
- -
-

0

-

Masculino

-
-
- -
-
- -
-
-
- -
-

0

-

Prefiero no decirlo

-
-
-
-
-
-
- - -
-
-
-

Generos

- -
-
-
-
-
-
-
-

Edades

- -
-
-
-
-
-
-
-

Estados

- -
-
-
-
-
-
-
-

Examenes

- -
-
-
-
-
-
- - - -
- - - - - - + + + + \ No newline at end of file