Conexion a APIS con Preguntas

This commit is contained in:
jls846
2025-11-19 18:24:38 -06:00
parent 1047a49171
commit db2dd0f97e
7 changed files with 526 additions and 359 deletions
+1 -16
View File
@@ -61,7 +61,6 @@
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -1633,7 +1632,6 @@
"integrity": "sha512-tBFxBp9Nfyy5rsmefN+WXc1JeW/j2BpBHFdLZbEVfs9wn3E3NRFxwV0pJg8M1qQAexFpvz73hJXFofV0ZAu92A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
@@ -1694,7 +1692,6 @@
"integrity": "sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.46.4",
"@typescript-eslint/types": "8.46.4",
@@ -2236,7 +2233,6 @@
"resolved": "https://registry.npmjs.org/@zxing/library/-/library-0.21.3.tgz",
"integrity": "sha512-hZHqFe2JyH/ZxviJZosZjV+2s6EDSY0O24R+FQmlWZBZXP9IqMo7S3nb3+2LBWxodJQkSurdQGnqE7KXqrYgow==",
"license": "MIT",
"peer": true,
"dependencies": {
"ts-custom-error": "^3.2.1"
},
@@ -2260,7 +2256,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -2660,7 +2655,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.25",
"caniuse-lite": "^1.0.30001754",
@@ -2878,8 +2872,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/cwise-compiler": {
"version": "1.1.3",
@@ -3306,7 +3299,6 @@
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -3492,7 +3484,6 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
@@ -5711,7 +5702,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -5721,7 +5711,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -6026,7 +6015,6 @@
"integrity": "sha512-Dqh7SiYcaFtdv5Wvku6QgS5IGPm281L+ZtVD1U2FJa7Q0EFRlq8Z3sjYtz6gYObsYThUOz9ArwFqPZx+1azILQ==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"chokidar": "^4.0.0",
"immutable": "^5.0.2",
@@ -6561,7 +6549,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -6764,7 +6751,6 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -7069,7 +7055,6 @@
"integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
"dev": true,
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
@@ -7,6 +7,7 @@ import Pregunta2_1 from "@/components/Equipo_Computo/Pregunta2_1";
import Pregunta3 from "@/components/Equipo_Computo/Pregunta3";
import Pregunta7EP from "@/components/Perifericos/Pregunta7EP";
import Pregunta9 from "@/components/Equipo_Computo/Pregunta9";
import Pregunta10 from "@/components/Equipo_Computo/pregunta10";
import "../../styles/layout/reporte.scss";
type PreguntaKey =
@@ -14,7 +15,8 @@ type PreguntaKey =
| "pregunta2"
| "pregunta3"
| "pregunta7EP"
| "pregunta9";
| "pregunta9"
| "pregunta10";
const LABELS: Record<PreguntaKey, string> = {
pregunta1: "Perfil de Usuario",
@@ -22,6 +24,7 @@ const LABELS: Record<PreguntaKey, string> = {
pregunta3: "Plataforma y tipo procesador",
pregunta7EP: "Laboratorios",
pregunta9: "Generales",
pregunta10: "Garantía de Proveedor",
};
// Mapeo de fondo por pregunta (puedes personalizarlo)
@@ -31,6 +34,7 @@ const TAB_BACKGROUNDS: Record<PreguntaKey, string> = {
pregunta3: "bg-gray",
pregunta7EP: "bg-gray",
pregunta9: "bg-blue",
pregunta10: "bg-blue",
};
export default function Page() {
@@ -48,6 +52,8 @@ export default function Page() {
return <Pregunta7EP />;
case "pregunta9":
return <Pregunta9 />;
case "pregunta10":
return <Pregunta10 />;
default:
return (
<div className="p-6 text-center text-gray-500">
+68 -78
View File
@@ -1,8 +1,9 @@
"use client";
import { useState } from "react";
import { useState, useEffect } from "react";
import axios from "axios";
import styles from "./pregunta2.module.scss";
import Cookies from "js-cookie";
type OsEntry = {
os: string;
count: number;
@@ -18,57 +19,6 @@ type PlatformKey =
type PlatformData = Record<PlatformKey, OsEntry[]>;
const MOCK_DATA: PlatformData = {
"pc-desktop": [
{ os: "Windows 11", count: 408 },
{ os: "Windows 10", count: 1171 },
{ os: "Windows 7/8", count: 177 },
{ os: "Windows XP/Vista", count: 43 },
{ os: "Linux", count: 45 },
{ os: "Total", count: 1844, isTotal: true },
],
"apple-desktop": [
{ os: "Mac OS X (13 - Ventura, 14 - Sonoma)", count: 205 },
{
os: "Mac OS X (Mojave, Catalina, 11 - Big Sur, 12 - Monterrey)",
count: 180,
},
{ os: "Mac OS X (Yosemite, El Capitan, Sierra, High Sierra)", count: 95 },
{ os: "Mac OS X (Snow Leopard, Mountain Lion, Mavericks)", count: 6 },
{ os: "Total", count: 480, isTotal: true },
],
"pc-laptop": [
{ os: "Windows 11", count: 40 },
{ os: "Windows 10", count: 171 },
{ os: "Windows 7/8", count: 17 },
{ os: "Windows XP/Vista", count: 3 },
{ os: "Linux", count: 5 },
{ os: "Total", count: 236, isTotal: true },
],
"apple-laptop": [
{ os: "Mac OS X (13 - Ventura, 14 - Sonoma)", count: 205 },
{
os: "Mac OS X (Mojave, Catalina, 11 - Big Sur, 12 - Monterrey)",
count: 180,
},
{ os: "Mac OS X (Yosemite, El Capitan, Sierra, High Sierra)", count: 95 },
{ os: "Mac OS X (Snow Leopard, Mountain Lion, Mavericks)", count: 6 },
{ os: "Total", count: 480, isTotal: true },
],
servers: [
{
os: "Linux (CentOS, Fedora, Ubuntu, Red Hat Enterprise, entre otros)",
count: 120,
},
{ os: "Unix (AIX, Mac OS Server, Solaris, etc.)", count: 80 },
{ os: "Windows Server 2022/2023", count: 50 },
{ os: "Windows Server 2016/2019", count: 80 },
{ os: "Windows Server 2008/2012", count: 50 },
{ os: "Windows Server 2000/2003", count: 12 },
{ os: "Total", count: 392, isTotal: true },
],
};
const PLATFORM_LABELS: Record<PlatformKey, string> = {
"pc-desktop": "Computadoras de escritorio Plataforma PC",
"apple-desktop": "Computadoras de escritorio Plataforma Apple",
@@ -76,23 +26,65 @@ const PLATFORM_LABELS: Record<PlatformKey, string> = {
"apple-laptop": "Computadoras portátiles Plataforma Apple",
servers: "Servidores de alto rendimiento",
};
interface RawOsEntry {
sistema_operativo: string;
total: string;
}
// ✔ Función profesional para transformar tu JSON a OsEntry[]
function transformPlatform(raw: RawOsEntry[]): OsEntry[] {
const rows: OsEntry[] = raw.map((item) => ({
os: item.sistema_operativo,
count: Number(item.total), // Convierte string a número
}));
export default function Pregunta1() {
const total = rows.reduce((acc, r) => acc + r.count, 0);
rows.push({
os: "Total",
count: total,
isTotal: true,
});
return rows;
}
export default function Pregunta2() {
const [activeTab, setActiveTab] = useState<PlatformKey>("pc-desktop");
const [data, setData] = useState<PlatformData | null>(null);
const currentData = MOCK_DATA[activeTab];
// ✔ GET AXIOS PROFESIONAL
useEffect(() => {
const token = Cookies.get("token");
const headers = {Authorization: `Bearer ${token}`};
axios
.get("https://venus.acatlan.unam.mx/censo_test/equipos/reporte/tipoEquipos_sistemasOperativos",{headers}) // ← TU API AQUI
.then((res) => {
const json = res.data; // Tu JSON con 5 arreglos
const formatted: PlatformData = {
"pc-desktop": transformPlatform(json[0]),
"apple-desktop": transformPlatform(json[1]),
"pc-laptop": transformPlatform(json[2]),
"apple-laptop": transformPlatform(json[3]),
servers: transformPlatform(json[4]),
};
setData(formatted);
})
.catch((err) => console.error("Error cargando datos", err));
}, []);
if (!data) return <div>Cargando datos...</div>;
const currentData = data[activeTab];
return (
<div className={styles.scanView_P1}>
<div className={styles.container_P1}>
<div className="contenedor-censo">
Censo de equipos periféricos - Equipo de digitalización
</div>
<div className="contenedor-censo">
Censo de equipos Sistemas Operativos
</div>
<div className="pregunta-cuadro">
5. Indique el número de equipos de digitalización de acuerdo con la
población universitaria al que se destina su uso primordialmente.
</div>
<div className={styles.header_P1}>
Presione cada pestaña para ver la información de las plataformas.
</div>
@@ -107,28 +99,26 @@ export default function Pregunta1() {
activeTab === key ? styles.active_P1 : ""
}`}
onClick={() => setActiveTab(key as PlatformKey)}
aria-selected={activeTab === key}
>
{label}
</button>
))}
</div>
{/* Data Table */}
<div className={styles["data-table_P1"]}>
{currentData.map((item, index) => (
<div
key={index}
className={`${styles["data-row_P1"]} ${
item.isTotal ? styles["total-row_P1"] : ""
}`}
>
<div className={styles["os-name_P1"]}>{item.os}</div>
<div className={styles["count-box_P1"]}>{item.count}</div>
</div>
))}
</div>
{/* Tabla */}
<div className={styles["data-table_P1"]}>
{currentData.map((item, index) => (
<div
key={index}
className={`${styles["data-row_P1"]} ${
item.isTotal ? styles["total-row_P1"] : ""
}`}
>
<div className={styles["os-name_P1"]}>{item.os}</div>
<div className={styles["count-box_P1"]}>{item.count}</div>
</div>
))}
</div>
</div>
</div>
</div>
+113 -177
View File
@@ -1,6 +1,8 @@
"use client";
import { useState } from "react";
import { useState, useEffect } from "react";
import axios from "axios";
import Cookies from "js-cookie";
import styles from "./pregunta3.module.scss";
type ProcessorEntry = {
@@ -23,161 +25,6 @@ type PlatformKey =
type PlatformData = Record<PlatformKey, ProcessorEntry[]>;
// Datos: solo "apple-desktop" tiene información en este caso
const MOCK_DATA: PlatformData = {
"pc-desktop": [],
"apple-desktop": [
{
tipo: "Core Ultra (i3, i5, i7) Serie 2",
alumnos: "",
profesores: "",
tecnicos: "",
investigadores: "",
administrativos: "",
total: "0",
},
{
tipo: "Core Ultra (i3, i5, i7) Serie 1",
alumnos: "",
profesores: "",
tecnicos: "",
investigadores: "",
administrativos: "",
total: "0",
},
{
tipo: "Familia M4",
alumnos: "",
profesores: "",
tecnicos: "",
investigadores: "",
administrativos: "2",
total: "2",
},
{
tipo: "Familia M3",
alumnos: "",
profesores: "1",
tecnicos: "",
investigadores: "",
administrativos: "1",
total: "2",
},
{
tipo: "Familia M2",
alumnos: "",
profesores: "2",
tecnicos: "",
investigadores: "",
administrativos: "",
total: "2",
},
{
tipo: "Familia M1",
alumnos: "51",
profesores: "1",
tecnicos: "",
investigadores: "",
administrativos: "",
total: "52",
},
{
tipo: "i9 o equivalentes (13a generación en adelante)",
alumnos: "",
profesores: "",
tecnicos: "",
investigadores: "",
administrativos: "",
total: "0",
},
{
tipo: "i7 o equivalentes (13a generación en adelante)",
alumnos: "",
profesores: "",
tecnicos: "",
investigadores: "",
administrativos: "",
total: "0",
},
{
tipo: "i7 o equivalentes (12a generación en adelante)",
alumnos: "",
profesores: "",
tecnicos: "",
investigadores: "",
administrativos: "1",
total: "1",
},
{
tipo: "i5 o equivalentes (13a generación en adelante)",
alumnos: "",
profesores: "",
tecnicos: "",
investigadores: "",
administrativos: "1",
total: "1",
},
{
tipo: "i5 o equivalentes (12a generación en adelante)",
alumnos: "11",
profesores: "1",
tecnicos: "",
investigadores: "",
administrativos: "",
total: "12",
},
{
tipo: "i3 o equivalentes (13a generación en adelante)",
alumnos: "175",
profesores: "5",
tecnicos: "",
investigadores: "",
administrativos: "26",
total: "206",
},
{
tipo: "i3 o equivalentes (12a generación en adelante)",
alumnos: "",
profesores: "",
tecnicos: "",
investigadores: "",
administrativos: "1",
total: "1",
},
{
tipo: "i3 o equivalentes (11a generación en adelante)",
alumnos: "",
profesores: "2",
tecnicos: "",
investigadores: "",
administrativos: "",
total: "2",
},
{
tipo: "Core2 Mac, Quad Core o anteriores",
alumnos: "12",
profesores: "3",
tecnicos: "3",
investigadores: "",
administrativos: "3",
total: "21",
},
{
tipo: "Total",
alumnos: "249",
profesores: "14",
tecnicos: "3",
investigadores: "0",
administrativos: "37",
total: "303",
isTotal: true,
},
],
"pc-laptop": [],
"apple-laptop": [],
servers: [],
};
const PLATFORM_LABELS: Record<PlatformKey, string> = {
"pc-desktop": "Computadoras de escritorio Plataforma PC",
"apple-desktop": "Computadoras de escritorio Plataforma Apple",
@@ -186,10 +33,111 @@ const PLATFORM_LABELS: Record<PlatformKey, string> = {
servers: "Alto rendimiento Servidores",
};
export default function Pregunta3_2() {
const [activeTab, setActiveTab] = useState<PlatformKey>("apple-desktop");
// Mapeo de "uso" del JSON a campos en ProcessorEntry
const USO_TO_FIELD: Record<string, keyof Omit<ProcessorEntry, "tipo" | "total" | "isTotal">> = {
ALUMNO: "alumnos",
PROFESOR: "profesores",
"TÉCNICO ACADEMICO": "tecnicos",
INVESTIGADOR: "investigadores",
ADMINISTRATIVO: "administrativos",
};
const currentData = MOCK_DATA[activeTab];
// Transforma un array plano del tipo [{procesador, uso, total}] en ProcessorEntry[]
function transformProcessorData(rawArray: { procesador: string; uso: string; total: string }[]): ProcessorEntry[] {
const map = new Map<string, ProcessorEntry>();
for (const item of rawArray) {
const { procesador, uso, total } = item;
if (!map.has(procesador)) {
map.set(procesador, {
tipo: procesador,
alumnos: "0",
profesores: "0",
tecnicos: "0",
investigadores: "0",
administrativos: "0",
total: "0",
});
}
const entry = map.get(procesador)!;
const field = USO_TO_FIELD[uso];
if (field) {
entry[field] = total;
}
}
// Convertimos a array y calculamos el total por fila
const rows = Array.from(map.values()).map((entry) => {
const totalNum =
parseInt(entry.alumnos || "0") +
parseInt(entry.profesores || "0") +
parseInt(entry.tecnicos || "0") +
parseInt(entry.investigadores || "0") +
parseInt(entry.administrativos || "0");
return {
...entry,
total: totalNum.toString(),
};
});
// Calculamos los totales generales
const grandTotal: ProcessorEntry = {
tipo: "Total",
alumnos: rows.reduce((sum, r) => sum + parseInt(r.alumnos || "0"), 0).toString(),
profesores: rows.reduce((sum, r) => sum + parseInt(r.profesores || "0"), 0).toString(),
tecnicos: rows.reduce((sum, r) => sum + parseInt(r.tecnicos || "0"), 0).toString(),
investigadores: rows.reduce((sum, r) => sum + parseInt(r.investigadores || "0"), 0).toString(),
administrativos: rows.reduce((sum, r) => sum + parseInt(r.administrativos || "0"), 0).toString(),
total: rows.reduce((sum, r) => sum + parseInt(r.total || "0"), 0).toString(),
isTotal: true,
};
return [...rows, grandTotal];
}
export default function Pregunta3_2() {
const [activeTab, setActiveTab] = useState<PlatformKey>("pc-desktop");
const [data, setData] = useState<PlatformData | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const token = Cookies.get("token");
if (!token) {
console.error("Token no encontrado");
setLoading(false);
return;
}
const headers = { Authorization: `Bearer ${token}` };
axios
.get("https://venus.acatlan.unam.mx/censo_test/equipos/reporte/tipoEquipos_procesador", { headers })
.then((res) => {
const json = res.data; // array de 5 arreglos
const formatted: PlatformData = {
"pc-desktop": transformProcessorData(json[0] || []),
"apple-desktop": transformProcessorData(json[1] || []),
"pc-laptop": transformProcessorData(json[2] || []),
"apple-laptop": transformProcessorData(json[3] || []),
servers: transformProcessorData(json[4] || []),
};
setData(formatted);
})
.catch((err) => {
console.error("Error cargando datos de procesadores", err);
})
.finally(() => {
setLoading(false);
});
}, []);
if (loading) return <div className={styles.scanView_P3}>Cargando datos...</div>;
if (!data) return <div className={styles.scanView_P3}>Error al cargar los datos.</div>;
const currentData = data[activeTab];
return (
<div className={styles.scanView_P3}>
@@ -199,21 +147,16 @@ export default function Pregunta3_2() {
<p className={styles.texto}>
3. Desglose la cantidad de población beneficiada por plataforma y tipo de procesador: *
</p>
<p className={styles.subtexto}>
Presione cada pestaña para ingresar la información.
</p>
<p className={styles.subtexto}>Presione cada pestaña para ingresar la información.</p>
</div>
{/* Contenido principal con pestañas a la izquierda */}
<div className={styles.mainContent_P3}>
{/* Pestañas verticales (izquierda) */}
{/* Pestañas verticales */}
<div className={styles.tabs_P3}>
{Object.entries(PLATFORM_LABELS).map(([key, label]) => (
<button
key={key}
className={`${styles.tab_P3} ${
activeTab === key ? styles.active_P3 : ""
}`}
className={`${styles.tab_P3} ${activeTab === key ? styles.active_P3 : ""}`}
onClick={() => setActiveTab(key as PlatformKey)}
aria-selected={activeTab === key}
>
@@ -222,7 +165,7 @@ export default function Pregunta3_2() {
))}
</div>
{/* Contenido de la tabla (derecha) */}
{/* Contenido */}
<div className={styles.content_P3}>
{currentData.length > 0 ? (
<>
@@ -231,10 +174,7 @@ export default function Pregunta3_2() {
<thead>
<tr>
<th rowSpan={2} className={styles.headerProcesador}>
{activeTab.includes("apple")
? "Plataforma Apple"
: "Plataforma PC"}{" "}
<br />
{activeTab.includes("apple") ? "Plataforma Apple" : "Plataforma PC"} <br />
Tipo de procesador
</th>
<th colSpan={5} className={styles.headerPoblacion}>
@@ -256,9 +196,7 @@ export default function Pregunta3_2() {
{currentData.map((item, index) => (
<tr
key={index}
className={
item.isTotal ? styles.totalRow_P3 : styles.dataRow_P3
}
className={item.isTotal ? styles.totalRow_P3 : styles.dataRow_P3}
>
<td className={styles.processor_P3}>{item.tipo}</td>
<td>
@@ -318,8 +256,6 @@ export default function Pregunta3_2() {
)}
</div>
</div>
</div>
</div>
);
+122 -87
View File
@@ -1,12 +1,27 @@
"use client";
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import Cookies from "js-cookie";
import axios from "axios";
import "./pregunta9.css";
type AntiguedadItem = {
antiguedad: string | null;
total: string;
porcentaje: string; // lo ignoramos
};
type ApiResponse = {
escritorios: AntiguedadItem[];
portatiles: AntiguedadItem[];
altoRendimiento: AntiguedadItem[];
};
export default function Pregunta9() {
const [datos, setDatos] = useState([
{ nombre: "Computadoras de Escritorio", valores: ["", "", "", ""] },
{ nombre: "Computadoras Portátiles", valores: ["", "", "", ""] },
{ nombre: "Alto Rendimiento", valores: ["", "", "", ""] },
{ nombre: "Computadoras de Escritorio", valores: ["0.00", "0.00", "0.00", "0.00","0.00"] },
{ nombre: "Computadoras Portátiles", valores: ["0.00", "0.00", "0.00", "0.00","0.00"] },
{ nombre: "Alto Rendimiento", valores: ["0.00", "0.00", "0.00", "0.00","0.00"] },
]);
const [garantia, setGarantia] = useState({
@@ -15,66 +30,141 @@ export default function Pregunta9() {
altoRendimiento: "",
});
// Función para actualizar datos de Pregunta 9
const handleChange = (filaIndex: number, colIndex: number, value: string) => {
const nuevosDatos = [...datos];
nuevosDatos[filaIndex].valores[colIndex] = value;
setDatos(nuevosDatos);
const [loading, setLoading] = useState(true);
// Transforma los datos del backend al formato de 4 columnas con % calculados
const transformarDatos = (items: AntiguedadItem[]): string[] => {
let menores2 = 0;
let entre2_3 = 0;
let entre4_6 = 0;
let mayores6 = 0;
let notfound = 0;
for (const item of items) {
const total = Number(item.total) || 0;
switch (item.antiguedad) {
case "MENOR A 2":
menores2 += total;
break;
case "ENTRE 2 Y 3":
entre2_3 += total;
break;
case "ENTRE 4 Y 5":
entre4_6 += total;
break;
case "MAYORES DE 6":
mayores6 += total;
break;
// Cualquier otro valor (aunque no debería haber) lo meteríamos en mayores6
default:notfound += total; break;
}
}
const totalEquipo = menores2 + mayores6+ entre2_3 + entre4_6 + notfound;
if (totalEquipo === 0) {
return ["0.00", "0.00", "0.00", "0.00","0.00"];
}
const pct = (valor: number) => ((valor / totalEquipo) * 100).toFixed(2);
// [Menor a 2, Entre 2-3, Entre 4-5, Mayor a 6]
return [pct(menores2), pct(entre2_3), pct(entre4_6), pct(mayores6),pct(notfound)];
};
// Función para calcular total de cada fila en Pregunta 9
const calcularTotal = (valores: string[]) =>
valores.reduce((acc, val) => acc + (Number(val) || 0), 0);
useEffect(() => {
const token = Cookies.get("token");
if (!token) {
console.error("Token no encontrado");
setLoading(false);
return;
}
axios
.get<ApiResponse>("https://venus.acatlan.unam.mx/censo_test/equipos/reporte/tipoEquipos_antiguedad", {
headers: { Authorization: `Bearer ${token}` },
})
.then((res) => {
const { escritorios, portatiles, altoRendimiento } = res.data;
setDatos([
{
nombre: "Computadoras de Escritorio",
valores: transformarDatos(escritorios),
},
{
nombre: "Computadoras Portátiles",
valores: transformarDatos(portatiles),
},
{
nombre: "Alto Rendimiento",
valores: transformarDatos(altoRendimiento),
},
]);
})
.catch((err) => {
console.error("Error al cargar datos de antigüedad", err);
})
.finally(() => {
setLoading(false);
});
}, []);
const calcularTotalFila = (valores: string[]) =>
valores.reduce((sum, val) => sum + parseFloat(val), 0);
if (loading) {
return <div className="contenedor-pregunta">Cargando datos...</div>;
}
return (
<div className="contenedor-pregunta">
<div className="pregunta-cuadro" style={{ marginTop: "30px" }}>
{/* Pregunta intro (servidores) */}
<div className="pregunta-cuadro" style={{ marginTop: "30px" }}>
Indique cuantos servidores son utilizados en ambientes productivos y si en ellos se almacenan datos personales.
</div>
{/* Pregunta 9 */}
{/* Pregunta 9: Antigüedad */}
<div className="pregunta-cuadro" style={{ marginTop: "30px" }}>
Calcule porcentualmente (%) la antiguedad que tienen los equipos de
cómputo del área universitaria.
Calcule porcentualmente (%) la antigüedad que tienen los equipos de cómputo del área universitaria.
</div>
<div className="tabla-contenedor">
<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((valor, colIdx) => (
<td key={colIdx}>
<div className="input-contenedor">
<input
type="number"
step="0.01"
value={valor}
onChange={(e) =>
handleChange(filaIndex, colIndex, e.target.value)
}
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>
@@ -84,62 +174,7 @@ export default function Pregunta9() {
</table>
</div>
{/* Pregunta 10 */}
<div className="pregunta-cuadro" style={{ marginTop: "30px" }}>
¿Cuántos equipos de cómputo tienen garantía de proveedor?.
</div>
<div className="tabla-contenedor">
<table className="tabla">
<thead>
<tr>
<th className="azul-marino">Computadoras de Escritorio (247)</th>
<th className="azul-marino">Computadoras Portátiles (767)</th>
<th className="azul-marino">Alto Rendimiento (17)</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div className="input-contenedor input-sp">
<input
type="number"
value={garantia.escritorio}
onChange={(e) =>
setGarantia({ ...garantia, escritorio: e.target.value })
}
/>
</div>
</td>
<td>
<div className="input-contenedor input-sp">
<input
type="number"
value={garantia.portatil}
onChange={(e) =>
setGarantia({ ...garantia, portatil: e.target.value })
}
/>
</div>
</td>
<td>
<div className="input-contenedor input-sp">
<input
type="number"
value={garantia.altoRendimiento}
onChange={(e) =>
setGarantia({
...garantia,
altoRendimiento: e.target.value,
})
}
/>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
);
}
}
@@ -0,0 +1,109 @@
/* === Cuadro de la pregunta === */
.pregunta-cuadro {
border-left: 6px solid #001f3f;
padding: 15px;
border-radius: 8px;
font-size: 16px;
margin-bottom: 25px;
}
/* === Contenedor de tabla === */
.tabla-contenedor {
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
overflow-x: auto;
}
/* === Estilos de la tabla === */
.tabla {
width: 100%;
border-collapse: collapse;
text-align: center;
color: black;
}
.tabla th,
.tabla td {
border: 1px solid #ddd;
padding: 12px;
}
.tabla th {
background-color: #002855;
color: white;
font-weight: 600;
font-size: 15px;
}
.tabla td {
font-size: 14px;
}
/* === Colores personalizados === */
.azul-marino {
background-color: #002855 !important;
color: white !important;
}
.rosa-fuerte {
background-color: #dc1557 !important;
color: white !important;
}
/* === Input === */
.input-contenedor {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.input-contenedor input {
width: 40%;
padding: 6px;
border: 2px solid #002855;
border-radius: 6px;
font-size: 14px;
color: #333;
text-align: center;
outline: none;
background-color: #e8e2e2;
box-sizing: border-box;
}
.input-contenedor input::-webkit-inner-spin-button,
.input-contenedor input::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Focus del input */
.input-contenedor input:focus {
border-color: #001f3f;
box-shadow: 0 0 6px rgba(0, 47, 95, 0.3);
}
/* Placeholder */
.input-contenedor input::placeholder {
color: #bbb;
}
/* Para celdas del total */
.total-celda {
font-weight: bold;
color: #002855;
background-color: #eef2f6;
}
/* Error de total */
.total-error {
background-color: #ffcccc;
color: #a80000;
}
/* Ajuste especial para inputs */
.input-sp input {
width: 38%;
}
@@ -0,0 +1,106 @@
"use client";
import React, { useState, useEffect } from "react";
import axios from "axios";
import Cookies from "js-cookie";
import "./pregunta10.css";
export default function Pregunta10() {
const [garantia, setGarantia] = useState({
escritorio: "",
portatil: "",
altoRendimiento: "",
});
const [loading, setLoading] = useState(true);
useEffect(() => {
const token = Cookies.get("token");
if (!token) {
console.error("Token no encontrado");
setLoading(false);
return;
}
axios
.get<number[]>("https://venus.acatlan.unam.mx/censo_test/equipos/reporte/garantia", {
headers: { Authorization: `Bearer ${token}` },
})
.then((res) => {
const [escritorio, portatil, altoRendimiento] = res.data;
setGarantia({
escritorio: escritorio?.toString() || "0",
portatil: portatil?.toString() || "0",
altoRendimiento: altoRendimiento?.toString() || "0",
});
})
.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(() => {
setLoading(false);
});
}, []);
if (loading) {
return (
<div className="pregunta-cuadro" style={{ marginTop: "30px" }}>
Cargando datos de garantía...
</div>
);
}
return (
<>
<div className="pregunta-cuadro" style={{ marginTop: "30px" }}>
¿Cuántos equipos de cómputo tienen garantía de proveedor?
</div>
<div className="tabla-contenedor">
<table className="tabla">
<thead>
<tr>
<th className="azul-marino">Computadoras de Escritorio (247)</th>
<th className="azul-marino">Computadoras Portátiles (767)</th>
<th className="azul-marino">Alto Rendimiento (17)</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div className="input-contenedor input-sp">
<input
type="number"
value={garantia.escritorio}
readOnly // 👈 solo lectura, como en otros reportes
/>
</div>
</td>
<td>
<div className="input-contenedor input-sp">
<input
type="number"
value={garantia.portatil}
readOnly
/>
</div>
</td>
<td>
<div className="input-contenedor input-sp">
<input
type="number"
value={garantia.altoRendimiento}
readOnly
/>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</>
);
}