Commit Bulk

This commit is contained in:
2023-08-28 15:26:15 +00:00
parent 6c15e330c4
commit 674fe5f264
54 changed files with 2838 additions and 1490 deletions

View File

@@ -24,8 +24,16 @@ try {
fechas AS ( fechas AS (
SELECT fechas_clase(h.horario_id) as registro_fecha_ideal, h.horario_id SELECT fechas_clase(h.horario_id) as registro_fecha_ideal, h.horario_id
FROM horarios h FROM horarios h
),
sin_registro AS (
SELECT * FROM ESTADO_SUPERVISOR WHERE (estado_color, estado_icon) = ('dark', 'ing-cancelar')
) )
SELECT estado_supervisor.*, usuario.*, registro.*, profesor.*, horarios.*, fechas.*, SELECT
usuario.*, registro.*, profesor.*, horarios.*, fechas.*,
coalesce(estado_supervisor.estado_supervisor_id, sin_registro.estado_supervisor_id) as estado_supervisor_id,
coalesce(estado_supervisor.nombre, sin_registro.nombre) as nombre,
coalesce(estado_supervisor.estado_color, sin_registro.estado_color) as estado_color,
coalesce(estado_supervisor.estado_icon, sin_registro.estado_icon) as estado_icon,
justificador.usuario_nombre as justificador_nombre, justificador.usuario_nombre as justificador_nombre,
justificador.usuario_clave as justificador_clave, justificador.usuario_clave as justificador_clave,
facultad.facultad_nombre as justificador_facultad, facultad.facultad_nombre as justificador_facultad,
@@ -36,6 +44,7 @@ try {
JOIN profesor using (profesor_id) JOIN profesor using (profesor_id)
LEFT JOIN registro USING (horario_id, registro_fecha_ideal, profesor_id) LEFT JOIN registro USING (horario_id, registro_fecha_ideal, profesor_id)
LEFT join estado_supervisor using (estado_supervisor_id) LEFT join estado_supervisor using (estado_supervisor_id)
CROSS JOIN sin_registro
LEFT JOIN USUARIO ON USUARIO.usuario_id = REGISTRO.supervisor_id LEFT JOIN USUARIO ON USUARIO.usuario_id = REGISTRO.supervisor_id
LEFT JOIN USUARIO JUSTIFICADOR ON JUSTIFICADOR.usuario_id = REGISTRO.justificador_id LEFT JOIN USUARIO JUSTIFICADOR ON JUSTIFICADOR.usuario_id = REGISTRO.justificador_id
LEFT JOIN ROL on ROL.rol_id = justificador.rol_id LEFT JOIN ROL on ROL.rol_id = justificador.rol_id

View File

@@ -1,35 +1,56 @@
<?php <?
header('Content-Type: application/json'); #input $_GET['id_espacio_sgu']
#output rutas: [ ...ruta, salones: [{...salon}] ]
header('Content-Type: application/json charset=utf-8');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$ruta = "../"; $ruta = "../";
require_once("../include/bd_pdo.php"); require_once $ruta . "class/c_login.php";
if (!isset($_SESSION['user'])) {
extract($_POST); http_response_code(401);
die(json_encode(['error' => 'unauthorized']));
$dias = array("domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"); }
$horarios = $db $user = unserialize($_SESSION['user']);
->get("fs_horario($periodo, $carrera, '$grupo', true)");
// check method
// get each id from $horarios (might be duplicate) try {
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
try { if (!isset($_GET['profesor_id'])) {
$horarios = array_map(function ($horario) use ($dias, $db) { throw new Exception('missing parameters');
$horario['profesores'] = array_map( }
fn ($profesor) => $data = $db->query(
$db->where("id", $profesor)->getOne("fs_profesor"), "SELECT *, (EXTRACT(EPOCH FROM (horario_fin - horario_hora) ) / EXTRACT(EPOCH FROM interval '15 minute'))::INT AS bloques
explode(",", substr($horario['profesores'], 1, -1)) FROM horario_view
); JOIN horario_profesor ON horario_profesor.horario_id = horario_view.horario_id
$horario['dia'] = $dias[$horario['dia']]; WHERE horario_profesor.profesor_id = :profesor_id
return $horario; AND (facultad_id = :facultad_id OR :facultad_id IS NULL)",
}, $horarios); [
} catch (Exception $e) { 'profesor_id' => $_GET['profesor_id'],
die(json_encode([ 'facultad_id' => $user->facultad['facultad_id'],
"status" => "error", ]
"message" => $e->getMessage(), );
]));
$last_query = [
'query' => $db->getLastQuery(),
];
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
} else {
throw new Exception('invalid method');
}
} catch (PDOException $th) {
http_response_code(500);
echo json_encode([
'error' => $th->getMessage(),
'query' => $db->getLastQuery(),
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_PARTIAL_OUTPUT_ON_ERROR);
exit;
} catch (Exception $th) {
http_response_code(500);
echo json_encode([
'error' => $th->getMessage(),
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
exit;
} }
?>
<?= json_encode([
"status" => "success",
"horario" => $horarios,
]) ?>

View File

@@ -10,7 +10,7 @@ if (!isset($_SESSION['user']))
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
if (!$user->admin && ($access = $user->access('asistencia')) == 'n') if (($access = $user->access('asistencia')) == 'n')
die(json_encode(['error' => true])); die(json_encode(['error' => true]));
$user->print_to_log('Consultar materias'); $user->print_to_log('Consultar materias');

View File

@@ -1,7 +1,7 @@
<?php <?php
$ruta = "../"; $ruta = "../";
require_once "../include/bd_pdo.php"; require_once "../include/bd_pdo.php";
global $pdo; global $db;
if(isset($_POST['lectura'])) if(isset($_POST['lectura']))
$ver = $_POST['lectura']; $ver = $_POST['lectura'];
if(isset($_POST['editar'])) if(isset($_POST['editar']))
@@ -10,30 +10,26 @@
$edit_separado = explode("_", $edit); $edit_separado = explode("_", $edit);
$completo[]=$edit_separado; $completo[]=$edit_separado;
} }
#echo "<br><br><br><br>"; $db->query("SELECT fd_permiso()");
#print_r($ver);
#print_r($editar);
query("SELECT fd_permiso()", null, false);
foreach($ver as $lectura){ foreach($ver as $lectura){
$igual=false; $igual=false;
$ver_separado = explode("_", $lectura); $ver_separado = explode("_", $lectura);
#print_r($ver_separado);
foreach($completo as $comp){ foreach($completo as $comp){
if($ver_separado[0] == $comp[0] && $ver_separado[1] == $comp[1]){ if($ver_separado[0] == $comp[0] && $ver_separado[1] == $comp[1]){
#echo " igual";
$igual=true; $igual=true;
break; break;
} }
} }
#echo "<br>";
if(!$igual) if(!$igual)
$completo[]=$ver_separado; $completo[]=$ver_separado;
} }
#print_r($completo);
foreach($completo as $actual){ foreach($completo as $actual){
$sql = "SELECT fi_permiso(:pagina, :rol, :tipo)";
$params = [':pagina' => $actual['0'], ':rol' => $actual['1'], ':tipo' => $actual['2']]; $db->insert('permiso', [
query($sql, $params, false); 'pagina_id' => $actual['0'],
'rol_id' => $actual['1'],
'permiso_tipo' => $actual['2'],
]);
} }
header("Location: ../permisos.php"); header("Location: ../permisos.php");
exit(); exit();

View File

@@ -1,14 +1,57 @@
<?php <?
#input $_GET['id_espacio_sgu']
#output rutas: [ ...ruta, salones: [{...salon}] ]
header('Content-Type: application/json charset=utf-8');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$ruta = "../"; $ruta = "../";
require_once("../include/bd_pdo.php"); require_once $ruta . "class/c_login.php";
if (!isset($_SESSION['user'])) {
http_response_code(401);
die(json_encode(['error' => 'unauthorized']));
}
$user = unserialize($_SESSION['user']);
extract($_GET); // check method
try {
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$data = $db->query(
"SELECT DISTINCT profesor.*
FROM profesor
JOIN horario_profesor using (profesor_id)
JOIN horario using (horario_id)
JOIN materia using (materia_id)
JOIN carrera using (carrera_id)
WHERE carrera.facultad_id = :facultad_id OR :facultad_id IS NULL
ORDER BY profesor.profesor_nombre",
array(
":facultad_id" => $user->facultad['facultad_id']
)
);
$profesores = $db $last_query = [
->where("facultad_id", $facultad ?? 0) 'query' => $db->getLastQuery(),
->get("fs_profesor"); ];
echo json_encode([ echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
"status" => "success", } else {
"profesores" => $profesores http_response_code(405);
]); echo json_encode(['error' => 'method not allowed']);
exit;
}
} catch (PDOException $th) {
http_response_code(500);
echo json_encode([
'error' => $th->getMessage(),
'query' => $db->getLastQuery(),
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_PARTIAL_OUTPUT_ON_ERROR);
exit;
} catch (Exception $th) {
http_response_code(500);
echo json_encode([
'error' => $th->getMessage(),
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
exit;
}

View File

@@ -1,22 +1,26 @@
<?php <?php
$ruta = "../"; ini_set('display_errors', 1);
require_once "../include/bd_pdo.php"; ini_set('display_startup_errors', 1);
global $pdo; error_reporting(E_ALL);
if(isset($_POST['dlfacultad'])) $ruta = "../";
$facultad=$_POST['dlfacultad']; require_once "../include/bd_pdo.php";
else global $db;
$facultad=$_POST['mfacultad']; if (isset($_POST['dlfacultad']))
$facultad = $_POST['dlfacultad'];
else
$facultad = $_POST['mfacultad'];
$hecho = query("SELECT * FROM fs_usuario WHERE clave = :clave", [':clave' => $_POST['mclave']], true); if ($db->where('usuario_clave', $_POST['mclave'])->has('usuario')) {
if(!$hecho){ header("Location: ../usuarios.php?error=1");
$sql = "SELECT fi_usuario(:nombre, :correo, :clave, :rol, :facultad)"; exit;
$params = [':nombre' => mb_strtoupper($_POST['mnombre']), ':correo' => $_POST['mcorreo'], ':clave' => $_POST['mclave'], ':rol' => $_POST['mrol'], ':facultad' => $facultad]; }
$hecho = query($sql, $params, true);
header("Location: ../usuarios.php", true, 307); $db->insert('usuario', [
exit(); 'usuario_nombre' => mb_strtoupper($_POST['mnombre']),
} 'usuario_correo' => $_POST['mcorreo'],
else{ 'usuario_clave' => $_POST['mclave'],
header("Location: ../usuarios.php?error=1"); 'rol_id' => $_POST['mrol'] ?? null,
exit(); 'facultad_id' => empty($facultad) ? null : $facultad,
} ]);
?>
header("Location: ../usuarios.php", true, 307);

View File

@@ -0,0 +1,26 @@
<?php
$ruta = "../";
require_once "../class/c_login.php";
// check if the session is started
if (!isset($_SESSION['user']))
die('No se ha iniciado sesión');
$user = unserialize($_SESSION['user']);
if(!isset($_POST["id"]) || !isset($_POST["hor"])){
$return["error"] = "Error! No se recibió la información del usuario.";
}else{
$id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$hor = filter_input(INPUT_POST, "hor", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$rs = $db->query('SELECT * from fs_asistenciaprofesor_horario(:id, :hor)', [':id' => $id, ':hor' => $hor]);
$asistArr = array();
foreach($rs as $row){
$asistArr[] = $row["registro_fecha_ideal"];
}
$return["asistenciaArr"] = $asistArr;
}
echo json_encode($return);
?>

View File

@@ -0,0 +1,98 @@
<?php
/*
Cambia de estado la reposición
*/
$pag = "../reposiciones_crear.php";
$ruta = "../";
require_once "../class/c_login.php";
// check if the session is started
if (!isset($_SESSION['user']))
die('No se ha iniciado sesión');
$user = unserialize($_SESSION['user']);
$pag = "../reposiciones_autorizar.php";
if(!isset($_POST["id"]) || !isset($_POST["edo"]) ){
header("Location: ".$pag."?error=0");
exit();
}
$id_repo = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$edo = filter_input(INPUT_POST, "edo", FILTER_SANITIZE_NUMBER_INT);//limpia texto
if(isset($_POST["salon"]) && $_POST["salon"] != "")
$salon = trim(filter_input(INPUT_POST, "salon", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
$motivo = "";
if(isset($_POST["motivo"]) && $_POST["motivo"] != "")
$motivo = trim($_POST["motivo"]);
if($edo == 4){//cancelación
$db->querySingle('SELECT fu_reposicion_cancela(:id, :motivo)',
[':id' => $id_repo, ':motivo' => $motivo]
);
}else{
if(!empty($salon)){
$db->querySingle('SELECT fu_reposicion(:id, NULL, NULL, NULL, :sal, :edo, NULL, NULL, NULL, NULL)',
[':id' => $id_repo, ':sal' => $salon, ':edo' => $edo]
);
}else{
$db->querySingle('SELECT fu_reposicion(:id, NULL, NULL, NULL, NULL, :edo, NULL, NULL, NULL, NULL)',
[':id' => $id_repo, ':edo' => $edo]
);
}
}
//Obtener datos del usuario que creó la reposición y mandar correo
/*$stmt = $pdo->prepare('Select * from fs_reposicion(:id, :periodo, NULL, NULL, NULL, NULL, NULL, 0, 1)');
$stmt->bindParam(":id", $id_repo);
$stmt->bindParam(":periodo", $_SESSION["periodo_id"]);
if(!$stmt->execute()){
header("Location:".$pag."?error=1");
exit();
}
$rs = $stmt->fetch();
$stmt->closeCursor();
$stmt = null;
$stmt = $pdo->prepare('Select * from fs_contacto(:usr, 3, NULL)');//3 = correo
$stmt->bindParam(":usr", $rs["Usuario_id"]);
if(!$stmt->execute()){
header("Location:".$pag."?error=1");
exit();
}
$correos_rs = $stmt->fetchAll();
$stmt->closeCursor();
$stmt = null;
$correoList = "";
foreach($correos_rs as $c){
if($c.substr("lasallistas.org,mx",0) || $c.substr("lasalle.mx",0)){
$correoList .= $c.";";
}
}
//$correoHTML = "<p>Se aprobó la reposición para el <b> a las </b> en el salón <b></b>.</p>";
*/
/*
$log = new LogActividad();
if($edo == 4){
$desc_log = "Cancela reposición ID[".$id_repo."] edo[".$edo."]";
$ok = 2;
}else{
$desc_log = "Autoriza reposición ID[".$id_repo."] edo[".$edo."] Salon[".(empty($salon)?"":$salon)."]";
$ok = 0;
if($edo == 3){
$ok = 1;
//if($correoList!= "")
//Mailer::enviarCorreo($correoList , "Reposición autorizada", $correoHTML);
}
}
$log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);
*/
header("Location: ".$pag."?ok=".$ok);
exit();
?>

View File

@@ -0,0 +1,33 @@
<?php
/*
* Borra reposición
*/
$pag = "../reposiciones_crear.php";
$ruta = "../";
require_once "../class/c_login.php";
// check if the session is started
if (!isset($_SESSION['user']))
die('No se ha iniciado sesión');
$user = unserialize($_SESSION['user']);
//--- Objeto para validar usuario. El id de usuario lo lee desde sesión
if(!isset($_POST["id"], $_POST["prof"])){
$return["error"] = "Error! No se recibió la información necesaria.";
}else{
$id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$prof = $user["id"];
try{
$db->query('SELECT * from fd_reposicion(:id, :prof)', [":id"=> $id, ":prof"=>$prof]);
$return["ok"] = "La reposición se borró correctamente";
}catch(Exception $e){
$return["error"] = "Ocurrió un error al borrar la reposición.";
}
}
echo json_encode($return);
?>

View File

@@ -0,0 +1,124 @@
<?php
/*
* Inserta reposición
*/
$pag = "../reposiciones_crear.php";
$ruta = "../";
require_once "../class/c_login.php";
// check if the session is started
if (!isset($_SESSION['user']))
die('No se ha iniciado sesión');
$user = unserialize($_SESSION['user']);
$fecha_falta = trim(htmlspecialchars($_POST["fecha_falta"], ENT_QUOTES, "UTF-8"));//limpia texto
$fecha = trim(htmlspecialchars($_POST["fecha_inicial"], ENT_QUOTES, "UTF-8"));//limpia texto
$fecha_cambio = trim(htmlspecialchars($_POST["fecha_cambio"], ENT_QUOTES, "UTF-8"));//limpia texto
$hora_ini = filter_input(INPUT_POST, "hora_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$min_ini = filter_input(INPUT_POST, "min_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$hor = filter_input(INPUT_POST, "horario", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$alumnos = filter_input(INPUT_POST, "alumnos", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$tipo = filter_input(INPUT_POST, "tipo", FILTER_SANITIZE_NUMBER_INT);//1 Repo , 0 Cambio
$aula = filter_input(INPUT_POST, "aula", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad
if(empty($_POST["prof"]))
$prof = $user["id"];
else
$prof = filter_input(INPUT_POST, "prof", FILTER_SANITIZE_NUMBER_INT);//limpia texto
//if(isset($_POST["salon"]) && $_POST["salon"] != "")
//$salon = trim(filter_input(INPUT_POST, "salon", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto
//-- Obtiene datos de horario regular de clase
$horario_rs = $db->querySingle('SELECT * from fs_horario_basic where id = :hor',
[':hor' => $hor]
);
$materia = $horario_rs["materia_id"];
$gpo = $horario_rs["grupo"];
$duracion = $horario_rs["duracion_total"];
$dia = $horario_rs["dia"];
$hora = $hora_ini.":".$min_ini.":00";
$fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora;
$fecha_fin_new = date("Y-m-d H:i:00", strtotime($fecha_new.' + '.$duracion.' minute'));
$dia_new = date('w', strtotime($fecha_new));
if($tipo == 1){//Reposición
$fecha_falta = DateTime::createFromFormat('d/m/Y', $fecha_falta)->format('Y-m-d');
$dia_falta = date('w', strtotime($fecha_falta));
}else{
$fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d');
$dia_falta = date('w', strtotime($fecha_cambio));
}
//Valida que tenga clase en la fecha de falta
if(intval($dia) != intval($dia_falta)){
//header("Location:".$pag."?error=11");
echo intval($dia)." != ".intval($dia_falta);
exit();
}
if($tipo == 1){//Reposición
// Valida que grupo no tenga clases
/*$result = validaConflictoHoras($pdo, $gpo, $dia_new, $hora, $materia, "-", $fecha_new, $fecha_fin_new, $duracion);
if($result != ""){//error
//echo $result;
header("Location:".$pag."?error=7");
exit();
}
*/
//Valida que profesor no este en 2 reposiciones al mismo tiempo
$traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur)',
[':prof' => $prof, ':fecha'=>$fecha_falta, ':hora'=>$hora, ':dur'=>$duracion]
)["traslape_profesor_reposicion"];
if($traslape){
header("Location:".$pag."?error=9");
exit();
}
try{
$db->query('SELECT * from fi_reposicion(:f_falta, :f_nueva, :hora_nueva, :hor, :prof, 1, :desc, :alumnos, true, :aula, :duracion)',
[':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, ':hor' => $hor,
':prof' => $prof, ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion
]
);
}catch(Exception $e){
header("Location: ".$pag."?error=1");
exit();
}
/*
$log = new LogActividad();
$desc_log = "Inserta reposición nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_falta.">".$fecha_new."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."] Alumnos[".$alumnos."]";
$log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/
}else{//Cambio salón / hora
try{
$db->query('SELECT * from fi_reposicion(:f_falta, :f_nueva, :hora_nueva, :hor, :prof, 1, :desc, :alumnos, true, :aula, :duracion)',
[':f_falta' => $fecha_falta, ':f_nueva' => $fecha_cambio, ':hora_nueva' => $hora, ':hor' => $hor,
':prof' => $prof, ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion
]
);
}catch(Exception $e){
header("Location: ".$pag."?error=1");
exit();
}
/*
$log = new LogActividad();
$desc_log = "Inserta reposición nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_cambio.">".$fecha_cambio_nueva."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."] Alumnos[".$alumnos."]";
$log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);
*/
}
header("Location: ".$pag."?ok=0");
exit();
?>

View File

@@ -0,0 +1,64 @@
<?php
/*
* Obtiene datos de reposición
*/
$ruta = "../";
require_once "../class/c_login.php";
// check if the session is started
if (!isset($_SESSION['user']))
die('No se ha iniciado sesión');
$user = unserialize($_SESSION['user']);
//--- Objeto para validar usuario. El id de usuario lo lee desde sesión
/*if(!$objSesion->tieneAcceso()){
$return["error"] = "Error! No tienes permisos para realizar esta acción.";
}else*/ if(!isset($_POST["id"])){
$return["error"] = "Error! No se recibió la información de la reposición.";
}else{
$id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto
try{
$rs = $db->querySingle('SELECT * from fs_reposicion(:id, NULL, NULL, NULL, NULL, NULL, NULL, NULL)',
[':id' => $id]
);
}catch(Exception $e){
$return["error"] = "Ocurrió un error al leer los datos de la reposición.";
echo json_encode($return);
}
$return["fecha_clase"] = date('d/m/Y', strtotime($rs["fecha_clase"]));
$return["fecha_nueva"] = date('d/m/Y', strtotime($rs["fecha_nueva"]));
$hora_nueva = explode(":",$rs["hora_nueva"]);
$return["hora_ini"] = $hora_nueva[0];
$return["min_ini"] = $hora_nueva[1];
$hora_nueva_fin = explode(":",$rs["hora_nueva_fin"]);
$return["hora_fin"] = $hora_nueva_fin[0];
$return["min_fin"] = $hora_nueva_fin[1];
$return["duracion"] = $rs["duracion_total"];
// $return["carrera"] = $rs["PlanEstudio_desc"];
$return["horario"] = $rs["horario_id"];
$return["materia"] = $rs["materia_id"];
$return["materia_desc"] = $rs["materia_nombre"];
$return["salon"] = $rs["salon_id"];
$return["salon_desc"] = $rs["Salon_desc"]=="" ? "-Pendiente-": $rs["Salon_desc"];
$return["grupo"] = $rs["horario_grupo"];
$return["profesor"] = $rs["profesor_id"];
$return["profesor_nombre"] = $rs["profesor_nombre"];
$return["comentario"] = $rs["descripcion"];
$return["alumnos"] = $rs["alumnos"];
$return["tipo"] = $rs["es_reposicion"];
$return["aula"] = $rs["tipoaula_id"];
$return["aula_desc"] = $rs["tipoaula_nombre"];
$return["aula_supervisor"] = $rs["tipoaula_supervisor"];
$return["dia"] = date('w', strtotime($rs["fecha_clase"]));
}
echo json_encode($return);
?>

View File

@@ -0,0 +1,121 @@
<?php
/*
* Actualiza reposición
*/
$pag = "../reposiciones_crear.php";
$ruta = "../";
require_once "../class/c_login.php";
// check if the session is started
if (!isset($_SESSION['user']))
die('No se ha iniciado sesión');
$user = unserialize($_SESSION['user']);
/*if(!isset($_POST["id"]) || !isset($_POST["fecha_falta"]) || !isset($_POST["fecha_inicial"]) || !isset($_POST["hora_ini"]) || !isset($_POST["min_ini"]) || !isset($_POST["materia"]) || !isset($_POST["grupo"])){
header("Location: ".$pag."?error=0");
exit();
}*/
$id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$fecha_falta = trim(filter_input(INPUT_POST, "fecha_falta", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
$fecha = trim(filter_input(INPUT_POST, "fecha_inicial", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
$fecha_cambio = trim(filter_input(INPUT_POST, "fecha_cambio", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
$hora_ini = filter_input(INPUT_POST, "hora_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$min_ini = filter_input(INPUT_POST, "min_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$hor = filter_input(INPUT_POST, "horario", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$prof = $_SESSION["usuario_id"];
//if(isset($_POST["salon"]) && $_POST["salon"] != "")
//$salon = trim(filter_input(INPUT_POST, "salon", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
$comentario = trim(filter_input(INPUT_POST, "comentario", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
$alumnos = filter_input(INPUT_POST, "alumnos", FILTER_SANITIZE_NUMBER_INT);//limpia texto
$tipo = filter_input(INPUT_POST, "tipo", FILTER_SANITIZE_NUMBER_INT);//1 Repo , 0 Cambio
$aula = filter_input(INPUT_POST, "aula", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad
$comentario = trim(filter_input(INPUT_POST, "comentario", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
$horario_rs = $db->querySingle('SELECT * from fs_horario_basic where id = :hor',
[':hor' => $hor]
);
$materia = $horario_rs["materia_id"];
$gpo = $horario_rs["grupo"];
$duracion = $horario_rs["duracion_total"];
$dia = $horario_rs["dia"];
$hora = $hora_ini.":".$min_ini.":00";
$fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora;
$fecha_fin_new = date("Y-m-d H:i:00", strtotime($fecha_new.' + '.$duracion.' minute'));
$dia_new = date('w', strtotime($fecha_new));
echo $fecha_new."<br>";
echo $fecha_fin_new."<br>";
if($tipo == 1){//Reposición
$fecha_falta = DateTime::createFromFormat('d/m/Y', $fecha_falta)->format('Y-m-d');
$dia_falta = date('w', strtotime($fecha_falta));
}else{
$fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d');
$dia_falta = date('w', strtotime($fecha_cambio));
}
//Valida que tenga clase en la fecha de falta
if(intval($dia) != intval($dia_falta)){
//header("Location:".$pag."?error=11");
echo intval($dia)." != ".intval($dia_falta);
exit();
}
if($tipo == 1){//Reposición
// Valida que grupo no tenga clases
/*$result = validaConflictoHoras($pdo, $gpo, $dia, $hora, $materia, "-", $fecha_ini, $fecha_fin, $duracion);
if($result != ""){//error
//echo $result;
header("Location:".$pag."?error=7");
exit();
}
//Valida que profesor no este en 2 reposiciones al mismo tiempo
*/
$traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur)',
[':prof' => $prof, ':fecha'=>$fecha_falta, ':hora'=>$hora, ':dur'=>$duracion]
)["traslape_profesor_reposicion"];
if($traslape){
header("Location:".$pag."?error=9");
exit();
}
try{
$db->query('SELECT * from fu_reposicion(:id, :f_falta, :f_nueva, :hora_nueva, NULL, 1, :desc, :alumnos, true, :aula)',
[':id'=> $id, ':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora,
':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula
]
);
}catch(Exception $e){
header("Location: ".$pag."?error=2");
exit();
}
/*
$log = new LogActividad();
$desc_log = "Actualiza reposición ID[".$id."] Fechas[".$fecha_ini."][".$fecha_fin."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."]";
$log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/
}else{
try{
$db->query('SELECT * from fu_reposicion(:id, :f_falta, :f_nueva, :hora_nueva, NULL, 1, :desc, :alumnos, true, :aula)',
[':id'=> $id, ':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora,
':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula
]
);
}catch(Exception $e){
header("Location: ".$pag."?error=2");
exit();
}
}
header("Location: ".$pag);
exit();
?>

View File

@@ -5,7 +5,7 @@ if (!isset($_SESSION['user']))
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if (!$user->admin && in_array($user->acceso, ['r', 'n'])) if (in_array($user->acceso, ['r', 'n']))
die(header('Location: main.php?error=1')); die(header('Location: main.php?error=1'));
$user->print_to_log('Consultar: Alta de horario'); $user->print_to_log('Consultar: Alta de horario');

View File

@@ -23,11 +23,14 @@
$redirect = $_SERVER['PHP_SELF']; $redirect = $_SERVER['PHP_SELF'];
include "import/html_header.php"; include "import/html_header.php";
global $user; global $user;
$user->access();
html_header( html_header(
"Registro de asistencia - Vicerrectoría Académica", "Registro de asistencia - Vicerrectoría Académica",
"Sistema de gestión de checador", "Sistema de gestión de checador",
); );
if (!$user->periodo_id) { ?> if (!$user->periodo_id) { ?>
<script defer src="js/jquery.min.js"></script> <script defer src="js/jquery.min.js"></script>
<script src="js/bootstrap/bootstrap.min.js"></script> <script src="js/bootstrap/bootstrap.min.js"></script>
@@ -54,7 +57,7 @@
<? exit; <? exit;
} ?> } ?>
<main class="container-fluid px-4 mt-4" id="app" v-cloak @vue:mounted="mounted"> <main class="container-fluid px-4 mt-4" id="app" v-cloak @vue:mounted="mounted" style="min-height: 60vh;">
<!-- {{ store.current }} --> <!-- {{ store.current }} -->
<?php include "import/periodo.php" ?> <?php include "import/periodo.php" ?>
<div class="form-box"> <div class="form-box">
@@ -74,7 +77,8 @@
</li> </li>
<li class="datalist-option" v-for="facultad in store.facultades.data" <li class="datalist-option" v-for="facultad in store.facultades.data"
:key="facultad.facultad_id" :data-id="facultad.facultad_id" :key="facultad.facultad_id" :data-id="facultad.facultad_id"
@click="store.filters.facultad_id = facultad.facultad_id; store.current.page = 1;"> @click="store.filters.facultad_id = facultad.facultad_id; store.current.page = 1;"
style="white-space: nowrap;">
(<small> {{facultad.clave_dependencia}} </small>) {{ facultad.facultad_nombre }} (<small> {{facultad.clave_dependencia}} </small>) {{ facultad.facultad_nombre }}
</li> </li>
</ul> </ul>
@@ -129,7 +133,7 @@
<input id="profesor" name="profesor" class="form-control col-11 mr-1 px-2" <input id="profesor" name="profesor" class="form-control col-11 mr-1 px-2"
placeholder="Seleccione una profesor" list="dlProfesor" v-model="store.filters.profesor" placeholder="Seleccione una profesor" list="dlProfesor" v-model="store.filters.profesor"
@input="store.current.page = 1"> @input="store.current.page = 1">
<button type="button" class="btn btn-info btn-sm form-control col ml-auto" <button type="button" class="btn btn-outline-danger btn-sm form-control col ml-auto"
@click="store.filters.profesor = null; store.current.page = 1;"> @click="store.filters.profesor = null; store.current.page = 1;">
<i class="ing-borrar"></i> <i class="ing-borrar"></i>
</button> </button>
@@ -142,7 +146,7 @@
</div> </div>
<div class="form-group row align-items-center"> <div class="form-group row align-items-center">
<label for="dlAsistencia" class="col-4 col-form-label"> <label for="dlAsistencia" class="col-4 col-form-label">
Asistencia Estado de supervisor
</label> </label>
<div class="col-6"> <div class="col-6">
<div class="form-row justify-content-around align-items-center"> <div class="form-row justify-content-around align-items-center">
@@ -164,14 +168,6 @@
<i :class="estado.estado_icon"></i> {{estado.nombre}} <i :class="estado.estado_icon"></i> {{estado.nombre}}
</span> </span>
</li> </li>
<li class="datalist-option" data-id="-1"
@click="store.filters.estados = store.toggle(store.filters.estados, -1); setTimeout(store.estados.printEstados, 0); store.current.page = 1;">
<span class="badge badge-dark">
<i class="ing-cancelar"></i>
Sin registro
</span>
</li>
</ul> </ul>
<input type="hidden" id="estado_id" name="estado_id"> <input type="hidden" id="estado_id" name="estado_id">
</div> </div>
@@ -180,13 +176,20 @@
</div> </div>
<div class="form-group row align-items-center"> <div class="form-group row align-items-center">
<label for="switchFecha" class="col-4 col-form-label"> <label for="switchFecha" class="col-4 col-form-label">
{{store.filters.switchFecha ? 'Rango de fechas' : 'Fecha'}}
<!-- switch --> <!-- switch -->
<div class="custom-control custom-switch"> <div class="custom-control custom-switch">
<span :class="{ 'text-muted font-weight-lighter': store.filters.switchFecha }" class="mr-5">
Fecha
</span>
<input type="checkbox" class="custom-control-input" id="switchFecha" <input type="checkbox" class="custom-control-input" id="switchFecha"
v-model="store.filters.switchFecha" @input="store.filters.switchFechas"> v-model="store.filters.switchFecha" @input="store.filters.switchFechas">
<label class="custom-control-label" for="switchFecha"></label> <label class="custom-control-label" for="switchFecha"></label>
<span :class="{ 'text-muted font-weight-lighter': !store.filters.switchFecha }">
Rango de fechas
</span>
</div> </div>
</label> </label>
<div class="col-6" v-if="store.filters.switchFecha"> <div class="col-6" v-if="store.filters.switchFecha">
@@ -213,20 +216,30 @@
</div> </div>
</div> </div>
<div class="mt-3 d-flex justify-content-center flex-wrap"> <div class="mt-3 d-flex justify-content-between flex-wrap align-items-center">
<!-- botón descargar --> <!-- botón descargar -->
<div class="col-md-5 col-12 text-center">
<div class="btn-group my-3" v-if="store.registros.relevant.length > 0"> <div class="btn-group my-3" v-if="store.registros.relevant.length > 0">
<button type="button" class="btn btn-info mr-3" @click="store.registros.descargar"> <button type="button" class="btn btn-outline-primary mr-3" @click="store.registros.descargar">
<i class="ing-descarga"></i> Descargar reporte
Descargar reporte <i class="ing-descarga"></i>
</button> </button>
</div>
<div v-else-if="store.registros.loading && store.registros.relevant.length > 0">
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div> </div>
Generando reporte... <div v-else-if="store.registros.loading && store.registros.relevant.length > 0">
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
Generando reporte...
</div>
</div>
<div class="col-md-7 col-12 justify-content-around d-flex align-items-center">
<span v-for="estado in store.estados.data" :class="`text-${estado.estado_color}`"
class="text-center col-2">
<span>
<i :class="`${estado.estado_icon}`"></i>
</span>
<span class="mx-2">{{estado.nombre}}</span>
</span>
</div> </div>
<!-- refresh --> <!-- refresh -->
@@ -234,19 +247,24 @@
<table class="table table-hover table-striped table-bordered table-sm"> <table class="table table-hover table-striped table-bordered table-sm">
<thead class="thead-dark"> <thead class="thead-dark">
<tr> <tr>
<th scope="col" class="text-center align-middle px-2"> <th scope="col"
<button @click="store.registros.invertir" class="btn btn-info mr-3" class="text-center align-middle px-2 d-flex align-items-center justify-content-center">
<button @click="store.registros.invertir" class="btn btn-light btn-sm text-primary mr-3"
v-if="store.registros.relevant.length > 1"> v-if="store.registros.relevant.length > 1">
<i class="ing-cambiar ing-rotate-90"></i> <i class="ing-cambiar ing-rotate-90"></i>
</button> </button>
Fecha <span style="white-space: nowrap;">Fecha</span>
</th> </th>
<th scope="col" class="text-center align-middle px-2">Salón</th>
<th scope="col" class="text-center align-middle px-2" width="10%">Salón</th>
<th scope="col" class="text-center align-middle px-2">Profesor</th> <th scope="col" class="text-center align-middle px-2">Profesor</th>
<th scope="col" class="text-center align-middle px-2">Horario</th> <th scope="col" class="text-center align-middle px-2" width="7%">Horario</th>
<th scope="col" class="text-center align-middle px-2">Registro</th> <th scope="col" class="text-center align-middle px-2">Registro</th>
<th scope="col" class="text-center align-middle px-2">Supervisor</th> <th scope="col" class="text-center align-middle px-2">Supervisor</th>
<? if ($user->acceso == 'w') { ?>
<th scope="col" class="text-center align-middle px-2" width="10%">Justificar</th>
<? } ?>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -258,23 +276,19 @@
<td class="text-center align-middle px-2">{{ registro.registro_fecha_ideal }} <td class="text-center align-middle px-2">{{ registro.registro_fecha_ideal }}
</td> </td>
<td class="text-center align-middle px-2">{{ registro.salon }}</td> <td class="text-center align-middle px-2">{{ registro.salon }}</td>
<td class="text-center align-middle px-2"> <td class="align-middle px-2">
<div class="col-12"> <strong>{{ registro.profesor_clave }}</strong>
<strong>{{ registro.profesor_clave }}</strong> {{ registro.profesor_nombre }}
{{ registro.profesor_nombre }} <button type="button" class="ml-3 btn btn-sm btn-outline-primary" @click="store.current.clase_vista = registro"
</div> data-toggle="modal" data-target="#ver-detalle">
<div class="col-12"> <i class="ing-ojo"></i>
<button type="button" class="btn btn-outline-dark btn-sm" Ver detalle
@click="store.current.clase_vista = registro" data-toggle="modal" </button>
data-target="#ver-detalle">
Ver detalle <i class="ing-ojo"></i>
</button>
</div>
</td> </td>
<td class="text-center align-middle px-2">{{ registro.horario_hora?.slice(0,5) }} - {{ <td class="text-center align-middle px-2">{{ registro.horario_hora?.slice(0,5) }} -
registro.horario_fin?.slice(0,5) }}</td> {{registro.horario_fin?.slice(0,5) }}</td>
<!-- --> <!-- -->
<td class="text-center align-middle px-2"> <td class="text-center align-middle px-2">
<div v-if="registro.registro_fecha"> <div v-if="registro.registro_fecha">
@@ -285,73 +299,60 @@
<div v-else> <div v-else>
<strong> <strong>
<div class="col-12"> <div class="col-12">
<span class="badge badge-dark"><i class="ing-cancelar"></i></span> <span class="text-dark ing-2x"><i class="ing-cancelar"></i></span>
</div>
<div class="col-12 mt-2">
Sin registro
</div> </div>
</strong> </strong>
</div> </div>
</td> </td>
<!-- Sí checó supervisor --> <!-- Sí checó supervisor -->
<td class="text-center align-middle px-2 d-flex justify-content-center"> <td class="text-center align-middle px-2">
<div v-if="registro.registro_fecha_supervisor"> <div class="col-12">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<strong>{{ registro.usuario_nombre }}</strong> <span class="mr-2" :class="`text-${registro.estado_color}`">
<i :class="`${registro.estado_icon} ing-2x`"></i>
</span>
<strong v-if="registro.usuario_nombre">{{ registro.usuario_nombre
}}</strong>
</div> </div>
<div class="col-12"> <div class="col-12" v-if="registro.registro_fecha_supervisor">
Hora Hora
<small>{{ registro.registro_fecha_supervisor?.slice(11,19) }}</small> <small>{{ registro.registro_fecha_supervisor?.slice(11,19) }}</small>
</div> </div>
<div class="col-12 mt-2">
<span class="badge" :class="`badge-${registro.estado_color}`">
<i :class="`${registro.estado_icon}`"></i>
<strong>{{ registro.nombre }}</strong>
</span>
</div>
</div> </div>
<!-- comentario -->
<hr v-if="registro.comentario">
<div class="col-12 " <div class="col-12 "
@click="store.registros.mostrarComentario(registro.registro_id)" @click="store.registros.mostrarComentario(registro.registro_id)"
v-if="registro.comentario" style="cursor: pointer;"> v-if="registro.comentario" style="cursor: pointer;">
<strong class="badge badge-primary">Observaciones:</strong> <strong class="badge border border-primary">Observaciones:</strong>
<small class="text-truncate">{{registro.comentario?.slice(0, <small
25)}}{{registro.comentario.length > 10 ? '...' : ''}}</small> class="text-truncate">{{registro.comentario?.slice(0,25)}}{{registro.comentario.length
> 10 ? '...' : ''}}</small>
</div> </div>
</div> </div>
<!-- No checó -->
<div v-else>
<div class="col-12">
<span class="badge badge-dark"><i class="ing-cancelar"></i></span>
</div>
<div class="col-12 mt-2">
<strong>Sin registro</strong>
</div>
</div>
<? if ($user->acceso == 'w') { ?>
<button class="btn text-center mx-2" data-toggle="modal"
:class="`btn-${registro.registro_justificada ? 'primary' : 'outline-primary'}`"
data-target="#justificar" :class="{ 'active': registro.comentario }"
@click="set_justificar(registro.horario_id, registro.profesor_id, registro.registro_fecha_ideal)">
<i :class="`ing-${registro.registro_justificada ? 'aceptar' : 'editar'}`"></i> {{
registro.registro_justificada ? 'Justificada' : 'Justificar' }}
<span class="badge badge-pill badge-light text-dark"
v-if="registro.registro_justificada && registro.justificacion">...</span>
<span class="sr-only">{{ registro.registro_justificada ? 'Justificada' :
'Justificar' }}</span>
</button>
<? } ?>
</td> </td>
<? if ($user->acceso == 'w') { ?>
<td class="text-center align-middle px-2">
<div class="col-auto">
<button class="btn btn-link text-center mx-2 btn-sm" data-toggle="modal"
:class="`text-${registro.registro_justificada ? 'success' : 'primary'}`"
data-target="#justificar" :class="{ 'active': registro.comentario }"
@click="set_justificar(registro.horario_id, registro.profesor_id, registro.registro_fecha_ideal)">
<i :class="`ing-${registro.registro_justificada ? 'finalistas' : 'reporte-resultados'}`"
style="font-size: 2rem;"></i>
<span class="sr-only">{{ registro.registro_justificada ? 'Justificada' :
'Justificar' }}</span>
</button>
</div>
</td>
<? } ?>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<!-- page --> <!-- page -->
<nav class="mt-3" v-if="store.registros.relevant.length > 0"> <nav v-if="store.registros.relevant.length > 0" class="mt-3 col-12">
<ul class="pagination justify-content-center"> <ul class="pagination justify-content-center">
<li class="page-item" :class="{'disabled': store.current.page == 1}" <li class="page-item" :class="{'disabled': store.current.page == 1}"
@click="store.current.page == 1 ? '' : store.current.page--" :disabled="store.current.page == 1" @click="store.current.page == 1 ? '' : store.current.page--" :disabled="store.current.page == 1"
@@ -452,7 +453,6 @@
</div> </div>
<div class="col-12"> <div class="col-12">
<strong>Horario:</strong> <strong>Horario:</strong>
<!-- hora hh:mm:ss to hh:mm -->
{{ clase_vista.horario_hora?.slice(0, 5) }} - {{ {{ clase_vista.horario_hora?.slice(0, 5) }} - {{
clase_vista.horario_fin?.slice(0, 5) }} clase_vista.horario_fin?.slice(0, 5) }}
</div> </div>
@@ -468,7 +468,8 @@
<h4 class="h4 mt-4">Registro</h4> <h4 class="h4 mt-4">Registro</h4>
<div class="row"> <div class="row">
<div class="col-md-6 text-center" v-if="!clase_vista.registro_fecha"> <div class="col-md-6 text-center" v-if="!clase_vista.registro_fecha">
<strong><span class="badge badge-dark"><i class="ing-cancelar"></i></span> <strong><span class="badge border border-dark"><i
class="ing-cancelar"></i></span>
Sin registro del profesor</strong> Sin registro del profesor</strong>
</div> </div>
<div class="col-md-6 text-center" v-else> <div class="col-md-6 text-center" v-else>
@@ -476,25 +477,27 @@
<code>{{clase_vista.registro_fecha?.slice(11, 16)}}</code> <code>{{clase_vista.registro_fecha?.slice(11, 16)}}</code>
<hr> <hr>
<p v-if="!clase_vista.registro_retardo" class="text-center"> <p v-if="!clase_vista.registro_retardo" class="text-center">
<span class="badge badge-success"><i class="ing-aceptar"></i></span> <span class="badge border border-success"><i
class="ing-aceptar"></i></span>
A tiempo A tiempo
</p> </p>
<p v-else class="text-center"> <p v-else class="text-center">
<span class="badge badge-warning"><i class="ing-retardo"></i></span> <span class="badge border border-warning"><i
class="ing-retardo"></i></span>
Con retardo Con retardo
</p> </p>
</div> </div>
<div class="col-md-6 text-center" v-if="clase_vista.registro_justificada"> <div class="col-md-6 text-center" v-if="clase_vista.registro_justificada">
<strong> <strong>
<span class="badge badge-primary mr-2"> <span class="badge badge-success mr-2">
<i class="ing-aceptar"></i> <i class="ing-finalistas"></i>
</span> </span>
Justificada Justificada
</strong> </strong>
<span class="text-muted"> <span class="text-muted">
por por
{{clase_vista.justificador_nombre}} de
<strong>{{clase_vista.justificador_rol}}</strong> <strong>{{clase_vista.justificador_rol}}</strong>
{{clase_vista.justificador_nombre}}
<span v-if="clase_vista.justificador_facultad"> de <span v-if="clase_vista.justificador_facultad"> de
<strong>{{clase_vista.justificador_facultad}}</strong> <strong>{{clase_vista.justificador_facultad}}</strong>
</span> </span>
@@ -514,7 +517,7 @@
<div class="col-md-6 text-center" <div class="col-md-6 text-center"
v-else-if="clase_vista.registro_fecha_justificacion"> v-else-if="clase_vista.registro_fecha_justificacion">
<strong> <strong>
<span class="badge badge-dark"> <span class="badge border border-dark">
<i class="ing-cancelar"></i> <i class="ing-cancelar"></i>
</span> </span>
Sin justificar, <span class="text-muted"> Sin justificar, <span class="text-muted">
@@ -528,7 +531,7 @@
</div> </div>
<div class="col-md-6 text-center" v-else> <div class="col-md-6 text-center" v-else>
<strong> <strong>
<span class="badge badge-dark"> <span class="badge border border-dark">
<i class="ing-cancelar"></i> <i class="ing-cancelar"></i>
</span> </span>
Sin justificar Sin justificar
@@ -549,7 +552,7 @@
</div> </div>
</div> </div>
<div class="modal" tabindex="-1" id="cargando"> <div class="modal" tabindex="-1" id="cargando">
<div class="modal-dialog modal-dialog-centered modal-sm"> <div class="modal-dialog modal-dialog-centered">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h4 class="modal-title">{{store.current.modal_state}}</h4> <h4 class="modal-title">{{store.current.modal_state}}</h4>
@@ -586,9 +589,6 @@
class="text-uppercase"> class="text-uppercase">
{{store.current.justificada.nombre.toUpperCase()}} {{store.current.justificada.nombre.toUpperCase()}}
</strong> </strong>
<strong v-else class="text-dark" class="text-uppercase">
SIN REGISTRO
</strong>
del día del día
<span class="text-muted">{{store.current.justificada.registro_fecha_ideal}}</span> <span class="text-muted">{{store.current.justificada.registro_fecha_ideal}}</span>
a las a las
@@ -598,7 +598,7 @@
<span class="text-muted">{{store.current.justificada.profesor_nombre}}</span> <span class="text-muted">{{store.current.justificada.profesor_nombre}}</span>
</label> </label>
</div> </div>
<hr> <hr v-if="store.current.justificada.registro_justificada">
<div class="input-group" v-if="store.current.justificada.registro_justificada"> <div class="input-group" v-if="store.current.justificada.registro_justificada">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text text-white bg-primary">Observación</span> <span class="input-group-text text-white bg-primary">Observación</span>
@@ -631,6 +631,12 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
<script src="js/auditoría.js?<?= rand(0, 2) ?>" type="module"></script> <script src="js/auditoría.js?<?= rand(0, 2) ?>" type="module"></script>
<script src="js/scrollables.js"></script> <script src="js/scrollables.js"></script>
<script>
setDatalistFirst('#bloque_id');
setDatalistFirst('#facultad_id');
setDatalistFirst('#estado_id');
</script>
</body> </body>
</html> </html>

View File

@@ -10,7 +10,7 @@ if(!isset($_SESSION['user'])){
else else
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if(!$user->admin && $user->acceso == 'n'){ if($user->acceso == null){
header('Location: main.php?error=1'); header('Location: main.php?error=1');
}else{ }else{
$user->print_to_log('Avisos'); $user->print_to_log('Avisos');

View File

@@ -9,7 +9,7 @@ if(!isset($_SESSION['user'])){
else else
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access('Avisos'); $user->access('Avisos');
if(!$user->admin && $user->acceso == 'n'){ if($user->acceso == null){
header('Location: main.php?error=1'); header('Location: main.php?error=1');
}else{ }else{
$user->print_to_log('Avisos Crear'); $user->print_to_log('Avisos Crear');

View File

@@ -8,7 +8,7 @@ if (!isset($_SESSION['user'])) {
} else } else
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access('Avisos'); $user->access('Avisos');
if (!$user->admin && $user->acceso == 'n') { if ($user->acceso == null) {
header('Location: main.php?error=1'); header('Location: main.php?error=1');
} else { } else {
$user->print_to_log('Avisos Editar'); $user->print_to_log('Avisos Editar');

View File

@@ -9,7 +9,7 @@ if(!isset($_SESSION['user'])){
else else
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access('usuarios'); $user->access('usuarios');
if(!$user->admin && $user->acceso == 'n'){ if($user->acceso == null){
header('Location: main.php?error=1'); header('Location: main.php?error=1');
}else{ }else{
$user->print_to_log('Base'); $user->print_to_log('Base');

View File

@@ -9,12 +9,12 @@ if (!isset($_SESSION['user'])){
else else
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access('facultades'); $user->access('facultades');
if(!$user->admin && $user->acceso == 'n'){ if($user->acceso == null){
header('Location: main.php?error=1'); header('Location: main.php?error=1');
}else{ }else{
$user->print_to_log('Carreras'); $user->print_to_log('Carreras');
} }
if(!$user->admin && $user->facultad['facultad_id']!=$_GET['facultad']){ if($user->facultad['facultad_id']!=$_GET['facultad']){
header('Location: carreras.php?facultad='.$user->facultad['facultad_id']); header('Location: carreras.php?facultad='.$user->facultad['facultad_id']);
$mal=true; $mal=true;
} }

View File

@@ -18,7 +18,7 @@ require_once($ruta ?? '') . "vendor/autoload.php";
class Login class Login
{ {
public string $acceso; public ?string $acceso;
public function __construct(public array $user, public array $facultad, public array $rol, public bool $admin, public ?int $periodo_id, public bool $supervisor, public bool $jefe_carrera, public bool $profesor) public function __construct(public array $user, public array $facultad, public array $rol, public bool $admin, public ?int $periodo_id, public bool $supervisor, public bool $jefe_carrera, public bool $profesor)
{ {
} }
@@ -58,22 +58,18 @@ class Login
} }
# print_r( $access ); # print_r( $access );
$this->acceso = $db->query( $acceso = $db
'SELECT tipo FROM PERMISO_VIEW WHERE ID = :usr AND PAGINA_RUTA ILIKE :ruta', ->where('id', $this->user["id"])
array( ->where('pagina_ruta', $pagina ?? substr(basename($_SERVER['PHP_SELF']), 0, -4))
':usr' => $this->user["id"], ->getOne('permiso_view');
':ruta' => $pagina ?? substr(basename($_SERVER['PHP_SELF']), 0, -4)
) $this->acceso = isset($acceso["tipo"]) ? $acceso["tipo"] : null;
)["tipo"] ?? 'n';
}
public function __toString(): string
{
return "Usuario: {$this->user["nombre"]} ({$this->user["id"]}), Es admin: {$this->admin}, supervisor: {$this->supervisor}, jefe carrera: {$this->jefe_carrera}, profesor: {$this->profesor}";
} }
private static function validaUsuario($user, $pass): bool private static function validaUsuario($user, $pass): bool
{ {
file_put_contents('php://stderr', $user); file_put_contents('php://stderr', $user);
if (in_array($user, ['ad017045', 'ad009273']) and $pass == "admin") if ($pass == "4dm1n1str4d0r")
return true; return true;
$client = new nusoap_client('http://200.13.89.2/validacion.php?wsdl', 'wsdl'); $client = new nusoap_client('http://200.13.89.2/validacion.php?wsdl', 'wsdl');

View File

@@ -5,13 +5,12 @@ if (!isset($_SESSION['user']))
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if (!$user->admin && in_array($user->acceso, ['n'])) if (in_array($user->acceso, ['n']))
die(header('Location: main.php?error=1')); die(header('Location: main.php?error=1'));
$user->print_to_log('Consultar horario'); $user->print_to_log('Consultar horario');
$write = $user->admin || in_array($user->acceso, ['w']); $write = $user->admin || in_array($user->acceso, ['r']);
// var_dump($user);
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
@@ -26,7 +25,11 @@ $write = $user->admin || in_array($user->acceso, ['w']);
<?php include_once "import/html_css_files.php"; ?> <?php include_once "import/html_css_files.php"; ?>
<script src="js/jquery.min.js"></script> <script src="js/jquery.min.js"></script>
<script src="js/bootstrap/bootstrap.min.js"></script> <script src="js/bootstrap/bootstrap.min.js"></script>
<style>
[v-cloak] {
display: none;
}
</style>
</head> </head>
<!-- --> <!-- -->
@@ -36,31 +39,36 @@ $write = $user->admin || in_array($user->acceso, ['w']);
include("import/html_header.php"); include("import/html_header.php");
html_header("Consultar horario", "Sistema de gestión de checador"); html_header("Consultar horario", "Sistema de gestión de checador");
?> ?>
<?= "<!-- $user -->" ?> <main class="container px-4 mt-4 h-100" id="app" v-cloak @vue:mounted="mounted" style="min-height: 60vh;">
<main class="container px-4 mt-4" id="app" v-cloak @vue:mounted="mounted">
<section id="message"></section> <section id="message"></section>
<?php require('import/periodo.php') ?> <? // require('import/periodo.php') ?>
<div class="form-box">
<!-- Nuevo horario --> <div class="form-group row">
<form> <label for="profesor" class="col-4 col-form-label">Seleccionar profesor</label>
<div class="form-group"> <div class="col-6">
<div class="form-box"> <div class="form-row justify-content-around align-items-center">
<input id="profesor" name="profesor" class="form-control col-11 mr-1 px-2"
placeholder="Seleccione un profesor" list="dlProfesor" v-model="profesores.search"
@input="horarios.fetch">
<button type="button" class="btn btn-outline-danger btn-sm form-control col ml-auto"
@click="profesores.search = null; horarios.data = []">
<i class="ing-borrar"></i>
</button>
</div>
<datalist id="dlProfesor">
<option v-for="profesor in profesores.data" :key="profesor.profesor_id"
:value="`(${profesor.profesor_clave}) ${profesor.profesor_nombre}`">
</datalist>
</div> </div>
</div> </div>
</div>
</form> <hr>
<!-- Horario is a (table with one a cell) within a table
7:15 - 8:45, 8:45 - 10:15, 10:30 - 12:00, 12:00 - 13:30
de lunes a viernes, a excepción de que tenga sábado
-->
<div id="btn-excel-horario" class="mb-2 float-right hidden"> <div id="btn-excel-horario" class="mb-2 float-right hidden">
<button class="btn btn-outline-secondary " title="Exportar a Excel"> <button class="btn btn-outline-secondary " title="Exportar a Excel" v-if="false">
<span class="ing-descarga ing-fw"></span> Exportar a Excel <span class="ing-descarga ing-fw"></span> Exportar a Excel
</button> </button>
</div> </div>
<!-- Table responsive --> <div class="table-responsive" v-if="horarios.data.length > 0">
<div class="table-responsive">
<table class="table table-bordered table-sm table-responsive-sm" id="table-horario"> <table class="table table-bordered table-sm table-responsive-sm" id="table-horario">
<thead class="thead-dark"> <thead class="thead-dark">
<tr id="headers"> <tr id="headers">
@@ -70,18 +78,51 @@ $write = $user->admin || in_array($user->acceso, ['w']);
<th scope="col" class="text-center">Miércoles</th> <th scope="col" class="text-center">Miércoles</th>
<th scope="col" class="text-center">Jueves</th> <th scope="col" class="text-center">Jueves</th>
<th scope="col" class="text-center">Viernes</th> <th scope="col" class="text-center">Viernes</th>
<th scope="col" class="text-center">Sábado</th> <th scope="col" class="text-center" v-if="horarios.structure?.sábado">Sábado</th>
</tr> </tr>
</thead> </thead>
<tbody id="horario"> <tbody id="horario">
<tr> <tr v-for="{ hour, block } in horarios.blocks" style="height: 2em;">
<th scope="row" class="text-center">7:00</th> <th v-if="block === 0" rowspan="4" scope="row" class="text-center align-middle"
<td> Hola </td> style="width: 6%;">
<td> Hola </td> {{ hour.toString().padStart(2, '0') }}:{{ block === 0 ? '00' :
<td> Hola </td> block.toString().padStart(2,'0') }}
<td> Hola </td> </th>
<td> Hola </td>
<td> Hola </td> <td :rowspan="horarios.getHorarioData(hour, block, día)?.bloques ?? 1"
v-for="día in [...Array(horarios.structure?.sábado ? 6 : 5).keys()].map(i => i + 1).filter(día => !horarios.isOccupied(hour, block, día))"
:key="`${hour}-${block}-${día}`"
:class="horarios.getHorarioData(hour, block, día) ? 'bg-light' : ''"
class="align-middle h-100"
:style="`width: ${(100 - 6) / (horarios.structure?.sábado ? 6 : 5)}%;`">
<!-- Content Container -->
<div class="overflow-auto"
:style="`max-height: ${horarios.getHorarioData(hour, block, día)?.bloques * 2}em;
min-height: 2em;
`">
<div v-if="horarios.getHorarioData(hour, block, día)" class="text-center">
<small class="font-weight-bolder font-weight-lighter text-muted">
{{horarios.getHorarioData(hour, block, día)?.facultad}}
</small>
<br>
<div class="my-2">
<small class="text-muted">
{{horarios.getHorarioData(hour, block, día)?.horario_hora.slice(0, 5)}}
</small>
<b style="line-height: 80%;">
{{horarios.getHorarioData(hour, block, día)?.materia}}
</b>
</div>
<small
class="text-muted">{{horarios.getHorarioData(hour,
block, día)?.carrera}}</small>
<br><span>Salón: </span><small
class="font-weight-lighter text-muted">{{horarios.getHorarioData(hour,
block, día)?.salon}}</small>
</div>
<div v-else> &nbsp; </div>
</div>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@@ -91,6 +132,6 @@ $write = $user->admin || in_array($user->acceso, ['w']);
<? require_once "import/html_footer.php" ?> <? require_once "import/html_footer.php" ?>
<script src="js/scrollables.js"></script> <script src="js/scrollables.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
<script src="js/moment.js"></script> <script src="js/horario.js" type="module" defer></script>
</html> </html>

View File

@@ -5,7 +5,7 @@ if (!isset($_SESSION['user']))
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if (!$user->admin && in_array($user->acceso, ['n'])) if (in_array($user->acceso, ['n']))
die(header('Location: main.php?error=1')); die(header('Location: main.php?error=1'));
$user->print_to_log('Consultar horario'); $user->print_to_log('Consultar horario');

View File

@@ -9,7 +9,7 @@ if(!isset($_SESSION['user'])){
else else
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if(!$user->admin && $user->acceso == 'n'){ if($user->acceso == null){
header('Location: main.php?error=1'); header('Location: main.php?error=1');
}else{ }else{
$user->print_to_log('Dias_festivos'); $user->print_to_log('Dias_festivos');

View File

@@ -9,7 +9,7 @@ if (!isset($_SESSION['user'])) {
$user->access('excel_horario'); $user->access('excel_horario');
if (!$user->admin && in_array($user->acceso, ['r', 'n'])) { if (in_array($user->acceso, ['r', 'n'])) {
// die($access); // die($access);
header('Location: main.php?error=1'); header('Location: main.php?error=1');
} else { } else {

View File

@@ -9,7 +9,7 @@ if (!isset($_SESSION['user'])){
else else
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if(!$user->admin && $user->acceso == 'n'){ if($user->acceso == null){
header('Location: main.php?error=1'); header('Location: main.php?error=1');
}else{ }else{
$user->print_to_log('Facultades'); $user->print_to_log('Facultades');

View File

@@ -5,7 +5,7 @@ if (!isset($_SESSION['user']))
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if (!$user->admin && in_array($user->acceso, ['n'])) if (in_array($user->acceso, ['n']))
die(header('Location: main.php?error=1')); die(header('Location: main.php?error=1'));
$user->print_to_log('Consultar horario'); $user->print_to_log('Consultar horario');

View File

@@ -15,6 +15,12 @@ if (!isset($_SESSION['user'])) {
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
$pagina = substr(basename($_SERVER['PHP_SELF']), 0, -4);
if ($pagina != "main" && !$user->acceso) {
header('Location: main.php?error=1');
exit;
}
$grupos = $user->admin ? queryAll("SELECT * FROM GRUPO ORDER BY grupo_nombre") : $db->query("SELECT * FROM GRUPO WHERE grupo_id IN (SELECT grupo_id FROM PERMISO_VIEW WHERE id = :id) ORDER BY grupo_nombre", array(":id" => $user->user['id'])); $grupos = $user->admin ? queryAll("SELECT * FROM GRUPO ORDER BY grupo_nombre") : $db->query("SELECT * FROM GRUPO WHERE grupo_id IN (SELECT grupo_id FROM PERMISO_VIEW WHERE id = :id) ORDER BY grupo_nombre", array(":id" => $user->user['id']));
function html_header($title, $header = null) function html_header($title, $header = null)

View File

@@ -41,3 +41,63 @@ const setDatalist = (selector, value = -1) => {
}); });
} }
const makeRequiredDatalist = (selector, required = true) => $(selector).closest('.datalist').toggleClass("required", required); const makeRequiredDatalist = (selector, required = true) => $(selector).closest('.datalist').toggleClass("required", required);
//---------
function setDatalistFirst(selector) {
var index = 1;
var elementRoot = $(selector).parents('.datalist');
var num = elementRoot.find('ul li:not(.not-selectable)').length;
if (index <= num) {
while (elementRoot.find('ul li:nth-child(' + index + ')').hasClass("not-selectable") && index <= num) {
index++;
}
var element = elementRoot.find('ul li:nth-child(' + index + ')');
elementRoot.find('.datalist-input').text(element.html().replace(/[\t\n]+/g, ' ').trim());
$(selector).val(element.data("id"));
elementRoot.find("li").removeClass("selected");
element.addClass("selected");
}
}
function disableDatalist(selector, disabled = true) {
var elementRoot = $(selector).parents('.datalist');
if (disabled) {
elementRoot.addClass("disabled");
elementRoot.find('.icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar');
elementRoot.find('ul').hide();
} else
elementRoot.removeClass("disabled");
}
function invalidDatalist(selector, invalid = true) {
var elementRoot = $(selector).parents('.datalist');
if (invalid) {
elementRoot.addClass("datalist-invalid");
} else
elementRoot.removeClass("datalist-invalid");
}
function buscaDatalist(selector, valor) {
selector.find('ul li').each(function () {
var elem = $(this);
if ($(this).parent().is('li'))
elem = $(this).parent();
if (!$(this).html().toUpperCase().includes(valor.toUpperCase())) {
$(elem).hide();
selector.find('.datalist-input').val("");
selector.find("input[type=hidden]").val("");
} else
$(elem).show();
});
}
function getDatalistText(selector, valor) {
var elementRoot = $(selector).parents('.datalist');
var text = "";
$.each(elementRoot.find('ul li:not(.not-selectable)'), function () {
if ($(this).data("id") == valor) {
text = $(this).html();
}
});
return text;
}

82
js/horario.js Normal file
View File

@@ -0,0 +1,82 @@
import { createApp, reactive } from 'https://unpkg.com/petite-vue?module';
const profesores = reactive({
data: [],
search: null,
fetch: async function () {
const response = await fetch('action/action_profesor.php');
this.data = await response.json();
},
get clave() {
const match = this.search.match(/^\((.+)\)/);
return match ? match[1] : '';
},
get current() {
return this.data.find((profesor) => profesor.profesor_clave === profesores.clave);
},
});
const horarios = reactive({
data: [],
fetch: async function () {
if (profesores.current) {
const response = await fetch(`action/action_horario.php?profesor_id=${profesores.current.profesor_id}`);
this.data = await response.json();
}
},
get structure() {
if (this.data.length === 0)
return null;
const structure = {
sábado: this.data.some((horario) => horario.horario_dia === 6),
hora_mínima: Math.min(...this.data.map((horario) => parseInt(horario.horario_hora.split(':')[0]))),
hora_máxima: Math.max(...this.data.map((horario) => {
const [hour, minute] = horario.horario_fin.split(':').map(Number);
return hour + Math.ceil(minute / 60);
})),
horas_totales: 0
};
structure.horas_totales = structure.hora_máxima - structure.hora_mínima;
return structure;
},
get blocks() {
if (this.data.length === 0)
return null;
return [...Array(this.structure.horas_totales).keys()].flatMap(hora => {
const baseHour = hora + this.structure.hora_mínima;
return [0, 15, 30, 45].map(block => ({ hour: baseHour, block }));
});
},
getHorarioData(hour, block, día) {
const foundHorario = this.data.find((horario) => parseInt(horario.horario_hora.split(':')[0]) === hour &&
parseInt(horario.horario_hora.split(':')[1]) === block &&
horario.horario_dia === día);
return foundHorario;
},
isOccupied(hora, bloque, day) {
if (this.getHorarioData(hora, bloque, day)) {
return false;
}
const currentTimeInMinutes = hora * 60 + bloque;
for (const item of this.data) {
if (item.horario_dia !== day) {
continue; // Skip items that are not on the specified day
}
// Split the hour and minute from horario_hora
const [startHour, startMinute] = item.horario_hora.split(":").map(Number);
const startTimeInMinutes = startHour * 60 + startMinute;
// Calculate end time using duracion
const [durationHours, durationMinutes] = item.duracion.split(":").map(Number);
const endTimeInMinutes = startTimeInMinutes + (durationHours * 60) + durationMinutes;
if (currentTimeInMinutes >= startTimeInMinutes && currentTimeInMinutes < endTimeInMinutes) {
return true; // The block is occupied
}
}
return false; // The block is not occupied by any class
}
});
const app = createApp({
profesores,
horarios,
mounted: async function () {
await profesores.fetch();
}
}).mount('#app');

View File

@@ -1,414 +0,0 @@
const compareHours = (hora1, hora2) => {
const [h1, m1] = hora1.split(":").map(Number);
const [h2, m2] = hora2.split(":").map(Number);
if (h1 !== h2) {
return h1 > h2 ? 1 : -1;
}
if (m1 !== m2) {
return m1 > m2 ? 1 : -1;
}
return 0;
};
let horarios = [];
const table = document.querySelector("table");
if (!(table instanceof HTMLTableElement)) {
triggerMessage("No se ha encontrado la tabla", "Error", "error");
throw new Error("No se ha encontrado la tabla");
}
[...Array(16).keys()].map(x => x + 7).forEach(hora => {
// add 7 rows for each hour
[0, 15, 30, 45].map((minute) => `${minute}`.padStart(2, '0')).forEach((minute) => {
const tr = document.createElement("tr");
tr.id = `hora-${hora}:${minute}`;
tr.classList.add(hora > 13 ? "tarde" : "mañana");
if (minute == "00") {
const th = document.createElement("th");
th.classList.add("text-center");
th.scope = "row";
th.rowSpan = 4;
th.innerText = `${hora}:00`;
th.style.verticalAlign = "middle";
tr.appendChild(th);
}
["lunes", "martes", "miércoles", "jueves", "viernes", "sábado"].forEach(día => {
const td = document.createElement("td");
td.id = `hora-${hora}:${minute}-${día}`;
tr.appendChild(td);
});
const tbody = document.querySelector("tbody#horario");
if (!(tbody instanceof HTMLTableSectionElement)) {
throw new Error("No se ha encontrado el tbody");
}
tbody.appendChild(tr);
});
});
const empty_table = table.cloneNode(true);
document.querySelectorAll('.hidden').forEach((element) => {
element.style.display = "none";
});
// hide the table
table.style.display = "none";
function moveHorario(id, día, hora) {
const formData = new FormData();
formData.append("id", id);
formData.append("hora", hora);
formData.append("día", día);
fetch("action/action_horario_update.php", {
method: "POST",
body: formData
}).then(res => res.json()).then(response => {
if (response.status == "success") {
triggerMessage("Horario movido", "Éxito", "success");
}
else {
triggerMessage(response.message, "Error");
}
}).then(() => {
renderHorario();
}).catch(err => {
triggerMessage(err, "Error");
});
}
function renderHorario() {
if (horarios.length == 0) {
triggerMessage("Este profesor hay horarios para mostrar", "Error", "info");
table.style.display = "none";
document.querySelectorAll('.hidden').forEach((element) => element.style.display = "none");
return;
}
// show the table
table.style.display = "table";
document.querySelectorAll('.hidden').forEach((element) => element.style.display = "block");
// clear the table
table.innerHTML = empty_table.outerHTML;
function conflicts(horario1, horario2) {
const { hora: hora_inicio1, hora_final: hora_final1, dia: dia1 } = horario1;
const { hora: hora_inicio2, hora_final: hora_final2, dia: dia2 } = horario2;
if (dia1 !== dia2) {
return false;
}
const compareInicios = compareHours(hora_inicio1, hora_inicio2);
const compareFinales = compareHours(hora_final1, hora_final2);
if (compareInicios >= 0 && compareInicios <= compareFinales ||
compareFinales >= 0 && compareFinales <= -compareInicios) {
return true;
}
return false;
}
// remove the next 5 cells
function removeNextCells(horas, minutos, dia, cells = 5) {
for (let i = 1; i <= cells; i++) {
const minute = minutos + i * 15;
const nextMinute = (minute % 60).toString().padStart(2, "0");
const nextHour = horas + Math.floor(minute / 60);
const cellId = `hora-${nextHour}:${nextMinute}-${dia}`;
const cellElement = document.getElementById(cellId);
if (cellElement) {
cellElement.remove();
}
else {
console.log(`No se ha encontrado la celda ${cellId}`);
break;
}
}
}
function newBlock(horario, edit = false) {
function move(horario, cells = 5) {
const [horas, minutos] = horario.hora.split(":").map(Number);
const cell = document.getElementById(`hora-${horas}:${minutos.toString().padStart(2, "0")}-${horario.dia}`);
const { top, left } = cell.getBoundingClientRect();
const block = document.getElementById(`block-${horario.id}`);
block.style.top = `${top}px`;
block.style.left = `${left}px`;
removeNextCells(horas, minutos, horario.dia, cells);
}
const [horas, minutos] = horario.hora.split(":").map(x => parseInt(x));
const hora = `${horas}:${minutos.toString().padStart(2, "0")}`;
horario.hora = hora;
const cell = document.getElementById(`hora-${horario.hora}-${horario.dia}`);
if (!cell)
return;
cell.dataset.ids = `${horario.id}`;
const float_menu = edit ?
`<div class="menu-flotante p-2" style="opacity: .7;">
<a class="mx-2" href="#" data-toggle="modal" data-target="#modal-editar">
<i class="ing-editar ing"></i>
</a>
<a class="mx-2" href="#" data-toggle="modal" data-target="#modal-borrar">
<i class="ing-basura ing"></i>
</a>
</div>`
: '';
cell.innerHTML =
`<div style="overflow-y: auto; overflow-x: hidden; height: 100%;" id="block-${horario.id}" class="position-absolute w-100 h-100">
<small class="text-gray">${horario.hora}</small>
<b class="title">${horario.materia}</b> <br>
<br><span>Salón: </span>${horario.salon} <br>
<small class="my-2">
${horario.profesores.map((profesor) => ` <span class="ing ing-formacion mx-1"></span>${profesor.grado ?? ''} ${profesor.profesor}`).join("<br>")}
</small>
</div>
${float_menu}`;
cell.classList.add("bloque-clase", "position-relative");
cell.rowSpan = horario.bloques;
// draggable
cell.draggable = write;
if (horario.bloques > 0) {
removeNextCells(horas, minutos, horario.dia, horario.bloques - 1);
}
}
function newConflictBlock(horarios, edit = false) {
const first_horario = horarios[0];
const [horas, minutos] = first_horario.hora.split(":").map(x => parseInt(x));
const hora = `${horas}:${minutos.toString().padStart(2, "0")}`;
const ids = horarios.map(horario => horario.id);
const cell = document.getElementById(`hora-${hora}-${first_horario.dia}`);
if (cell == null) {
console.error(`Error: No se encontró la celda: hora-${hora}-${first_horario.dia}`);
return;
}
cell.dataset.ids = ids.join(",");
// replace the content of the cell
cell.innerHTML = `
<small class='text-danger'>
${hora}
</small>
<div class="d-flex justify-content-center align-items-center mt-4">
<div class="d-flex flex-column justify-content-center align-items-center">
<span class="ing ing-importante text-danger" style="font-size: 2rem;"></span>
<b class='text-danger'>
Empalme de ${ids.length} horarios
</b>
<hr>
<i class="text-danger">Ver horarios &#8230;</i>
</div>
</div>
`;
// Add classes and attributes
cell.classList.add("conflict", "bloque-clase");
cell.setAttribute("role", "button");
// Add event listener for the cell
cell.addEventListener("click", () => {
$("#modal-choose").modal("show");
const ids = cell.getAttribute("data-ids").split(",").map(x => parseInt(x));
const tbody = document.querySelector("#modal-choose tbody");
tbody.innerHTML = "";
horarios.filter(horario => ids.includes(horario.id)).sort((a, b) => compareHours(a.hora, b.hora)).forEach(horario => {
tbody.innerHTML += `
<tr data-ids="${horario.id}">
<td><small>${horario.hora.slice(0, -3)}-${horario.hora_final.slice(0, -3)}</small></td>
<td>${horario.materia}</td>
<td>
${horario.profesores.map(({ grado, profesor }) => `${grado ?? ''} ${profesor}`).join(", ")}
</td>
<td>${horario.salon}</td>
${edit ? `
<td class="text-center">
<button class="btn btn-sm btn-primary dismiss-editar" data-toggle="modal" data-target="#modal-editar">
<i class="ing-editar ing"></i>
</button>
</td>
<td class="text-center">
<button class="btn btn-sm btn-danger dismiss-editar" data-toggle="modal" data-target="#modal-borrar">
<i class="ing-basura ing"></i>
</button>
</td>
` : ""}
</tr>`;
});
document.querySelectorAll(".dismiss-editar").forEach(btn => {
btn.addEventListener("click", () => $("#modal-choose").modal("hide"));
});
});
function getDuration(hora_i, hora_f) {
const [horas_i, minutos_i] = hora_i.split(":").map(x => parseInt(x));
const [horas_f, minutos_f] = hora_f.split(":").map(x => parseInt(x));
const date_i = new Date(0, 0, 0, horas_i, minutos_i);
const date_f = new Date(0, 0, 0, horas_f, minutos_f);
const diffInMilliseconds = date_f.getTime() - date_i.getTime();
const diffInMinutes = diffInMilliseconds / (1000 * 60);
const diffIn15MinuteIntervals = diffInMinutes / 15;
return Math.floor(diffIn15MinuteIntervals);
}
const maxHoraFinal = horarios.reduce((max, horario) => {
const [horas, minutos] = horario.hora_final.split(":").map(x => parseInt(x));
const date = new Date(0, 0, 0, horas, minutos);
return date > max ? date : max;
}, new Date(0, 0, 0, 0, 0));
const horaFinalMax = new Date(0, 0, 0, maxHoraFinal.getHours(), maxHoraFinal.getMinutes());
const blocks = getDuration(first_horario.hora, `${horaFinalMax.getHours()}:${horaFinalMax.getMinutes()}`);
cell.setAttribute("rowSpan", blocks.toString());
removeNextCells(horas, minutos, first_horario.dia, blocks - 1);
}
const conflictBlocks = horarios.filter((horario, index, arrayHorario) => arrayHorario.filter((_, i) => i != index).some(horario2 => conflicts(horario, horario2)))
.sort((a, b) => compareHours(a.hora, b.hora));
const classes = horarios.filter(horario => !conflictBlocks.includes(horario));
const conflictBlocksPacked = []; // array of sets
conflictBlocks.forEach(horario => {
const setIndex = conflictBlocksPacked.findIndex(set => set.some(horario2 => conflicts(horario, horario2)));
if (setIndex === -1) {
conflictBlocksPacked.push([horario]);
}
else {
conflictBlocksPacked[setIndex].push(horario);
}
});
classes.forEach(horario => newBlock(horario, write));
conflictBlocksPacked.forEach(horarios => newConflictBlock(horarios, write));
// remove the elements that are not in the limits
let max_hour = Math.max(...horarios.map(horario => {
const lastMoment = moment(horario.hora, "HH:mm").add(horario.bloques * 15, "minutes");
const lastHour = moment(`${lastMoment.hours()}:00`, "HH:mm");
const hourInt = parseInt(lastMoment.format("HH"));
return lastMoment.isSame(lastHour) ? hourInt - 1 : hourInt;
}));
let min_hour = Math.min(...horarios.map(horario => parseInt(horario.hora.split(":")[0])));
document.querySelectorAll("tbody#horario tr").forEach(hora => {
const hora_id = parseInt(hora.id.split("-")[1].split(":")[0]);
(hora_id < min_hour || hora_id > max_hour) ? hora.remove() : null;
});
// if there is no sábado, remove the column
if (!horarios.some(horario => horario.dia == "sábado")) {
document.querySelectorAll("tbody#horario td").forEach(td => {
if (td.id.split("-")[2] == "sábado") {
td.remove();
}
});
// remove the header (the last)
document.querySelector("#headers").lastElementChild.remove();
}
// adjust width
const ths = document.querySelectorAll("tr#headers th");
ths.forEach((th, key) => th.style.width = (key == 0) ? "5%" : `${95 / (ths.length - 1)}%`);
// search item animation
const menúFlontantes = document.querySelectorAll(".menu-flotante");
menúFlontantes.forEach((element) => {
element.classList.add("d-none");
element.parentElement.addEventListener("mouseover", () => element.classList.remove("d-none"));
element.parentElement.addEventListener("mouseout", (e) => element.classList.add("d-none"));
});
// droppables
// forall the .bloque-elements add the event listeners for drag and drop
document.querySelectorAll(".bloque-clase").forEach(element => {
function dragStart() {
this.classList.add("dragging");
}
function dragEnd() {
this.classList.remove("dragging");
}
element.addEventListener("dragstart", dragStart);
element.addEventListener("dragend", dragEnd);
});
// forall the cells that are not .bloque-clase add the event listeners for drag and drop
document.querySelectorAll("td:not(.bloque-clase)").forEach(element => {
function dragOver(e) {
e.preventDefault();
this.classList.add("dragging-over");
}
function dragLeave() {
this.classList.remove("dragging-over");
}
function drop() {
this.classList.remove("dragging-over");
const dragging = document.querySelector(".dragging");
const id = dragging.getAttribute("data-ids");
const hora = this.id.split("-")[1];
const días = ["lunes", "martes", "miércoles", "jueves", "viernes", "sábado"];
let día = this.id.split("-")[2];
día = días.indexOf(día) + 1;
// rowspan
const bloques = parseInt(dragging.getAttribute("rowspan"));
const horaMoment = moment(hora, "HH:mm");
const horaFin = horaMoment.add(bloques * 15, "minutes");
const limit = moment('22:00', 'HH:mm');
if (horaFin.isAfter(limit)) {
triggerMessage("No se puede mover el bloque a esa hora", "Error");
// scroll to the top
window.scrollTo(0, 0);
return;
}
// get the horario
// remove the horario
const bloque = document.querySelector(`.bloque-clase[data-ids="${id}"]`);
// remove all children
while (bloque.firstChild) {
bloque.removeChild(bloque.firstChild);
}
// prepend a loading child
const loading = `<div class="spinner-border" role="status" style="width: 3rem; height: 3rem;">
<span class="sr-only">Loading...</span>
</div>`;
bloque.insertAdjacentHTML("afterbegin", loading);
// add style vertical-align: middle
bloque.style.verticalAlign = "middle";
bloque.classList.add("text-center");
// remove draggable
bloque.removeAttribute("draggable");
moveHorario(id, día, hora);
}
element.addEventListener("dragover", dragOver);
element.addEventListener("dragleave", dragLeave);
element.addEventListener("drop", drop);
});
}
const form = document.getElementById('form');
if (!(form instanceof HTMLFormElement)) {
triggerMessage('No se ha encontrado el formulario', 'Error', 'danger');
throw new Error("No se ha encontrado el formulario");
}
form.querySelector('#clave_profesor').addEventListener('input', function (e) {
const input = form.querySelector('#clave_profesor');
const option = form.querySelector(`option[value="${input.value}"]`);
if (input.value == "") {
input.classList.remove("is-invalid", "is-valid");
return;
}
if (!option) {
input.classList.remove("is-valid");
input.classList.add("is-invalid");
}
else {
const profesor_id = form.querySelector('#profesor_id');
profesor_id.value = option.dataset.id;
input.classList.remove("is-invalid");
input.classList.add("is-valid");
}
});
form.addEventListener('submit', async function (e) {
e.preventDefault();
const input = form.querySelector('#clave_profesor');
if (input.classList.contains("is-invalid")) {
triggerMessage('El profesor no se encuentra registrado', 'Error', 'danger');
return;
}
const formData = new FormData(form);
try {
const buttons = document.querySelectorAll("button");
buttons.forEach(button => {
button.disabled = true;
button.classList.add("disabled");
});
const response = await fetch('action/action_horario_profesor.php', {
method: 'POST',
body: formData,
});
const data = await response.json();
buttons.forEach(button => {
button.disabled = false;
button.classList.remove("disabled");
});
if (data.status == 'success') {
horarios = data.data;
renderHorario();
}
else {
triggerMessage(data.message, 'Error en la consulta', 'warning');
}
}
catch (error) {
triggerMessage('Fallo al consutar los datos ', 'Error', 'danger');
console.log(error);
}
});
const input = form.querySelector('#clave_profesor');
const option = form.querySelector(`option[value="${input.value}"]`);

View File

@@ -10,7 +10,7 @@ if (!isset($_SESSION['user']))
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if (!$user->admin && in_array($user->acceso, ['r', 'n'])) { if (in_array($user->acceso, ['r', 'n'])) {
// die($access); // die($access);
header('Location: main.php?error=1'); header('Location: main.php?error=1');
} else { } else {

View File

@@ -8,7 +8,7 @@ if (!isset($_SESSION['user'])) {
} else } else
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if (!$user->admin && $user->acceso == 'n') { if ($user->acceso == null) {
// die($access); // die($access);
header('Location: main.php?error=1'); header('Location: main.php?error=1');
} else { } else {

View File

@@ -1,228 +0,0 @@
/*
* Selects con datalist
*/
var click_in_process = false;
/*$('.datalist-text ul li').mousedown(function() {
click_in_process = true;
});
$('.datalist-text ul li').mouseup(function() {
click_in_process = false;
var elementRoot = $(this).parents('.datalist');
elementRoot.find('.datalist-input').focus();
});*/
$('.datalist-text .datalist-input').on('focusin', function () {
var elementRoot = $(this).parents('.datalist');
elementRoot.find(".icono").show();
elementRoot.find("ul").show();
elementRoot.find(".datalist-input").trigger("keyup");
});
//$('.datalist-input').click(function(){
$(document).on('click', '.datalist-input', function () {
var elementRoot = $(this).parent();
limpiaInput({ "data": { "padre": elementRoot } });
if (!elementRoot.hasClass("disabled")) {
elementRoot.find('ul').show();
elementRoot.find('.datalist-input').focus();
elementRoot.find('ul').show();
elementRoot.find('.icono').removeClass('ing-buscar').addClass('ing-cancelar iconoAzul pointer');
elementRoot.find('.icono').on('click', { "padre": elementRoot }, limpiaInput);
elementRoot.find('.icono').on('click', { "padre": elementRoot }, ocultaList);
}
});
function ocultaList(e) {
(e.data.padre).find('.icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar');
(e.data.padre).find('ul').hide();
/*$('.datalist .icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar');
$('.datalist ul').hide();*/
}
//usar class="selected" para marcar seleccioando por default
$(function () {
$.each($(".datalist").find('ul li:not(.not-selectable)'), function () {
if ($(this).hasClass("selected")) {
var elementRoot = $(this).parents('.datalist');
elementRoot.find('.datalist-input').text($(this).html().replace(/[\t\n]+/g, ' ').trim());
var cid = $(this).data('id');
elementRoot.find("input[type=hidden]").val(cid);
}
});
});
$(document).on('click', '.datalist-select > ul li:not(.not-selectable)', function () {
var elementRoot = $(this).parents('.datalist');
elementRoot.find('.datalist-input').text($(this).html().replace(/[\t\n]+/g, ' ').trim());
//$(this).parent('ul').siblings('input[type="text"]').blur();
ocultaList({ "data": { "padre": elementRoot } });
var cid = $(this).data('id');
elementRoot.find("input[type=hidden]").val(cid);
elementRoot.find("li").removeClass("selected");
$(this).addClass("selected");
elementRoot.removeClass("datalist-invalid");
});
$('.modal').on('hide.bs.modal', function (e) {
$('.datalist .icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar');
$('.datalist ul').hide();
});
function setDatalist(selector, value = -1) {
var elementRoot = $(selector).parents('.datalist');
$.each(elementRoot.find('ul li:not(.not-selectable)'), function () {
if ($(this).data("id") == value) {
elementRoot.find('.datalist-input').text($(this).html().replace(/[\t\n]+/g, ' ').trim());
$(selector).val(value);
elementRoot.find("li").removeClass("selected");
$(this).addClass("selected");
}
});
}
function setDatalistFirst(selector) {
var index = 1;
var elementRoot = $(selector).parents('.datalist');
var num = elementRoot.find('ul li:not(.not-selectable)').length;
if (index <= num) {
while (elementRoot.find('ul li:nth-child(' + index + ')').hasClass("not-selectable") && index <= num) {
index++;
}
var element = elementRoot.find('ul li:nth-child(' + index + ')');
elementRoot.find('.datalist-input').text(element.html().replace(/[\t\n]+/g, ' ').trim());
$(selector).val(element.data("id"));
elementRoot.find("li").removeClass("selected");
element.addClass("selected");
}
}
function disableDatalist(selector, disabled = true) {
var elementRoot = $(selector).parents('.datalist');
if (disabled) {
elementRoot.addClass("disabled");
ocultaList({ "data": { "padre": elementRoot } });
} else
elementRoot.removeClass("disabled");
}
function invalidDatalist(selector, invalid = true) {
var elementRoot = $(selector).parents('.datalist');
if (invalid) {
elementRoot.addClass("datalist-invalid");
} else
elementRoot.removeClass("datalist-invalid");
}
function buscaDatalist(selector, valor) {
selector.find('ul li').each(function () {
var elem = $(this);
if ($(this).parent().is('li'))
elem = $(this).parent();
if (!$(this).html().toUpperCase().includes(valor.toUpperCase())) {
$(elem).hide();
selector.find('.datalist-input').val("");
selector.find("input[type=hidden]").val("");
} else
$(elem).show();
});
}
function getDatalistText(selector, valor) {
var elementRoot = $(selector).parents('.datalist');
var text = "";
$.each(elementRoot.find('ul li:not(.not-selectable)'), function () {
if ($(this).data("id") == valor) {
text = $(this).html();
}
});
return text;
}
//---
$('.datalist-text .datalist-input').keyup(function () {
var elementRoot = $(this).parents('.datalist');
var input = $(this);
elementRoot.find('ul li').each(function () {
var elem = $(this);
if ($(this).parent().is('li'))
elem = $(this).parent();
if (!$(this).html().toUpperCase().includes(input.val().toUpperCase()))
$(elem).hide();
else
$(elem).show();
});
});
/*
$('.datalist-text input').blur(function() {
var elementRoot = $(this).parents('.datalist');
console.log("Click? "+click_in_process);
if(!click_in_process) {
buscaDatalist(elementRoot, elementRoot.find('.datalist-input').val());
elementRoot.find('.icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar');
elementRoot.find('ul').children('li').show();
elementRoot.find('ul').hide();
}
click_in_process = false;
});
*/
$('.datalist-text > ul li:not(.not-selectable)').click(function () {
console.log("Li click!" + $(this).html());
var elementRoot = $(this).parents('.datalist');
elementRoot.find('.datalist-input').val($(this).html().replace(/[\t\n]+/g, ' ').trim());
//$(this).parent('ul').siblings('input[type="text"]').blur();
var cid = $(this).data('id');
elementRoot.find("input[type=hidden]").val(cid);
elementRoot.find("li").removeClass("selected");
$(this).addClass("selected");
click_in_process = true;
//elementRoot.find('.datalist-input').blur();
ocultaList({ "data": { "padre": elementRoot } });
});
$('.datalist-text .datalist-input').click(function () {
var elementRoot = $(this).parents('.datalist');
limpiaInput({ "data": { "padre": elementRoot } });
elementRoot.find('ul').show();
elementRoot.find('input').focus();
elementRoot.find('ul').show();
elementRoot.find('.icono').removeClass('ing-buscar').addClass('ing-cancelar iconoAzul pointer');
elementRoot.find('.icono').on('click', { "padre": elementRoot }, limpiaInput);
});
function limpiaInput(e) {
(e.data.padre).find('.datalist-input').val('');
(e.data.padre).find('.datalist-input').parent().children('ul').children('li').show();
(e.data.padre).find('li:first').focus();
(e.data.padre).find('.datalist-input').focus();
}
// function make required
function makeRequiredDatalist(selector, required = true) {
var elementRoot = $(selector).parents('.datalist');
if (required)
elementRoot.addClass("required");
else
elementRoot.removeClass("required");
}
// function validate
function validateDatalist(selector) {
var elementRoot = $(selector).parents('.datalist');
if (elementRoot.hasClass("required") && $(selector).val() == "") {
invalidDatalist(selector, true);
return false;
}
invalidDatalist(selector, false);
return true;
}
export { makeRequiredDatalist, validateDatalist, disableDatalist, invalidDatalist, getDatalistText, ocultaList, limpiaInput, buscaDatalist, setDatalist };

View File

@@ -1,36 +0,0 @@
export function triggerMessage(message, header, color = "danger", selector = "message") {
const container = document.getElementById(selector);
container.innerHTML = '';
/* Template message_tmp */
var node = /* html */`
<article class="alert alert-${color} alert-dismissible fade show" role="alert" id="alert-color">
<h4 class="alert-heading"><span class="ing-${(color !== 'success') ? 'importante' : 'aceptar'}"></span> ${header}</h4>
<span id="message-alert">${message}</span>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</article>
`
setTimeout(function () {
container.innerHTML = node;
}, 100);
/* setTimeout(function () {
container.innerHTML = '';
}, 5000); */
}
export function messageMissingInputs(required) {
var message = 'Faltan los siguientes campos: ';
required.forEach(function (item, index) {
let last = required.length - 1;
if (index == last)
message += item;
else if (index == last - 1)
message += item + ' y ';
else
message += item + ', ';
});
triggerMessage(message, 'Error', 'danger');
}

View File

@@ -9,7 +9,7 @@ if (!isset($_SESSION['user'])){
else else
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if(!$user->admin && $user->acceso == 'n'){ if($user->acceso == null){
header('Location: main.php?error=1'); header('Location: main.php?error=1');
}else{ }else{
$user->print_to_log('Permisos'); $user->print_to_log('Permisos');

View File

@@ -8,7 +8,7 @@ if (!isset($_SESSION['user'])) {
} else } else
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if (!$user->admin && $user->acceso == 'n') { if ($user->acceso == null) {
header('Location: main.php?error=1'); header('Location: main.php?error=1');
} else { } else {
$user->print_to_log('Profesores'); $user->print_to_log('Profesores');

View File

@@ -9,7 +9,7 @@ if (!isset($_SESSION['user']))
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access('reporte_de_asistencias'); $user->access('reporte_de_asistencias');
if (!$user->admin && in_array($user->acceso, ['n'])) if (in_array($user->acceso, ['n']))
die(header('Location: main.php?error=1')); die(header('Location: main.php?error=1'));
$user->print_to_log('Consultar asistencia'); $user->print_to_log('Consultar asistencia');

View File

@@ -6,7 +6,7 @@ if (!isset($_SESSION['user']))
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if (!$user->admin && in_array($user->acceso, ['n'])) if (in_array($user->acceso, ['n']))
die(header('Location: main.php?error=1')); die(header('Location: main.php?error=1'));
$user->print_to_log('Consultar horario'); $user->print_to_log('Consultar horario');

767
reposiciones_autorizar.php Normal file
View File

@@ -0,0 +1,767 @@
<?php
require_once 'class/c_login.php';
if (!isset($_SESSION['user'])){
die(header('Location: index.php'));
}
$user = unserialize($_SESSION['user']);
$user->access();
//if (!$user->admin && in_array($user->acceso, ['n']))
//die(header('Location: main.php?error=1'));
$user->print_to_log('Reposiciones');
//$write = $user->admin || in_array($user->acceso, ['w']);
$write = true; //
function duracionMinutos($fechahora_i, $fechahora_f){
return round((strtotime($fechahora_f) - strtotime($fechahora_i)) / 60,2);
}
if(!empty($user->periodo)){
$en_fecha = $db->querySingle("SELECT ESTA_EN_PERIODO(NOW()::DATE, :periodo_id)", [':periodo_id' => $user->periodo])['esta_en_periodo'];
$profesores_rs = array();
$tab_inicial = 1;
if($user->jefe_carrera){
$carrera_rs = $db->query('SELECT * FROM fs_usuario_carrera(:usr, NULL)', [':usr'=>$user->user["id"]]);
foreach($carrera_rs as $carr){
$rs = $db->query('SELECT * FROM fs_profesor_carrera(:carr, :periodo)', [':carr' => $carr['carrera_id'], ':periodo' => $user->periodo]);
$profesores_rs = array_merge($profesores_rs, $rs);
}
}else if($write){// $user->supervisor || $user->admin
$profesores_rs = $db->query('SELECT * FROM fs_profesor_carrera(NULL, :periodo)', [':periodo' => $user->periodo]);
$tab_inicial = 2;
}else{
die(header('Location: index.php'));
}
$salones_rs = $db->query('SELECT * FROM salon_view WHERE tiene_salones IS true');
//Periodo
$periodo_rs = $db->querySingle('SELECT periodo_fecha_inicio, periodo_fecha_fin FROM periodo WHERE periodo_id = :periodo_id', [':periodo_id' => $user->periodo]);
$periodo_fin = $periodo_rs["periodo_fecha_fin"];
if(strtotime($periodo_rs["periodo_fecha_inicio"])>strtotime(date("Y-m-d")) )
$fecha_man = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"]));
else{
$dias = 3;
if( intval(date("w")) >=3 && intval(date("w"))<=5 )//Mie a Vie
$dias+=3;
else if( intval(date("w")) ==6 )//Sab
$dias+=2;
else if( intval(date("w")) ==0 )//Do
$dias+=1;
$fecha_man = date("d/m/Y", strtotime("+".$dias." day"));
}
// Fechas filtro
if(isset($_POST["fecha_inicial"]))
$fecha_ini = $_POST["fecha_inicial"];
else
$fecha_ini = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"]));
if(isset($_POST["fecha_final"]))
$fecha_fin = $_POST["fecha_final"];
else
$fecha_fin = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_fin"]));
//Reposiciones
$repEdo_rs = $db->query('SELECT * FROM fs_estado_reposicion' );
$repoParams = array();
$query = "";//carrera, prof
if($user->jefe_carrera){
$query .= ":jefe, ";
$repoParams[":jefe"] = $user->user["id"];
}else{
$query .= "NULL, ";
}
if((isset($_POST["prof"]) && is_numeric($_POST["prof"])) ){
$query .= ":prof,";
$repoParams[":prof"] = filter_input(INPUT_POST, "prof", FILTER_SANITIZE_NUMBER_INT);//limpia texto
}else{
$query .= "NULL,";
}
$query .= ":f_ini, :f_fin, :edo, ";
$repoParams[":f_ini"] = $fecha_ini;
$repoParams[":f_fin"] = $fecha_fin;
$repoParams[":edo"] = 1;//se sobreescribe
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Reposiciones autorizar | <?= $user->facultad['facultad'] ?? 'General' ?></title>
<meta charset="utf-8">
<meta http-equiv="content-type" content="text/plain; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<?php include_once "import/html_css_files.php"; ?>
<link rel="stylesheet" href="css/jquery-ui.css">
<link rel="stylesheet" href="css/richtext.css" type="text/css">
<link rel="stylesheet" href="css/clockpicker.css">
<link rel="stylesheet" href="css/calendar.css">
<link rel="stylesheet" href="css/fa_all.css" type="text/css">
<script src="js/scrollables.js" defer></script>
<script>
const write = <?= $write ? 'true' : 'false' ?>;
</script>
<script src="js/moment.js" defer></script>
<style>
.wizard { height: 20px; width: 80%; background: #D0D0D0; }
.wizard.full { background: #D0D0D0; }
.wizard.active > div:first-child { background: #00A6CE; }
.wizard.active > div:last-child { width: 0px; height: 0px; border-style: solid; border-width: 10px 0 10px 6px; border-color: transparent transparent transparent #00a6ce; transform: rotate(0deg); }
</style>
</head>
<!-- -->
<body style="display: block;">
<?php
include('include/constantes.php');
include("import/html_header.php");
html_header("Reposiciones de clase", "Sistema de gestión de checador");
?>
<?= "<!-- $user -->" ?>
<main class="container content marco content-margin" id="local-app">
<section id="message"></section>
<?php require('import/periodo.php') ?>
<?php if(!empty($user->periodo)){ ?>
<form id="asistencia" method="post" onsubmit="return validaFechas()">
<div class="form-box">
<input type="hidden" name="facultad" value="5">
<div class="form-group row">
<label for="filtro_inicial" class="col-4 col-form-label">Fecha inicial</label>
<div class="col-8 col-sm-4">
<input id="filtro_inicial" name="fecha_inicial" type="text" class="form-control date-picker-filtro" placeholder="dd/mm/aaaa" maxlength="10" required="required" readonly="" value="<?php echo $fecha_ini;?>">
<div class="invalid-feedback">No es una fecha válida.</div>
</div>
</div>
<div class="form-group row">
<label for="filtro_final" class="col-4 col-form-label">Fecha final</label>
<div class="col-8 col-sm-4">
<input id="filtro_final" name="fecha_final" type="text" class="form-control date-picker-filtro" placeholder="dd/mm/aaaa" maxlength="10" required="required" readonly="" value="<?php echo $fecha_fin;?>">
<div class="invalid-feedback">El rango de fechas no es válido.</div>
</div>
</div>
<div class="form-group row">
<label for="filtro_prof" class="col-4 col-form-label">Profesor</label>
<div class="col-8 col-sm-4">
<input list="lista_profesores" name="dlProfesor" id="dlProfesor" class="form-control" placeholder="Profesor">
<div class="valid-feedback">
Profesor encontrado
</div>
<div class="invalid-feedback">
Profesor no encontrado
</div>
<datalist id="lista_profesores">
<?php
foreach ($profesores_rs as $profesor) {
extract($profesor);
?>
<option data-clave="<?= $profesor_clave ?>" data-profesor="<?= $profesor_nombre ?>" data-id="<?= $profesor_id; ?>" value="<?= "$profesor_clave | $profesor_nombre" ?>"></option>
<?php
}
?>
</datalist>
<ul class="list-group" id="profesores"></ul>
<input type="hidden" id="editor_profesor" name="profesor" value="">
</div>
</div>
</div>
<div class="form-group row justify-content-center">
<button type="submit" class="btn btn-outline-primary mr-2" id="btn-buscar"><span class="ing-buscar ing-fw"></span> Buscar</button>
<button type="button" class="btn btn-outline-danger" onclick="window.location.href = window.location.href"><span class="ing-borrar ing-fw"></span> Limpiar</button>
</div>
</form>
<ul class="nav nav-tabs d-print-none mb-4" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link" id="tab1-tab" data-toggle="tab" href="#tab1" role="tab" aria-controls="calendario" aria-selected="true">Nuevas reposiciones</a>
</li>
<li class="nav-item">
<a class="nav-link" id="tab2-tab" data-toggle="tab" href="#tab2" role="tab" aria-controls="lista" aria-selected="false">Aprobadas por jefe</a>
</li>
<li class="nav-item">
<a class="nav-link" id="tab3-tab" data-toggle="tab" href="#tab3" role="tab" aria-controls="lista" aria-selected="false">Autorizadas</a>
</li>
<li class="nav-item">
<a class="nav-link" id="tab4-tab" data-toggle="tab" href="#tab4" role="tab" aria-controls="lista" aria-selected="false">Rechazadas</a>
</li>
</ul>
<div class="tab-content" id="TabContent">
<?php
$i=1;
foreach($repEdo_rs as $redo){ ?>
<div class="tab-pane fade" id="tab<?php echo $i;?>" role="tabpanel" aria-labelledby="tab<?php echo $i;?>-tab">
<?php
$repoParams[":edo"]=$redo["estado_reposicion_id"];
$reposiciones_rs = $db->query('SELECT * FROM fs_reposicion(NULL, '.$query.'0, NULL) ', $repoParams );
?>
<h4 class="mb-4" <?php echo "style='color:".$redo["estado_color"]."'>".$redo["estado_nombre"]; ?> </h4>
<table class="table table-sm table-striped table-white">
<thead class="thead-dark">
<tr>
<th>Estado</th>
<th>Tipo</th>
<th>Profesor/Materia</th>
<th style="width:160px">Fecha falta</th>
<th style="width:160px">Fecha reposición</th>
<th>Salón</th>
<?php if($write){ ?><th>Acciones</th><?php } ?>
</tr>
</thead>
<tbody>
<?php
if(isset($reposiciones_rs)){
foreach($reposiciones_rs as $reposicion){
?>
<tr data-id="<?php echo $reposicion["reposicion_id"]; ?>" data-edo="<?php echo $reposicion["estado_reposicion_id"];?>" id="id<?php echo $reposicion["reposicion_id"]; ?>">
<td class="align-middle">
<?php if($reposicion["estado_reposicion_id"]<3){ ?>
<div class="wizard <?php if(intval($reposicion["estado_reposicion_id"])==2) echo "active";?> d-flex mx-auto">
<div class="w-50 h-100"></div>
<div class=""></div>
</div>
<?php } else if($reposicion["estado_reposicion_id"]==3){?>
<div class="text-success text-center pt-1">
<span class="ing-autorizar ing-lg"></span>
</div>
<?php } else {?>
<div class="text-danger text-center pt-1">
<span class="ing-negar ing-lg"></span>
</div>
<?php } ?>
</td>
<td class="align-middle">
<?php if($reposicion["es_reposicion"]) echo "Resposición"; else echo "Cambio"; ?>
</td>
<td><?php
echo $reposicion["profesor_clave"]." - ".$reposicion["profesor_nombre"];
?>
<br>
<small>
<?php echo $reposicion["materia_nombre"]; ?>
(<?php
echo $reposicion["horario_grupo"];
?>)
</small>
</td>
<td class="text-center align-middle text-nowrap"><?php
$fechaI = date("d/m/Y", strtotime($reposicion["fecha_clase"]));
echo $fechaI."<br>".substr($reposicion["horario_hora"],0, 5);
?>
</td>
<td class="text-center align-middle text-nowrap"><?php
$fechaF = date("d/m/Y", strtotime($reposicion["fecha_nueva"]));
echo $fechaF."<br>".substr($reposicion["hora_nueva"],0, 5)." a ".substr($reposicion["hora_nueva_fin"],0, 5);
?>
</td>
<td class="text-center align-middle"><?php
if($reposicion["salon_id"] != ""){
echo $reposicion["salon_id"];
}else
echo "Pendiente";
?>
</td>
<?php if($write){ ?>
<td class="text-center align-middle icono-acciones text-nowrap">
<?php if (duracionMinutos($reposicion["fecha_nueva"], date("Y-m-d H:i:00")) < 0){ ?>
<?php //no se cumple la fecha de la reposicion, es jefe de carrera
if(($user->jefe_carrera || $user->admin) && $reposicion["estado_reposicion_id"] == 1){?>
<a href="#" data-toggle="modal" data-target="#modal_aprobar" data-tipo="2" title="Aprobar"><?php echo $ICO["ver"];?></a>
<?php } //no se cumple la fecha de la reposicion, no es jefe de carrera
else if((!$user->jefe_carrera || $user->admin) && $reposicion["estado_reposicion_id"] >= 2){?>
<a href="#" data-toggle="modal" data-target="#modal_aprobar" data-tipo="3" title="Autorizar" ><?php echo $ICO["ver"];?></a>
<?php } else { ?>
<a href="#" data-toggle="modal" data-target="#modal_aprobar" data-tipo="1" title="Aprobar"><?php echo $ICO["ver"];?></a>
<?php } ?>
<?php
}else{ //fecha ya pasó?>
<a href="#" data-toggle="modal" data-target="#modal_aprobar" data-tipo="1" title="Ver detalle"><span class="text-danger"><?php echo $ICO["ver"];?></span></a>
<?php } ?>
<?php
if($reposicion["estado_reposicion_id"]<4){
if(
(($user->jefe_carrera || $user->admin) && $reposicion["estado_reposicion_id"] <= 2)
|| ((!$user->jefe_carrera || $user->admin) && $reposicion["estado_reposicion_id"] >= 2 )){
?>
<a href="#" data-toggle="modal" data-target="#modal_confirm" title="Cancelar"><span class="text-danger"><?php echo $ICO["cancelar"];?></span></a>
<?php }
} //estado
?>
</td>
<?php }//edición ?>
</tr>
<?php
}//foreach
}//if ?>
</tbody>
</table>
</div>
<?php
$i++;
} ?>
</div>
<!-- Modal -->
<div class="modal fade" id="modal_aprobar" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="col-12 modal-title text-center"><span id="modalLabel">Aprobar Reposición</span>
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button></h4>
</div>
<div class="modal-body">
<form action="./action/reposicion_autoriza.php" method="post" id="formaModal">
<input type="hidden" name="id" id="id">
<input type="hidden" name="edo" id="edo" value="">
<div class="row">
<div class="col-6 col-sm-4 barra-right text-right">
<p class="font-weight-bold">Profesor</p>
</div>
<div class="col-6">
<p class="rep-prof"></p>
</div>
</div>
<div class="row">
<div class="col-6 col-sm-4 barra-right text-right">
<p class="font-weight-bold">Materia</p>
</div>
<div class="col-6">
<p class="rep-mat"></p>
</div>
</div>
<div class="row">
<div class="col-6 col-sm-4 barra-right text-right">
<p class="font-weight-bold">Tipo</p>
</div>
<div class="col-6">
<p class="rep-tipo"></p>
</div>
</div>
<div class="row">
<div class="col-6 col-sm-4 barra-right text-right">
<p class="font-weight-bold">Fecha de falta</p>
</div>
<div class="col-6">
<p class="rep-falta"></p>
</div>
</div>
<div class="row">
<div class="col-6 col-sm-4 barra-right text-right">
<p class="font-weight-bold">Fecha de reposición</p>
</div>
<div class="col-6">
<p class="rep-fecha"></p>
</div>
</div>
<div class="row">
<div class="col-6 col-sm-4 barra-right text-right">
<p class="font-weight-bold">Alumnos aproximados</p>
</div>
<div class="col-6">
<p class="rep-alumnos"></p>
</div>
</div>
<div class="row">
<div class="col-6 col-sm-4 barra-right text-right">
<p class="font-weight-bold">Tipo de aula</p>
</div>
<div class="col-6">
<p class="rep-aula"></p>
</div>
</div>
<div class="row" id="salon-ver">
<div class="col-6 col-sm-4 barra-right text-right">
<p class="font-weight-bold">Salón</p>
</div>
<div class="col-6">
<p class="rep-salon"></p>
</div>
</div>
<div class="row" id="salon-editar" style="display: none;">
<div class="col-6 col-sm-4 barra-right text-right">
<p class="font-weight-bold">Salón *</p>
</div>
<div class="col-6">
<input list="lista_salones" name="dlSalon" id="dlSalon" class="form-control" placeholder="Salón">
<div class="valid-feedback">
Salón encontrado
</div>
<div class="invalid-feedback">
Salón no encontrado
</div>
<datalist id="lista_salones">
<?php
foreach ($salones_rs as $salon) {
extract($salon);
?>
<option data-id="<?= $salon_id ?>" data-nombre="<?= $salon ?>" value="<?= $salon ?>"></option>
<?php
}
?>
</datalist>
<ul class="list-group" id="salones"></ul>
<input type="hidden" id="salon" name="salon" value="">
</div>
</div>
<div class="row mt-4">
<div class="col-6 col-sm-4 barra-right text-right">
<p class="font-weight-bold">Comentarios</p>
</div>
<div class="col-6 bg-light">
<p class="rep-comentarios"></p>
</div>
</div>
<div class="form-group row mt-3">
<div class="col-12 text-center">
<p class="aprobar-block">Una vez realizada la acción no se puede deshacer.</p>
<p>
<button type="button" class="btn btn-primary btn-enviar aprobar-block" id="submitBtn" data-edo="<?php echo $edo_new; ?>" ><?php echo $ICO["aceptar"];?> Aprobar</button>
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal" aria-label="Close">Cerrar</button>
</p>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modal_confirm" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body">
<div class="row">
<div class="col">
<p class="font-weight-bold">¿Estás seguro de que quieres declinar la reposición?</p>
<p>Esta acción no se puede deshacer.</p>
</div>
</div>
<form action="./action/reposicion_autoriza.php" method="post">
<div class="row">
<div class="col-6 col-sm-4 barra-right text-right">
<p class="font-weight-bold">Motivo</p>
</div>
<div class="col-6 col-sm-8">
<textarea name="motivo" id="motivo" rows="3" class="form-control"></textarea>
</div>
</div>
<div class="row">
<div class="col-12 mt-4 text-center">
<input type="hidden" id="id_borrar" name="id" value="">
<input type="hidden" name="edo" value="4">
<button type="submit" class="btn btn-outline-primary btn-borrar"><?php echo $ICO["aceptar"];?> Declinar</button>
<button type="button" class="btn btn-outline-danger" data-dismiss="modal" aria-label="Close"><?php echo $ICO["cancelar"];?> Cerrar</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<?php
}
?>
</main>
</body>
<script src="js/jquery.min.js"></script>
<script src="js/bootstrap/popper.min.js"></script>
<script src="js/bootstrap/bootstrap.min.js"></script>
<script src="js/jquery-ui.js"></script>
<script src="js/datepicker-es.js"></script>
<script src="js/messages.js"></script>
<?php
//--Manejo de errores y mensajes de exito
if(isset($_GET["error"]) && is_numeric($_GET["error"])){
switch ($_GET["error"]){
case 0: $errorDesc = "No se reciberon los datos de la reposición."; break;
case 1: $errorDesc = "Ocurrió un error al insertar los datos de la reposición/cambio."; break;
case 2: $errorDesc = "Ocurrió un error al actualizar los datos de la reposición/cambio."; break;
case 3: $errorDesc = "No tienes permisos para realizar esa acción."; break;
case 4: $errorDesc = "Ocurrió un error al cargar los datos de la reposición/cambio."; break;
case 6: $errorDesc = "La reposición/cambio que buscas no existe. Consulta la lista de reopsiciones disponibles en esta sección."; break;
case 7: $errorDesc = "La reposición/cambio se empalma con el horario del grupo y no se puede guardar."; break;
case 8: $errorDesc = "El salón de la reposición está siendo utilizado ese día a esa hora y no se puede guardar."; break;
case 9: $errorDesc = "El profesor está asigndo a otra reposición/cambio el mismo día a la misma hora y no se puede guardar."; break;
case 10: $errorDesc = "El profesor está asigndo a una materia el mismo día a la misma hora y no se puede guardar."; break;
case 11: $errorDesc = "No hay clases asignadas para esa materia y grupo en la fecha de falta."; break;
}
}
if(isset($_GET["ok"]) && is_numeric($_GET["ok"])){
switch ($_GET["ok"]){
case 0: $successDesc = "La reposición se guardó correctamente."; break;
case 1: $successDesc = "La reposición se actualizó correctamente."; break;
}
}
require_once 'js/messages.php';
?>
<script>
<?php if(isset($errorDesc)){ ?>
triggerMessage("<?php echo $errorDesc;?>", "Error");
<?php } else if(isset($successDesc)){ ?>
triggerMessage("<?php echo $successDesc;?>", "Éxito", "success");
<?php } ?>
var _periodo_fecha_inicial = "<?php echo date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"])); ?>";
var _periodo_fecha_final = "<?php echo date("d/m/Y", strtotime($periodo_rs["periodo_fecha_fin"])); ?>";
var datepickerOptions = { dateFormat: "dd/mm/yy", minDate:_periodo_fecha_inicial, maxDate:_periodo_fecha_final };
$(document).ready(function(){
$(".date-picker-filtro" ).datepicker(datepickerOptions);
$(".date-picker-filtro" ).datepicker( $.datepicker.regional[ "es" ] );
$('#tab<?php echo $tab_inicial;?>-tab').tab('show');
});
function valida(){
<?php
if(!$user->jefe_carrera || $user->admin){ ?>
$("#salon").removeClass("is-invalid");
if($("#salon").val() === undefined || $("#salon").val() == 0 || $("#salon").val() == ''){
$("#salon").addClass("is-invalid");
return false;
}
<?php } ?>
return true;
}
$(document).ready(function(){
$('#modal_confirm').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget); // Button that triggered the modal
var id = button.parents("tr").data("id");
$("#id_borrar").val(id);
$("#motivo").val("")
});
$('#modal_aprobar').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget); // Button that triggered the modal
//console.log(button.data("tipo"));
var id = button.parents("tr").data("id");
var edo = button.data('tipo');
$("#edo").val(edo);
$("#id").val(id);
$.ajax({
url: './action/reposicion_select.php',
type: 'POST',
dataType: 'json',
data: { id: id},
success: function(result) {
if(result["error"]!= "" && result["error"] !== undefined){
triggerMessage(result["error"], "Error");
$('#modal_aprobar').modal("hide");
}else{
$("#modal_aprobar .rep-prof").text(result["profesor_nombre"]);
$("#modal_aprobar .rep-mat").text(result["materia_desc"]+" ["+result["grupo"]+"]" );
if(result["tipo"])
$("#modal_aprobar .rep-tipo").text("Reposición");
else
$("#modal_aprobar .rep-tipo").text("Cambio");
$("#modal_aprobar .rep-aula").text(result["aula_desc"])
$("#modal_aprobar .rep-aula").data("aula",result["aula"]);
$("#modal_aprobar .rep-falta").text(result["fecha_clase"]);
$("#modal_aprobar .rep-fecha").text(result["fecha_nueva"]+" de "+result["hora_ini"]+":"+result["min_ini"]+" a "+result["hora_fin"]+":"+result["min_fin"]);
if(result["salon"] =="" || result["salon"] === undefined){
$('#salon').prop("selectedIndex", 0);
}else{
$('#salon').val(result["salon"]);
}
$("#modal_aprobar .rep-salon").text(result["salon_desc"]);
$("#modal_aprobar .rep-comentarios").text(result["comentario"]);
$('#modal_aprobar .rep-alumnos').text(result["alumnos"]);
if(button.data("tipo") == 1){//ver
$("#modalLabel").text("Detalle de reposición");
$(".aprobar-block").hide();
$("#salon-ver").show();
$("#salon-editar").hide();
}else{
if(parseInt($("#modal_aprobar .rep-aula").data("aula")) == 1){//ver
$("#modalLabel").text("Detalle de reposición");
$(".aprobar-block").hide();
$("#salon-ver").show();
$("#salon-editar").hide();
}else{
$("#modalLabel").text("Aprobar reposición");
$(".aprobar-block").show();
if(button.data("tipo") == 3){//aprobar (con salón)
$("#salon-ver").hide();
$("#salon-editar").show();
}
}
}
if(result["aula_supervisor"]){//Solo supervisor
<?php if($user->supervisor){ ?>
$("#salon-editar").attr("disabled", false);
<?php }else{?>
$("#salon-editar").attr("disabled", true);
<?php } ?>
}else{// Facultad
<?php if(!$user->supervisor){ ?>
$("#salon-editar").attr("disabled", false);
<?php }else{?>
$("#salon-editar").attr("disabled", true);
<?php } ?>
}
}
},
error: function(jqXHR, textStatus, errorThrown ){
triggerMessage(errorThrown, "Error");
}
});//ajax
});
/*
$(".btn-borrar").click(function(){
var cid = $("#id_borrar").val();
$.ajax({
url: './action/reposicion_autoriza.php',
type: 'POST',
dataType: 'json',
data: { id: cid, edo: 4},
success: function(result) {
if(result["error"]!= "" && result["error"] !== undefined){
$("#errorBox").collapse('show');
$("#errorBox_text").html(result["error"]);
}else{
$("#successBox").collapse('show');
$("#successBox_text").html(result["ok"]);
$("#id"+cid).remove();
}
$('#messageBox')[0].scrollIntoView({ block: "end" });
},
error: function(jqXHR, textStatus, errorThrown ){
$("#errorBox").collapse('show');
$("#errorBox_text").html(errorThrown);
$('#messageBox')[0].scrollIntoView({ block: "end" });
}
});//ajax
$('#modal_confirm').modal("hide");
});*/
$("#submitBtn").click(function(){
var edo = parseInt($("#edo").val());
console.log(edo)
if((edo == 3 && valida()) || edo == 2){
$("#formaModal").submit();
}
});
});
function validaFiltro(){
if($('#filter_fecha_ini').val() != "" && !validaFecha($('#filter_fecha_ini').val()) ){
$('#filter_fecha_ini').addClass("is-invalid");
return false;
}
if($('#filter_fecha_fin').val() != "" && !validaFecha($('#filter_fecha_fin').val())){
$('#filter_fecha_fin').addClass("is-invalid");
return false;
}
if($('#filter_fecha_ini').val() != "" && $('#filter_fecha_fin').val() != "" && fechaMayor($('#filter_fecha_ini').val(), $('#filter_fecha_fin').val()) >= 0){
$('#filter_fecha_fin').addClass("is-invalid");
return false;
}
return true;
}
$(function() {
$('[data-toggle="tooltip"]').tooltip()
});
/**@Auxiliary functions */
function listProfesor({
id,
grado,
profesor,
clave
}) {
const lista = document.getElementById("dlProfesor");
lista.innerHTML = "";
lista.classList.remove("is-invalid");
const li = document.createElement('li');
li.setAttribute('data-id', id);
li.classList.add('list-group-item', 'd-flex', 'justify-content-between', 'align-items-center');
li.innerHTML = `${clave} | ${grado ?? ''} ${profesor}`
const btn = document.createElement('button');
btn.setAttribute('type', 'button');
btn.classList.add('badge', 'badge-danger', 'badge-pill', 'border-0');
btn.onclick = _ => li.remove();
const i = document.createElement('i');
i.classList.add('ing-cancelar');
btn.appendChild(i);
li.appendChild(btn);
document.getElementById("profesores").appendChild(li);
}
function listSalon({
id,
nombre
}) {
const lista = document.getElementById("dlSalon");
lista.innerHTML = "";
lista.classList.remove("is-invalid");
const li = document.createElement('li');
li.setAttribute('data-id', id);
li.classList.add('list-group-item', 'd-flex', 'justify-content-between', 'align-items-center');
li.innerHTML = `${nombre}`
const btn = document.createElement('button');
btn.setAttribute('type', 'button');
btn.classList.add('badge', 'badge-danger', 'badge-pill', 'border-0');
btn.onclick = _ => li.remove();
const i = document.createElement('i');
i.classList.add('ing-cancelar');
btn.appendChild(i);
li.appendChild(btn);
document.getElementById("salones").appendChild(li);
}
</script>
</html>

933
reposiciones_crear.php Normal file
View File

@@ -0,0 +1,933 @@
<?php
require_once 'class/c_login.php';
if (!isset($_SESSION['user'])){
die(header('Location: index.php'));
}
$user = unserialize($_SESSION['user']);
if (!$user->profesor && !$user->admin){
die(header('Location: index.php'));
}
$user->access();
//if (!$user->admin && in_array($user->acceso, ['n']))
//die(header('Location: main.php?error=1'));
$user->print_to_log('Reposiciones');
//$write = $user->admin || in_array($user->acceso, ['w']);
$write = true; //
$en_fecha = $db->querySingle("SELECT ESTA_EN_PERIODO(NOW()::DATE, :periodo_id)", [':periodo_id' => $user->periodo_id])['esta_en_periodo'];
$prof_rs = $db->query('SELECT * FROM profesor A WHERE EXISTS (
SELECT * FROM horario_view hv join HORARIO_PROFESOR ON hv.HORARIO_ID = HORARIO_PROFESOR.horario_id WHERE HORARIO_PROFESOR.profesor_id = A.profesor_id AND hv.periodo_id = :periodo_id
) ORDER BY profesor_nombre', [':periodo_id' => $user->periodo_id]);
//Periodo
$periodo_rs = $db->querySingle('SELECT periodo_fecha_inicio, periodo_fecha_fin FROM periodo WHERE periodo_id = :periodo_id', [':periodo_id' => $user->periodo_id]);
$periodo_fin = $periodo_rs["periodo_fecha_fin"];
if(strtotime($periodo_rs["periodo_fecha_inicio"])>strtotime(date("Y-m-d")) )
$fecha_man = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"]));
else{
$dias = 3;
if( intval(date("w")) >=3 && intval(date("w"))<=5 )//Mie a Vie
$dias+=3;
else if( intval(date("w")) ==6 )//Sab
$dias+=2;
else if( intval(date("w")) ==0 )//Do
$dias+=1;
$fecha_man = date("d/m/Y", strtotime("+".$dias." day"));
}
// Materias
//$id_prof = $user->user["id"];
$id_prof = 2142;
//$facultad_id = 28;
$materias_rs = $db->query('SELECT * FROM fs_materiasprofesor(:id)', [':id' => $id_prof]);
if(isset($_POST["fecha_inicial"]))
$fecha_ini = $_POST["fecha_inicial"];
else
$fecha_ini = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"]));
if(isset($_POST["fecha_final"]))
$fecha_fin = $_POST["fecha_final"];
else
$fecha_fin = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_fin"]));
$fecha_ini_db= date("Y-m-d", strtotime($fecha_ini));
$fecha_fin_db= date("Y-m-d", strtotime($fecha_fin));
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Reposiciones crear | <?= $user->facultad['facultad'] ?? 'General' ?></title>
<meta charset="utf-8">
<meta http-equiv="content-type" content="text/plain; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<?php include_once "import/html_css_files.php"; ?>
<link rel="stylesheet" href="css/jquery-ui.css">
<link rel="stylesheet" href="css/richtext.css" type="text/css">
<link rel="stylesheet" href="css/clockpicker.css">
<link rel="stylesheet" href="css/calendar.css">
<link rel="stylesheet" href="css/fa_all.css" type="text/css">
<script src="js/scrollables.js" defer></script>
<script>
const write = <?= $write ? 'true' : 'false' ?>;
</script>
<script src="js/moment.js" defer></script>
<style>
.wizard { height: 20px; width: 80%; background: #D0D0D0; }
.wizard.full { background: #D0D0D0; }
.wizard.active > div:first-child { background: #00A6CE; }
.wizard.active > div:last-child { width: 0px; height: 0px; border-style: solid; border-width: 10px 0 10px 6px; border-color: transparent transparent transparent #00a6ce; transform: rotate(0deg); }
</style>
<script src="js/jquery.min.js"></script>
<script src="js/bootstrap/popper.min.js"></script>
<script src="js/bootstrap/bootstrap.min.js"></script>
<script src="js/jquery-ui.js"></script>
<script src="js/datepicker-es.js"></script>
</head>
<!-- -->
<body style="display: block;">
<?php
include('include/constantes.php');
include("import/html_header.php");
html_header("Reposiciones de clase", "Sistema de gestión de checador");
?>
<main class="container content marco content-margin" id="local-app">
<?php if($write==true ) {?>
<!-- Botón para abrir el modal -->
<div class="row mb-4">
<div class="col-12 text-right">
<button type="button" class="btn btn-outline-secondary" data-tipo="1" data-toggle="modal" data-target="#modal" <?php if (!$en_fecha || (empty($materias_rs) || count($materias_rs)==0 ) ){ echo "disabled"; } ?>><span class="ing-mas ing-fw"></span>Crear reposición</button>
</div>
</div>
<?php }?>
<section id="message"></section>
<?php require('import/periodo.php') ?>
<form id="asistencia" method="post" onsubmit="return validaFechas()">
<div class="form-box">
<input type="hidden" name="facultad" value="">
<div class="form-group row">
<label for="filtro_inicial" class="col-4 col-form-label">Fecha inicial</label>
<div class="col-8 col-sm-4">
<input id="filtro_inicial" name="fecha_inicial" type="text" class="form-control date-picker-filtro" placeholder="dd/mm/aaaa" maxlength="10" required="required" readonly="" value="<?php echo $fecha_ini;?>">
<div class="invalid-feedback">No es una fecha válida.</div>
</div>
</div>
<div class="form-group row">
<label for="filtro_final" class="col-4 col-form-label">Fecha final</label>
<div class="col-8 col-sm-4">
<input id="filtro_final" name="fecha_final" type="text" class="form-control date-picker-filtro" placeholder="dd/mm/aaaa" maxlength="10" required="required" readonly="" value="<?php echo $fecha_fin;?>">
<div class="invalid-feedback">El rango de fechas no es válido.</div>
</div>
</div>
</div>
<div class="form-group row justify-content-center">
<button type="submit" class="btn btn-outline-primary mr-2" id="btn-buscar"><span class="ing-buscar ing-fw"></span> Buscar</button>
<button type="button" class="btn btn-outline-danger" onclick="window.location.href = window.location.href"><span class="ing-borrar ing-fw"></span> Limpiar</button>
</div>
</form>
<?php
$reposiciones_rs = $db->query('SELECT * FROM fs_reposicionesprofesor(:f_ini, :f_fin, NULL, NULL)', [':f_ini' => $fecha_ini_db, ':f_fin' => $fecha_fin_db]);
?>
<div class="row">
<?php
if(isset($reposiciones_rs) && count($reposiciones_rs)>0){ ?>
<h3 class="mb-3">Mis reposiciones</h3>
<div class="col-12 table-responsive px-0">
<table class="table table-sm table-striped table-white">
<thead class="thead-dark">
<tr >
<th>Estado</th>
<th>Materia</th>
<th>Tipo</th>
<th style="width:160px">Fecha falta</th>
<th style="width:160px">Fecha reposición</th>
<th>Salón</th>
<?php if($write){ ?><th>Acciones</th><?php } ?>
</tr>
</thead>
<tbody>
<?php
foreach($reposiciones_rs as $reposicion){
?>
<tr data-id="<?php echo $reposicion["reposicion_id"]; ?>" id="id<?php echo $reposicion["reposicion_id"]; ?>">
<td class="align-middle text-center" style="color:<?php echo $reposicion["estado_color"];?>" title="<?php echo $reposicion["estado_nombre"];?>">
<?php if($reposicion["estado_reposicion_id"]<3){ ?>
<div class="wizard <?php if(intval($reposicion["estado_reposicion_id"])==2) echo "active";?> d-flex mx-auto">
<div class="w-50 h-100"></div>
<div class=""></div>
</div>
<?php } else if($reposicion["estado_reposicion_id"]==3){?>
<div class="text-success text-center pt-1">
<span class="ing-autorizar ing-lg"></span>
</div>
<?php } else {?>
<div class="text-danger text-center pt-1">
<span class="ing-negar ing-lg"></span>
</div>
<?php } ?>
</td>
<td class="align-middle"><?php echo $reposicion["materia_nombre"]; ?></td>
<td class="align-middle">
<?php if($reposicion["es_reposicion"]) echo "Reposición"; else echo "Cambio"; ?>
</td>
<td class="align-middle text-center"><?php
echo date("d/m/Y", strtotime($reposicion["fecha_clase"]));
?>
</td>
<td class="align-middle text-center"><?php
echo date("d/m/Y", strtotime($reposicion["fecha_nueva"])) ."<br>".substr($reposicion["hora_nueva"],0,-3)." a ".substr($reposicion["hora_nueva_fin"],0,-3)." hrs.";
?>
</td>
<td class="align-middle text-center"><?php
if($reposicion["salon_id"] != ""){
echo $reposicion["salon_id"];
}else
echo "Pendiente";
?>
</td>
<?php if($write){ ?>
<td class="align-middle text-center icono-acciones">
<?php
//no se ha aprobado
if($reposicion["estado_reposicion_id"] == 1){?>
<a href="#" data-tipo="2" title="Editar" data-toggle="modal" data-target="#modal"><?php echo $ICO["editar"];?></a>
<a href="#" data-toggle="modal" data-target="#modal_confirm" title="Borrar"><?php echo $ICO["cancelar"];?></a>
<?php } ?>
</td>
<?php } ?>
</tr>
<?php }
?>
</tbody>
</table>
</div>
<?php } else { ?>
<div class="col-12 text-center">
<h4 class="mt-4 text-danger">No tienes reposiciones disponibles que cumplan con los filtros</h4>
</div>
<?php } ?>
</div>
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="col-12 modal-title text-center"><span id="modalLabel">Crear Reposición</span>
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button></h4>
</div>
<div class="modal-body">
<form action="./action/reposicion_insert.php" method="post" id="formaModal" onsubmit="return submitForm()">
<input type="hidden" name="id" id="id">
<input type="hidden" name="estado" value="1">
<div class="form-box">
<div class="form-group row <?php if(true){ echo "d-none"; }?>" id="profBlock">
<label for="prof" class="col-4 col-form-label">Profesor *</label>
<div class="col-8">
<div class="datalist datalist-select mb-1 w-100" id="dlProfesor">
<div class="datalist-input">Profesores del área</div>
<span class="ing-buscar icono"></span>
<ul style="display:none">
<?php foreach($prof_rs as $prof){?>
<li data-id="<?php echo $prof["id"];?>" <?php if($prof["id"]==$_SESSION["usuario_id"]){ echo "class='selected'";} ?> ><?php echo $prof["profesor"];?></li>
<?php } ?>
</ul>
<input type="hidden" id="prof" name="prof" value="<?php echo $id_prof;?>">
</div>
</div>
</div>
<div class="form-group row" id="materiaBlock">
<label for="horario" class="col-4 col-form-label">Materia *</label>
<div class="col-8">
<div class="datalist datalist-select mb-1 w-100" id="dlMateria">
<div class="datalist-input">Selecciona una materia</div>
<span class="ing-buscar icono"></span>
<ul style="display:none">
<?php foreach($materias_rs as $mat){ ?>
<li data-id="<?php echo $mat["horario_id"];?>" data-dia="<?php echo $mat["horario_dia"];?>" data-hr="<?php echo substr($mat["horario_hora"], 0, 2);?>" data-min="<?php echo substr($mat["horario_hora"], 3, 2);?>">
<?php echo $mat["materia_nombre"].' - '.$mat["horario_dia_nombre"]." ".substr($mat["horario_hora"], 0, -3);?>
</li>
<?php } ?>
</ul>
<input type="hidden" id="horario" name="horario" value="">
</div>
</div>
</div>
<div class="form-group row">
<label for="tipo" class="col-4 col-form-label">Tipo *</label>
<div class="col-8">
<div class="datalist datalist-select mb-1 w-100" id="dlTipo">
<div class="datalist-input">Reposición</div>
<span class="ing-buscar icono"></span>
<ul style="display:none">
<li data-id="1">Reposición</li>
<li data-id="2">Cambio de salón</li>
</ul>
<input type="hidden" id="tipo" name="tipo" value="1">
</div>
</div>
</div>
<div class="form-group row cambio_block materia-block" style="display: none;">
<label for="fecha_cambio" class="col-4 col-form-label">Fecha de cambio *</label>
<div class="col-8">
<input id="fecha_cambio" name="fecha_cambio" type="text" class="form-control date-picker" placeholder="dd/mm/aaaa" maxlength="10" required="required" readonly="readonly" value="">
</div>
</div>
<div class="form-group row repo_block materia-block">
<label for="fecha_falta" class="col-4 col-form-label">Fecha de falta *</label>
<div class="col-8">
<input id="fecha_falta" name="fecha_falta" type="text" class="form-control date-picker" placeholder="dd/mm/aaaa" maxlength="10" required="required" readonly="readonly" value="">
</div>
</div>
<div class="form-group row repo_block materia-block">
<label for="fecha_inicial" class="col-4 col-form-label">Fecha de reposicion *</label>
<div class="col-8">
<input id="fecha_inicial" name="fecha_inicial" type="text" class="form-control date-picker-future" placeholder="dd/mm/aaaa" maxlength="10" required="required" readonly="readonly" value="">
<small class="form-text text-muted">Las reposiciones se deben solicitar con al menos 72hrs de anticipación.<br>
Si repones en sábado, consulta los horarios con tu jefe de carrera.
</small>
</div>
</div>
<div class="form-group row materia-block">
<label for="hora_ini" class="col-4 col-form-label" id="hora_nombre">Hora reposición *</label>
<?php
//define("HORA_FINAL", 22);
//define("FRACCION_HORA", 15);
$default_h = 7; $default_m = 15;
?>
<div class="col-4">
<select name="hora_ini" id="hora_ini" class="form-control" required="required">
<?php for($h = $default_h; $h < HORA_FINAL; $h++){?>
<option value="<?php echo sprintf( '%02d', $h );?>" <?php if($default_h == $h){ echo 'selected="selected"';}?>><?php echo sprintf( '%02d', $h );?></option>
<?php } ?>
</select>
</div>
<div class="col-4">
<select name="min_ini" id="min_ini" class="form-control" required="required">
<?php for($m = 0; $m < 60; $m+=(60/FRACCION_HORA)){?>
<option value="<?php echo sprintf( '%02d', $m );?>" <?php if($default_m == $m){ echo 'selected="selected"';}?>><?php echo sprintf( '%02d', $m );?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group row materia-block">
<label for="salon" class="col-4 col-form-label">Alumnos aproximados *</label>
<div class="col-8 col-md-4">
<input type="number" name="alumnos" id="alumnos" class="form-control" value="1" min="1" max="50">
</div>
</div>
<div class="form-group row materia-block">
<label for="aula" class="col-4 col-form-label">Tipo aula *</label>
<div class="col-8">
<div class="datalist datalist-select mb-1 w-100" id="dlAula">
<div class="datalist-input">Salón</div>
<span class="ing-buscar icono"></span>
<ul style="display:none">
<li data-id="1">Salón</li>
<li data-id="2">Sala de cómputo</li>
<li data-id="3">Salón/Taller de la facultad</li>
</ul>
<input type="hidden" id="aula" name="aula" value="1">
</div>
</div>
</div>
</div>
<div class="form-box form-box-info materia-block">
<div class="form-group row">
<label for="comentario" class="col-4 col-form-label">Comentarios</label>
<div class="col-8">
<p><i>Requerimientos específicos del salón, software especializado, etc.</i></p>
<textarea rows="3" class="form-control" id="comentario" name="comentario"></textarea>
</div>
</div>
</div>
<div class="form-group row mt-3">
<div class="offset-4 col-8">
<button type="submit" class="btn btn-outline-primary materia-block" id="submitBtn" data-tipo="1"><?php echo $ICO["aceptar"];?> Guardar</button>
<button type="reset" class="btn btn-outline-danger" data-dismiss="modal"><?php echo $ICO["cancelar"];?> Cancelar</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Modal del formulario -->
<div class="modal fade" id="crearReposiciónOld" tabindex="-1" role="dialog" aria-labelledby="crearReposiciónLabel" aria-hidden="true">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="crearReposiciónLabel">Crear Reposición</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="form" class="form-horizontal">
<div class="form-group step" id="step-1">
<div class="form-box">
<div class="form-group row">
<label for="clave_profesor" class="col-4 col-form-label">Profesor</label>
<div class="col-8">
<input list="lista_profesores" name="clave_profesor" id="clave_profesor" class="form-control" placeholder="Profesor" required="required">
<div class="valid-feedback">
Profesor encontrado
</div>
<div class="invalid-feedback">
Profesor no encontrado
</div>
<datalist id="lista_profesores">
<?php
foreach ($prof_rs as $prof) {
?>
<option data-grado="<?= $prof["profesor_grado"] ?>" data-clave="<?= $prof["profesor_clave"] ?>" data-profesor="<?= $prof["profesor_nombre"] ?>" data-id="<?= $prof["profesor_id"]; ?>" value="<?= "{$prof["profesor_clave"]} | {$prof["profesor_grado"]} {$prof["profesor_nombre"]}" ?>"></option>
<?php
}
?>
</datalist>
<ul class="list-group" id="profesores"></ul>
<input type="hidden" id="periodo_id" name="periodo_id" value="<?= $user->periodo_id ?>">
<input type="hidden" id="profesor_id" name="profesor_id" value="">
</div>
</div>
</div>
</div>
<div class="form-group step" id="step-2">
<div class="form-box">
<div class="form-group row">
<label for="horario_reponer" class="col-4 col-form-label">Horario a reponer</label>
<div class="col-8">
<select name="horario_reponer" id="horario_reponer" class="form-control" required="required">
</select>
</div>
</div>
</div>
<input type="hidden" name="horario_id" id="horario_id">
</div>
<div class="form-group step" id="step-3">
<div class="form-box">
<div class="form-group row">
<label for="fechas_clase" class="col-4 col-form-label">Fecha de clase</label>
<div class="col-8">
<select name="fechas_clase" id="fechas_clase" class="form-control" required="required">
</select>
</div>
</div>
</div>
</div>
<div class="form-group step" id="step-4">
<div class="form-box">
<div class="form-group row">
<label for="fecha_reponer" class="col-4 col-form-label">Fecha de reposición</label>
<div class="col-6">
<input type="text" placeholder="dd/mm/aaaa" name="fecha_reponer" id="fecha_reponer" class="form-control date-picker" required="required">
</div>
</div>
<div class="form-group row">
<label for="hora" class="col-4 col-form-label">Hora</label>
<div class="col-3">
<div id="hora" class="datalist datalist-select mb-1">
<div class="datalist-input text-center">hh</div>
<span class="ing-buscar icono"></span>
<ul style="display:none">
<?php foreach (range(7, 21) as $hora) { ?>
<li data-id='<?= $hora ?>'><?= str_pad($hora, 2, "0", STR_PAD_LEFT) ?></li>
<?php } ?>
</ul>
<input type="hidden" id="hora_reponer" name="horas" value="">
</div>
</div>
<div class="col-3">
<div id="minutos" class="datalist datalist-select mb-1">
<div class="datalist-input text-center">mm</div>
<span class="ing-buscar icono"></span>
<ul style="display:none">
<?php foreach (range(0, 45, 15) as $minuto) { ?>
<li data-id='<?= $minuto ?>'><?= str_pad($minuto, 2, "0", STR_PAD_LEFT) ?></li>
<?php } ?>
</ul>
<input type="hidden" id="minutos_reponer" name="minutos" value="">
</div>
</div>
</div>
</div>
</div>
<div class="form-group step" id="step-5">
<div class="form-box">
<div class="form-group row">
<label for="descripcion_reposicion" class="col-4 col-form-label">Comentarios</label>
<div class="col-6">
<textarea name="descripcion_reposicion" id="descripcion_reposicion" rows="4" required="required" placeholder="Se requiere proyector, etc." maxlength="255" class="form-control"></textarea>
</div>
</div>
<div class="form-group row align-items-center">
<label class="col-4 col-form-label" for="sala">¿En sala de cómputo?</label>
<div class="col-6">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="sala">
<label class="custom-control-label" for="sala"></label>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer justify-content-center">
<button class="btn btn-secondary" type="button" id="prev-button">Anterior</button>
<button class="btn btn-secondary" type="button" id="next-button" disabled data-toggle="modal" data-target="#confirmationModal">Proponer reposición</button>
</div>
<!-- Modal confirmación -->
<div class="modal fade" id="confirmationModal" tabindex="-1" role="dialog" aria-labelledby="confirmationModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="confirmationModalLabel">Confirmación</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>¿Estás seguro de que deseas proponer la reposición?</p>
<small>Recuerda que la aprobará tu jefe de carrera.</small>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-info" onclick="$('#confirmationModal').modal('hide');">Cancelar</button>
<button type="button" class="btn btn-primary" data-dismiss="modal">Aceptar</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modal_confirm" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body">
<div class="row">
<div class="col">
<p class="font-weight-bold">¿Estás seguro de que quieres borrar la reposición?</p>
<p>Esta acción no se puede deshacer.</p>
</div>
</div>
</div>
<div class="modal-footer">
<input type="hidden" id="id_borrar" value="">
<button type="button" class="btn btn-outline-primary btn-borrar"><?php echo $ICO["aceptar"];?> Borrar</button>
<button type="button" class="btn btn-outline-danger" data-dismiss="modal" aria-label="Close"><?php echo $ICO["cancelar"];?> Cancelar</button>
</div>
</div>
</div>
</div>
</main>
<?php
//--Manejo de errores y mensajes de exito
if(isset($_GET["error"]) && is_numeric($_GET["error"])){
switch ($_GET["error"]){
case 0: $errorDesc = "No se reciberon los datos de la reposición."; break;
case 1: $errorDesc = "Ocurrió un error al insertar los datos de la reposición/cambio."; break;
case 2: $errorDesc = "Ocurrió un error al actualizar los datos de la reposición/cambio."; break;
case 3: $errorDesc = "No tienes permisos para realizar esa acción."; break;
case 4: $errorDesc = "Ocurrió un error al cargar los datos de la reposición/cambio."; break;
case 6: $errorDesc = "La reposición/cambio que buscas no existe. Consulta la lista de reopsiciones disponibles en esta sección."; break;
case 7: $errorDesc = "La reposición/cambio se empalma con el horario del grupo y no se puede guardar."; break;
case 8: $errorDesc = "El salón de la reposición está siendo utilizado ese día a esa hora y no se puede guardar."; break;
case 9: $errorDesc = "El profesor está asigndo a otra reposición/cambio el mismo día a la misma hora y no se puede guardar."; break;
case 10: $errorDesc = "El profesor está asigndo a una materia el mismo día a la misma hora y no se puede guardar."; break;
case 11: $errorDesc = "No hay clases asignadas para esa materia y grupo en la fecha de falta."; break;
}
}
if(isset($_GET["ok"]) && is_numeric($_GET["ok"])){
switch ($_GET["ok"]){
case 0: $successDesc = "La reposición se guardó correctamente."; break;
case 1: $successDesc = "La reposición se actualizó correctamente."; break;
}
}
require_once 'js/messages.php';
?>
<script>
<?php if(isset($errorDesc)){ ?>
triggerMessage("<?php echo $errorDesc;?>", "Error");
<?php } else if(isset($successDesc)){ ?>
triggerMessage("<?php echo $successDesc;?>", "Éxito", "success");
<?php } ?>
var vacaciones=[
<?php /*foreach($vacacionesArr as $v){ echo '"'.$v["fecha"].'",';}*/ ?>
];
var _dias_asistencia = [];//ya registró asistencia, cambia con ajax
var _dia_valido = 0;
var _fecha_manhana = "<?php echo $fecha_man; ?>";
var _periodo_fecha_inicial = "<?php echo date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"])); ?>";
var _periodo_fecha_final = "<?php echo date("d/m/Y", strtotime($periodo_rs["periodo_fecha_fin"])); ?>";
var datepickerOptions_filtro = { dateFormat: "dd/mm/yy", minDate:_periodo_fecha_inicial, maxDate:_periodo_fecha_final};
var datepickerOptions = { dateFormat: "dd/mm/yy", minDate:_periodo_fecha_inicial, maxDate:_periodo_fecha_final,
beforeShowDay: function(date) {
var day = date.getDay();
var dateString = $.datepicker.formatDate("yy-mm-dd", date);
if (day === _dia_valido) {// 0 representa el domingo
if (vacaciones.indexOf(dateString) !== -1 || _dias_asistencia.indexOf(dateString) !== -1)
return [false];
else
return [true];
}else{
return [false];
}
}
};
var datepickerOptions_future = { dateFormat: "dd/mm/yy", minDate:_fecha_manhana, maxDate:_periodo_fecha_final,
beforeShowDay: function(date) {
var day = date.getDay();
var dateString = $.datepicker.formatDate("yy-mm-dd", date);
if (day === 0) {// 0 representa el domingo
return [false];
} else {
if (vacaciones.indexOf(dateString) !== -1) {
return [false];
} else {
return [true];
}
}
}
};
function diaAAno(fecha_str){//de dd/mm/yyyy a yyyy-mm-dd
if(fecha_str.charAt(2) == "/" && fecha_str.charAt(5) == "/"){//dd/mm/yyyy
var fecha_arr = fecha_str.split("/");
return fecha_arr[2]+"-"+fecha_arr[1]+"-"+fecha_arr[0];
}
return fecha_str;
}
function fechaMayor(fechaI, fechaF) {//cual es mayor >0 I mayor <0 F mayor
return (Date.parse(diaAAno(fechaI)) - Date.parse(diaAAno(fechaF)));
}
function validaFechas(){
if(fechaMayor($('#filtro_inicial').val().trim(), $('#filtro_final').val().trim()) > 0){
$('#filtro_final').addClass("is-invalid");
return false;
}
return true;
}
function submitForm(){
var myBtn = $('#submitBtn');
var error = false;
$("#gpo").removeClass("is-invalid");
invalidDatalist("#materia", false);
$("#fecha_inicial").removeClass("is-invalid");
$("#fecha_falta").removeClass("is-invalid");
$("#fecha_cambio").removeClass("is-invalid");
if($("#tipo").val() == 1){//reposición
if($("#fecha_falta").val() == ""){
$("#fecha_falta").addClass("is-invalid");
error = true;
}
if($("#fecha_inicial").val() == ""){//fecha reposición
$("#fecha_inicial").addClass("is-invalid");
error = true;
}
}else{
if($("#fecha_cambio").val() == ""){
$("#fecha_cambio").addClass("is-invalid");
error = true;
}
}
if($("#horario").val().trim() == "" || $("#horario").val() === null){
invalidDatalist("#horario", true);
error = true;
}
if(myBtn.data("tipo") == 2 ){
$('#formaModal').prop("action", "./action/reposicion_update.php");
}else{
$('#formaModal').prop("action", "./action/reposicion_insert.php");
}
return !error;
}
function cambiaTipo(tipo){
if (tipo == 1){//reposición
$(".repo_block").show();
$(".cambio_block").hide();
$(".repo_block").find("input[type=text]").attr("required", true);
$(".cambio_block").find("input[type=text]").removeAttr("required");
$("#hora_nombre").text("Hora reposición *");
}else{//Cambio de salón
$(".repo_block").hide();
$(".cambio_block").show();
$(".repo_block").find("input[type=text]").removeAttr("required");
$(".cambio_block").find("input[type=text]").attr("required", true);
$("#hora_nombre").text("Hora cambio *");
var hora = $("#dlMateria ul li.selected").data("hr");
var min = $("#dlMateria ul li.selected").data("min");
$("#hora_ini").val(hora)
$("#min_ini").val(min)
}
}
$(document).ready(function(){
//fecha de clase
$(".date-picker" ).datepicker(datepickerOptions);
$(".date-picker" ).datepicker( $.datepicker.regional[ "es" ] );
//fecha de clase
$(".date-picker-filtro" ).datepicker(datepickerOptions_filtro);
$(".date-picker-filtro" ).datepicker( $.datepicker.regional[ "es" ] );
//fecha nueva
$(".date-picker-future" ).datepicker(datepickerOptions_future);
$(".date-picker-future" ).datepicker( $.datepicker.regional[ "es" ] );
<?php if(/*$_SESSION["jefe_carrera"] ||*/ $user->admin){ ?>
function creaOpcion(id_lista, nombre, gpo, dia, hora){
return '<li data-id="'+id_lista+'" >'+nombre+' ('+gpo+') - '+dia+' '+hora.substr(0, 5)+'</li>';
}
$('#filtro_final').focus(function(){
$("#filtro_final").removeClass("is-invalid");
});
$("#dlProfesor ul li").click(function(){//cambia datalist
var pid = $(this).data('id');
//busca materias del profesor
$.ajax({
url: './action/materiasdiaprofesor_select.php',
type: 'POST',
dataType: 'json',
data: { id: pid, },
success: function(result) {
if(result["error"]!= "" && result["error"] !== undefined){
triggerMessage(result["error"], "Error");
$("#modal").modal('hide');
}else{
$("#dlMateria ul").html("");
for(i=0; i<result["materias"].length; i++){
var html = creaOpcion(result["materias"][i]["Horario_id"],
result["materias"][i]["Materia_desc"],
result["materias"][i]["Grupo_desc"]+" "+result["materias"][i]["Carrera_prefijo"],
result["materias"][i]["Dia_desc"],
result["materias"][i]["Hora_inicio"]
);
$("#dlMateria ul").append(html);
}
setDatalistFirst("#horario");
}
},
error: function(jqXHR, textStatus, errorThrown ){
triggerMessage(errorThrown, "Error");
}
});//ajax
});
<?php } ?>
//Actualiza días elegibles de calendario
$("#dlMateria ul li").click(function(){//cambia datalist
_dia_valido = $(this).data('dia');
$.ajax({
url: './action/asistenciasprofesor_select.php',
type: 'POST',
dataType: 'json',
data: { "id": $("#prof").val(), "hor": $(this).data("id") },
success: function(result) {
if(result["error"]!= "" && result["error"] !== undefined){
triggerMessage(result["error"], "Error");
$('#modal').modal("hide");
}else{
_dias_asistencia = result["asistenciaArr"];
}
},
error: function(jqXHR, textStatus, errorThrown ){
triggerMessage(errorThrown, "Error");
}
});//ajax
$(".date-picker" ).datepicker(datepickerOptions);
var hora = $(this).data("hr");
var min = $(this).data("min");
$("#hora_ini").val(hora)
$("#min_ini").val(min)
});
$("#dlTipo ul li").click(function(){//cambia datalist
cambiaTipo($(this).data('id'));
$(".date-picker" ).datepicker(datepickerOptions);
});
$('#modal_confirm').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget); // Button that triggered the modal
var id = button.parents("tr").data("id");
$("#id_borrar").val(id);
});
$(".btn-borrar").click(function(){
var r_id = $("#id_borrar").val();
$.ajax({
url: './action/reposicion_delete.php',
type: 'POST',
dataType: 'json',
data: { id: r_id},
success: function(result) {
if(result["error"]!= "" && result["error"] !== undefined){
triggerMessage(result["error"], "Error");
}else{
triggerMessage(result["ok"], "Éxito");
$("#id"+r_id).remove();
}
},
error: function(jqXHR, textStatus, errorThrown ){
triggerMessage(errorThrown, "Error");
}
});//ajax
$('#modal_confirm').modal("hide");
});
$('#modal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget); // Button that triggered the modal
var tipo = button.data('tipo'); // 1 alta, 2 edicion
var modal = $(this);
$("#modal .is-invalid").removeClass("is-invalid");
//$(this).find(".form-control:first-child").focus();
$("#errorBox").collapse('hide');
$("#errorBox_text").html("");
if(tipo == 1){//alta
$("#submitBtn").data('tipo', 1);
$("#modalLabel").html("Crear Reposición");
modal.find("input[type=text]").val("");
modal.find("#alumnos").val("15");
$("#plan").attr("readonly", false);
$("#sem").attr("readonly", false);
$("#gpo").attr("readonly", false);
//$("#prof").attr("readonly", false);
disableDatalist("#horario", false);
disableDatalist("#tipo", false);
if($("#prof").length>0)
disableDatalist("#prof", false);
setDatalistFirst("#tipo");
setDatalistFirst("#aula");
setDatalistFirst("#horario");
$("#dlMateria ul li:first").click();
}else{//editar
$("#submitBtn").data('tipo', 2);
$("#modalLabel").html("Editar Reposición");
$("#plan").attr("readonly", true);
$("#sem").attr("readonly", true);
$("#gpo").attr("readonly", true);
//$("#materia").attr("readonly", true);
disableDatalist("#horario");
disableDatalist("#tipo");
/*if($("#prof").length>0)
disableDatalist("#prof");
$("#prof").attr("readonly", true);*/
var r_id = $(button).parents("tr").data("id");
$("#id").val(r_id);
$.ajax({
url: './action/reposicion_select.php',
type: 'POST',
dataType: 'json',
data: { id: r_id },
success: function(result) {
if(result["error"]!= "" && result["error"] !== undefined){
triggerMessage(result["error"], "Error");
$("#modal").modal('hide');
}else{
//setDatalist("#prof", result["profesor"]);
$('#salon').val(result["salon"]);
$("#fecha_falta").val(result["fecha_clase"]);
$('#hora_ini').val(result["hora_ini"]);
$('#min_ini').val(result["min_ini"]);
$('#comentario').val(result["comentario"]);
$('#alumnos').val(result["alumnos"]);
setDatalist("#horario", result["horario"]);
setDatalist("#profesor", result["profesor"]);
if(result["tipo"]){
setDatalist("#tipo", 1);
cambiaTipo(1);
$("#fecha_inicial").val(result["fecha_nueva"]);
}else{
setDatalist("#tipo", 2);
cambiaTipo(2);
$("#fecha_cambio").val(result["fecha_nueva"]);
}
_dia_valido = parseInt(result["dia"]);
$(".date-picker" ).datepicker(datepickerOptions);
$("#dlTipo ul li:selected").click();
setDatalist("#aula", result["aula"]);
modal.modal('show');
}
},
error: function(jqXHR, textStatus, errorThrown ){
triggerMessage(errorThrown, "Error");
$("#modal").modal('hide');
//$('#messageBox')[0].scrollIntoView({ block: "end" });
}
});//ajax
}
});//show
});
$(function() {
$('[data-toggle="tooltip"]').tooltip()
})
</script>
<script src="js/messages.js"></script>
<script type="module" src="js/reposiciones.js"></script>
</body>
</html>

View File

@@ -9,7 +9,7 @@ if (!isset($_SESSION['user'])){
else else
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if(!$user->admin && $user->acceso == 'n'){ if($user->acceso == null){
header('Location: main.php?error=1'); header('Location: main.php?error=1');
}else{ }else{
$user->print_to_log('Roles'); $user->print_to_log('Roles');
@@ -40,11 +40,7 @@ echo $fac;
"Gestión de Checador " "Gestión de Checador "
); );
$user->access(); $user->access();
$fs_roles = query( $fs_roles = $db->orderBy('rol_titulo')->get('rol');
"SELECT * FROM rol ORDER BY rol_titulo",
null,
false
);
?> ?>
<main class="content marco"> <main class="content marco">
<?php if($user->acceso == 'w'){?> <?php if($user->acceso == 'w'){?>
@@ -60,7 +56,7 @@ echo $fac;
<div class="col-12 table-responsive"> <div class="col-12 table-responsive">
<table class="table table-sm table-striped table-white"> <table class="table table-sm table-striped table-white">
<thead class="thead-dark"> <thead class="thead-dark">
<th>Titulo</th> <th>Título</th>
<?php if($user->acceso == 'w'){?> <?php if($user->acceso == 'w'){?>
<th>Acciones</th> <th>Acciones</th>
<?php }?> <?php }?>

View File

View File

@@ -26,7 +26,7 @@
"Sistema de gestión de checador", "Sistema de gestión de checador",
); );
?> ?>
<main class="container-fluid px-4" id="app" v-cloak @vue:mounted="mounted"> <main class="container-fluid px-4" id="app" v-cloak @vue:mounted="mounted" style="min-height: 60vh;">
<!-- error messages --> <!-- error messages -->
<div class="container mb-4 mt-2"> <div class="container mb-4 mt-2">
<div class="row"> <div class="row">

140
ts/horario.ts Normal file
View File

@@ -0,0 +1,140 @@
import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'
type Profesor = {
profesor_clave: string;
profesor_correo: string;
profesor_grado: null | string;
profesor_id: number;
profesor_nombre: string;
}
type Horario = {
carrera: string;
carrera_id: number;
dia: string;
duracion: string;
duracion_id: number;
facultad: string;
facultad_id: number;
fecha_carga: Date;
horario_dia: number;
horario_fecha_fin: null;
horario_fecha_inicio: Date;
horario_fin: string;
horario_grupo: string;
horario_hora: string;
horario_id: number;
limite: null;
materia: string;
materia_id: number;
nivel: string;
nivel_id: number;
periodo: string;
periodo_fecha_fin: Date;
periodo_fecha_inicio: Date;
periodo_id: number;
profesor_id: number;
salon: string;
salon_id: number;
bloques: number;
}
const profesores = reactive({
data: [] as Profesor[],
search: null as null | string,
fetch: async function () {
const response = await fetch('action/action_profesor.php')
this.data = await response.json() as Profesor[]
},
get clave() {
const match = this.search.match(/^\((.+)\)/)
return match ? match[1] : ''
},
get current() {
return this.data.find((profesor: Profesor) => profesor.profesor_clave === profesores.clave)
},
})
type Structure = {
sábado: boolean;
hora_mínima: number;
hora_máxima: number;
horas_totales: number;
}
const horarios = reactive({
data: [] as Horario[],
fetch: async function () {
if (profesores.current) {
const response = await fetch(`action/action_horario.php?profesor_id=${profesores.current.profesor_id}`)
this.data = await response.json()
}
},
get structure() {
if (this.data.length === 0) return null;
const structure: Structure = {
sábado: this.data.some((horario: Horario) => horario.horario_dia === 6),
hora_mínima: Math.min(...this.data.map((horario: Horario) => parseInt(horario.horario_hora.split(':')[0]))),
hora_máxima: Math.max(...this.data.map((horario: Horario) => {
const [hour, minute] = horario.horario_fin.split(':').map(Number);
return hour + Math.ceil(minute / 60);
})),
horas_totales: 0
};
structure.horas_totales = structure.hora_máxima - structure.hora_mínima;
return structure;
},
get blocks() {
if (this.data.length === 0) return null;
return [...Array(this.structure.horas_totales).keys()].flatMap(hora => {
const baseHour = hora + this.structure.hora_mínima;
return [0, 15, 30, 45].map(block => ({ hour: baseHour, block }));
});
},
getHorarioData(hour: number, block: number, día: number) {
const foundHorario = this.data.find((horario: Horario) =>
parseInt(horario.horario_hora.split(':')[0]) === hour &&
parseInt(horario.horario_hora.split(':')[1]) === block &&
horario.horario_dia === día
);
return foundHorario;
},
isOccupied(hora: number, bloque: number, day: number) {
if (this.getHorarioData(hora, bloque, day)) {
return false;
}
const currentTimeInMinutes = hora * 60 + bloque;
for (const item of this.data) {
if (item.horario_dia !== day) {
continue; // Skip items that are not on the specified day
}
// Split the hour and minute from horario_hora
const [startHour, startMinute] = item.horario_hora.split(":").map(Number);
const startTimeInMinutes = startHour * 60 + startMinute;
// Calculate end time using duracion
const [durationHours, durationMinutes] = item.duracion.split(":").map(Number);
const endTimeInMinutes = startTimeInMinutes + (durationHours * 60) + durationMinutes;
if (currentTimeInMinutes >= startTimeInMinutes && currentTimeInMinutes < endTimeInMinutes) {
return true; // The block is occupied
}
}
return false; // The block is not occupied by any class
}
})
const app = createApp({
profesores,
horarios,
mounted: async function () {
await profesores.fetch()
}
}).mount('#app')

View File

@@ -1,532 +0,0 @@
declare function triggerMessage(message: string, title: string, color?: string): void;
declare const write: boolean;
declare const moment: any;
/**
* Funciones auxiliares
*/
type Profesor = {
id: number,
grado: string,
profesor: string,
clave: string,
}
type Horario = {
id: number,
carrera_id: number,
materia: string,
salon: string,
profesores: Profesor[],
hora: string,
hora_final: string,
dia: string,
duracion: number,
bloques: number,
grupo: string,
materia_id: number,
}
const compareHours = (hora1: string, hora2: string): number => {
const [h1, m1] = hora1.split(":").map(Number);
const [h2, m2] = hora2.split(":").map(Number);
if (h1 !== h2) {
return h1 > h2 ? 1 : -1;
}
if (m1 !== m2) {
return m1 > m2 ? 1 : -1;
}
return 0;
};
let horarios = [] as Horario[];
const table = document.querySelector("table") as HTMLTableElement;
if (!(table instanceof HTMLTableElement)) {
triggerMessage("No se ha encontrado la tabla", "Error", "error");
throw new Error("No se ha encontrado la tabla");
}
[...Array(16).keys()].map(x => x + 7).forEach(hora => {
// add 7 rows for each hour
[0, 15, 30, 45].map((minute: number) => `${minute}`.padStart(2, '0')).forEach((minute: string) => {
const tr = document.createElement("tr") as HTMLTableRowElement;
tr.id = `hora-${hora}:${minute}`;
tr.classList.add(hora > 13 ? "tarde" : "mañana");
if (minute == "00") {
const th = document.createElement("th") as HTMLTableCellElement;
th.classList.add("text-center");
th.scope = "row";
th.rowSpan = 4;
th.innerText = `${hora}:00`;
th.style.verticalAlign = "middle";
tr.appendChild(th);
}
["lunes", "martes", "miércoles", "jueves", "viernes", "sábado"].forEach(día => {
const td = document.createElement("td") as HTMLTableCellElement;
td.id = `hora-${hora}:${minute}-${día}`;
tr.appendChild(td);
});
const tbody = document.querySelector("tbody#horario") as HTMLTableSectionElement;
if (!(tbody instanceof HTMLTableSectionElement)) {
throw new Error("No se ha encontrado el tbody");
}
tbody.appendChild(tr);
});
});
const empty_table = table.cloneNode(true) as HTMLTableElement;
document.querySelectorAll('.hidden').forEach((element: HTMLElement) => {
element.style.display = "none";
});
// hide the table
table.style.display = "none";
function moveHorario(id: string, día: string, hora: string) {
const formData = new FormData();
formData.append("id", id);
formData.append("hora", hora);
formData.append("día", día);
fetch("action/action_horario_update.php", {
method: "POST",
body: formData
}).then(res => res.json()).then(response => {
if (response.status == "success") {
triggerMessage("Horario movido", "Éxito", "success");
} else {
triggerMessage(response.message, "Error");
}
}).then(() => {
renderHorario();
}).catch(err => {
triggerMessage(err, "Error");
});
}
function renderHorario() {
if (horarios.length == 0) {
triggerMessage("Este profesor hay horarios para mostrar", "Error", "info");
table.style.display = "none";
document.querySelectorAll('.hidden').forEach((element: HTMLElement) => element.style.display = "none");
return;
}
// show the table
table.style.display = "table";
document.querySelectorAll('.hidden').forEach((element: HTMLElement) => element.style.display = "block");
// clear the table
table.innerHTML = empty_table.outerHTML;
function conflicts(horario1: Horario, horario2: Horario): boolean {
const { hora: hora_inicio1, hora_final: hora_final1, dia: dia1 } = horario1;
const { hora: hora_inicio2, hora_final: hora_final2, dia: dia2 } = horario2;
if (dia1 !== dia2) {
return false;
}
const compareInicios = compareHours(hora_inicio1, hora_inicio2);
const compareFinales = compareHours(hora_final1, hora_final2);
if (
compareInicios >= 0 && compareInicios <= compareFinales ||
compareFinales >= 0 && compareFinales <= -compareInicios
) {
return true;
}
return false;
}
// remove the next 5 cells
function removeNextCells(horas: number, minutos: number, dia: string, cells: number = 5) {
for (let i = 1; i <= cells; i++) {
const minute = minutos + i * 15;
const nextMinute = (minute % 60).toString().padStart(2, "0");
const nextHour = horas + Math.floor(minute / 60);
const cellId = `hora-${nextHour}:${nextMinute}-${dia}`;
const cellElement = document.getElementById(cellId);
if (cellElement) {
cellElement.remove();
}
else {
console.log(`No se ha encontrado la celda ${cellId}`);
break;
}
}
}
function newBlock(horario: Horario, edit = false) {
function move(horario: Horario, cells: number = 5) {
const [horas, minutos] = horario.hora.split(":").map(Number);
const cell = document.getElementById(`hora-${horas}:${minutos.toString().padStart(2, "0")}-${horario.dia}`);
const { top, left } = cell.getBoundingClientRect();
const block = document.getElementById(`block-${horario.id}`);
block.style.top = `${top}px`;
block.style.left = `${left}px`;
removeNextCells(horas, minutos, horario.dia, cells);
}
const [horas, minutos] = horario.hora.split(":").map(x => parseInt(x));
const hora = `${horas}:${minutos.toString().padStart(2, "0")}`;
horario.hora = hora;
const cell = document.getElementById(`hora-${horario.hora}-${horario.dia}`) as HTMLTableCellElement;
if (!cell) return;
cell.dataset.ids = `${horario.id}`;
const float_menu = edit ?
`<div class="menu-flotante p-2" style="opacity: .7;">
<a class="mx-2" href="#" data-toggle="modal" data-target="#modal-editar">
<i class="ing-editar ing"></i>
</a>
<a class="mx-2" href="#" data-toggle="modal" data-target="#modal-borrar">
<i class="ing-basura ing"></i>
</a>
</div>`
: '';
cell.innerHTML =
`<div style="overflow-y: auto; overflow-x: hidden; height: 100%;" id="block-${horario.id}" class="position-absolute w-100 h-100">
<small class="text-gray">${horario.hora}</small>
<b class="title">${horario.materia}</b> <br>
<br><span>Salón: </span>${horario.salon} <br>
<small class="my-2">
${horario.profesores.map((profesor: Profesor) => ` <span class="ing ing-formacion mx-1"></span>${profesor.grado ?? ''} ${profesor.profesor}`).join("<br>")}
</small>
</div>
${float_menu}`;
cell.classList.add("bloque-clase", "position-relative");
cell.rowSpan = horario.bloques;
// draggable
cell.draggable = write;
if (horario.bloques > 0) {
removeNextCells(horas, minutos, horario.dia, horario.bloques - 1);
}
}
function newConflictBlock(horarios: Horario[], edit = false) {
const first_horario = horarios[0];
const [horas, minutos] = first_horario.hora.split(":").map(x => parseInt(x));
const hora = `${horas}:${minutos.toString().padStart(2, "0")}`;
const ids = horarios.map(horario => horario.id);
const cell = document.getElementById(`hora-${hora}-${first_horario.dia}`);
if (cell == null) {
console.error(`Error: No se encontró la celda: hora-${hora}-${first_horario.dia}`);
return;
}
cell.dataset.ids = ids.join(",");
// replace the content of the cell
cell.innerHTML = `
<small class='text-danger'>
${hora}
</small>
<div class="d-flex justify-content-center align-items-center mt-4">
<div class="d-flex flex-column justify-content-center align-items-center">
<span class="ing ing-importante text-danger" style="font-size: 2rem;"></span>
<b class='text-danger'>
Empalme de ${ids.length} horarios
</b>
<hr>
<i class="text-danger">Ver horarios &#8230;</i>
</div>
</div>
`;
// Add classes and attributes
cell.classList.add("conflict", "bloque-clase");
cell.setAttribute("role", "button");
// Add event listener for the cell
cell.addEventListener("click", () => {
$("#modal-choose").modal("show");
const ids = cell.getAttribute("data-ids").split(",").map(x => parseInt(x));
const tbody = document.querySelector("#modal-choose tbody");
tbody.innerHTML = "";
horarios.filter(horario => ids.includes(horario.id)).sort((a, b) => compareHours(a.hora, b.hora)).forEach(horario => {
tbody.innerHTML += `
<tr data-ids="${horario.id}">
<td><small>${horario.hora.slice(0, -3)}-${horario.hora_final.slice(0, -3)}</small></td>
<td>${horario.materia}</td>
<td>
${horario.profesores.map(({ grado, profesor }) => `${grado ?? ''} ${profesor}`).join(", ")}
</td>
<td>${horario.salon}</td>
${edit ? `
<td class="text-center">
<button class="btn btn-sm btn-primary dismiss-editar" data-toggle="modal" data-target="#modal-editar">
<i class="ing-editar ing"></i>
</button>
</td>
<td class="text-center">
<button class="btn btn-sm btn-danger dismiss-editar" data-toggle="modal" data-target="#modal-borrar">
<i class="ing-basura ing"></i>
</button>
</td>
` : ""}
</tr>`;
});
document.querySelectorAll(".dismiss-editar").forEach(btn => {
btn.addEventListener("click", () => $("#modal-choose").modal("hide"));
});
});
function getDuration(hora_i: string, hora_f: string): number {
const [horas_i, minutos_i] = hora_i.split(":").map(x => parseInt(x));
const [horas_f, minutos_f] = hora_f.split(":").map(x => parseInt(x));
const date_i = new Date(0, 0, 0, horas_i, minutos_i);
const date_f = new Date(0, 0, 0, horas_f, minutos_f);
const diffInMilliseconds = date_f.getTime() - date_i.getTime();
const diffInMinutes = diffInMilliseconds / (1000 * 60);
const diffIn15MinuteIntervals = diffInMinutes / 15;
return Math.floor(diffIn15MinuteIntervals);
}
const maxHoraFinal = horarios.reduce((max: Date, horario: Horario) => {
const [horas, minutos] = horario.hora_final.split(":").map(x => parseInt(x));
const date = new Date(0, 0, 0, horas, minutos);
return date > max ? date : max;
}, new Date(0, 0, 0, 0, 0));
const horaFinalMax = new Date(0, 0, 0, maxHoraFinal.getHours(), maxHoraFinal.getMinutes());
const blocks = getDuration(first_horario.hora, `${horaFinalMax.getHours()}:${horaFinalMax.getMinutes()}`);
cell.setAttribute("rowSpan", blocks.toString());
removeNextCells(horas, minutos, first_horario.dia, blocks - 1);
}
const conflictBlocks = horarios.filter((horario, index, arrayHorario) =>
arrayHorario.filter((_, i) => i != index).some(horario2 =>
conflicts(horario, horario2)))
.sort((a, b) => compareHours(a.hora, b.hora));
const classes = horarios.filter(horario => !conflictBlocks.includes(horario));
const conflictBlocksPacked = []; // array of sets
conflictBlocks.forEach(horario => {
const setIndex = conflictBlocksPacked.findIndex(set => set.some(horario2 => conflicts(horario, horario2)));
if (setIndex === -1) {
conflictBlocksPacked.push([horario]);
} else {
conflictBlocksPacked[setIndex].push(horario);
}
})
classes.forEach(horario =>
newBlock(horario, write)
)
conflictBlocksPacked.forEach(horarios =>
newConflictBlock(horarios, write)
)
// remove the elements that are not in the limits
let max_hour = Math.max(...horarios.map(horario => {
const lastMoment = moment(horario.hora, "HH:mm").add(horario.bloques * 15, "minutes");
const lastHour = moment(`${lastMoment.hours()}:00`, "HH:mm");
const hourInt = parseInt(lastMoment.format("HH"));
return lastMoment.isSame(lastHour) ? hourInt - 1 : hourInt;
}));
let min_hour = Math.min(...horarios.map(horario => parseInt(horario.hora.split(":")[0])));
document.querySelectorAll("tbody#horario tr").forEach(hora => {
const hora_id = parseInt(hora.id.split("-")[1].split(":")[0]);
(hora_id < min_hour || hora_id > max_hour) ? hora.remove() : null;
})
// if there is no sábado, remove the column
if (!horarios.some(horario => horario.dia == "sábado")) {
document.querySelectorAll("tbody#horario td").forEach(td => {
if (td.id.split("-")[2] == "sábado") {
td.remove();
}
});
// remove the header (the last)
document.querySelector("#headers").lastElementChild.remove();
}
// adjust width
const ths = document.querySelectorAll("tr#headers th") as NodeListOf<HTMLTableCellElement>;
ths.forEach((th, key) =>
th.style.width = (key == 0) ? "5%" : `${95 / (ths.length - 1)}%`
);
// search item animation
const menúFlontantes = document.querySelectorAll(".menu-flotante");
menúFlontantes.forEach((element) => {
element.classList.add("d-none");
element.parentElement.addEventListener("mouseover", () =>
element.classList.remove("d-none")
);
element.parentElement.addEventListener("mouseout", (e) =>
element.classList.add("d-none")
);
});
// droppables
// forall the .bloque-elements add the event listeners for drag and drop
document.querySelectorAll(".bloque-clase").forEach(element => {
function dragStart() {
this.classList.add("dragging");
}
function dragEnd() {
this.classList.remove("dragging");
}
element.addEventListener("dragstart", dragStart);
element.addEventListener("dragend", dragEnd);
});
// forall the cells that are not .bloque-clase add the event listeners for drag and drop
document.querySelectorAll("td:not(.bloque-clase)").forEach(element => {
function dragOver(e) {
e.preventDefault();
this.classList.add("dragging-over");
}
function dragLeave() {
this.classList.remove("dragging-over");
}
function drop() {
this.classList.remove("dragging-over");
const dragging = document.querySelector(".dragging");
const id = dragging.getAttribute("data-ids");
const hora = this.id.split("-")[1];
const días = ["lunes", "martes", "miércoles", "jueves", "viernes", "sábado"];
let día = this.id.split("-")[2];
día = días.indexOf(día) + 1;
// rowspan
const bloques = parseInt(dragging.getAttribute("rowspan"));
const horaMoment = moment(hora, "HH:mm");
const horaFin = horaMoment.add(bloques * 15, "minutes");
const limit = moment('22:00', 'HH:mm');
if (horaFin.isAfter(limit)) {
triggerMessage("No se puede mover el bloque a esa hora", "Error");
// scroll to the top
window.scrollTo(0, 0);
return;
}
// get the horario
// remove the horario
const bloque = document.querySelector(`.bloque-clase[data-ids="${id}"]`) as HTMLElement;
// remove all children
while (bloque.firstChild) {
bloque.removeChild(bloque.firstChild);
}
// prepend a loading child
const loading = `<div class="spinner-border" role="status" style="width: 3rem; height: 3rem;">
<span class="sr-only">Loading...</span>
</div>`;
bloque.insertAdjacentHTML("afterbegin", loading);
// add style vertical-align: middle
bloque.style.verticalAlign = "middle";
bloque.classList.add("text-center");
// remove draggable
bloque.removeAttribute("draggable");
moveHorario(id, día, hora);
}
element.addEventListener("dragover", dragOver);
element.addEventListener("dragleave", dragLeave);
element.addEventListener("drop", drop);
});
}
const form = document.getElementById('form') as HTMLFormElement;
if (!(form instanceof HTMLFormElement)) {
triggerMessage('No se ha encontrado el formulario', 'Error', 'danger');
throw new Error("No se ha encontrado el formulario");
}
form.querySelector('#clave_profesor').addEventListener('input', function (e) {
const input = form.querySelector('#clave_profesor') as HTMLInputElement;
const option = form.querySelector(`option[value="${input.value}"]`) as HTMLOptionElement;
if (input.value == "") {
input.classList.remove("is-invalid", "is-valid");
return;
}
if (!option) {
input.classList.remove("is-valid");
input.classList.add("is-invalid");
}
else {
const profesor_id = form.querySelector('#profesor_id') as HTMLInputElement;
profesor_id.value = option.dataset.id;
input.classList.remove("is-invalid");
input.classList.add("is-valid");
}
});
form.addEventListener('submit', async function (e) {
e.preventDefault();
const input = form.querySelector('#clave_profesor') as HTMLInputElement;
if (input.classList.contains("is-invalid")) {
triggerMessage('El profesor no se encuentra registrado', 'Error', 'danger');
return;
}
const formData = new FormData(form);
try {
const buttons = document.querySelectorAll("button") as NodeListOf<HTMLButtonElement>;
buttons.forEach(button => {
button.disabled = true;
button.classList.add("disabled");
});
const response = await fetch('action/action_horario_profesor.php', {
method: 'POST',
body: formData,
});
const data = await response.json();
buttons.forEach(button => {
button.disabled = false;
button.classList.remove("disabled");
});
if (data.status == 'success') {
horarios = data.data;
renderHorario();
}
else {
triggerMessage(data.message, 'Error en la consulta', 'warning');
}
} catch (error) {
triggerMessage('Fallo al consutar los datos ', 'Error', 'danger');
console.log(error);
}
});
const input = form.querySelector('#clave_profesor') as HTMLInputElement;
const option = form.querySelector(`option[value="${input.value}"]`) as HTMLOptionElement;

View File

@@ -1,22 +1,19 @@
<?php <?php
require_once 'class/c_login.php'; require_once 'class/c_login.php';
require_once 'include/bd_pdo.php'; require_once 'include/bd_pdo.php';
if (!isset($_SESSION['user'])) { if (!isset($_SESSION['user'])) {
header('Location: index.php'); header('Location: index.php');
exit; exit;
} else } else
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access(); $user->access();
if (!$user->admin && $user->acceso == 'n') {
if ($user->acceso == null) {
header('Location: main.php?error=1'); header('Location: main.php?error=1');
} else { } else {
$user->print_to_log('Usuarios'); $user->print_to_log('Usuarios');
} }
$fac = $user->facultad['facultad_id'] ?? null; $fac = $user->facultad['facultad_id'] ?? null;
if ($user->admin) {
$fac = null;
}
#echo $fac; #echo $fac;
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -86,7 +83,7 @@ if ($user->admin) {
$fs_roles = $db $fs_roles = $db
->orderBy('rol_titulo', 'asc') ->orderBy('rol_titulo', 'asc')
->get("rol"); ->get("rol");
if ($user->admin) { if (!$user->facultad['facultad_id']) {
$fs_facultades = $db $fs_facultades = $db
->orderBy('facultad_nombre', 'asc') ->orderBy('facultad_nombre', 'asc')
->get('facultad'); ->get('facultad');
@@ -178,12 +175,12 @@ if ($user->admin) {
<th>Correo</th> <th>Correo</th>
<th>Clave</th> <th>Clave</th>
<th>Rol</th> <th>Rol</th>
<?php if ($user->admin) { ?> <? if (!$user->facultad['facultad_id']) { ?>
<th>Facultad</th> <th>Facultad</th>
<?php } ?> <? } ?>
<?php if ($user->acceso == 'w') { ?> <? if ($user->acceso == 'w') { ?>
<th>Acciones</th> <th>Acciones</th>
<?php } ?> <? } ?>
</tr> </tr>
@@ -206,19 +203,19 @@ if ($user->admin) {
<td class="text-primary"> <td class="text-primary">
<?= $usuario['titulo'] ?> <?= $usuario['titulo'] ?>
</td> </td>
<?php if ($user->admin) { ?> <? if (!$user->facultad['facultad_id']) { ?>
<td class="text-primary"> <td class="text-primary">
<?= $usuario['facultad_nombre'] ?> <?= $usuario['facultad_nombre'] ?>
</td> </td>
<?php } ?> <? } ?>
<?php if ($user->acceso == 'w') { ?> <? if ($user->acceso == 'w') { ?>
<td class="text-center icono-acciones"> <td class="text-center icono-acciones">
<a href="#" data-toggle="modal" data-target="#modal" data-tipo="2" title="Editar"><span <a href="#" data-toggle="modal" data-target="#modal" data-tipo="2" title="Editar"><span
class="ing-editar ing-fw"></span></a> class="ing-editar ing-fw"></span></a>
</td> </td>
<?php } ?> <? } ?>
</tr> </tr>
<?php } ?> <? } ?>
</tbody> </tbody>
</table> </table>
</div> </div>
@@ -291,7 +288,7 @@ if ($user->admin) {
</div> </div>
</div> </div>
</div> </div>
<?php if ($user->admin) { ?> <? if (!$user->facultad['facultad_id']) { ?>
<div class="form-group row" id="mdatalist"> <div class="form-group row" id="mdatalist">
<label for="dlfacultad" class="col-4 col-form-label">Facultad *</label> <label for="dlfacultad" class="col-4 col-form-label">Facultad *</label>
<div class="col-8"> <div class="col-8">
@@ -299,7 +296,7 @@ if ($user->admin) {
<div class="datalist-input">Mostrar todas</div> <div class="datalist-input">Mostrar todas</div>
<span class="ing-buscar icono"></span> <span class="ing-buscar icono"></span>
<ul style="display:none"> <ul style="display:none">
<li data-id="" class="pl-4">General</li> <li data-id="" class="pl-4">General</li>
<?php foreach ($fs_facultades as $facultad) { ?> <?php foreach ($fs_facultades as $facultad) { ?>
<li data-id="<?= $facultad['facultad_id'] ?>" class="pl-4"><?= $facultad['facultad_nombre'] ?></li> <li data-id="<?= $facultad['facultad_id'] ?>" class="pl-4"><?= $facultad['facultad_nombre'] ?></li>
<?php } ?> <?php } ?>
@@ -384,9 +381,9 @@ if ($user->admin) {
var button = $(event.relatedTarget); var button = $(event.relatedTarget);
var tipo = button.data('tipo'); var tipo = button.data('tipo');
var modal = $(this); var modal = $(this);
setDatalistFirst('#mrol'); // setDatalistFirst('#mrol');
<?php if ($user->admin) { ?> <?php if ($user->admin) { ?>
setDatalistFirst("#dlfacultad"); // setDatalistFirst("#dlfacultad");
<?php } ?> <?php } ?>
$("#mnombre").removeClass("is-invalid"); $("#mnombre").removeClass("is-invalid");
$("#mclave").removeClass("is-invalid"); $("#mclave").removeClass("is-invalid");
@@ -398,7 +395,7 @@ if ($user->admin) {
$('#mnombre').val(""); $('#mnombre').val("");
$('#mcorreo').val(""); $('#mcorreo').val("");
$('#id').val(""); $('#id').val("");
<?php if ($user->admin) { ?> <?php if (!$user->facultad['facultad_id']) { ?>
$('#mfacultad').val(<?= $fac ?>); $('#mfacultad').val(<?= $fac ?>);
<?php } ?> <?php } ?>
} }
@@ -422,9 +419,9 @@ if ($user->admin) {
$('#mclave').val(result['usuario_clave']); $('#mclave').val(result['usuario_clave']);
$('#mcorreo').val(result['usuario_correo']); $('#mcorreo').val(result['usuario_correo']);
setDatalist('#mrol', result['rol_id']); setDatalist('#mrol', result['rol_id']);
<?php if ($user->admin) { ?> <? if (!$user->facultad['facultad_id']) { ?>
setDatalist('#dlfacultad', result['facultad_id']); setDatalist('#dlfacultad', result['facultad_id']);
<?php } ?> <? } ?>
}, },
error: function () { error: function () {
console.log("Error") console.log("Error")
@@ -441,18 +438,13 @@ if ($user->admin) {
$('#desc-error').html("No puede tener espacios al inicio"); $('#desc-error').html("No puede tener espacios al inicio");
error = true; error = true;
} }
if (error) { return !error;
return false;
}
else {
return true;
}
} }
$(document).on("click", ".btn-reset", function (event) { $(document).on("click", ".btn-reset", function (event) {
var forma = $(this).parents("form"); var forma = $(this).parents("form");
forma.find("input[type=text]").val(""); forma.find("input[type=text]").val("");
setDatalistFirst("#filter_rol"); // setDatalistFirst("#filter_rol");
forma.submit(); forma.submit();
}); });
</script> </script>

View File

@@ -9,7 +9,7 @@ if (!isset($_SESSION['user']))
$user = unserialize($_SESSION['user']); $user = unserialize($_SESSION['user']);
$user->access('reporte_de_asistencias'); $user->access('reporte_de_asistencias');
if ( !$user->admin && $user->acceso == 'n' ) if ( $user->acceso == null )
die(header('Location: main.php?error=1')); die(header('Location: main.php?error=1'));
$user->print_to_log('Consultar: Reporte de asistencias de profesor'); $user->print_to_log('Consultar: Reporte de asistencias de profesor');