se modifico el reporte de inscritos para poder buscar por rango ademas de agregar la columna del periodo y porder descargar un excel

This commit is contained in:
2026-03-19 18:33:56 -06:00
parent 4d727d1766
commit 1f29e72ad2
2 changed files with 141 additions and 34 deletions
+140 -33
View File
@@ -4,7 +4,8 @@ import { useEffect, useState } from "react";
import axios from "axios";
import Cookies from "js-cookie";
import "./inscripciones.css";
import * as XLSX from "xlsx";
import { saveAs } from "file-saver";
interface Periodo {
id_periodo: number;
@@ -12,18 +13,19 @@ interface Periodo {
}
interface ApiResponse {
semestre: string;
carrera: string;
profesor: string;
profesor: string;
femenino: string;
masculino: string;
total: string;
}
type TipoConteo = "WINDOWS" | "MACINTOSH" | "LINUX" | "PROFESORES";
interface TablaRow {
carrera: string;
semestre: string;
WINDOWS: number;
MACINTOSH: number;
LINUX: number;
@@ -35,13 +37,13 @@ interface TablaRow {
export default function Inscripciones() {
const [periodo, setPeriodo] = useState<Periodo[]>([]);
const [selectedPeriodo, setSelectedPeriodo] = useState<number | null>(null);
const [periodoInicio, setPeriodoInicio] = useState<number | null>(null);
const [periodoFin, setPeriodoFin] = useState<number | null>(null);
const [tablaData, setTablaData] = useState<TablaRow[]>([]);
const [rawData, setRawData] = useState<ApiResponse[]>([]);
const token = Cookies.get("token");
const headers = { Authorization: `Bearer ${token}` };
useEffect(() => {
const getPeriodo = async () => {
const response = await axios.get(`${envConfig.apiUrl}/periodo`, { headers });
@@ -50,29 +52,41 @@ export default function Inscripciones() {
getPeriodo();
}, []);
const handleBuscar = async (e: React.FormEvent) => {
e.preventDefault();
const handleBuscar = async (e: React.FormEvent) => {
e.preventDefault();
if (!selectedPeriodo) return;
if (!periodoInicio || !periodoFin) {
alert("Selecciona ambos periodos");
return;
}
const response = await axios.get(
`${envConfig.apiUrl}/alumno-inscrito/inscritos/${selectedPeriodo}`,
{ headers }
);
if (periodoInicio > periodoFin) {
alert("El periodo inicio no puede ser mayor al final");
return;
}
const esMismoPeriodo = periodoInicio === periodoFin;
try {
const url = esMismoPeriodo
? `${envConfig.apiUrl}/alumno-inscrito/inscritos/${periodoInicio}` // 👈 uno solo
: `${envConfig.apiUrl}/alumno-inscrito/inscritos/${periodoInicio}/${periodoFin}`; // 👈 rango
const response = await axios.get(url, { headers });
const data: ApiResponse[] = response.data;
setRawData(data);
const agrupado: Record<string, TablaRow> = {};
data.forEach((item) => {
const carrera = item.carrera;
const key = `${item.carrera}-${item.semestre}`;
if (!agrupado[carrera]) {
agrupado[carrera] = {
carrera: carrera,
if (!agrupado[key]) {
agrupado[key] = {
carrera: item.carrera,
semestre: item.semestre,
WINDOWS: 0,
MACINTOSH: 0,
LINUX: 0,
@@ -83,20 +97,98 @@ export default function Inscripciones() {
};
}
const fila = agrupado[carrera];
const tipoProfesor = item.profesor as TipoConteo;
const totalPlataforma = Number(item.total);
const fila = agrupado[key];
const tipoProfesor = item.profesor as TipoConteo;
const total = Number(item.total);
const fem = Number(item.femenino);
const masc = Number(item.masculino);
fila[tipoProfesor] += totalPlataforma;
fila.TOTAL += totalPlataforma;
fila[tipoProfesor] += total;
fila.TOTAL += total;
fila.femenino += fem;
fila.masculino += masc;
});
setTablaData(Object.values(agrupado));
} catch (error) {
console.error("Error al obtener inscritos", error);
}
};
// Export Excel
const exportarExcel = () => {
if (!rawData.length) return;
const periodosUnicos = Array.from(
new Set(rawData.map((t) => t.semestre))
).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
const carrerasUnicas = Array.from(
new Set(rawData.map((t) => t.carrera))
);
const dataExcel = carrerasUnicas.map((carrera) => {
const fila: any = { Carrera: carrera };
let totalFila = 0;
let totalFemenino = 0;
let totalMasculino = 0;
periodosUnicos.forEach((periodo) => {
const items = rawData.filter(
(t) => t.carrera === carrera && t.semestre === periodo
);
const totalPeriodo = items.reduce(
(acc, item) => acc + Number(item.total),
0
);
fila[periodo] = totalPeriodo;
totalFila += totalPeriodo;
totalFemenino += items.reduce(
(acc, item) => acc + Number(item.femenino),
0
);
totalMasculino += items.reduce(
(acc, item) => acc + Number(item.masculino),
0
);
});
fila["Femenino"] = totalFemenino;
fila["Masculino"] = totalMasculino;
fila["Total"] = totalFila;
return fila;
});
const worksheet = XLSX.utils.json_to_sheet(dataExcel);
worksheet["!cols"] = [
{ wch: 25 },
...periodosUnicos.map(() => ({ wch: 15 })),
{ wch: 15 },
{ wch: 15 },
{ wch: 15 },
];
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Inscritos");
const excelBuffer = XLSX.write(workbook, {
bookType: "xlsx",
type: "array",
});
const blob = new Blob([excelBuffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});
saveAs(blob, "reporte_inscritos.xlsx");
};
return (
@@ -104,15 +196,20 @@ export default function Inscripciones() {
<h2 className="title">INSCRITOS</h2>
<form className="containerForm" onSubmit={handleBuscar}>
<label>Seleccione el periodo</label>
<label>Seleccione rango de periodos</label>
<div className="groupInput">
<select
onChange={(e) => setSelectedPeriodo(Number(e.target.value))}
defaultValue=""
>
<option value="" disabled>
Seleccione
</option>
<select onChange={(e) => setPeriodoInicio(Number(e.target.value))} defaultValue="">
<option value="" disabled>Inicio</option>
{periodo.map((p) => (
<option key={p.id_periodo} value={p.id_periodo}>
{p.semestre}
</option>
))}
</select>
<select onChange={(e) => setPeriodoFin(Number(e.target.value))} defaultValue="">
<option value="" disabled>Fin</option>
{periodo.map((p) => (
<option key={p.id_periodo} value={p.id_periodo}>
{p.semestre}
@@ -123,6 +220,14 @@ export default function Inscripciones() {
<button className="button buttonSearch" type="submit">
Buscar
</button>
<button
type="button"
className="button buttonSearch"
onClick={exportarExcel}
>
Exportar Excel
</button>
</div>
</form>
@@ -131,6 +236,7 @@ export default function Inscripciones() {
<thead>
<tr>
<th>Carrera</th>
<th>Periodo</th>
<th>Femenino</th>
<th>Masculino</th>
<th>WINDOWS</th>
@@ -145,6 +251,7 @@ export default function Inscripciones() {
{tablaData.map((row, index) => (
<tr key={index}>
<td className="textLeft">{row.carrera}</td>
<td>{row.semestre}</td>
<td>{row.femenino}</td>
<td>{row.masculino}</td>
<td>{row.WINDOWS}</td>
+1 -1
View File
@@ -113,7 +113,7 @@ export default function ReporteTotalesPage() {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});
saveAs(data, "reporte_pivot.xlsx");
saveAs(data, "reporte_periodo.xlsx");
};
// FETCH