This commit is contained in:
2025-11-21 12:11:37 -06:00
parent 4833c24571
commit 97ef0add39
7 changed files with 129 additions and 105 deletions
@@ -14,6 +14,7 @@ type PreguntaKey =
| "pregunta2"
| "pregunta3"
| "pregunta7EP"
| "pregunta8"
| "pregunta9";
const LABELS: Record<PreguntaKey, string> = {
@@ -21,6 +22,7 @@ const LABELS: Record<PreguntaKey, string> = {
pregunta2: "Sistema Operativo",
pregunta3: "Plataforma y tipo procesador",
pregunta7EP: "Laboratorios",
pregunta8:"Proyectos",
pregunta9: "Generales",
};
@@ -30,6 +32,7 @@ const TAB_BACKGROUNDS: Record<PreguntaKey, string> = {
pregunta2: "bg-gray",
pregunta3: "bg-gray",
pregunta7EP: "bg-gray",
pregunta8:"bg-gray",
pregunta9: "bg-blue",
};
@@ -45,12 +48,9 @@ export default function Page() {
case "pregunta3":
return <Pregunta3 />;
case "pregunta7EP":
return (
<>
<Pregunta7EP />
<Pregunta8 />
</>
);
return <Pregunta7EP />
case "pregunta8":
return <Pregunta8 />;
case "pregunta9":
return <Pregunta9 />;
default:
+9
View File
@@ -110,6 +110,15 @@ tr:nth-child(even) {
}
}
.total-labs {
margin-top: 20px;
padding: 10px;
font-size: 18px;
text-align: center;
background: #fff;
border-radius: 8px;
}
@media (max-width: 768px) {
.controls {
flex-direction: column;
+94 -82
View File
@@ -1,99 +1,113 @@
"use client";
import React, { useState, useEffect } from "react";
import axios from "axios";
import { useState, useEffect } from "react";
import Cookies from "js-cookie";
import axios from "axios";
import "./pregunta7.css";
interface AntiguedadItem {
antiguedad: string;
total: number;
porcentaje?: string;
}
type AntiguedadItem = {
antiguedad: string | null;
total: number | string;
};
interface RespuestaAntiguedad {
type RespuestaAntiguedad = {
impresion: AntiguedadItem[];
digitalizacion: AntiguedadItem[];
}
};
export default function Pregunta7() {
const [datos, setDatos] = useState([
{ nombre: "Impresión", valores: ["0.00", "0.00", "0.00", "0.00"] },
{ nombre: "Digitalización", valores: ["0.00", "0.00", "0.00", "0.00"] },
{ nombre: "Impresión", valores: ["0.00", "0.00", "0.00", "0.00", "0.00"] },
{
nombre: "Digitalización",
valores: ["0.00", "0.00", "0.00", "0.00", "0.00"],
},
]);
const [loading, setLoading] = useState(true);
const api_url = process.env.NEXT_PUBLIC_API_URL;
const calcularTotal = (valores: string[]) =>
valores.reduce((acc, val) => acc + (Number(val) || 0), 0);
// ------------------------------
// TRANSFORMADOR (maneja null)
// ------------------------------
const transformarDatos = (items: AntiguedadItem[]): string[] => {
let menores2 = 0;
let entre2_3 = 0;
let entre4_5 = 0;
let mayores6 = 0;
let notfound = 0;
for (const item of items) {
const total = Number(item.total) || 0;
const antig = item.antiguedad ? item.antiguedad.toUpperCase().trim() : null;
switch (antig) {
case "MENORES DE 2":
menores2 += total;
break;
case "ENTRE 2 Y 3":
entre2_3 += total;
break;
case "ENTRE 4 Y 5":
entre4_5 += total;
break;
case "ENTRE 6 Y MAYORES":
mayores6 += total;
break;
default:
notfound += total; // incluye null
}
}
const total = menores2 + entre2_3 + entre4_5 + mayores6 + notfound;
if (total === 0) return ["0.00", "0.00", "0.00", "0.00", "0.00"];
const pct = (v: number) => ((v / total) * 100).toFixed(2);
return [
pct(menores2),
pct(entre2_3),
pct(entre4_5),
pct(mayores6),
pct(notfound),
];
};
// ------------------------------
// CARGA DE DATOS
// ------------------------------
useEffect(() => {
const token = Cookies.get("token");
const headers = { Authorization: `Bearer ${token}` };
axios
.get(`${api_url}/equipos/reporte/contar_perifericos_antiguedad`, {
headers,
})
.get<RespuestaAntiguedad>(
`${api_url}/equipos/reporte/contar_perifericos_antiguedad`,
{
headers: { Authorization: `Bearer ${token}` },
}
)
.then((res) => {
const data: RespuestaAntiguedad = res.data;
const { impresion, digitalizacion } = res.data;
const orden = [
"MENORES DE 2",
"ENTRE 2 Y 3",
"ENTRE 4 Y 5",
"MAYOR A 6",
];
const nuevaTabla = [
{ nombre: "Impresión", totales: [0, 0, 0, 0] },
{ nombre: "Digitalización", totales: [0, 0, 0, 0] },
];
if (Array.isArray(data.impresion)) {
data.impresion.forEach((item) => {
const antig = item.antiguedad.toUpperCase().trim();
const i = orden.indexOf(antig);
if (i !== -1) nuevaTabla[0].totales[i] = Number(item.total) || 0;
});
}
if (Array.isArray(data.digitalizacion)) {
data.digitalizacion.forEach((item) => {
const antig = item.antiguedad.toUpperCase().trim();
const i = orden.indexOf(antig);
if (i !== -1) nuevaTabla[1].totales[i] = Number(item.total) || 0;
});
}
const tablaConPorcentajes = nuevaTabla.map((fila) => {
const totalFila = fila.totales.reduce((a, b) => a + b, 0);
let valores = ["0", "0", "0", "0"];
if (totalFila > 0) {
valores = fila.totales.map((v) =>
((v / totalFila) * 100).toFixed(2)
);
}
return { nombre: fila.nombre, valores };
});
setDatos(tablaConPorcentajes);
setDatos([
{ nombre: "Impresión", valores: transformarDatos(impresion) },
{ nombre: "Digitalización", valores: transformarDatos(digitalizacion) },
]);
})
.catch((err) => {
console.error("Error cargando datos:", err);
});
.catch((err) => console.error("Error cargando datos:", err))
.finally(() => setLoading(false));
}, []);
const calcularTotalFila = (valores: string[]) =>
valores.reduce((t, v) => t + Number(v), 0);
if (loading) return <div className="contenedor-pregunta">Cargando datos...</div>;
return (
<div className="contenedor-pregunta">
<div className="contenedor-censo">
Censo de equipos periféricos - Estado del equipo periférico (impresión y
digitalización.)
</div>
<div className="pregunta-cuadro">
<div className="pregunta-cuadro" style={{ marginTop: "30px" }}>
Antigüedad que tienen los equipos periféricos del área universitaria.
</div>
@@ -101,36 +115,34 @@ export default function Pregunta7() {
<table className="tabla">
<thead>
<tr>
<th className="azul-marino">% Antiguedad de los equipos</th>
<th className="azul-marino">% Antigüedad de los equipos</th>
<th className="rosa-fuerte">Menor a 2 años</th>
<th className="rosa-fuerte">Entre 2 y 3 años</th>
<th className="rosa-fuerte">Entre 4 y 5 años</th>
<th className="rosa-fuerte">Mayor a 6 años</th>
<th className="rosa-fuerte">No registrados</th>
<th className="azul-marino">Total</th>
</tr>
</thead>
<tbody>
{datos.map((fila, filaIndex) => {
const total = calcularTotal(fila.valores);
{datos.map((fila, idx) => {
const total = calcularTotalFila(fila.valores);
return (
<tr key={filaIndex}>
<tr key={idx}>
<td>{fila.nombre}</td>
{fila.valores.map((valor, colIndex) => (
<td key={colIndex}>
{fila.valores.map((v, c) => (
<td key={c}>
<div className="input-contenedor">
<input type="number" value={valor} disabled />
<input type="number" value={v} readOnly />
<span className="porcentaje">%</span>
</div>
</td>
))}
<td
className={`total-celda ${
total > 100 ? "total-error" : ""
}`}
>
<td className={`total-celda ${total > 100.1 ? "total-error" : ""}`}>
{total.toFixed(2)}%
</td>
</tr>
+4 -11
View File
@@ -1,16 +1,15 @@
"use client";
import React, { useState, useEffect } from "react";
import { useState, useEffect } from "react";
import Cookies from "js-cookie";
import axios from "axios";
import "./pregunta9.css";
import Pregunta4 from "./Pregunta_4";
import Pregunta10 from "./pregunta10";
type AntiguedadItem = {
antiguedad: string | null;
total: string;
porcentaje: string; // lo ignoramos
porcentaje: string;
};
type ApiResponse = {
@@ -26,12 +25,6 @@ export default function Pregunta9() {
{ nombre: "Alto Rendimiento", valores: ["0.00", "0.00", "0.00", "0.00","0.00"] },
]);
const [garantia, setGarantia] = useState({
escritorio: "",
portatil: "",
altoRendimiento: "",
});
const [loading, setLoading] = useState(true);
// Transforma los datos del backend al formato de 4 columnas con % calculados
@@ -48,7 +41,7 @@ export default function Pregunta9() {
const total = Number(item.total) || 0;
switch (item.antiguedad) {
case "MENOR A 2":
case "MENORES DE 2":
menores2 += total;
break;
case "ENTRE 2 Y 3":
@@ -57,7 +50,7 @@ export default function Pregunta9() {
case "ENTRE 4 Y 5":
entre4_6 += total;
break;
case "MAYORES DE 6":
case "ENTRE 6 Y MAYORES":
mayores6 += total;
break;
// Cualquier otro valor (aunque no debería haber) lo meteríamos en mayores6
+2 -3
View File
@@ -1,6 +1,6 @@
"use client";
import React, { useState, useEffect } from "react";
import { useState, useEffect } from "react";
import axios from "axios";
import Cookies from "js-cookie";
import "./pregunta10.css";
@@ -37,7 +37,6 @@ export default function Pregunta10() {
})
.catch((err) => {
console.error("Error al cargar datos de garantía", err);
// Opcional: establecer valores por defecto en caso de error
setGarantia({ escritorio: "0", portatil: "0", altoRendimiento: "0" });
})
.finally(() => {
@@ -75,7 +74,7 @@ export default function Pregunta10() {
<input
type="number"
value={garantia.escritorio}
readOnly // 👈 solo lectura, como en otros reportes
readOnly
/>
</div>
</td>
+6 -3
View File
@@ -73,12 +73,11 @@ export default function Pregunta7EP() {
const startItem = (currentPage - 1) * recordsPerPage + 1;
const endItem = Math.min(startItem + recordsPerPage - 1, sortedData.length);
const totalLaboratorios = data.reduce((sum, item) => sum + Number(item.cantidad), 0);
return (
<div className="container">
<div className="pregunta-cuadro">
Numero de laboratorios.
</div>
<div className="pregunta-cuadro">Numero de laboratorios.</div>
<div className="controls">
<div className="show-records">
@@ -138,6 +137,10 @@ export default function Pregunta7EP() {
</table>
</div>
<div className="total-labs">
Total de laboratorios: <strong>{totalLaboratorios}</strong>
</div>
<div className="pagination">
<button
onClick={() => setCurrentPage((prev) => Math.max(prev - 1, 1))}
+8
View File
@@ -73,6 +73,10 @@ export default function Pregunta8() {
const startItem = (currentPage - 1) * recordsPerPage + 1;
const endItem = Math.min(startItem + recordsPerPage - 1, sortedData.length);
const totalLaboratorios = data.reduce(
(sum, item) => sum + Number(item.cantidad),
0
);
return (
<div className="container">
@@ -135,6 +139,10 @@ export default function Pregunta8() {
</table>
</div>
<div className="total-labs">
Total de proyecto: <strong>{totalLaboratorios}</strong>
</div>
<div className="pagination">
<button
onClick={() => setCurrentPage((prev) => Math.max(prev - 1, 1))}