Files
paad/supervisor.php
2023-09-05 18:53:43 +00:00

800 lines
42 KiB
PHP

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Supervisor</title>
<?php
include 'import/html_css_files.php';
?>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<?
$redirect = $_SERVER['PHP_SELF'];
include "import/html_header.php";
global $user;
html_header(
"Registro de asistencia - Vicerrectoría Académica",
"Sistema de gestión de checador",
);
?>
<main class="container-fluid px-4" id="app" v-cloak @vue:mounted="mounted" style="min-height: 60vh;">
<!-- error messages -->
<div class="container mb-4 mt-2">
<div class="row">
<div class="col-12">
<div class="alert alert-dismissible fade show" role="alert" v-for="message in messages.data"
:class="`alert-${message.color}`" :key="message.hora">
<!-- messages: {error, hora} -->
<div :key="message" class="d-flex justify-content-between">
<span>
<code>[{{message.hora}}]</code>
<strong>{{message.prefix}}</strong>
</span>
{{ message.message }}
<button type="button" class="close"
@click="messages.data.splice(messages.data.indexOf(message), 1)" data-dismiss="alert">
<span aria-hidden="true">&times;</span>
</button>
</div>
</div>
</div>
</div>
</div>
<!-- filtros -->
<div v-if="store.rutas.data.length > 0">
<div class="card mt-4">
<div class="card-header bg-dark d-flex justify-content-between align-items-center flex-wrap text-white">
<h2 class="col-md-10 col-12 text-white font-weight-bold text-uppercase text-center">
{{ JSON.parse(store.rutas.data.find(ruta => ruta.salon_id === store.rutas.selected)?.salon_array
?? null)?.splice(1)?.join('/') ?? 'No datos' }}
</h2>
<div>
<button type="button" class="btn btn-info btn-sm"
@click="store.rutas.data = []; header = 'Seleccione una ruta'">
<i class="ing-flecha ing-rotate-180"></i>
</button>
<button type="button" class="btn btn-success btn-sm" data-toggle="modal"
data-target="#editar-ubicaciones">
<i class="ing-editar"></i>
</button>
</div>
</div>
<div class="card-body bg-info">
<div class="container-fluid">
<div class="row flex-nowrap mw-100 overflow-auto">
<!-- size big -->
<div class="mx-2 my-2 col-auto" v-for="ruta in store.rutas.data" :key="ruta.salon_id">
<span class="shadow badge badge-pill py-2 px-4" @click="store.selectRuta(ruta.salon_id)"
:class="{ 'badge-primary': store.rutas.selected == ruta.salon_id, 'badge-light text-primary': store.rutas.selected != ruta.salon_id, 'badge-dark text-muted disabled' : ruta.horarios.every(({estado_supervisor_id}) => estado_supervisor_id) && store.rutas.selected != ruta.salon_id }">
{{ JSON.parse(ruta.salon_array).splice(1).join('/') }}
<span class="badge mx-3"
v-if="ruta.horarios.some(({estado_supervisor_id}) => !estado_supervisor_id)"
:class="{ 'badge-success': ruta.horarios.length > 0, 'badge-danger': ruta.horarios.length == 0 }">
{{ ruta.horarios.filter(({estado_supervisor_id}) => estado_supervisor_id).length
}} / {{
ruta.horarios.length }}
</span>
<span v-else class="badge mx-3"
:class="{ 'badge-success': ruta.horarios.length > 0, 'badge-danger': ruta.horarios.length == 0 }">
<i class="ing-aceptar"></i>
</span>
<span class="sr-only">
Faltan {{ ruta.horarios.filter(({estado_supervisor_id}) =>
estado_supervisor_id).length }} horarios
por registrar
</span>
<span class="badge mx-1 badge-warning" @click="location.hash = '#sin-internet'"
v-if="ruta.horarios.some(({pendiente}) => pendiente)">
<i class="ing-importante2"></i>
</span>
</span>
</div>
</div>
</div>
</div>
<div class="card-footer bg-dark d-flex justify-content-between align-items-center flex-wrap text-white">
<button class="btn btn-info" :disabled="store.bloquesHorario.selected == 0"
@click="store.selectBloque(store.bloquesHorario.selected - 1); rutas(current_espacio)">
<i class="ing-caret ing-rotate-90"></i>
<span class="d-none d-md-inline-block">
Bloque horario anterior
</span>
</button>
<h3 class="text-white font-weight-bold text-uppercase text-center">
{{ store.hora_inicio?.slice(0, 5) }} - {{ store.hora_fin?.slice(0, 5) }}
</h3>
<button class="btn btn-info"
@click="store.selectBloque(store.bloquesHorario.selected + 1); rutas(current_espacio)"
:disabled="store.bloquesHorario.selected == store.bloquesHorario.data.length - 1">
<span class="d-none d-md-inline-block">
Bloque horario siguiente
</span>
<i class="ing-caret ing-rotate-270"></i>
</button>
</div>
</div>
<section id="#warnings" class="mt-4" v-if="clases.some(clase => clase.pendiente)">
<div class="alert alert-warning" role="alert">
<h4 class="alert-heading"><i class="ing-importante2"></i> Sin conexión a internet</h4>
<p>
Hay datos en esta ruta que no pudieron guardarse, por favor, revise su conexión a internet y dé
click en
<button class="btn btn-outline-dark btn-sm mb-4" @click="guardarCambios"><i
class="ing-guardar"></i> Guardar cambios</button>
</p>
<hr>
<p class="mb-0">
Los datos se mantendrán mientras tenga la página abierta, pero si la cierra o la refresca, se
perderán.
</p>
</div>
</section>
<div class="mt-3 d-flex justify-content-center">
<!-- refresh -->
<div class="table-responsive">
<table class="table table-hover table-striped table-bordered table-sm">
<thead class="thead-dark">
<tr>
<th scope="col" class="text-center align-middle text-nowrap px-2">
<button @click="invertir" class="btn btn-info mr-3" v-if="clases.length > 0">
<i class="ing-cambiar ing-rotate-90"></i>
</button>
Salón
</th>
<th scope="col" class="text-center align-middle text-nowrap px-2">Profesor</th>
<th scope="col" class="text-center align-middle text-nowrap px-2">Horario</th>
<th scope="col" class="text-center align-middle text-nowrap px-2">Acciones</th>
</tr>
</thead>
<tbody>
<tr v-if="clases.length == 0">
<td colspan="6" class="text-center">No hay clases en este horario</td>
</tr>
<tr v-for="clase in clases" :key="`${clase.horario_id}-${clase.profesor_id}`">
<td class="text-center align-middle">{{ clase.salon }}</td>
<td class="text-center align-middle">
<div class="col-12">
{{ clase.profesor_nombre }}
</div>
<div class="col-12">
<button type="button" class="btn btn-outline-dark btn-sm"
@click="store.profesor_selected.horario_id = clase.horario_id; store.profesor_selected.profesor_id = clase.profesor_id; store.profesor_selected.es_reposicion = false"
data-toggle="modal" data-target="#ver-detalle">
Ver detalle <i class="ing-ojo"></i>
</button>
</div>
</td>
<td class="text-center align-middle">
{{ clase.horario_hora?.slice(0, 5) }} - {{ clase.horario_fin?.slice(0, 5) }}
</td>
<td class="text-center align-middle text-nowrap">
<!-- data-toggle="button" -->
<div v-if="!clase.reposicion_id">
<button class="btn text-center mx-2" v-for="estado in estados" :key="estado.id"
@click="store.cambiarEstado(clase.horario_id, clase.profesor_id, estado.id === clase.estado_supervisor_id ? null : estado.id)"
:class="[{'active': estado.id === clase.estado_supervisor_id}, `btn-outline-${estado.color}`]"
:aria-pressed="estado.id === clase.estado_supervisor_id">
<i :class="estado.icon"></i>
</button>
<button class="btn btn-outline-primary text-center mx-2" data-toggle="modal"
data-target="#editar-comentario" :class="{ 'active': clase.comentario }"
@click="store.selectEditor(clase.horario_id)">
<i class="ing-editar"></i>
<span class="badge badge-pill badge-primary"
v-if="clase.comentario">...</span>
<span class="sr-only">Editar comentario</span>
</button>
</div>
<!-- italic -->
<div v-else class="text-muted font-italic">
Reposición el {{ clase.reposicion_fecha }} a las
{{ clase.reposicion_hora.slice(0, 5) }} h en el salón {{ clase.reposicion_salon
}}
</div>
</td>
</tr>
<tr class="table-primary" v-if="reposiciones.length > 0">
<th colspan="5" class="text-center align-middle">Reposiciones</th>
</tr>
<tr v-for="clase in reposiciones" :key="`reposicion-${clase.horario_id}-${clase.profesor_id}`">
<td class="text-center align-middle">{{ clase.salon }}</td>
<td class="text-center align-middle">
<div class="col-12">
{{ clase.profesor_nombre }}
</div>
<div class="col-12">
<button type="button" class="btn btn-outline-dark btn-sm"
@click="store.profesor_selected.horario_id = clase.horario_id; store.profesor_selected.profesor_id = clase.profesor_id; store.profesor_selected.es_reposicion = true"
data-toggle="modal" data-target="#ver-detalle">
Ver detalle <i class="ing-ojo"></i>
</button>
</div>
<td class="text-center align-middle">
{{ clase.reposicion_hora?.slice(0, 5) }} - {{ clase.horario_fin?.slice(0, 5) }}
</td>
<td class="text-center align-middle text-nowrap">
<!-- data-toggle="button" -->
<button class="btn text-center mx-2" v-for="estado in estados" :key="estado.id"
@click="store.cambiarEstado(clase.horario_id, clase.profesor_id, estado.id === clase.estado_supervisor_id ? null : estado.id, true)"
:class="[{'active': estado.id === clase.estado_supervisor_id}, `btn-outline-${estado.color}`]"
:aria-pressed="estado.id === clase.estado_supervisor_id">
<i :class="estado.icon"></i>
</button>
<button class="btn btn-outline-primary text-center mx-2" data-toggle="modal"
data-target="#editar-comentario" :class="{ 'active': clase.comentario }"
@click="store.selectEditor(clase.horario_id)">
<i class="ing-editar"></i>
<span class="badge badge-pill badge-primary" v-if="clase.comentario">...</span>
<span class="sr-only">Editar comentario</span>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<button class="btn btn-primary btn-lg btn-block mb-4" @click="guardarCambios">
<i class="ing-guardar"></i>
Guardar cambios
</button>
</div>
<div v-else-if="store.bloquesHorario.selected === -1">
<div class="list-group my-4 container">
<div class="card text-center">
<div class="card-header bg-dark text-white">
<h2 class="text-center">
{{header}}
</h2>
</div>
<div class="card-body" v-if="!loading">
<a :href="`#horario-${horario.id}`" class="list-group-item list-group-item-action"
v-for="horario in store.bloquesHorario.data" :key="horario.id"
@click="store.bloquesHorario.selected = store.bloquesHorario.data.indexOf(horario)">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{ horario.hora_inicio?.slice(0, 5) }} - {{horario.hora_fin?.slice(0,
5)
}}</h5>
</div>
</a>
</div>
<div class="card-body" v-else>
<div class="d-flex justify-content-center">
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Cargando...</span>
</div>
</div>
</div>
<div class="card-footer text-muted bg-dark text-white">
Lista de bloques horario
</div>
</div>
</div>
</div>
<div v-else>
<div class="list-group my-4 container">
<div class="card text-center">
<div class="card-header bg-dark text-white">
<h2 class="text-center">
{{header}}
</h2>
</div>
<div class="card-body" v-if="!loading">
<a :href="`#ruta-${ruta.id_espacio_sgu}`" class="list-group-item list-group-item-action"
v-for="ruta in catálogo_rutas.data.filter(ruta => ruta.subrutas.length > 0)"
:key="ruta.salon_id" @click="rutas(ruta.id_espacio_sgu)" disabled>
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{ ruta.salon }}</h5>
<small v-if="ruta.subrutas.length > 0">{{ ruta.subrutas.length }} espacios</small>
<small v-else class="text-danger">Sin espacios</small>
</div>
</a>
</div>
<div class="card-body" v-else>
<div class="d-flex justify-content-center">
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Cargando...</span>
</div>
</div>
</div>
<div class="card-footer text-muted bg-dark text-white">
Rutas de la Universidad La Salle
</div>
</div>
</div>
</div>
<!-- MODAL -->
<div class="modal" tabindex="-1" id="editar-ubicaciones">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Editar rutas</h5>
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container">
<h2>Reordena las rutas</h2>
<ul id="sortable" class="list-group">
<li class="list-group-item" v-for="ruta in store.rutas.data" :key="ruta.salon_id"
:id="'ruta-' + ruta.salon_id"
:class="[ruta.horarios.every(horario => horario.estado_supervisor_id) ? ['disabled', 'bg-light', 'undraggable'] : '']">
{{ JSON.parse(ruta.salon_array).join('/') }}
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="modal" tabindex="-1" id="editar-comentario">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Añadir comentario</h5>
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container">
<h2 class="text-center">Comentarios de la clase</h2>
<br>
<!-- FREQUENT COMMENTS -->
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text bg-primary text-white">Comentario
<button class="btn btn-light ml-2 text-primary"
@click="store.limpiarComentario">
<i class="ing-borrar"></i>
</button>
</span>
</div>
<textarea class="form-control" aria-label="Comentarios de la clase"
v-model="store.editor.texto"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-danger" data-dismiss="modal">
<i class="ing-cancelar"></i>
Cancelar
</button>
<button type="button" class="btn btn-primary" data-dismiss="modal"
@click="store.guardarComentario">
Guardar comentario
</button>
</div>
</div>
</div>
</div>
<div class="modal" tabindex="-1" id="ver-detalle">
<div class="modal-dialog modal-dialog-centered modal-xl" v-if="clase_vista">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title" :data-id="`h${clase_vista.horario_id} - p${clase_vista.profesor_id}`">
Detalle de la clase</h2>
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container" v-if="store.profesor_selected">
<div class="row">
<section class="col-12 col-md-6">
<h4 class="h4">Profesor</h4>
<div class="row">
<div class="col-12">
<strong>Nombre:</strong>
{{ clase_vista.profesor_nombre }}
</div>
<div class="col-12">
<strong>Correo:</strong>
<a :href="`mailto:${clase_vista.profesor_correo}`"><strong>{{
clase_vista.profesor_correo }}</strong></a>
</div>
<div class="col-12">
<strong>Clave:</strong>
{{ clase_vista.profesor_clave }}
</div>
<div class="col-12">
<strong>Facultad:</strong>
{{ clase_vista.facultad }}
</div>
</div>
</section>
<section class="col-12 col-md-6">
<h4 class="h4">Clase</h4>
<div class="row">
<div class="col-12">
<strong>Materia:</strong>
{{ clase_vista.materia }}
</div>
<div class="col-12">
<strong>Carrera:</strong>
{{ clase_vista.carrera }}
</div>
<div class="col-12">
<strong>Grupo:</strong>
{{ clase_vista.horario_grupo }}
</div>
<div class="col-12">
<strong>Horario:</strong>
<!-- hora hh:mm:ss to hh:mm -->
{{ clase_vista.horario_hora?.slice(0, 5) }} - {{
clase_vista.horario_fin?.slice(0, 5) }}
</div>
<div class="col-12">
<strong>Salón:</strong>
{{ clase_vista.salon }}
</div>
</div>
</section>
</div>
<div class="row">
<section class="col-12">
<h4 class="h4 mt-4">Registro</h4>
<div class="row">
<div class="col-12 text-center" v-if="!clase_vista.registro_fecha">
<strong><span class="badge badge-danger"><i class="ing-cancelar"></i></span>
El profesor aún no ha registrado su asistencia</strong>
</div>
<div class="col-6 text-center" v-else>
El profesor registró su asistencia a las
<code>{{clase_vista.registro_fecha?.slice(11, 16)}}</code>
<hr>
<p v-if="!clase_vista.registro_retardo" class="text-center">
<span class="badge badge-success"><i class="ing-aceptar"></i></span>
A tiempo
</p>
<p v-else class="text-center">
<span class="badge badge-warning"><i class="ing-retardo"></i></span>
Con retardo
</p>
</div>
</div>
</section>
</div>
</div>
</div>
<div class="modal-footer">
<!-- botón aceptar -->
<button type="button" class="btn btn-outline-primary" data-dismiss="modal">
<i class="ing-aceptar"></i>
Aceptar
</button>
</div>
</div>
</div>
<div class="modal-dialog modal-dialog-centered modal-xl" v-else>
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">Error al cargar la clase</h2>
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<!-- cuerpo del modal -->
</div>
</div>
</div>
</main>
<?php
include "import/html_footer.php";
?>
<!-- filtro modal -->
<script src="js/jquery.min.js"></script>
<script src="js/jquery-ui.js"></script>
<script src="js/jquery-ui.touch-punch.min.js"></script>
<script src="js/bootstrap/bootstrap.min.js"></script>
<?php include_once 'js/messages.php'; ?>
<script src="https://unpkg.com/petite-vue"></script>
<script src="js/scrollables.js"></script>
<script>
const estados = [
{
color: "success",
icon: "ing-autorizar",
id: 1,
},
{
color: "danger",
icon: "ing-negar",
id: 2,
},
{
color: "warning",
icon: "ing-retardo",
id: 3,
},
{
color: "info",
icon: "ing-justificar",
id: 4,
},
];
const messages = PetiteVue.reactive({
data: [],
push_message(message, silent = false) {
if (silent) {
return
}
// go to the top
window.scrollTo({
top: 0,
behavior: 'smooth'
});
this.data.push(message);
setTimeout(() => {
this.data.pop();
}, 5000);
},
});
const store = PetiteVue.reactive({
messages,
bloquesHorario: {
data: [],
selected: 0
},
rutas: {
data: [],
selected: 0
},
editor: {
id: 0,
texto: "",
},
get hora_inicio() {
return this.bloquesHorario.data[this.bloquesHorario.selected]?.hora_inicio ?? "";
},
get hora_fin() {
return this.bloquesHorario.data[this.bloquesHorario.selected]?.hora_fin ?? "";
},
selectRuta(index) {
this.rutas.selected = index;
},
order() {
const finals = this.rutas.data.filter(ruta => ruta.horarios.length > 0 && ruta.horarios.every(horario => horario.estado_supervisor_id));
const lasts = this.rutas.data.filter(ruta => ruta.horarios.length == 0);
const notLasts = this.rutas.data.filter(ruta => ruta.horarios.some(horario => !horario.estado_supervisor_id));
this.rutas.data = [...notLasts, ...finals, ...lasts];
},
// clases
selectBloque(bloqueIndex) {
this.bloquesHorario.selected = bloqueIndex;
},
// estado
async cambiarEstado(horario_id, profesor_id, estadoId, reposicion = false) {
const ruta = store.rutas.data.find(ruta => ruta.salon_id == this.rutas.selected);
const clase = ruta[reposicion ? 'reposiciones' : 'horarios'].find(clase => clase.horario_id == horario_id && clase.profesor_id == profesor_id);
clase.estado_supervisor_id = estadoId;
try {
if (!navigator.onLine) {
clase.pendiente = true;
throw ("No hay conexión a internet");
}
const cambio = await fetch("action/registro_supervisor.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify([{
horario_id: horario_id,
estado: estadoId,
profesor_id: clase.profesor_id,
comentario: clase.comentario,
supervisor_id: <?= $user->user['id'] ?>,
}])
}).then(res => res.json());
if (cambio.error) throw cambio.error;
clase.pendiente = false;
} catch (error) {
messages.push_message({
message: error,
hora: new Date().toLocaleTimeString('es-MX', { timeZone: 'America/Mexico_City' }),
color: "danger",
prefix: "Error",
}, true);
}
// scroll to the top only if this ruta has no clases with estado 0
if (ruta.horarios.every(clase => clase.estado_supervisor_id != null))
window.scrollTo({
top: 0,
behavior: 'smooth'
});
this.order();
},
// editor
selectEditor(horario_id) {
this.editor.id = horario_id;
this.editor.texto = store.rutas.data.find(ruta => ruta.salon_id == this.rutas.selected).horarios.find(clase => clase.horario_id == horario_id).comentario;
},
guardarComentario() {
const ruta = store.rutas.data.find(ruta => ruta.salon_id == this.rutas.selected);
const clase = ruta.horarios.find(clase => clase.horario_id == this.editor.id);
clase.comentario = this.editor.texto;
store.cambiarEstado(clase.horario_id, clase.profesor_id, clase.estado_supervisor_id);
},
limpiarComentario() {
this.editor.texto = "";
},
profesor_selected: {
horario_id: null,
profesor_id: null,
},
});
$(document).ready(function () {
$("#sortable").sortable({
update: function (event, ui) {
// get the new order
var newOrder = $(this).children().map(function () {
// id = ruta-{id}
return parseInt(this.id.split('-')[1]);
}).get();
// store the new order
store.rutas.data = newOrder.map(function (id) {
return store.rutas.data.find(function (ruta) {
return ruta.salon_id === id;
});
});
},
items: "li:not(.undraggable)"
}).disableSelection();
$('#sortable>li:not(.undraggable)').draggable({
axis: 'y',
containment: 'parent',
})
});
PetiteVue.createApp({
store,
messages,
header: "Cargando auditoría",
loading: true,
catálogo_rutas: {
data: [],
selected: 0
},
get clases() {
const clases = store.rutas.data.find(ruta => ruta.salon_id == store.rutas.selected)?.horarios ?? [];
return clases;
},
get reposiciones() {
console.log('Rutas: ', store.rutas.data, store.rutas.selected);
const reposiciones = store.rutas.data.find(ruta => ruta.salon_id == store.rutas.selected)?.reposiciones ?? [];
return reposiciones;
},
async guardarCambios() {
try {
if (!navigator.onLine)
throw "No hay conexión a internet";
const cambio = await fetch("action/registro_supervisor.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(store.rutas.data.map(ruta => ruta.horarios).flat(1).filter(clase => clase.pendiente).map(clase => ({
horario_id: clase.horario_id,
estado: clase.estado_supervisor_id,
profesor_id: clase.profesor_id,
comentario: clase.comentario,
supervisor_id: <?= $user->user['id'] ?>,
}))),
}).then(res => res.json());
if (cambio.error) throw cambio.error;
} catch (error) {
messages.push_message({
message: error,
hora: new Date().toLocaleTimeString('es-MX', { timeZone: 'America/Mexico_City' }),
color: "danger",
prefix: "Error",
});
return
}
store.rutas.data.map(ruta => ruta.horarios).flat(1).filter(clase => clase.pendiente).forEach(clase => clase.pendiente = false);
messages.push_message({
message: "Cambios guardados",
hora: new Date().toLocaleTimeString('es-MX', { timeZone: 'America/Mexico_City' }),
color: "success",
prefix: "Éxito",
});
},
invertir() {
this.clases.reverse();
},
async mounted() {
store.bloquesHorario.data = await fetch('action/action_grupo_horario.php').then(res => res.json());
store.bloquesHorario.selected = store.bloquesHorario.data.findIndex(bloque => bloque.selected);
this.header = (store.bloquesHorario.selected == -1) ? "Seleccione un horario" : "Seleccione una ruta";
this.catálogo_rutas.data = await fetch('action/rutas.php').then(res => res.json());
this.loading = false;
},
current_espacio: null,
async rutas(id_espacio_sgu) {
store.rutas.data = [];
store.rutas.selected = 0;
this.loading = true;
this.current_espacio = id_espacio_sgu;
this.loading = true;
this.header = `Cargando rutas para ${this.catálogo_rutas.data.find(ruta => ruta.id_espacio_sgu == id_espacio_sgu).salon}`;
this.catálogo_rutas.selected = id_espacio_sgu;
const url = 'action/rutas_salón_horario.php'
const searchParams = new URLSearchParams({
id_espacio_sgu: id_espacio_sgu,
bloque_horario_id: store.bloquesHorario.data[store.bloquesHorario.selected].id
});
try {
const rutas = await fetch(`${url}?${searchParams}`).then(res => res.json());
store.rutas.data = rutas.filter(ruta => ruta.horarios.length > 0);
} catch (error) {
console.error(error);
this.header = `Error al cargar rutas`;
this.loading = false;
return
}
if (store.rutas.data.length == 0) {
this.header = `No hay clases en este horario`;
this.loading = false;
return
}
store.rutas.selected = store.rutas.data[0].salon_id;
store.order();
// inject horarios
this.loading = false;
},
get clase_vista() {
if (!store.profesor_selected.horario_id || !store.profesor_selected.profesor_id)
return false;
return store.profesor_selected.es_reposicion
? this.reposiciones.find(clase => clase.horario_id == store.profesor_selected.horario_id && clase.profesor_id == store.profesor_selected.profesor_id) ?? false
: this.clases.find(clase => clase.horario_id == store.profesor_selected.horario_id && clase.profesor_id == store.profesor_selected.profesor_id) ?? false;
},
}).mount('#app')
</script>
</body>
</html>