395 lines
15 KiB
TypeScript
395 lines
15 KiB
TypeScript
import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'
|
|
|
|
type Registro = {
|
|
carrera: string;
|
|
carrera_id: number;
|
|
comentario: null;
|
|
dia: string;
|
|
duracion: string;
|
|
duracion_id: number;
|
|
estado_supervisor_id: number;
|
|
facultad: string;
|
|
facultad_id: number;
|
|
horario_dia: number;
|
|
horario_fin: string;
|
|
horario_grupo: string;
|
|
horario_hora: string;
|
|
horario_id: number;
|
|
materia: string;
|
|
materia_id: number;
|
|
nombre: string;
|
|
periodo: string;
|
|
periodo_id: number;
|
|
profesor_clave: string;
|
|
profesor_correo: string;
|
|
profesor_grado: null;
|
|
profesor_id: number;
|
|
profesor_nombre: string;
|
|
registro_fecha: null;
|
|
registro_fecha_ideal: Date;
|
|
registro_fecha_supervisor: Date;
|
|
registro_id: number;
|
|
registro_justificada: null;
|
|
registro_retardo: null;
|
|
salon: string;
|
|
salon_id: number;
|
|
supervisor_id: number;
|
|
}
|
|
|
|
type Estado = {
|
|
color: string;
|
|
icon: string;
|
|
estado_supervisor_id: number;
|
|
}
|
|
|
|
type Facultad = {
|
|
clave_dependencia: string;
|
|
facultad_id: number;
|
|
facultad_nombre: string;
|
|
}
|
|
|
|
type Bloque_Horario = {
|
|
hora_fin: string;
|
|
hora_inicio: string;
|
|
id: number;
|
|
selected: boolean;
|
|
}
|
|
|
|
type Periodo = {
|
|
created_at: Date;
|
|
estado_id: number;
|
|
fecha_final: Date;
|
|
id_periodo_sgu: number;
|
|
nivel_id: number;
|
|
periodo_clave: string;
|
|
periodo_fecha_fin: Date;
|
|
periodo_fecha_inicio: Date;
|
|
periodo_id: number;
|
|
periodo_nombre: string;
|
|
}
|
|
|
|
declare var $: any
|
|
$('div.modal#cargando').modal({
|
|
backdrop: 'static',
|
|
keyboard: false,
|
|
show: false,
|
|
})
|
|
|
|
const store = reactive({
|
|
loading: false,
|
|
current: {
|
|
comentario: '',
|
|
clase_vista: null,
|
|
empty: '',
|
|
page: 1,
|
|
maxPages: 10,
|
|
perPage: 10,
|
|
modal_state: "Cargando datos...",
|
|
justificada: null as Registro | null,
|
|
fechas_clicked: false,
|
|
observaciones: false,
|
|
},
|
|
facultades: {
|
|
data: [] as Facultad[],
|
|
async fetch() {
|
|
this.data = [] as Facultad[]
|
|
const res = await fetch('action/action_facultad.php')
|
|
this.data = await res.json()
|
|
},
|
|
},
|
|
filters: {
|
|
facultad_id: null,
|
|
fecha: null,
|
|
fecha_inicio: null,
|
|
fecha_fin: null,
|
|
profesor: null,
|
|
periodo_id: null,
|
|
bloque_horario: null,
|
|
estados: [],
|
|
|
|
switchFecha: false,
|
|
async switchFechas() {
|
|
const periodo = await fetch('action/periodo_datos.php');
|
|
const periodo_data = await periodo.json() as Periodo;
|
|
|
|
if (!store.filters.switchFecha) {
|
|
$('div.modal#cargando').modal('show');
|
|
await store.registros.fetch()
|
|
$('div.modal#cargando').modal('hide');
|
|
}
|
|
$(function () {
|
|
store.filters.fecha_inicio = store.filters.fecha_fin = store.filters.fecha = null
|
|
$("#fecha, #fecha_inicio, #fecha_fin").datepicker({
|
|
minDate: new Date(`${periodo_data.periodo_fecha_inicio}:00:00:00`),
|
|
maxDate: new Date(`${periodo_data.fecha_final}:00:00:00`),
|
|
dateFormat: "yy-mm-dd",
|
|
showAnim: "slide",
|
|
beforeShowDay: (date: Date) => [(date.getDay() != 0), ""]
|
|
});
|
|
|
|
const fecha = $("#fecha"), inicio = $("#fecha_inicio"), fin = $("#fecha_fin")
|
|
fecha.datepicker("setDate", new Date(`${periodo_data.fecha_final}:00:00:00`));
|
|
inicio.on("change", function () {
|
|
store.current.fechas_clicked = false;
|
|
store.filters.fecha_inicio = inicio.val()
|
|
fin.datepicker("option", "minDate", inicio.val());
|
|
});
|
|
fin.on("change", function () {
|
|
store.current.fechas_clicked = false;
|
|
store.filters.fecha_fin = fin.val()
|
|
inicio.datepicker("option", "maxDate", fin.val());
|
|
});
|
|
fecha.on("change", async function () {
|
|
store.filters.fecha = fecha.val()
|
|
|
|
$('div.modal#cargando').modal('show');
|
|
await store.registros.fetch(store.filters.fecha)
|
|
$('div.modal#cargando').modal('hide');
|
|
|
|
});
|
|
});
|
|
},
|
|
async fetchByDate() {
|
|
store.current.fechas_clicked = true;
|
|
$('div.modal#cargando').modal('show');
|
|
await store.registros.fetch(undefined, store.filters.fecha_inicio, store.filters.fecha_fin);
|
|
store.current.page = 1;
|
|
$('div.modal#cargando').modal('hide');
|
|
}
|
|
},
|
|
estados: {
|
|
data: [] as Estado[],
|
|
async fetch() {
|
|
this.data = [] as Estado[]
|
|
const res = await fetch('action/action_estado_supervisor.php')
|
|
this.data = await res.json()
|
|
},
|
|
getEstado(id: number): Estado {
|
|
return this.data.find((estado: Estado) => estado.estado_supervisor_id === id) ?? {
|
|
estado_color: 'dark',
|
|
estado_icon: 'ing-cancelar',
|
|
nombre: 'Sin registro',
|
|
estado_supervisor_id: -1,
|
|
}
|
|
},
|
|
printEstados() {
|
|
if (store.filters.estados.length > 0)
|
|
document.querySelector('#estados')!.innerHTML = store.filters.estados.map((estado: number) =>
|
|
`<span class="mx-2 badge badge-${store.estados.getEstado(estado).estado_color}">
|
|
<i class="${store.estados.getEstado(estado).estado_icon}"></i> ${store.estados.getEstado(estado).nombre}
|
|
</span>`
|
|
).join('')
|
|
else
|
|
document.querySelector('#estados')!.innerHTML = `Todos los registros`
|
|
}
|
|
},
|
|
bloques_horario: {
|
|
data: [] as Bloque_Horario[],
|
|
async fetch() {
|
|
this.data = [] as Bloque_Horario[]
|
|
const res = await fetch('action/action_grupo_horario.php')
|
|
this.data = await res.json()
|
|
|
|
if (this.data.every((bloque: Bloque_Horario) => !bloque.selected))
|
|
this.data[0].selected = true
|
|
},
|
|
},
|
|
toggle(arr: any, element: any) {
|
|
const newArray = arr.includes(element) ? arr.filter((item: any) => item !== element) : [...arr, element]
|
|
// if all are selected, then unselect all
|
|
if (newArray.length === (this.estados.data.length + 1)) {
|
|
setTimeout(() => {
|
|
document.querySelectorAll('#dlAsistencia>ul>li.selected')!.forEach(element => element.classList.remove('selected'));
|
|
}, 100)
|
|
return []
|
|
}
|
|
return newArray
|
|
},
|
|
async justificar() {
|
|
if (!store.current.justificada) return;
|
|
store.current.justificada.registro_justificada = true
|
|
let data: {
|
|
justificador_nombre: string;
|
|
justificador_clave: string;
|
|
justificador_facultad: string;
|
|
justificador_rol: string;
|
|
registro_fecha_justificacion: Date;
|
|
};
|
|
try {
|
|
const res = await fetch('action/action_justificar.php', {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(store.current.justificada)
|
|
})
|
|
data = await res.json()
|
|
} catch (error) {
|
|
alert('Error al justificar')
|
|
store.current.justificada = store.current.clone_justificada
|
|
} finally {
|
|
delete store.current.clone_justificada
|
|
}
|
|
|
|
store.current.justificada.justificador_nombre = data.justificador_nombre
|
|
store.current.justificada.justificador_clave = data.justificador_clave
|
|
store.current.justificada.justificador_facultad = data.justificador_facultad
|
|
store.current.justificada.justificador_rol = data.justificador_rol
|
|
store.current.justificada.registro_fecha_justificacion = data.registro_fecha_justificacion
|
|
},
|
|
registros: {
|
|
data: [] as Registro[],
|
|
async fetch(fecha?: Date, fecha_inicio?: Date, fecha_fin?: Date) {
|
|
// if (!store.filters.facultad_id || !store.filters.periodo_id) return
|
|
|
|
this.loading = true
|
|
this.data = [] as Registro[]
|
|
const params = {
|
|
facultad_id: 19,
|
|
periodo_id: 2,
|
|
}
|
|
if (fecha) params['fecha'] = fecha
|
|
if (fecha_inicio) params['fecha_inicio'] = fecha_inicio
|
|
if (fecha_fin) params['fecha_fin'] = fecha_fin
|
|
|
|
const paramsUrl = new URLSearchParams(params as any).toString()
|
|
try {
|
|
const res = await fetch(`action/action_auditoria.php?${paramsUrl}`, {
|
|
method: 'GET',
|
|
})
|
|
this.data = await res.json()
|
|
} catch (error) {
|
|
alert('Error al cargar los datos')
|
|
}
|
|
this.loading = false
|
|
store.current.page = 1
|
|
},
|
|
invertir() {
|
|
this.data = this.data.reverse()
|
|
},
|
|
mostrarComentario(registro_id: number) {
|
|
const registro = this.data.find((registro: Registro) => registro.registro_id === registro_id)
|
|
store.current.comentario = registro.comentario
|
|
$('#ver-comentario').modal('show')
|
|
},
|
|
get relevant() {
|
|
/*
|
|
facultad_id: null,
|
|
fecha: null,
|
|
fecha_inicio: null,
|
|
fecha_fin: null,
|
|
profesor: null,
|
|
asistencia: null,
|
|
estado_id: null,
|
|
if one of the filters is null, then it is not relevant
|
|
|
|
*/
|
|
const filters = Object.keys(store.filters).filter((filtro) => store.filters[filtro] !== null || store.filters[filtro]?.length > 0 )
|
|
return this.data.filter((registro: Registro) => {
|
|
return filters.every((filtro) => {
|
|
switch (filtro) {
|
|
case 'fecha':
|
|
return registro.registro_fecha_ideal === store.filters[filtro];
|
|
case 'fecha_inicio':
|
|
return registro.registro_fecha_ideal >= store.filters[filtro];
|
|
case 'fecha_fin':
|
|
return registro.registro_fecha_ideal <= store.filters[filtro];
|
|
case 'profesor':
|
|
const textoFiltro = store.filters[filtro].toLowerCase();
|
|
if (/^\([^)]+\)\s[\s\S]+$/.test(textoFiltro)) {
|
|
const clave = registro.profesor_clave.toLowerCase();
|
|
const filtroClave = textoFiltro.match(/\((.*?)\)/)?.[1];
|
|
// console.log(clave, filtroClave);
|
|
return clave.includes(filtroClave);
|
|
} else {
|
|
const nombre = registro.profesor_nombre.toLowerCase();
|
|
return nombre.includes(textoFiltro);
|
|
}
|
|
case 'facultad_id':
|
|
|
|
return registro.facultad_id === store.filters[filtro];
|
|
case 'estados':
|
|
if (store.filters[filtro].length === 0) return true;
|
|
else if (store.filters[filtro].includes(-1) && registro.estado_supervisor_id === null) return true;
|
|
return store.filters[filtro].includes(registro.estado_supervisor_id);
|
|
case 'bloque_horario':
|
|
const bloque = store.bloques_horario.data.find((bloque: Bloque_Horario) => bloque.id === store.filters[filtro]) as Bloque_Horario;
|
|
return registro.horario_hora < bloque.hora_fin && registro.horario_fin > bloque.hora_inicio;
|
|
default: return true;
|
|
}
|
|
})
|
|
})
|
|
},
|
|
async descargar() {
|
|
store.current.modal_state = 'Generando reporte en Excel...'
|
|
$('div.modal#cargando').modal('show');
|
|
|
|
this.loading = true;
|
|
if (this.relevant.length === 0) return;
|
|
try {
|
|
const res = await fetch('export/supervisor_excel.php', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(this.relevant)
|
|
});
|
|
const blob = await res.blob();
|
|
(window as any).saveAs(blob, `auditoria_${new Date().toISOString().slice(0, 10)}.xlsx`);
|
|
|
|
} catch (error) {
|
|
if (error.response && error.response.status === 413) {
|
|
alert('Your request is too large! Please reduce the data size and try again.');
|
|
} else {
|
|
alert('An error occurred: ' + error.message);
|
|
}
|
|
}
|
|
finally {
|
|
$('#cargando').modal('hide');
|
|
this.loading = false;
|
|
}
|
|
},
|
|
loading: false,
|
|
get pages() {
|
|
return Math.ceil(this.relevant.length / store.current.perPage)
|
|
}
|
|
},
|
|
})
|
|
|
|
type Profesor = {
|
|
profesor_id: number;
|
|
profesor_nombre: string;
|
|
profesor_correo: string;
|
|
profesor_clave: string;
|
|
profesor_grado: string;
|
|
}
|
|
createApp({
|
|
store,
|
|
get clase_vista() {
|
|
return store.current.clase_vista
|
|
},
|
|
|
|
set_justificar(horario_id: Number, profesor_id: Number, registro_fecha_ideal: Date) {
|
|
store.current.justificada = store.registros.relevant.find((registro: Registro) => registro.horario_id === horario_id && registro.profesor_id === profesor_id && registro.registro_fecha_ideal === registro_fecha_ideal)
|
|
store.current.clone_justificada = JSON.parse(JSON.stringify(store.current.justificada))
|
|
store.current.observaciones = false
|
|
},
|
|
cancelar_justificacion() {
|
|
Object.assign(store.current.justificada, store.current.clone_justificada)
|
|
delete store.current.clone_justificada
|
|
},
|
|
profesores: [] as Profesor[],
|
|
async mounted() {
|
|
$('div.modal#cargando').modal('show');
|
|
|
|
// await store.registros.fetch()
|
|
await store.facultades.fetch()
|
|
await store.estados.fetch()
|
|
await store.bloques_horario.fetch()
|
|
await store.filters.switchFechas()
|
|
this.profesores = await (await fetch('action/action_profesor.php')).json() as Profesor[];
|
|
|
|
$('div.modal#cargando').modal('hide');
|
|
}
|
|
}).mount('#app')
|