utn-cli 2.0.96 → 2.0.98
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/backend/servicios/Nucleo/Miscelaneas.js +2 -0
- package/templates/backend/servicios/Nucleo/ReporteHTML.js +116 -1
- package/templates/backend/servicios/Nucleo/ReportePDF.js +80 -0
- package/templates/frontend/src/app/Componentes/Nucleo/graficos/graficos.component.css +25 -13
- package/templates/frontend/src/app/Componentes/Nucleo/graficos/graficos.component.html +32 -35
- package/templates/frontend/src/app/Componentes/Nucleo/graficos/graficos.component.ts +6 -1
- package/templates/frontend/src/app/Componentes/Nucleo/tarjeta-modulo/tarjeta-modulo.component.css +121 -60
- package/templates/frontend/src/app/Componentes/Nucleo/tarjeta-modulo/tarjeta-modulo.component.html +26 -17
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.css +6 -0
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.html +40 -18
- package/templates/frontend/src/app/Paginas/contenedor-principal/contenedor-principal.component.css +7 -3
- package/templates/frontend/src/app/Paginas/contenedor-principal/contenedor-principal.component.ts +59 -25
- package/templates/frontend/src/app/Paginas/gestion-de-reportes/gestion-de-reportes.component.css +7 -3
- package/templates/frontend/src/app/Paginas/gestion-graficos/gestion-graficos.component.css +44 -1
- package/templates/frontend/src/app/Paginas/gestion-graficos/gestion-graficos.component.html +6 -4
- package/templates/frontend/src/index.html +1 -0
package/package.json
CHANGED
|
@@ -825,8 +825,10 @@ class Miscelaneo {
|
|
|
825
825
|
`a`.`Version`, `a`.`FechaDePublicacion`, `a`.`AcuerdoDeNivelDeServicio`, `a`.`DiccionarioDeDatos`, `a`.`Repositorios`,\
|
|
826
826
|
`a`.`EnlaceDelVideo`,`a`.`EnlaceDelManual`\
|
|
827
827
|
, `a`.`Estado`, REGEXP_SUBSTR(`a`.`Repositorios`, '[^,]*front[^,]*') AS `Frontend`\
|
|
828
|
+
, `c`.`Etiqueta`, `c`.`ColorDeLaEtiqueta`\
|
|
828
829
|
FROM `SIGU`.`SIGU_ModulosV2` `a`\
|
|
829
830
|
JOIN `SIGU`.`SIGU_PermisosV2` `b` ON (`a`.`Nombre` = `b`.`Modulo`)\
|
|
831
|
+
LEFT JOIN `SIGU`.`SIGU_ModulosV2InformacionExtra` `c` ON (`a`.`Nombre` = `c`.`Modulo`)\
|
|
830
832
|
WHERE `a`.`Estado` = 'Activo' AND `a`.`Padre` = ? AND `b`.`PermisoId` IN (?)\
|
|
831
833
|
ORDER BY FIELD(a.Nombre, " + ModulosFavoritos + ") DESC, a.Nombre", [Padre, Permisos.map(p => p.PermisoId)]);
|
|
832
834
|
return Modulos.map((linea) => {
|
|
@@ -60,6 +60,48 @@ class ReporteHTML {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
GenerarReporteHTMLRegistrosVerticales(ElementosParaLaTabla, ParametrosExcluidos = [], ParametrosExtra = [], MostrarEncabezado = true) {
|
|
63
|
+
//Ejemplo ElementosParaLaTabla:
|
|
64
|
+
// [
|
|
65
|
+
// {
|
|
66
|
+
// "Fecha del traslado": "16-03-2026",
|
|
67
|
+
// "Justificacion": "Traslado por mantenimiento",
|
|
68
|
+
// "Dependencia que entrega": "Juan Pérez",
|
|
69
|
+
// "Dependencia que recibe": "María Gómez",
|
|
70
|
+
// Placa: "ABC123",
|
|
71
|
+
// "Descripción": "Laptop Dell",
|
|
72
|
+
// "Código de activo": "ACT-001",
|
|
73
|
+
// "N° de serie": "SN123456",
|
|
74
|
+
// Marca: "Dell",
|
|
75
|
+
// Modelo: "Latitude 5420",
|
|
76
|
+
// Estado: "Bueno",
|
|
77
|
+
// IdentificadorOrigen: 101,
|
|
78
|
+
// IdentificadorDestino: 202
|
|
79
|
+
// },
|
|
80
|
+
// {
|
|
81
|
+
// "Fecha del traslado": "16-03-2026",
|
|
82
|
+
// "Justificacion": "Traslado por mantenimiento",
|
|
83
|
+
// "Dependencia que entrega": "Juan Pérez",
|
|
84
|
+
// "Dependencia que recibe": "María Gómez",
|
|
85
|
+
// Placa: "XYZ789",
|
|
86
|
+
// "Descripción": "Monitor Samsung",
|
|
87
|
+
// "Código de activo": "ACT-002",
|
|
88
|
+
// "N° de serie": "SN654321",
|
|
89
|
+
// Marca: "Samsung",
|
|
90
|
+
// Modelo: "S24F350",
|
|
91
|
+
// Estado: "Excelente",
|
|
92
|
+
// IdentificadorOrigen: 101,
|
|
93
|
+
// IdentificadorDestino: 202
|
|
94
|
+
// }
|
|
95
|
+
// ]
|
|
96
|
+
// Espera un Array
|
|
97
|
+
//Ejemplo ParametrosExcluidos:
|
|
98
|
+
//const ParametrosExcluidos = ['IdentificadorOrigen', 'Justificacion', 'IdentificadorDestino'];
|
|
99
|
+
//Valores devueltos por el QUERY que no sean necesarios mostrar en la tabla.
|
|
100
|
+
|
|
101
|
+
//Ejemplo ParametrosExtra:
|
|
102
|
+
//const ParametrosExtra = ['Toma física'];
|
|
103
|
+
//En caso de necesitar un espacio extra en la tabla que no se encuentra en la lista principal.
|
|
104
|
+
|
|
63
105
|
if (!ElementosParaLaTabla?.length) return '<p>No hay datos para mostrar.</p>';
|
|
64
106
|
|
|
65
107
|
const baseColumnas = Object.keys(ElementosParaLaTabla[0]).filter(col => !ParametrosExcluidos.includes(col));
|
|
@@ -186,6 +228,48 @@ class ReporteHTML {
|
|
|
186
228
|
}
|
|
187
229
|
|
|
188
230
|
GenerarReporteHTMLTablas(ElementosParaLaTabla, ParametrosExcluidos = [], ParametrosExtra = []) {
|
|
231
|
+
//Ejemplo ElementosParaLaTabla:
|
|
232
|
+
// [
|
|
233
|
+
// {
|
|
234
|
+
// "Fecha del traslado": "16-03-2026",
|
|
235
|
+
// "Justificacion": "Traslado por mantenimiento",
|
|
236
|
+
// "Dependencia que entrega": "Juan Pérez",
|
|
237
|
+
// "Dependencia que recibe": "María Gómez",
|
|
238
|
+
// Placa: "ABC123",
|
|
239
|
+
// "Descripción": "Laptop Dell",
|
|
240
|
+
// "Código de activo": "ACT-001",
|
|
241
|
+
// "N° de serie": "SN123456",
|
|
242
|
+
// Marca: "Dell",
|
|
243
|
+
// Modelo: "Latitude 5420",
|
|
244
|
+
// Estado: "Bueno",
|
|
245
|
+
// IdentificadorOrigen: 101,
|
|
246
|
+
// IdentificadorDestino: 202
|
|
247
|
+
// },
|
|
248
|
+
// {
|
|
249
|
+
// "Fecha del traslado": "16-03-2026",
|
|
250
|
+
// "Justificacion": "Traslado por mantenimiento",
|
|
251
|
+
// "Dependencia que entrega": "Juan Pérez",
|
|
252
|
+
// "Dependencia que recibe": "María Gómez",
|
|
253
|
+
// Placa: "XYZ789",
|
|
254
|
+
// "Descripción": "Monitor Samsung",
|
|
255
|
+
// "Código de activo": "ACT-002",
|
|
256
|
+
// "N° de serie": "SN654321",
|
|
257
|
+
// Marca: "Samsung",
|
|
258
|
+
// Modelo: "S24F350",
|
|
259
|
+
// Estado: "Excelente",
|
|
260
|
+
// IdentificadorOrigen: 101,
|
|
261
|
+
// IdentificadorDestino: 202
|
|
262
|
+
// }
|
|
263
|
+
// ]
|
|
264
|
+
// Espera un Array
|
|
265
|
+
//Ejemplo ParametrosExcluidos:
|
|
266
|
+
//const ParametrosExcluidos = ['IdentificadorOrigen', 'Justificacion', 'IdentificadorDestino'];
|
|
267
|
+
//Valores devueltos por el QUERY que no sean necesarios mostrar en la tabla.
|
|
268
|
+
|
|
269
|
+
//Ejemplo ParametrosExtra:
|
|
270
|
+
//const ParametrosExtra = ['Toma física'];
|
|
271
|
+
//En caso de necesitar un espacio extra en la tabla que no se encuentra en la lista principal.
|
|
272
|
+
|
|
189
273
|
if (!ElementosParaLaTabla?.length) return '';
|
|
190
274
|
|
|
191
275
|
const baseColumnas = Object.keys(ElementosParaLaTabla[0]).filter(col => !ParametrosExcluidos.includes(col));
|
|
@@ -225,6 +309,37 @@ class ReporteHTML {
|
|
|
225
309
|
</table>`;
|
|
226
310
|
}
|
|
227
311
|
|
|
312
|
+
GenerarReporteHTMLDatosEnAgrupacion(titulo, valores) {
|
|
313
|
+
// Ejemplo titulo:
|
|
314
|
+
// "Residencia: Atenas 123"
|
|
315
|
+
// Espera un String. Puede contener texto simple o etiquetas HTML básicas.
|
|
316
|
+
|
|
317
|
+
// Ejemplo valores:
|
|
318
|
+
// {
|
|
319
|
+
// "Descripción": "Residencias principales del recinto",
|
|
320
|
+
// "Total de habitaciones disponibles": 3,
|
|
321
|
+
// "Estado": "Activo"
|
|
322
|
+
// }
|
|
323
|
+
// Espera un Objeto (JSON plano) donde cada par llave:valor será una línea en la agrupación.
|
|
324
|
+
// IMPORTANTE: Se recomienda construir este objeto a mano mapeando solo los datos necesarios
|
|
325
|
+
// de la base de datos, para evitar imprimir por error arreglos u objetos complejos anidados.
|
|
326
|
+
|
|
327
|
+
let htmlTarjeta = `
|
|
328
|
+
<div style="margin-bottom: 25px; padding: 15px; background-color: #f4f6f9; border-left: 4px solid #002f6b; border-radius: 4px;">
|
|
329
|
+
<h3 style="margin-top: 0; margin-bottom: 8px; color: #002f6b; font-size: 16px; font-weight: bold;">${titulo}</h3>
|
|
330
|
+
`;
|
|
331
|
+
|
|
332
|
+
const llaves = Object.keys(valores);
|
|
333
|
+
llaves.forEach((llave, index) => {
|
|
334
|
+
const margenInferior = (index === llaves.length - 1) ? '0' : '6px';
|
|
335
|
+
const valor = valores[llave] ?? '-';
|
|
336
|
+
htmlTarjeta += `<p style="margin: 0 0 ${margenInferior} 0; font-size: 13px; color: #444; line-height: 1.4;"><strong>${llave}:</strong> ${valor}</p>`;
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
htmlTarjeta += `</div>`;
|
|
340
|
+
return htmlTarjeta;
|
|
341
|
+
}
|
|
342
|
+
|
|
228
343
|
GenerarReporteHTMLPie() {
|
|
229
344
|
return `
|
|
230
345
|
</body>
|
|
@@ -232,4 +347,4 @@ class ReporteHTML {
|
|
|
232
347
|
}
|
|
233
348
|
}
|
|
234
349
|
|
|
235
|
-
module.exports = new ReporteHTML();
|
|
350
|
+
module.exports = new ReporteHTML();
|
|
@@ -460,6 +460,86 @@ class ReportePDF {
|
|
|
460
460
|
}
|
|
461
461
|
}
|
|
462
462
|
|
|
463
|
+
generarDatosEnAgrupacion(doc, titulo, valores) {
|
|
464
|
+
if (!valores || typeof valores !== 'object') return;
|
|
465
|
+
|
|
466
|
+
const margin = this.config.margin;
|
|
467
|
+
const pageWidth = doc.page.width;
|
|
468
|
+
const availableWidth = pageWidth - 2 * margin;
|
|
469
|
+
|
|
470
|
+
// Medidas
|
|
471
|
+
const padding = 15;
|
|
472
|
+
const gapTitulo = 8;
|
|
473
|
+
const gapLinea = 6;
|
|
474
|
+
const borderLeftWidth = 4;
|
|
475
|
+
|
|
476
|
+
// Calcular el alto necesario sin alterar doc.y ni doc.x aún
|
|
477
|
+
doc.fontSize(11).font(this.config.fuenteNegrita);
|
|
478
|
+
const tituloHeight = doc.heightOfString(titulo || '', { width: availableWidth - padding * 2 });
|
|
479
|
+
|
|
480
|
+
let contentHeight = 0;
|
|
481
|
+
const llaves = Object.keys(valores);
|
|
482
|
+
|
|
483
|
+
// Configurar fuente para medir contenido
|
|
484
|
+
doc.fontSize(this.config.fontSizeCuerpo);
|
|
485
|
+
|
|
486
|
+
llaves.forEach((llave, index) => {
|
|
487
|
+
const valor = valores[llave] ?? '-';
|
|
488
|
+
const text = `${llave}: ${valor}`;
|
|
489
|
+
|
|
490
|
+
// Se utiliza la misma fuente para calcular la altura (la negrita no suele cambiar el alto de la línea en Helvetica)
|
|
491
|
+
doc.font(this.config.fuenteNegrita);
|
|
492
|
+
const height = doc.heightOfString(text, { width: availableWidth - padding * 2 });
|
|
493
|
+
|
|
494
|
+
const margenInferior = (index === llaves.length - 1) ? 0 : gapLinea;
|
|
495
|
+
contentHeight += height + margenInferior;
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
const totalHeight = padding + tituloHeight + gapTitulo + contentHeight + padding;
|
|
499
|
+
|
|
500
|
+
// Revisar si cabe en la página actual
|
|
501
|
+
if (doc.y + totalHeight > doc.page.height - doc.page.margins.bottom - 20) {
|
|
502
|
+
doc.addPage();
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const currentY = doc.y;
|
|
506
|
+
|
|
507
|
+
// Fondo contenedor (#f4f6f9)
|
|
508
|
+
doc.save();
|
|
509
|
+
doc.rect(margin, currentY, availableWidth, totalHeight).fill("#f4f6f9");
|
|
510
|
+
// Borde izquierdo (#002f6b)
|
|
511
|
+
doc.rect(margin, currentY, borderLeftWidth, totalHeight).fill("#002f6b");
|
|
512
|
+
doc.restore();
|
|
513
|
+
|
|
514
|
+
let textY = currentY + padding;
|
|
515
|
+
const textX = margin + padding;
|
|
516
|
+
const textWidth = availableWidth - padding * 2;
|
|
517
|
+
|
|
518
|
+
// Dibujar Título
|
|
519
|
+
doc.fillColor("#002f6b").fontSize(11).font(this.config.fuenteNegrita);
|
|
520
|
+
doc.text(titulo || '', textX, textY, { width: textWidth });
|
|
521
|
+
textY = doc.y + gapTitulo;
|
|
522
|
+
|
|
523
|
+
// Dibujar Valores
|
|
524
|
+
doc.fillColor("#444444").fontSize(this.config.fontSizeCuerpo);
|
|
525
|
+
|
|
526
|
+
llaves.forEach((llave, index) => {
|
|
527
|
+
const valor = valores[llave] ?? '-';
|
|
528
|
+
|
|
529
|
+
doc.font(this.config.fuenteNegrita);
|
|
530
|
+
doc.text(`${llave}: `, textX, textY, { continued: true, width: textWidth });
|
|
531
|
+
|
|
532
|
+
doc.font(this.config.fuenteBase);
|
|
533
|
+
doc.text(`${valor}`, { continued: false });
|
|
534
|
+
|
|
535
|
+
const margenInferior = (index === llaves.length - 1) ? 0 : gapLinea;
|
|
536
|
+
textY = doc.y + margenInferior;
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// Mover cursor abajo dejando margen inferior
|
|
540
|
+
doc.y = currentY + totalHeight + 15;
|
|
541
|
+
}
|
|
542
|
+
|
|
463
543
|
generarTabla(doc, datos, metadatos) {
|
|
464
544
|
if (!datos || datos.length === 0) return;
|
|
465
545
|
|
|
@@ -1,29 +1,41 @@
|
|
|
1
|
-
.contenedor {
|
|
1
|
+
.contenedor {
|
|
2
|
+
/* This is the outermost div in graficos.component.html */
|
|
2
3
|
display: flex;
|
|
3
4
|
flex-wrap: wrap;
|
|
4
5
|
gap: 1rem;
|
|
5
6
|
justify-content: center;
|
|
6
7
|
width: 100%;
|
|
7
|
-
|
|
8
|
+
height: 100%;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
.grafico {
|
|
11
|
+
.grafico {
|
|
12
|
+
/* This is the div containing the h3 and canvas */
|
|
11
13
|
position: relative;
|
|
12
|
-
width: 100%;
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
width: 100%;
|
|
15
|
+
/* Take 100% of parent's width */
|
|
16
|
+
height: 100%;
|
|
17
|
+
/* Allow height to stretch based on parent */
|
|
18
|
+
max-height: 50vh;
|
|
19
|
+
/* Further reduce max-height to 50% of viewport height for increased vertical responsiveness */
|
|
15
20
|
padding: 0.5rem;
|
|
16
21
|
box-sizing: border-box;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
.grafico canvas {
|
|
21
|
-
width: 100% !important;
|
|
22
|
-
height: 100% !important;
|
|
23
|
-
display: block; /* Remove any default inline spacing */
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
h3 {
|
|
27
27
|
text-align: center;
|
|
28
28
|
margin-bottom: 0.5rem;
|
|
29
|
+
flex-shrink: 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.canvas-container {
|
|
33
|
+
position: relative;
|
|
34
|
+
flex: 1;
|
|
35
|
+
min-height: 0;
|
|
36
|
+
width: 100%;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.grafico canvas {
|
|
40
|
+
display: block;
|
|
29
41
|
}
|
|
@@ -1,45 +1,42 @@
|
|
|
1
1
|
<div class="contenedor">
|
|
2
2
|
|
|
3
3
|
@if(sinDatosReales) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
<div style="text-align:center; padding: 20px;">
|
|
5
|
+
<p><b>No se encontraron datos</b></p>
|
|
6
|
+
</div>
|
|
7
7
|
} @else {
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
9
|
+
@if(Datos && TipoDeGrafico==='Barras') {
|
|
10
|
+
<div class="grafico">
|
|
11
|
+
<h3>{{Titulo}}</h3>
|
|
12
|
+
<div class="canvas-container">
|
|
13
|
+
<canvas baseChart [data]="barChartData" [options]="barChartOptions" [type]="'bar'"
|
|
14
|
+
[plugins]="[pluginMostrarValores]">
|
|
15
|
+
</canvas>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
}
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
20
|
+
@if(Datos && TipoDeGrafico==='Pie') {
|
|
21
|
+
<div class="grafico">
|
|
22
|
+
<h3>{{Titulo}}</h3>
|
|
23
|
+
<div class="canvas-container">
|
|
24
|
+
<canvas baseChart [data]="pieChartData" [options]="pieChartOptions" [type]="'pie'">
|
|
25
|
+
</canvas>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
}
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
30
|
+
@if(Datos && TipoDeGrafico==='Línea') {
|
|
31
|
+
<div class="grafico">
|
|
32
|
+
<h3>{{Titulo}}</h3>
|
|
33
|
+
<div class="canvas-container">
|
|
34
|
+
<canvas baseChart [data]="lineChartData" [options]="lineChartOptions" [type]="'line'">
|
|
35
|
+
</canvas>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
}
|
|
42
39
|
|
|
43
40
|
}
|
|
44
41
|
|
|
45
|
-
</div>
|
|
42
|
+
</div>
|
|
@@ -83,7 +83,12 @@ export class GraficosComponent {
|
|
|
83
83
|
// =========================
|
|
84
84
|
public pieChartOptions: ChartConfiguration<'pie'>['options'] = {
|
|
85
85
|
responsive: true,
|
|
86
|
-
maintainAspectRatio: false
|
|
86
|
+
maintainAspectRatio: false,
|
|
87
|
+
layout: {
|
|
88
|
+
padding: {
|
|
89
|
+
bottom: 20
|
|
90
|
+
}
|
|
91
|
+
}
|
|
87
92
|
};
|
|
88
93
|
|
|
89
94
|
public pieChartData: ChartData<'pie', number[], string | string[]> = {
|
package/templates/frontend/src/app/Componentes/Nucleo/tarjeta-modulo/tarjeta-modulo.component.css
CHANGED
|
@@ -1,93 +1,154 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
bottom: 0;
|
|
4
|
-
right: 0;
|
|
5
|
-
width: 40px;
|
|
6
|
-
height: 40px;
|
|
7
|
-
background: linear-gradient(135deg, transparent 50%, rgba(0, 0, 0, 0.1) 50%);
|
|
8
|
-
pointer-events: none;
|
|
9
|
-
z-index: 1;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.pin-icon {
|
|
13
|
-
position: absolute;
|
|
14
|
-
top: 8px;
|
|
15
|
-
right: 8px;
|
|
16
|
-
font-size: 24px;
|
|
17
|
-
color: #888;
|
|
18
|
-
cursor: pointer;
|
|
19
|
-
z-index: 2;
|
|
20
|
-
transition: color 0.3s;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.pin-icon.pinned {
|
|
24
|
-
color: #222;
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
25
3
|
}
|
|
26
4
|
|
|
27
5
|
.modulo-card {
|
|
28
6
|
position: relative;
|
|
29
|
-
border: 1px solid #ccc;
|
|
30
|
-
border-radius: 8px;
|
|
31
|
-
padding: 16px;
|
|
32
7
|
width: 300px;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
8
|
+
/* Reduced from 380px */
|
|
9
|
+
height: 220px;
|
|
10
|
+
border-radius: 25px;
|
|
11
|
+
overflow: hidden;
|
|
12
|
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15);
|
|
13
|
+
border: 1px solid #0B4FCE;
|
|
14
|
+
/* Added border as requested */
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
17
|
+
background-color: #fff;
|
|
36
18
|
display: flex;
|
|
37
19
|
flex-direction: column;
|
|
38
|
-
justify-content: space-between;
|
|
39
20
|
margin: 10px;
|
|
40
|
-
|
|
21
|
+
/* Reduced to previous value */
|
|
41
22
|
}
|
|
42
23
|
|
|
43
24
|
.modulo-card:hover {
|
|
44
|
-
|
|
45
|
-
|
|
25
|
+
transform: translateY(-5px);
|
|
26
|
+
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
|
|
46
27
|
}
|
|
47
28
|
|
|
48
|
-
.modulo-header {
|
|
29
|
+
.modulo-card-header {
|
|
30
|
+
height: 105px;
|
|
31
|
+
/* Increased to reach the bottom of the icon container */
|
|
32
|
+
background-color: #f2f2f2;
|
|
49
33
|
display: flex;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
34
|
+
justify-content: space-between;
|
|
35
|
+
align-items: flex-start;
|
|
36
|
+
/* Align to top instead of center */
|
|
37
|
+
padding: 15px;
|
|
38
|
+
position: relative;
|
|
53
39
|
}
|
|
54
40
|
|
|
55
|
-
.modulo-
|
|
56
|
-
|
|
57
|
-
|
|
41
|
+
.modulo-tipo {
|
|
42
|
+
color: #3e5a7a;
|
|
43
|
+
font-size: 1.2rem;
|
|
44
|
+
font-weight: 500;
|
|
45
|
+
letter-spacing: 1px;
|
|
46
|
+
margin-top: 5px;
|
|
47
|
+
/* Slight adjustment for alignment */
|
|
58
48
|
}
|
|
59
49
|
|
|
60
|
-
.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
50
|
+
.pin-container {
|
|
51
|
+
width: 40px;
|
|
52
|
+
height: 40px;
|
|
53
|
+
background-color: #e6e6e6;
|
|
54
|
+
border-radius: 50%;
|
|
55
|
+
display: flex;
|
|
56
|
+
justify-content: center;
|
|
57
|
+
align-items: center;
|
|
58
|
+
color: #888;
|
|
59
|
+
transition: all 0.3s ease;
|
|
60
|
+
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.pin-container.pinned {
|
|
64
64
|
color: #333;
|
|
65
|
+
background-color: #ddd;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
.
|
|
68
|
-
font-size:
|
|
69
|
-
|
|
68
|
+
.pin-icon {
|
|
69
|
+
font-size: 24px;
|
|
70
|
+
transform: rotate(30deg);
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
.
|
|
73
|
-
|
|
73
|
+
.modulo-icon-wrapper {
|
|
74
|
+
position: absolute;
|
|
75
|
+
top: 65px;
|
|
76
|
+
/* Center remains at 65px, so bottom is around 102.5px */
|
|
77
|
+
left: 50%;
|
|
78
|
+
transform: translate(-50%, -50%);
|
|
79
|
+
z-index: 10;
|
|
74
80
|
}
|
|
75
81
|
|
|
76
|
-
.
|
|
77
|
-
|
|
82
|
+
.modulo-icon-container {
|
|
83
|
+
width: 75px;
|
|
84
|
+
height: 75px;
|
|
85
|
+
background-color: #fff;
|
|
86
|
+
border-radius: 50%;
|
|
87
|
+
display: flex;
|
|
88
|
+
justify-content: center;
|
|
89
|
+
align-items: center;
|
|
90
|
+
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
|
91
|
+
padding: 10px;
|
|
78
92
|
}
|
|
79
93
|
|
|
80
|
-
.
|
|
81
|
-
|
|
94
|
+
.modulo-icon {
|
|
95
|
+
width: 100%;
|
|
96
|
+
height: 100%;
|
|
97
|
+
object-fit: contain;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.modulo-icon-placeholder {
|
|
101
|
+
width: 40px;
|
|
102
|
+
height: 40px;
|
|
103
|
+
background-color: #eee;
|
|
104
|
+
border-radius: 50%;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.modulo-card-body {
|
|
108
|
+
flex-grow: 1;
|
|
109
|
+
display: flex;
|
|
110
|
+
justify-content: center;
|
|
111
|
+
align-items: center;
|
|
112
|
+
padding: 15px 20px;
|
|
113
|
+
/* Reduced top padding as it doesn't need to clear the overlapping icon anymore */
|
|
114
|
+
text-align: center;
|
|
115
|
+
position: relative;
|
|
82
116
|
}
|
|
83
117
|
|
|
84
118
|
.modulo-descripcion {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
119
|
+
color: #1d3a5f;
|
|
120
|
+
font-size: 1.4rem;
|
|
121
|
+
/* Reduced from 1.6rem */
|
|
122
|
+
font-weight: 700;
|
|
123
|
+
line-height: 1.2;
|
|
124
|
+
margin: 0;
|
|
125
|
+
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
|
88
126
|
}
|
|
89
127
|
|
|
90
|
-
.
|
|
91
|
-
|
|
92
|
-
|
|
128
|
+
.esquina {
|
|
129
|
+
position: absolute;
|
|
130
|
+
bottom: 0;
|
|
131
|
+
right: 0;
|
|
132
|
+
width: 20px;
|
|
133
|
+
height: 20px;
|
|
134
|
+
background: linear-gradient(135deg, transparent 50%, rgba(255, 255, 255, 0.5) 50%);
|
|
135
|
+
pointer-events: none;
|
|
93
136
|
}
|
|
137
|
+
|
|
138
|
+
.cintillo-etiqueta {
|
|
139
|
+
position: absolute;
|
|
140
|
+
bottom: 20px;
|
|
141
|
+
right: -42px;
|
|
142
|
+
width: 170px;
|
|
143
|
+
/* Wider to accommodate longer text */
|
|
144
|
+
padding: 5px 0;
|
|
145
|
+
text-align: center;
|
|
146
|
+
color: white;
|
|
147
|
+
font-weight: 800;
|
|
148
|
+
font-size: 0.75rem;
|
|
149
|
+
/* Further reduced to ensure 'ACTUALIZADO' fits completely */
|
|
150
|
+
letter-spacing: 0.5px;
|
|
151
|
+
transform: rotate(-45deg);
|
|
152
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
|
|
153
|
+
z-index: 5;
|
|
154
|
+
}
|
package/templates/frontend/src/app/Componentes/Nucleo/tarjeta-modulo/tarjeta-modulo.component.html
CHANGED
|
@@ -1,21 +1,30 @@
|
|
|
1
|
-
<div class="modulo-card" (click)="onClick()"
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
<div class="modulo-card" (click)="onClick()">
|
|
2
|
+
<div class="modulo-card-header">
|
|
3
|
+
<span class="modulo-tipo">{{ modulo.Tipo | uppercase }}</span>
|
|
4
|
+
<div class="pin-container" (click)="alternarFavorito($event)" [ngClass]="{ 'pinned': estaEnFavoritos() }">
|
|
5
|
+
<span class="material-icons pin-icon">
|
|
6
|
+
push_pin
|
|
7
|
+
</span>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
@if(modulo.Icono) {
|
|
12
|
+
<div class="modulo-icon-wrapper">
|
|
13
|
+
<div class="modulo-icon-container">
|
|
14
|
+
<img src="{{ modulo.Icono }}" class="modulo-icon" alt="{{ modulo.Descripcion }}" />
|
|
14
15
|
</div>
|
|
15
16
|
</div>
|
|
16
|
-
<p class="modulo-descripcion">{{ modulo.Descripcion }}</p>
|
|
17
|
-
<div class="modulo-info"></div>
|
|
18
|
-
@if(modulo.Tipo === 'Servicio') {
|
|
19
|
-
<div class="esquina"></div>
|
|
20
17
|
}
|
|
18
|
+
|
|
19
|
+
<div class="modulo-card-body" [ngStyle]="{ 'background-color': modulo.Color }">
|
|
20
|
+
<p class="modulo-descripcion">{{ modulo.Descripcion }}</p>
|
|
21
|
+
@if(modulo.Tipo === 'Servicio') {
|
|
22
|
+
<!-- <div class="esquina"></div> -->
|
|
23
|
+
}
|
|
24
|
+
@if(modulo.Etiqueta) {
|
|
25
|
+
<div class="cintillo-etiqueta" [ngStyle]="{ 'background-color': modulo.ColorDeLaEtiqueta || '#4a90e2' }">
|
|
26
|
+
{{ modulo.Etiqueta | uppercase }}
|
|
27
|
+
</div>
|
|
28
|
+
}
|
|
29
|
+
</div>
|
|
21
30
|
</div>
|
|
@@ -43,6 +43,10 @@
|
|
|
43
43
|
border-radius: 50%;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
.ColorBlanco {
|
|
47
|
+
color: white;
|
|
48
|
+
}
|
|
49
|
+
|
|
46
50
|
.botonDeNavegacion:hover {
|
|
47
51
|
background-color: rgba(25, 118, 210, 0.1);
|
|
48
52
|
transform: scale(1.1);
|
|
@@ -93,6 +97,7 @@
|
|
|
93
97
|
font-size: 18px;
|
|
94
98
|
background-color: #002f6b;
|
|
95
99
|
color: white;
|
|
100
|
+
display: flex;
|
|
96
101
|
}
|
|
97
102
|
|
|
98
103
|
.encabezado {
|
|
@@ -156,6 +161,7 @@
|
|
|
156
161
|
}
|
|
157
162
|
|
|
158
163
|
.zona-scrollable {
|
|
164
|
+
margin-top: 3px;
|
|
159
165
|
flex-grow: 1;
|
|
160
166
|
overflow-y: auto;
|
|
161
167
|
display: flex;
|
|
@@ -7,41 +7,62 @@
|
|
|
7
7
|
</div>
|
|
8
8
|
<div class="pie-col derecha">
|
|
9
9
|
@if(TienePermiso) {
|
|
10
|
-
<button class="botonDeNavegacion" matTooltip="Salir" (click)="Salir()">
|
|
10
|
+
<button class="botonDeNavegacion" matTooltip="Salir" title="Salir" (click)="Salir()">
|
|
11
11
|
<mat-icon>logout</mat-icon>
|
|
12
12
|
</button>
|
|
13
|
-
<button class="botonDeNavegacion" [matTooltip]="NombreUsuario || 'Perfil'"
|
|
13
|
+
<button class="botonDeNavegacion" [matTooltip]="NombreUsuario || 'Perfil'" [title]="NombreUsuario || 'Perfil'"
|
|
14
|
+
(click)="irAPerfil()">
|
|
14
15
|
<mat-icon>person</mat-icon>
|
|
15
16
|
</button>
|
|
16
17
|
} @else {
|
|
17
|
-
<button class="botonDeNavegacion" matTooltip="Entrar" (click)="Entrar()">
|
|
18
|
+
<button class="botonDeNavegacion" matTooltip="Entrar" title="Entrar" (click)="Entrar()">
|
|
18
19
|
<mat-icon>login</mat-icon>
|
|
19
20
|
</button>
|
|
20
21
|
}
|
|
21
22
|
</div>
|
|
22
23
|
</div>
|
|
23
24
|
|
|
25
|
+
@if(TienePermiso){
|
|
26
|
+
<div class="titulo">
|
|
27
|
+
<div class="pie-col izquierda"></div>
|
|
28
|
+
<div class="pie-col centro">{{ Titulo }}</div>
|
|
29
|
+
<div class="pie-col derecha">
|
|
30
|
+
<button class="botonDeNavegacion ColorBlanco" matTooltip="Ir atrás" title="Ir atrás" (click)="irAtras()">
|
|
31
|
+
<mat-icon>arrow_back</mat-icon>
|
|
32
|
+
</button>
|
|
33
|
+
<button class="botonDeNavegacion ColorBlanco" matTooltip="Ir al menú del módulo" title="Ir al menú del módulo"
|
|
34
|
+
(click)="irAlMenuDeModulo()">
|
|
35
|
+
<mat-icon>menu</mat-icon>
|
|
36
|
+
</button>
|
|
37
|
+
<!-- <button class="botonDeNavegacion" matTooltip="Ir al móudulo padre" title="Ir al móudulo padre" (click)="irAlModuloPadre()">
|
|
38
|
+
<mat-icon>apps</mat-icon>
|
|
39
|
+
</button> -->
|
|
40
|
+
<button class="botonDeNavegacion ColorBlanco" matTooltip="Ir al inicio" title="Ir al inicio"
|
|
41
|
+
(click)="irAlInicio()">
|
|
42
|
+
<mat-icon>home</mat-icon>
|
|
43
|
+
</button>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
}
|
|
24
47
|
<div class="zona-scrollable">
|
|
25
|
-
@if(TienePermiso){
|
|
26
|
-
<div class="titulo">{{ Titulo }}</div>
|
|
27
|
-
}
|
|
28
48
|
<div [ngClass]="claseDelContenedor">
|
|
29
|
-
@if(TienePermiso) {
|
|
49
|
+
<!-- @if(TienePermiso) {
|
|
30
50
|
<div class="botonesDeNavegacion">
|
|
31
|
-
<button class="botonDeNavegacion" matTooltip="Ir atrás" (click)="irAtras()">
|
|
51
|
+
<button class="botonDeNavegacion" matTooltip="Ir atrás" title="Ir atrás" (click)="irAtras()">
|
|
32
52
|
<mat-icon>arrow_back</mat-icon>
|
|
33
53
|
</button>
|
|
34
|
-
<button class="botonDeNavegacion" matTooltip="Ir al menú del módulo"
|
|
54
|
+
<button class="botonDeNavegacion" matTooltip="Ir al menú del módulo" title="Ir al menú del módulo"
|
|
55
|
+
(click)="irAlMenuDeModulo()">
|
|
35
56
|
<mat-icon>menu</mat-icon>
|
|
36
|
-
</button>
|
|
37
|
-
|
|
57
|
+
</button> -->
|
|
58
|
+
<!-- <button class="botonDeNavegacion" matTooltip="Ir al móudulo padre" title="Ir al móudulo padre" (click)="irAlModuloPadre()">
|
|
38
59
|
<mat-icon>apps</mat-icon>
|
|
39
60
|
</button> -->
|
|
40
|
-
|
|
61
|
+
<!-- <button class="botonDeNavegacion" matTooltip="Ir al inicio" title="Ir al inicio" (click)="irAlInicio()">
|
|
41
62
|
<mat-icon>home</mat-icon>
|
|
42
63
|
</button>
|
|
43
64
|
</div>
|
|
44
|
-
}
|
|
65
|
+
} -->
|
|
45
66
|
<div class="contenido">
|
|
46
67
|
@if(TienePermiso){
|
|
47
68
|
<div class="cabecera2">
|
|
@@ -79,7 +100,8 @@
|
|
|
79
100
|
</div>
|
|
80
101
|
</div>
|
|
81
102
|
<div class="pie-col derecha">
|
|
82
|
-
<button class="botonDeNavegacion" matTooltip="Aplicaciones"
|
|
103
|
+
<button class="botonDeNavegacion" matTooltip="Aplicaciones" title="Aplicaciones"
|
|
104
|
+
[matMenuTriggerFor]="menuAplicaciones">
|
|
83
105
|
<mat-icon>keyboard_arrow_up</mat-icon>
|
|
84
106
|
</button>
|
|
85
107
|
|
|
@@ -97,7 +119,7 @@
|
|
|
97
119
|
</mat-menu>
|
|
98
120
|
|
|
99
121
|
@if(TienePermiso) {
|
|
100
|
-
<button class="botonDeNavegacion" matTooltip="Mensajes" (click)="irAMensajes()">
|
|
122
|
+
<button class="botonDeNavegacion" matTooltip="Mensajes" title="Mensajes" (click)="irAMensajes()">
|
|
101
123
|
@if (Mensajes.length > 0) {
|
|
102
124
|
<mat-icon>mark_email_unread</mat-icon>
|
|
103
125
|
} @else {
|
|
@@ -106,16 +128,16 @@
|
|
|
106
128
|
</button>
|
|
107
129
|
}
|
|
108
130
|
@if(EnlaceDelVideo !== '-') {
|
|
109
|
-
<button class="botonDeNavegacion" matTooltip="Vídeo" (click)="irAVideo()">
|
|
131
|
+
<button class="botonDeNavegacion" matTooltip="Vídeo" title="Vídeo" (click)="irAVideo()">
|
|
110
132
|
<mat-icon>live_tv</mat-icon>
|
|
111
133
|
</button>
|
|
112
134
|
}
|
|
113
135
|
@if(EnlaceDelManual !== '-') {
|
|
114
|
-
<button class="botonDeNavegacion" matTooltip="Ayuda" (click)="irAAyuda()">
|
|
136
|
+
<button class="botonDeNavegacion" matTooltip="Ayuda" title="Ayuda" (click)="irAAyuda()">
|
|
115
137
|
<mat-icon>help</mat-icon>
|
|
116
138
|
</button>
|
|
117
139
|
}
|
|
118
|
-
<button class="botonDeNavegacion" matTooltip="Reporte" (click)="irASoporte()">
|
|
140
|
+
<button class="botonDeNavegacion" matTooltip="Reporte" title="Reporte" (click)="irASoporte()">
|
|
119
141
|
<mat-icon>support_agent</mat-icon>
|
|
120
142
|
</button>
|
|
121
143
|
</div>
|
package/templates/frontend/src/app/Paginas/contenedor-principal/contenedor-principal.component.css
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
width: 100%;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
/*
|
|
10
|
+
/* Pantallas grandes: se adaptan dinámicamente, máximo 300px, caben tantas como sea posible */
|
|
11
11
|
.contenido>div[cdkDrag] {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
flex: 1 1 300px;
|
|
13
|
+
max-width: 300px;
|
|
14
14
|
box-sizing: border-box;
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -43,12 +43,16 @@
|
|
|
43
43
|
/* Responsividad: 2 columnas en tablets, 1 en móviles */
|
|
44
44
|
@media (max-width: 1200px) {
|
|
45
45
|
.contenido>div[cdkDrag] {
|
|
46
|
+
flex: none;
|
|
47
|
+
max-width: none;
|
|
46
48
|
width: calc(50% - 8px);
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
@media (max-width: 600px) {
|
|
51
53
|
.contenido>div[cdkDrag] {
|
|
54
|
+
flex: none;
|
|
55
|
+
max-width: none;
|
|
52
56
|
width: 100%;
|
|
53
57
|
}
|
|
54
58
|
}
|
package/templates/frontend/src/app/Paginas/contenedor-principal/contenedor-principal.component.ts
CHANGED
|
@@ -7,6 +7,8 @@ import { TarjetaPersonalizadaComponent } from "../../Componentes/Nucleo/tarjeta-
|
|
|
7
7
|
import { HttpClient } from "@angular/common/http";
|
|
8
8
|
import { DatosGlobalesService } from '../../datos-globales.service';
|
|
9
9
|
import { DragDropModule, CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
|
10
|
+
import { forkJoin, of } from 'rxjs';
|
|
11
|
+
import { catchError } from 'rxjs/operators';
|
|
10
12
|
|
|
11
13
|
interface BaseTarjetaConfig {
|
|
12
14
|
type: 'single' | 'multiple' | 'report' | 'custom';
|
|
@@ -195,31 +197,63 @@ export class ContenedorPrincipalComponent implements OnInit {
|
|
|
195
197
|
}
|
|
196
198
|
];
|
|
197
199
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
200
|
+
forkJoin({
|
|
201
|
+
permisoExtra: this.http.get(`${this.datosGlobalesService.ObtenerURL()}Personas/PermisoExtra`).pipe(
|
|
202
|
+
catchError(error => {
|
|
203
|
+
console.error('Problemas al intentar obtener los datos de PermisoExtra: ', error);
|
|
204
|
+
return of({ body: null });
|
|
205
|
+
})
|
|
206
|
+
),
|
|
207
|
+
// configuracion: this.http.get(`${this.datosGlobalesService.ObtenerURL()}ConfiguracionDeTarjetas/obtener`).pipe(
|
|
208
|
+
// catchError(error => {
|
|
209
|
+
// console.error('Error al obtener configuración de tarjetas:', error);
|
|
210
|
+
// return of({ body: [] });
|
|
211
|
+
// })
|
|
212
|
+
// )
|
|
213
|
+
}).subscribe({
|
|
214
|
+
next: (results: any) => {
|
|
215
|
+
// // 2. Handle extra permissions
|
|
216
|
+
// if (results.permisoExtra && results.permisoExtra.body) {
|
|
217
|
+
// const personasCard: TarjetaMultipleConfig = {
|
|
218
|
+
// type: 'multiple',
|
|
219
|
+
// position: 25,
|
|
220
|
+
// titulo: 'Personas',
|
|
221
|
+
// descripcion: 'Módulo para el mantenimiento de los datos relacionados con personas',
|
|
222
|
+
// rutas: [
|
|
223
|
+
// { nombre: 'Personas', ruta: 'tablaPersonas' },
|
|
224
|
+
// { nombre: 'Correos', ruta: 'tablaCorreosPersonas' },
|
|
225
|
+
// { nombre: 'Cuentas bancarias', ruta: 'tablaCuentasPersonas' },
|
|
226
|
+
// { nombre: 'Teléfonos', ruta: 'tablaTelefonosPersonas' },
|
|
227
|
+
// { nombre: 'Ubicación', ruta: 'tablaUbicacionPersona' },
|
|
228
|
+
// ]
|
|
229
|
+
// };
|
|
230
|
+
// if (!baseTarjetas.find(t => t.titulo === 'Personas')) {
|
|
231
|
+
// baseTarjetas.push(personasCard);
|
|
232
|
+
// }
|
|
233
|
+
// }
|
|
234
|
+
|
|
235
|
+
// 3. Apply saved configurations
|
|
236
|
+
if (results.configuracion && results.configuracion.body && results.configuracion.body.length > 0) {
|
|
237
|
+
const savedConfigs = results.configuracion.body;
|
|
238
|
+
baseTarjetas.forEach(tarjeta => {
|
|
239
|
+
const config = savedConfigs.find((c: any) => c.Titulo === tarjeta.titulo);
|
|
240
|
+
if (config) {
|
|
241
|
+
tarjeta.position = config.Posicion;
|
|
242
|
+
if (config.ColorDeBorde) {
|
|
243
|
+
tarjeta.ColorDeBorde = config.ColorDeBorde;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
this.tarjetas = baseTarjetas.sort((a, b) => a.position - b.position);
|
|
249
|
+
},
|
|
250
|
+
error: (error) => {
|
|
251
|
+
console.error('Error crítico en el proceso de inicialización:', error);
|
|
252
|
+
this.tarjetas = baseTarjetas.sort((a, b) => a.position - b.position);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
223
257
|
// 3. Load user-specific positions from backend
|
|
224
258
|
this.http.get(`${this.datosGlobalesService.ObtenerURL()}ConfiguracionDeTarjetas/obtener`).subscribe({
|
|
225
259
|
next: (res: any) => {
|
package/templates/frontend/src/app/Paginas/gestion-de-reportes/gestion-de-reportes.component.css
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
width: 100%;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
/*
|
|
10
|
+
/* Pantallas grandes: se adaptan dinámicamente, máximo 300px, caben tantas como sea posible */
|
|
11
11
|
.contenido>* {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
flex: 1 1 300px;
|
|
13
|
+
max-width: 300px;
|
|
14
14
|
box-sizing: border-box;
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -43,12 +43,16 @@
|
|
|
43
43
|
/* Responsividad: 2 columnas en tablets, 1 en móviles */
|
|
44
44
|
@media (max-width: 1200px) {
|
|
45
45
|
.contenido>* {
|
|
46
|
+
flex: none;
|
|
47
|
+
max-width: none;
|
|
46
48
|
width: calc(50% - 8px);
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
@media (max-width: 600px) {
|
|
51
53
|
.contenido>* {
|
|
54
|
+
flex: none;
|
|
55
|
+
max-width: none;
|
|
52
56
|
width: 100%;
|
|
53
57
|
}
|
|
54
58
|
}
|
|
@@ -4,10 +4,53 @@
|
|
|
4
4
|
left: 0;
|
|
5
5
|
width: 100%;
|
|
6
6
|
height: 100%;
|
|
7
|
-
background: rgba(255,255,255,0.8);
|
|
7
|
+
background: rgba(255, 255, 255, 0.8);
|
|
8
8
|
display: flex;
|
|
9
9
|
flex-direction: column;
|
|
10
10
|
justify-content: center;
|
|
11
11
|
align-items: center;
|
|
12
12
|
z-index: 2000;
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
.contenedor {
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
height: calc(100vh - 64px);
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
padding: 0;
|
|
21
|
+
box-sizing: border-box;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.grid-graficos {
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
flex: 1;
|
|
28
|
+
justify-content: flex-start;
|
|
29
|
+
align-items: center;
|
|
30
|
+
padding: 1rem 2rem 2rem 2rem;
|
|
31
|
+
box-sizing: border-box;
|
|
32
|
+
width: 100%;
|
|
33
|
+
gap: 3rem;
|
|
34
|
+
min-height: 0;
|
|
35
|
+
overflow-y: auto;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.grid-graficos app-graficos {
|
|
39
|
+
width: 100%;
|
|
40
|
+
max-width: 800px;
|
|
41
|
+
height: 400px;
|
|
42
|
+
flex-shrink: 0;
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@media (max-width: 768px) {
|
|
48
|
+
.contenedor {
|
|
49
|
+
height: 100vh;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.grid-graficos {
|
|
53
|
+
padding: 1rem;
|
|
54
|
+
gap: 2rem;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<div>
|
|
1
|
+
<div class="contenedor">
|
|
2
2
|
<!-- <h3>Gráficos sobre módulos del SIGU</h3> -->
|
|
3
3
|
@if(cargando) {
|
|
4
4
|
<div class="cargando-overlay">
|
|
@@ -6,8 +6,10 @@
|
|
|
6
6
|
<p>Procesando, por favor espere...</p>
|
|
7
7
|
</div>
|
|
8
8
|
} @else {
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
[
|
|
9
|
+
<div class="grid-graficos">
|
|
10
|
+
<app-graficos [TipoDeGrafico]="'Pie'" [Datos]="datosParaElGraficoPie" [Titulo]="'Módulos desarrollados en SIGU'" />
|
|
11
|
+
<app-graficos [TipoDeGrafico]="'Barras'" [Datos]="datosParaElGraficoBarras"
|
|
12
|
+
[Titulo]="'Total de nacimientos por mes'" />
|
|
13
|
+
</div>
|
|
12
14
|
}
|
|
13
15
|
</div>
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
|
|
19
19
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
20
20
|
<script src="https://accounts.google.com/gsi/client" async defer></script>
|
|
21
|
+
<meta description="Universidad Técnica Nacional - SIGU">
|
|
21
22
|
</head>
|
|
22
23
|
|
|
23
24
|
<body>
|