cordenadas a1-a6
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
'use client'
|
||||
|
||||
import axios from "axios";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Bar, BarChart, CartesianGrid, Legend, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
|
||||
|
||||
interface antiguedad{
|
||||
antiguedad:string;
|
||||
total:number;
|
||||
}
|
||||
|
||||
export default function Antiguedad() {
|
||||
const [antiguedad,setAntiguedad]=useState<antiguedad[]>([])
|
||||
|
||||
useEffect(()=>{
|
||||
const getAntiguedad = async()=>{
|
||||
const response = await axios.get("http://localhost:3001/equipos/grafica")
|
||||
|
||||
setAntiguedad(response.data)
|
||||
}
|
||||
getAntiguedad()
|
||||
},[])
|
||||
|
||||
return (
|
||||
<ResponsiveContainer width="100%" aspect={2}>
|
||||
<BarChart data={antiguedad}
|
||||
width={500}
|
||||
height={300}
|
||||
margin={{
|
||||
top:20,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3"/>
|
||||
<XAxis dataKey="antiguedad"/>
|
||||
<YAxis/>
|
||||
<Tooltip/>
|
||||
<Legend/>
|
||||
<Bar dataKey="total" fill="#0d6efd"/>
|
||||
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
export default function FormEquipo() {
|
||||
return (
|
||||
<form>
|
||||
<label >Selecciona la antiguedad</label>
|
||||
<select>
|
||||
<option value=""></option>
|
||||
</select>
|
||||
<label>Selecciona la adscripcion</label>
|
||||
<select>
|
||||
<option value=""></option>
|
||||
</select>
|
||||
<label >Selecciona el edificio</label>
|
||||
<select>
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
@@ -49,6 +49,11 @@ function BarNavigation() {
|
||||
<span>Perifericos</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="subMenu" onClick={toggleMenu}>
|
||||
<Link href="/reportesGraficas" className="links">
|
||||
<span>Reportes y Graficas</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="subMenu">
|
||||
<button className="logout-button" onClick={cerrarSesion}>
|
||||
Cerrar sesión
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
"use client";
|
||||
|
||||
import { MapContainer, ImageOverlay, useMap } from "react-leaflet";
|
||||
import L from "leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import "leaflet.heat";
|
||||
import { useEffect } from "react";
|
||||
|
||||
// 🔷 Ajustar vista automáticamente
|
||||
function AjustarVista({ bounds }) {
|
||||
const map = useMap();
|
||||
|
||||
useEffect(() => {
|
||||
map.fitBounds(bounds);
|
||||
}, [map, bounds]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function HeatLayer() {
|
||||
const map = useMap();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
// ESCALADOS A 4768x3368
|
||||
const edificios = {
|
||||
A1: [[1400, 3060], [1470, 3060], [1470, 3360], [1400, 3360]],
|
||||
A2: [[1570, 3130], [1570, 3190], [1850, 3190], [1850, 3130]],
|
||||
A3: [[1640, 2650], [1705, 2650], [1705, 2950], [1640, 2950]],
|
||||
A4: [[1235, 2260], [1235, 2360], [1610, 2360], [1610, 2260]],
|
||||
A5: [[2250, 2480], [2580, 2480], [2580, 2580], [2250, 2580]],
|
||||
A6: [[1390, 2385], [1480, 2385], [1480, 2655], [1390, 2655]],
|
||||
A7: [[2080, 2080], [2250, 2080], [2250, 2480], [2080, 2480]],
|
||||
A8: [[1820, 2280], [2100, 2280], [2100, 2380], [1820, 2380]],
|
||||
A9: [[1950, 1880], [2250, 1880], [2250, 1980], [1950, 1980]],
|
||||
A10: [[1730, 1780], [1900, 1780], [1900, 2130], [1730, 2130]],
|
||||
A11: [[1700, 1580], [2050, 1580], [2050, 1710], [1700, 1710]],
|
||||
A12: [[2050, 1280], [2250, 1280], [2250, 1780], [2050, 1780]],
|
||||
A13: [[1530, 680], [1700, 680], [1700, 1050], [1530, 1050]],
|
||||
A14: [[1700, 630], [2050, 630], [2050, 750], [1700, 750]],
|
||||
A15: [[2027, 2580], [2087, 2580], [2087, 2900], [2027, 2900]],
|
||||
CEDTEC: [[900, 2900], [1100, 2900], [1100, 3200], [900, 3200]],
|
||||
BIBLIOTECA: [[1200, 1600], [1500, 1600], [1500, 1900], [1200, 1900]],
|
||||
POSGRADO: [[1100, 1525], [860, 1525], [860, 1325], [1100, 1325]]
|
||||
|
||||
};
|
||||
|
||||
|
||||
const puntos = [];
|
||||
|
||||
Object.entries(edificios).forEach(([nombre, poligono]) => {
|
||||
for (let i = 0; i < 15; i++) {
|
||||
|
||||
const x = poligono[0][0] + Math.random() * (poligono[1][0] - poligono[0][0]);
|
||||
const y = poligono[0][1] + Math.random() * (poligono[2][1] - poligono[0][1]);
|
||||
|
||||
const intensidad = Math.random();
|
||||
|
||||
puntos.push([x, y, intensidad]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const heat = L.heatLayer(puntos, {
|
||||
radius: 35,
|
||||
blur: 25,
|
||||
maxZoom: 2,
|
||||
gradient: {
|
||||
0.2: "#00f",
|
||||
0.4: "#0ff",
|
||||
0.6: "#0f0",
|
||||
0.8: "#ff0",
|
||||
1.0: "#f00"
|
||||
}
|
||||
});
|
||||
|
||||
heat.addTo(map);
|
||||
|
||||
|
||||
Object.entries(edificios).forEach(([nombre, coords]) => {
|
||||
L.polygon(coords, {
|
||||
color: "#77ee9f",
|
||||
weight: 2,
|
||||
fillOpacity: 0.25
|
||||
})
|
||||
.bindPopup(`🏢 ${nombre}`)
|
||||
.addTo(map);
|
||||
});
|
||||
|
||||
// 🔥 DEBUG PRO (CLICK PARA COORDENADAS EXACTAS)
|
||||
map.on("click", function (e) {
|
||||
console.log("📍 Coordenadas exactas:", e.latlng);
|
||||
});
|
||||
|
||||
return () => {
|
||||
map.removeLayer(heat);
|
||||
};
|
||||
|
||||
}, [map]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default function MapaCalor() {
|
||||
|
||||
const bounds = [
|
||||
[0, 0],
|
||||
[3368, 4768] // 🔥 DIMENSIÓN REAL
|
||||
];
|
||||
|
||||
return (
|
||||
|
||||
<div style={{
|
||||
width: "100%",
|
||||
height: "650px",
|
||||
marginTop: "40px",
|
||||
borderRadius: "12px",
|
||||
overflow: "hidden",
|
||||
boxShadow: "0 6px 25px rgba(0,0,0,0.3)"
|
||||
}}>
|
||||
|
||||
<MapContainer
|
||||
crs={L.CRS.Simple}
|
||||
minZoom={-2}
|
||||
style={{ height: "100%", width: "100%" }}
|
||||
>
|
||||
|
||||
<ImageOverlay
|
||||
url="/plano.png"
|
||||
bounds={bounds}
|
||||
/>
|
||||
|
||||
<AjustarVista bounds={bounds} />
|
||||
|
||||
<HeatLayer />
|
||||
|
||||
</MapContainer>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import Cookies from "js-cookie";
|
||||
import axios from "axios";
|
||||
import "./pregunta7.css";
|
||||
import ToggleButton from "../Toggle/ToggleButton";
|
||||
import MapaCalor from "./MapaCalor";
|
||||
|
||||
type AntiguedadItem = {
|
||||
antiguedad: string | null;
|
||||
@@ -41,19 +42,19 @@ export default function Pregunta7() {
|
||||
const antig = item.antiguedad?.toLowerCase().trim();
|
||||
|
||||
switch (antig) {
|
||||
case "Menor a 2 años":
|
||||
case "menor a 2 años":
|
||||
menor2 += total;
|
||||
break;
|
||||
|
||||
case "Entre 2 y 3 años":
|
||||
case "entre 2 y 3 años":
|
||||
entre2_3 += total;
|
||||
break;
|
||||
|
||||
case "Entre 4 y 5 años":
|
||||
case "entre 4 y 5 años":
|
||||
entre4_5 += total;
|
||||
break;
|
||||
|
||||
case "Mayor a 6 años":
|
||||
case "mayor a 6 años":
|
||||
mayor6 += total;
|
||||
break;
|
||||
}
|
||||
@@ -167,6 +168,7 @@ export default function Pregunta7() {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<MapaCalor />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ function Header() {
|
||||
"/ranking",
|
||||
];
|
||||
|
||||
const privateNav = ["/equipoComputo", "/crearCuenta", "/perifericos"];
|
||||
const privateNav = ["/equipoComputo", "/crearCuenta", "/perifericos","/reportesGraficas"];
|
||||
|
||||
return (
|
||||
<header className={header.header}>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
.container{
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding:20px;
|
||||
background:white;
|
||||
border-radius:10px;
|
||||
box-shadow:0 2px 8px rgba(0,0,0,0.08);
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
.title{
|
||||
font-size:18px;
|
||||
margin-bottom:15px;
|
||||
}
|
||||
|
||||
.label{
|
||||
font-size:13px;
|
||||
color:#444;
|
||||
}
|
||||
|
||||
.listaContainer{
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
.subtitle{
|
||||
font-size:14px;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
.empty{
|
||||
font-size:13px;
|
||||
color:#777;
|
||||
}
|
||||
|
||||
.lista{
|
||||
display:flex;
|
||||
flex-wrap:wrap;
|
||||
gap:8px;
|
||||
}
|
||||
|
||||
.chip{
|
||||
display:flex;
|
||||
align-items:center;
|
||||
background:#f1f3f5;
|
||||
border-radius:20px;
|
||||
padding:5px 10px;
|
||||
font-size:13px;
|
||||
}
|
||||
|
||||
.remove{
|
||||
border:none;
|
||||
background:none;
|
||||
margin-left:6px;
|
||||
cursor:pointer;
|
||||
color:#777;
|
||||
}
|
||||
|
||||
.remove:hover{
|
||||
color:#c0392b;
|
||||
}
|
||||
|
||||
.button{
|
||||
margin-top:20px;
|
||||
padding:8px 14px;
|
||||
border:none;
|
||||
border-radius:6px;
|
||||
background:#2563eb;
|
||||
color:white;
|
||||
font-size:13px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.button:hover{
|
||||
background:#1d4ed8;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
"use client"
|
||||
|
||||
import Select from "react-select"
|
||||
import { useState } from "react"
|
||||
import styles from "./Reporte.module.css"
|
||||
|
||||
type AdscripcionOption = {
|
||||
value: string
|
||||
label: string
|
||||
}
|
||||
|
||||
export default function Reporte() {
|
||||
|
||||
const [adscripcionesSeleccionadas, setAdscripcionesSeleccionadas] = useState<AdscripcionOption[]>([])
|
||||
|
||||
const adscripciones: AdscripcionOption[] = [
|
||||
{ value: "informatica", label: "Informática" },
|
||||
{ value: "rh", label: "Recursos Humanos" },
|
||||
{ value: "finanzas", label: "Finanzas" },
|
||||
{ value: "juridico", label: "Jurídico" }
|
||||
]
|
||||
|
||||
const agregarAdscripcion = (option: AdscripcionOption | null) => {
|
||||
|
||||
if (!option) return
|
||||
|
||||
const existe = adscripcionesSeleccionadas.some(a => a.value === option.value)
|
||||
|
||||
if (!existe) {
|
||||
setAdscripcionesSeleccionadas([...adscripcionesSeleccionadas, option])
|
||||
}
|
||||
}
|
||||
|
||||
const eliminarAdscripcion = (value: string) => {
|
||||
setAdscripcionesSeleccionadas(
|
||||
adscripcionesSeleccionadas.filter(a => a.value !== value)
|
||||
)
|
||||
}
|
||||
|
||||
const generarReporte = () => {
|
||||
console.log("Adscripciones seleccionadas:", adscripcionesSeleccionadas)
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
<div className={styles.container}>
|
||||
|
||||
<h2 className={styles.title}>Reporte de Antigüedad de Equipos</h2>
|
||||
|
||||
<label className={styles.label}>Buscar adscripción</label>
|
||||
|
||||
<Select
|
||||
options={adscripciones}
|
||||
placeholder="Escribe para buscar..."
|
||||
onChange={(value) => agregarAdscripcion(value)}
|
||||
/>
|
||||
|
||||
<div className={styles.listaContainer}>
|
||||
|
||||
<h4 className={styles.subtitle}>
|
||||
Adscripciones seleccionadas ({adscripcionesSeleccionadas.length})
|
||||
</h4>
|
||||
|
||||
{adscripcionesSeleccionadas.length === 0 && (
|
||||
<p className={styles.empty}>No hay adscripciones seleccionadas</p>
|
||||
)}
|
||||
|
||||
<div className={styles.lista}>
|
||||
|
||||
{adscripcionesSeleccionadas.map((ads) => (
|
||||
<div key={ads.value} className={styles.chip}>
|
||||
|
||||
<span>{ads.label}</span>
|
||||
|
||||
<button
|
||||
className={styles.remove}
|
||||
onClick={() => eliminarAdscripcion(ads.value)}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
</div>
|
||||
))}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<button
|
||||
className={styles.button}
|
||||
onClick={generarReporte}
|
||||
>
|
||||
Generar reporte
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user