Initial Commit
This commit is contained in:
394
ts/auditoría.ts
Normal file
394
ts/auditoría.ts
Normal file
@@ -0,0 +1,394 @@
|
||||
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')
|
||||
39
ts/faltas.ts
Normal file
39
ts/faltas.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { createApp, reactive } from 'https://unpkg.com/petite-vue?module';
|
||||
// define that $ has type any
|
||||
declare const $: any;
|
||||
|
||||
const filter = reactive({
|
||||
facultad: -1,
|
||||
profesor: '',
|
||||
porcentaje: 0
|
||||
});
|
||||
const app = createApp({
|
||||
filter,
|
||||
facultades: [],
|
||||
profesores: [],
|
||||
|
||||
faltas: [],
|
||||
openModal() {
|
||||
const modal = document.getElementById('cargando');
|
||||
$(modal).modal('show');
|
||||
},
|
||||
closeModal() {
|
||||
const modal = document.getElementById('cargando');
|
||||
$(modal).modal('hide');
|
||||
},
|
||||
|
||||
async refresh() {
|
||||
alert(`Facultad: ${filter.facultad} - Profesor: ${filter.profesor} - Porcentaje: ${filter.porcentaje}%`
|
||||
if(filter.facultad == -1 || filter.porcetaje < 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.openModal();
|
||||
this.faltas = await fetch(`action/profesor_faltas.php?facultad=${this.filter.facultad}&profesor=${this.filter.profesor}&porcentaje=${this.filter.porcentaje}`).then(res => res.json());
|
||||
this.closeModal();
|
||||
},
|
||||
async mounted() {
|
||||
this.facultades = await fetch('action/action_facultad.php').then(res => res.json());
|
||||
this.profesores = await fetch('action/action_profesor.php').then(res => res.json());
|
||||
}
|
||||
}).mount('#app');
|
||||
Reference in New Issue
Block a user