utn-cli 2.0.53 → 2.0.54
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/rutas/misc.js +17 -0
- package/templates/backend/server.js +4 -2
- package/templates/backend/servicios/Nucleo/Miscelaneas.js +54 -9
- package/templates/frontend/src/app/Componentes/Nucleo/gestion-actividad/gestion-actividad.component.css +193 -0
- package/templates/frontend/src/app/Componentes/Nucleo/gestion-actividad/gestion-actividad.component.html +50 -0
- package/templates/frontend/src/app/Componentes/Nucleo/gestion-actividad/gestion-actividad.component.ts +61 -0
- package/templates/frontend/src/app/Componentes/Nucleo/tabla/paginador-personalizado.ts +3 -0
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.css +52 -6
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.html +28 -14
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.ts +8 -1
- package/templates/frontend/src/app/app.config.ts +1 -4
- package/templates/frontend/src/app/app.routes.ts +2 -0
package/package.json
CHANGED
|
@@ -4,6 +4,23 @@ const Router = express.Router();
|
|
|
4
4
|
const Miscelaneo = require('./../servicios/Nucleo/Miscelaneas.js');
|
|
5
5
|
const ManejadorDeErrores = require('../servicios/Nucleo/ManejadorDeErrores.js');
|
|
6
6
|
|
|
7
|
+
Router.get('/ListarActividades', async (solicitud, respuesta, next) => {
|
|
8
|
+
try {
|
|
9
|
+
if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
|
|
10
|
+
try {
|
|
11
|
+
return respuesta.json({ body: await Miscelaneo.ListarActividades(solicitud.headers.authorization), error: undefined });
|
|
12
|
+
} catch (error) {
|
|
13
|
+
const MensajeDeError = 'No fue posible listar las actividades';
|
|
14
|
+
console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, `Dirección IP: ${solicitud.ip}`));
|
|
15
|
+
return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return respuesta.status(401).json({ body: undefined, error: ManejadorDeErrores.mensajeDeError401() });
|
|
19
|
+
} catch (error) {
|
|
20
|
+
next(error);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
7
24
|
Router.get('/UsuariosActuales', async (solicitud, respuesta, next) => {
|
|
8
25
|
try {
|
|
9
26
|
if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
|
|
@@ -30,7 +30,7 @@ app.use(async (solicitud, respuesta, next) => {
|
|
|
30
30
|
cookies: solicitud.cookies,
|
|
31
31
|
signedCookies: solicitud.signedCookies,
|
|
32
32
|
userAgent: solicitud.get('User-Agent'),
|
|
33
|
-
authUser: solicitud.
|
|
33
|
+
authUser: await Miscelaneo.obtenerDatosDelUsuario(solicitud.headers.authorization) ?? null,
|
|
34
34
|
};
|
|
35
35
|
try {
|
|
36
36
|
const { ejecutarConsultaSIGU } = require('./servicios/Nucleo/db.js');
|
|
@@ -61,7 +61,9 @@ asignarRutasAExpress(app);
|
|
|
61
61
|
|
|
62
62
|
app.use((error, solicitud, respuesta, next) => {
|
|
63
63
|
const { envioDeCorreo } = require('./servicios/Nucleo/EnvioDeCorreos.js');
|
|
64
|
-
|
|
64
|
+
const route = solicitud.originalUrl;
|
|
65
|
+
const message = `<b>Ruta consultada:</b> ${route}<BR /><BR />` + error.stack;
|
|
66
|
+
envioDeCorreo(process.env.DESTINATARIODEINFORMESDEERROR, 'Informe de error desde: ' + process.env.NOMBRECANONICODELMODULO, message);
|
|
65
67
|
console.error(error.stack);
|
|
66
68
|
respuesta.status(500).send('Error interno del servidor, el detalle del mismo fue enviado a ' + process.env.DESTINATARIODEINFORMESDEERROR);
|
|
67
69
|
});
|
|
@@ -40,6 +40,51 @@ class Miscelaneo {
|
|
|
40
40
|
this.EnlaceDeAcceso = undefined;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
+
async ListarActividades(Datos) {
|
|
44
|
+
try {
|
|
45
|
+
const decoded = await this.obtenerDatosDelUsuario(Datos);
|
|
46
|
+
const RUTAS_EXCLUIDAS = [
|
|
47
|
+
'/misc',
|
|
48
|
+
'/Actividad',
|
|
49
|
+
'/misc/ListarActividades',
|
|
50
|
+
'/misc/obtenerNotificaciones',
|
|
51
|
+
'/misc/configurarFrontend',
|
|
52
|
+
'/ConsentimientoInformado/ConsentimientoInformado',
|
|
53
|
+
'/misc/obtenerMensajesModulares',
|
|
54
|
+
'/misc/obtenerDetalleDelModulo',
|
|
55
|
+
'/misc/validarToken',
|
|
56
|
+
'/misc/UsuariosActuales',
|
|
57
|
+
'/misc/obtenerEnlaceDePortal',
|
|
58
|
+
'/Personas/PermisoExtra'
|
|
59
|
+
];
|
|
60
|
+
const datos = await ejecutarConsultaSIGU(`
|
|
61
|
+
SELECT
|
|
62
|
+
Consecutivo,
|
|
63
|
+
LastUpdate AS Fecha,
|
|
64
|
+
JSON_VALUE(Solicitud, '$.ip') AS IP,
|
|
65
|
+
JSON_VALUE(Solicitud, '$.userAgent') AS Navegador,
|
|
66
|
+
JSON_VALUE(Solicitud, '$.method') AS Metodo,
|
|
67
|
+
JSON_VALUE(Solicitud, '$.originalUrl') AS URL,
|
|
68
|
+
IFNULL(JSON_VALUE(Solicitud, '$.country'), 'Costa Rica') AS Pais,
|
|
69
|
+
CASE
|
|
70
|
+
WHEN JSON_VALUE(Solicitud, '$.userAgent') LIKE '%Mobile%' THEN 'Móvil'
|
|
71
|
+
WHEN JSON_VALUE(Solicitud, '$.userAgent') LIKE '%Android%' AND JSON_VALUE(Solicitud, '$.userAgent') NOT LIKE '%Mobile%' THEN 'Tablet'
|
|
72
|
+
WHEN JSON_VALUE(Solicitud, '$.userAgent') LIKE '%iPad%' THEN 'Tablet'
|
|
73
|
+
ELSE 'PC'
|
|
74
|
+
END AS Dispositivo
|
|
75
|
+
FROM SIGU.SIGU_BitacoraDeSolicitudes
|
|
76
|
+
WHERE JSON_VALUE(Solicitud, '$.authUser.uid') = ?
|
|
77
|
+
AND JSON_VALUE(Solicitud, '$.originalUrl') NOT IN (?)
|
|
78
|
+
ORDER BY Consecutivo DESC
|
|
79
|
+
LIMIT 100
|
|
80
|
+
`, [decoded.uid, RUTAS_EXCLUIDAS]);
|
|
81
|
+
return datos;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error('Error al listar actividad:', error);
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
43
88
|
async UsuariosActuales() {
|
|
44
89
|
const ConexionSigu = await crearObjetoConexionSIGU();
|
|
45
90
|
const Actuales = await ConexionSigu.query("SELECT COUNT(DISTINCT `Identificador`) AS `Total` FROM `SIGU`.`SIGU_Sesiones` WHERE `LastUpdate` >= NOW() - INTERVAL 2 HOUR");
|
|
@@ -494,15 +539,15 @@ class Miscelaneo {
|
|
|
494
539
|
}
|
|
495
540
|
|
|
496
541
|
async generarLastUser(Solicitud) {
|
|
497
|
-
|
|
498
|
-
try {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
} catch (error) {
|
|
504
|
-
|
|
505
|
-
}
|
|
542
|
+
const Resultado = await this.obtenerDatosDelUsuario(Solicitud.headers.authorization);
|
|
543
|
+
// try {
|
|
544
|
+
// Resultado = await this.obtenerDatosDelUsuario(Solicitud.headers.authorization);
|
|
545
|
+
// if (!Resultado) {
|
|
546
|
+
// throw new ManejadorDeErrores(ManejadorDeErrores.mensajeDeErrorVerificacionDeToken(), ManejadorDeErrores.obtenerNumeroDeLinea());
|
|
547
|
+
// }
|
|
548
|
+
// } catch (error) {
|
|
549
|
+
// console.log(error);
|
|
550
|
+
// }
|
|
506
551
|
let LastUser = '';
|
|
507
552
|
if (Resultado) {
|
|
508
553
|
LastUser = Resultado.uid;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
.contenedor-actividad {
|
|
2
|
+
background-color: transparent;
|
|
3
|
+
margin: 0;
|
|
4
|
+
padding: 10px;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.header-actividad {
|
|
8
|
+
background-color: white;
|
|
9
|
+
padding: 20px 24px;
|
|
10
|
+
border-radius: 12px;
|
|
11
|
+
margin-bottom: 20px;
|
|
12
|
+
border: 1px solid #e0e6ed;
|
|
13
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
14
|
+
text-align: left;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.header-actividad h2 {
|
|
18
|
+
margin: 0;
|
|
19
|
+
color: #002f6b;
|
|
20
|
+
font-size: 1.5rem;
|
|
21
|
+
font-weight: 700;
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
gap: 12px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.header-actividad h2 mat-icon {
|
|
28
|
+
font-size: 28px;
|
|
29
|
+
width: 28px;
|
|
30
|
+
height: 28px;
|
|
31
|
+
color: #0b4fce;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.header-actividad p {
|
|
35
|
+
margin: 8px 0 0 0;
|
|
36
|
+
color: #5f6368;
|
|
37
|
+
font-size: 0.95rem;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.mensaje-informativo {
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
gap: 12px;
|
|
44
|
+
background-color: #e3f2fd;
|
|
45
|
+
border-left: 4px solid #1976d2;
|
|
46
|
+
padding: 12px 16px;
|
|
47
|
+
margin-top: 20px;
|
|
48
|
+
border-radius: 4px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.mensaje-informativo mat-icon {
|
|
52
|
+
color: #1976d2;
|
|
53
|
+
font-size: 24px;
|
|
54
|
+
width: 24px;
|
|
55
|
+
height: 24px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.mensaje-informativo p {
|
|
59
|
+
margin: 0 !important;
|
|
60
|
+
font-size: 13.5px !important;
|
|
61
|
+
color: #0d47a1 !important;
|
|
62
|
+
line-height: 1.4;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.mensaje-informativo strong {
|
|
66
|
+
color: #d32f2f;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.lista-actividad {
|
|
70
|
+
display: flex;
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
gap: 12px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.actividad-item {
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
padding: 16px;
|
|
79
|
+
background-color: white;
|
|
80
|
+
border: 1px solid #e0e6ed;
|
|
81
|
+
border-radius: 12px;
|
|
82
|
+
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
83
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
84
|
+
text-align: left;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.actividad-item:hover {
|
|
88
|
+
transform: translateY(-2px);
|
|
89
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
90
|
+
border-color: #0b4fce;
|
|
91
|
+
background-color: #f0f7ff;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.item-icono {
|
|
95
|
+
margin-right: 12px;
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
width: 40px;
|
|
100
|
+
height: 40px;
|
|
101
|
+
border-radius: 50%;
|
|
102
|
+
background-color: #f1f3f4;
|
|
103
|
+
flex-shrink: 0;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.item-icono mat-icon {
|
|
107
|
+
font-size: 20px;
|
|
108
|
+
width: 20px;
|
|
109
|
+
height: 20px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Colores por método */
|
|
113
|
+
.metodo-get { color: #0069B4; background-color: #e3f2fd; }
|
|
114
|
+
.metodo-post { color: #518a5f; background-color: #e8f5e9; }
|
|
115
|
+
.metodo-put { color: #FFA757; background-color: #fff3e0; }
|
|
116
|
+
.metodo-delete { color: #F82617; background-color: #ffebee; }
|
|
117
|
+
.metodo-default { color: #7d7d7d; background-color: #f5f5f5; }
|
|
118
|
+
|
|
119
|
+
.item-contenido {
|
|
120
|
+
flex: 1;
|
|
121
|
+
display: flex;
|
|
122
|
+
flex-direction: column;
|
|
123
|
+
min-width: 0; /* Evita que el flex desborde */
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.item-titulo {
|
|
127
|
+
font-size: 14px;
|
|
128
|
+
color: #002f6b;
|
|
129
|
+
font-weight: 600;
|
|
130
|
+
word-break: break-all;
|
|
131
|
+
margin-bottom: 2px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.item-detalles {
|
|
135
|
+
display: flex;
|
|
136
|
+
flex-wrap: wrap;
|
|
137
|
+
gap: 8px;
|
|
138
|
+
font-size: 12px;
|
|
139
|
+
color: #5f6368;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.item-detalles span {
|
|
143
|
+
display: flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
gap: 3px;
|
|
146
|
+
white-space: nowrap;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.item-detalles mat-icon {
|
|
150
|
+
font-size: 14px;
|
|
151
|
+
width: 14px;
|
|
152
|
+
height: 14px;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.detalle-dispositivo mat-icon { color: #673ab7; }
|
|
156
|
+
.detalle-browser mat-icon { color: #5f6368; }
|
|
157
|
+
.detalle-ip mat-icon { color: #0069B4; }
|
|
158
|
+
.detalle-pais mat-icon { color: #F87600; }
|
|
159
|
+
|
|
160
|
+
.item-fecha {
|
|
161
|
+
font-size: 11px;
|
|
162
|
+
color: #9aa0a6;
|
|
163
|
+
white-space: nowrap;
|
|
164
|
+
margin-left: 12px;
|
|
165
|
+
display: flex;
|
|
166
|
+
flex-direction: column;
|
|
167
|
+
align-items: flex-end;
|
|
168
|
+
font-family: 'Roboto Mono', monospace;
|
|
169
|
+
flex-shrink: 0;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
mat-progress-bar {
|
|
173
|
+
height: 4px;
|
|
174
|
+
border-radius: 2px;
|
|
175
|
+
margin-bottom: 10px;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@media (max-width: 600px) {
|
|
179
|
+
.actividad-item {
|
|
180
|
+
flex-direction: column;
|
|
181
|
+
align-items: flex-start;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.item-icono {
|
|
185
|
+
margin-bottom: 12px;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.item-fecha {
|
|
189
|
+
margin-left: 0;
|
|
190
|
+
margin-top: 12px;
|
|
191
|
+
align-items: flex-start;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<div class="contenedor-actividad">
|
|
2
|
+
<div class="header-actividad">
|
|
3
|
+
<h2><mat-icon>history</mat-icon> Actividad reciente de la cuenta</h2>
|
|
4
|
+
<p>Historial de acciones realizadas en el sistema</p>
|
|
5
|
+
|
|
6
|
+
<div class="mensaje-informativo">
|
|
7
|
+
<mat-icon>info</mat-icon>
|
|
8
|
+
<p>Si tiene dudas sobre la información que ve en pantalla, por favor comparta una captura de pantalla al correo <strong>soporte@utn.ac.cr</strong>.</p>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
@if(cargando){
|
|
13
|
+
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
<div class="lista-actividad">
|
|
17
|
+
@if(actividad.length === 0 && !cargando) {
|
|
18
|
+
<p class="sin-datos">No hay actividad reciente.</p>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@for (item of actividad; track item.Consecutivo) {
|
|
22
|
+
<div class="actividad-item">
|
|
23
|
+
<div class="item-icono" [ngClass]="{
|
|
24
|
+
'metodo-get': item.Metodo === 'GET',
|
|
25
|
+
'metodo-post': item.Metodo === 'POST',
|
|
26
|
+
'metodo-put': item.Metodo === 'PUT',
|
|
27
|
+
'metodo-delete': item.Metodo === 'DELETE'
|
|
28
|
+
}">
|
|
29
|
+
<mat-icon [matTooltip]="item.Metodo">{{ getIcon(item.Metodo) }}</mat-icon>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="item-contenido">
|
|
32
|
+
<div class="item-titulo">{{ item.URL }}</div>
|
|
33
|
+
<div class="item-detalles">
|
|
34
|
+
<span class="detalle-dispositivo">
|
|
35
|
+
<mat-icon>{{ item.Dispositivo === 'Móvil' ? 'smartphone' : (item.Dispositivo === 'Tablet' ? 'tablet' : 'laptop') }}</mat-icon>
|
|
36
|
+
{{ item.Dispositivo }}
|
|
37
|
+
</span>
|
|
38
|
+
<span class="detalle-browser"><mat-icon>public</mat-icon> {{ item.Navegador }}</span>
|
|
39
|
+
<span class="detalle-ip"><mat-icon>lan</mat-icon> {{ item.IP }}</span>
|
|
40
|
+
<span class="detalle-pais"><mat-icon>location_on</mat-icon> {{ item.Pais }}</span>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="item-fecha">
|
|
44
|
+
<span>{{ item.Fecha | date: 'dd/MM/yyyy' }}</span>
|
|
45
|
+
<strong>{{ item.Fecha | date: 'HH:mm:ss' }}</strong>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
}
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Component, OnInit } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { HttpClient } from '@angular/common/http';
|
|
4
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
5
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
6
|
+
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
7
|
+
import { DatosGlobalesService } from '../../../datos-globales.service';
|
|
8
|
+
|
|
9
|
+
@Component({
|
|
10
|
+
selector: 'app-gestion-actividad',
|
|
11
|
+
standalone: true,
|
|
12
|
+
imports: [CommonModule, MatIconModule, MatTooltipModule, MatProgressBarModule],
|
|
13
|
+
templateUrl: './gestion-actividad.component.html',
|
|
14
|
+
styleUrls: ['./gestion-actividad.component.css']
|
|
15
|
+
})
|
|
16
|
+
export class GestionActividadComponent implements OnInit {
|
|
17
|
+
public actividad: any[] = [];
|
|
18
|
+
public cargando = false;
|
|
19
|
+
|
|
20
|
+
constructor(private http: HttpClient, private datosGlobalesService: DatosGlobalesService) { }
|
|
21
|
+
|
|
22
|
+
ngOnInit(): void {
|
|
23
|
+
this.obtenerActividad();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
obtenerActividad(): void {
|
|
27
|
+
this.http.get(`${this.datosGlobalesService.ObtenerURL()}misc/ListarActividades`).subscribe({
|
|
28
|
+
next: (datos: any) => {
|
|
29
|
+
this.actividad = datos.body;
|
|
30
|
+
},
|
|
31
|
+
error: (error) => {
|
|
32
|
+
console.error('Error al obtener actividad:', error);
|
|
33
|
+
this.cargando = false;
|
|
34
|
+
},
|
|
35
|
+
complete: () => {
|
|
36
|
+
this.cargando = false;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
// this.cargando = true;
|
|
40
|
+
// this.http.get<any[]>(`${this.datosGlobalesService.ObtenerURL()}Actividad`).subscribe({
|
|
41
|
+
// next: (datos) => {
|
|
42
|
+
// this.actividad = datos;
|
|
43
|
+
// this.cargando = false;
|
|
44
|
+
// },
|
|
45
|
+
// error: (error) => {
|
|
46
|
+
// console.error('Error al obtener actividad:', error);
|
|
47
|
+
// this.cargando = false;
|
|
48
|
+
// }
|
|
49
|
+
// });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getIcon(metodo: string): string {
|
|
53
|
+
switch (metodo) {
|
|
54
|
+
case 'GET': return 'search';
|
|
55
|
+
case 'POST': return 'add_circle';
|
|
56
|
+
case 'PUT': return 'edit';
|
|
57
|
+
case 'DELETE': return 'delete';
|
|
58
|
+
default: return 'help_outline';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
1
2
|
import { MatPaginatorIntl } from '@angular/material/paginator';
|
|
3
|
+
|
|
4
|
+
@Injectable()
|
|
2
5
|
export class PaginadorPersonalizado extends MatPaginatorIntl {
|
|
3
6
|
override itemsPerPageLabel = 'Elementos por página:';
|
|
4
7
|
override nextPageLabel = 'Siguiente página';
|
|
@@ -38,6 +38,15 @@
|
|
|
38
38
|
border: none;
|
|
39
39
|
background: none;
|
|
40
40
|
cursor: pointer;
|
|
41
|
+
transition: all 0.2s ease;
|
|
42
|
+
padding: 4px;
|
|
43
|
+
border-radius: 50%;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.botonDeNavegacion:hover {
|
|
47
|
+
background-color: rgba(25, 118, 210, 0.1);
|
|
48
|
+
transform: scale(1.1);
|
|
49
|
+
color: #0b4fce;
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
/* Contenedor */
|
|
@@ -107,27 +116,24 @@
|
|
|
107
116
|
|
|
108
117
|
.pie-col {
|
|
109
118
|
display: flex;
|
|
110
|
-
gap:
|
|
119
|
+
gap: 5px;
|
|
111
120
|
align-items: center;
|
|
112
121
|
flex: 1;
|
|
113
|
-
/* Cada columna ocupará el mismo espacio */
|
|
114
122
|
overflow: hidden;
|
|
115
|
-
/* Evita que el contenido desborde el tercio asignado */
|
|
116
123
|
}
|
|
117
124
|
|
|
118
125
|
.pie-col.izquierda {
|
|
119
126
|
justify-content: flex-start;
|
|
120
|
-
direction: ltr;
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
.pie-col.centro {
|
|
124
130
|
justify-content: center;
|
|
131
|
+
flex: 0 1 auto;
|
|
132
|
+
min-width: 0;
|
|
125
133
|
}
|
|
126
134
|
|
|
127
135
|
.pie-col.derecha {
|
|
128
136
|
justify-content: flex-end;
|
|
129
|
-
flex-direction: row-reverse;
|
|
130
|
-
direction: rtl;
|
|
131
137
|
}
|
|
132
138
|
|
|
133
139
|
/* Página */
|
|
@@ -225,3 +231,43 @@
|
|
|
225
231
|
opacity: 1;
|
|
226
232
|
}
|
|
227
233
|
}
|
|
234
|
+
|
|
235
|
+
/* Estilos para el mat-menu de aplicaciones */
|
|
236
|
+
::ng-deep .mat-mdc-menu-panel {
|
|
237
|
+
border-radius: 12px !important;
|
|
238
|
+
border: 1px solid rgba(0, 47, 107, 0.1) !important;
|
|
239
|
+
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15) !important;
|
|
240
|
+
margin-top: 8px !important;
|
|
241
|
+
background-color: white !important;
|
|
242
|
+
min-width: 200px !important;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
::ng-deep .mat-mdc-menu-item {
|
|
246
|
+
height: 48px !important;
|
|
247
|
+
padding: 0 20px !important;
|
|
248
|
+
transition: background-color 0.2s ease !important;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
::ng-deep .mat-mdc-menu-item:hover {
|
|
252
|
+
background-color: #f0f7ff !important;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
::ng-deep .mat-mdc-menu-item .mat-icon {
|
|
256
|
+
color: #002f6b !important;
|
|
257
|
+
margin-right: 12px !important;
|
|
258
|
+
font-size: 22px !important;
|
|
259
|
+
width: 22px !important;
|
|
260
|
+
height: 22px !important;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
::ng-deep .mat-mdc-menu-item span {
|
|
264
|
+
font-size: 14px !important;
|
|
265
|
+
font-weight: 500 !important;
|
|
266
|
+
color: #444 !important;
|
|
267
|
+
margin-left: 0 !important;
|
|
268
|
+
/* Material sometimes adds weird margins */
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
::ng-deep .mat-mdc-menu-item:hover span {
|
|
272
|
+
color: #0b4fce !important;
|
|
273
|
+
}
|
|
@@ -7,14 +7,14 @@
|
|
|
7
7
|
</div>
|
|
8
8
|
<div class="pie-col derecha">
|
|
9
9
|
@if(TienePermiso) {
|
|
10
|
-
<button class="botonDeNavegacion" matTooltip="Salir"
|
|
10
|
+
<button class="botonDeNavegacion" matTooltip="Salir" (click)="Salir()">
|
|
11
11
|
<mat-icon>logout</mat-icon>
|
|
12
12
|
</button>
|
|
13
|
-
<button class="botonDeNavegacion" matTooltip="Perfil"
|
|
13
|
+
<button class="botonDeNavegacion" matTooltip="Perfil" (click)="irAPerfil()">
|
|
14
14
|
<mat-icon>person</mat-icon>
|
|
15
15
|
</button>
|
|
16
16
|
} @else {
|
|
17
|
-
<button class="botonDeNavegacion" matTooltip="Entrar"
|
|
17
|
+
<button class="botonDeNavegacion" matTooltip="Entrar" (click)="Entrar()">
|
|
18
18
|
<mat-icon>login</mat-icon>
|
|
19
19
|
</button>
|
|
20
20
|
}
|
|
@@ -28,16 +28,16 @@
|
|
|
28
28
|
<div [ngClass]="claseDelContenedor">
|
|
29
29
|
@if(TienePermiso) {
|
|
30
30
|
<div class="botonesDeNavegacion">
|
|
31
|
-
<button class="botonDeNavegacion" matTooltip="Ir atrás"
|
|
31
|
+
<button class="botonDeNavegacion" matTooltip="Ir atrás" (click)="irAtras()">
|
|
32
32
|
<mat-icon>arrow_back</mat-icon>
|
|
33
33
|
</button>
|
|
34
|
-
<button class="botonDeNavegacion" matTooltip="Ir al menú del módulo"
|
|
34
|
+
<button class="botonDeNavegacion" matTooltip="Ir al menú del módulo" (click)="irAlMenuDeModulo()">
|
|
35
35
|
<mat-icon>menu</mat-icon>
|
|
36
36
|
</button>
|
|
37
|
-
<!-- <button class="botonDeNavegacion" matTooltip="Ir al móudulo padre"
|
|
37
|
+
<!-- <button class="botonDeNavegacion" matTooltip="Ir al móudulo padre" (click)="irAlModuloPadre()">
|
|
38
38
|
<mat-icon>apps</mat-icon>
|
|
39
39
|
</button> -->
|
|
40
|
-
<button class="botonDeNavegacion" matTooltip="Ir al inicio"
|
|
40
|
+
<button class="botonDeNavegacion" matTooltip="Ir al inicio" (click)="irAlInicio()">
|
|
41
41
|
<mat-icon>home</mat-icon>
|
|
42
42
|
</button>
|
|
43
43
|
</div>
|
|
@@ -79,8 +79,25 @@
|
|
|
79
79
|
</div>
|
|
80
80
|
</div>
|
|
81
81
|
<div class="pie-col derecha">
|
|
82
|
+
<button class="botonDeNavegacion" matTooltip="Aplicaciones" [matMenuTriggerFor]="menuAplicaciones">
|
|
83
|
+
<mat-icon>keyboard_arrow_up</mat-icon>
|
|
84
|
+
</button>
|
|
85
|
+
|
|
86
|
+
<mat-menu #menuAplicaciones="matMenu">
|
|
87
|
+
<button mat-menu-item (click)="irASugerencias()">
|
|
88
|
+
<mat-icon>lightbulb</mat-icon>
|
|
89
|
+
<span>Sugerencias</span>
|
|
90
|
+
</button>
|
|
91
|
+
@if(TienePermiso) {
|
|
92
|
+
<button mat-menu-item (click)="irAActividad()">
|
|
93
|
+
<mat-icon>history</mat-icon>
|
|
94
|
+
<span>Actividad de la cuenta</span>
|
|
95
|
+
</button>
|
|
96
|
+
}
|
|
97
|
+
</mat-menu>
|
|
98
|
+
|
|
82
99
|
@if(TienePermiso) {
|
|
83
|
-
<button class="botonDeNavegacion" matTooltip="Mensajes"
|
|
100
|
+
<button class="botonDeNavegacion" matTooltip="Mensajes" (click)="irAMensajes()">
|
|
84
101
|
@if (Mensajes.length > 0) {
|
|
85
102
|
<mat-icon>mark_email_unread</mat-icon>
|
|
86
103
|
} @else {
|
|
@@ -89,21 +106,18 @@
|
|
|
89
106
|
</button>
|
|
90
107
|
}
|
|
91
108
|
@if(EnlaceDelVideo !== '-') {
|
|
92
|
-
<button class="botonDeNavegacion" matTooltip="Vídeo"
|
|
109
|
+
<button class="botonDeNavegacion" matTooltip="Vídeo" (click)="irAVideo()">
|
|
93
110
|
<mat-icon>live_tv</mat-icon>
|
|
94
111
|
</button>
|
|
95
112
|
}
|
|
96
113
|
@if(EnlaceDelManual !== '-') {
|
|
97
|
-
<button class="botonDeNavegacion" matTooltip="Ayuda"
|
|
114
|
+
<button class="botonDeNavegacion" matTooltip="Ayuda" (click)="irAAyuda()">
|
|
98
115
|
<mat-icon>help</mat-icon>
|
|
99
116
|
</button>
|
|
100
117
|
}
|
|
101
|
-
<button class="botonDeNavegacion" matTooltip="Reporte"
|
|
118
|
+
<button class="botonDeNavegacion" matTooltip="Reporte" (click)="irASoporte()">
|
|
102
119
|
<mat-icon>support_agent</mat-icon>
|
|
103
120
|
</button>
|
|
104
|
-
<button class="botonDeNavegacion" matTooltip="Sugerencias" mat-button (click)="irASugerencias()">
|
|
105
|
-
<mat-icon>lightbulb</mat-icon>
|
|
106
|
-
</button>
|
|
107
121
|
</div>
|
|
108
122
|
</div>
|
|
109
123
|
</div>
|
|
@@ -11,9 +11,11 @@ import { MensajesComponent } from '../../../Componentes/Nucleo/mensajes/mensajes
|
|
|
11
11
|
import { MensajeConfirmacionHTMLComponent } from '../../../Componentes/Nucleo/mensaje-confirmacion-html/mensaje-confirmacion-html';
|
|
12
12
|
import { ReporteDeSugerenciasComponent } from '../../../Componentes/Nucleo/reporte-de-sugerencias/reporte-de-sugerencias.component';
|
|
13
13
|
|
|
14
|
+
import { MatMenuModule } from '@angular/material/menu';
|
|
15
|
+
|
|
14
16
|
@Component({
|
|
15
17
|
selector: 'app-contenedor-componentes',
|
|
16
|
-
imports: [RouterOutlet, MatIconModule, MatTooltipModule, CommonModule],
|
|
18
|
+
imports: [RouterOutlet, MatIconModule, MatTooltipModule, CommonModule, MatMenuModule],
|
|
17
19
|
templateUrl: './contenedor-componentes.component.html',
|
|
18
20
|
styleUrl: './contenedor-componentes.component.css'
|
|
19
21
|
})
|
|
@@ -210,6 +212,11 @@ export class ContenedorComponentesComponent implements OnInit, OnDestroy {
|
|
|
210
212
|
this.dialog.open(ReporteDeSugerenciasComponent);
|
|
211
213
|
}
|
|
212
214
|
|
|
215
|
+
irAActividad(): void {
|
|
216
|
+
const url = new URL(window.location.href);
|
|
217
|
+
window.location.href = `${url.origin}/Actividad`;
|
|
218
|
+
}
|
|
219
|
+
|
|
213
220
|
ngOnDestroy() {
|
|
214
221
|
if (this.intervaloUsuarios) {
|
|
215
222
|
clearInterval(this.intervaloUsuarios);
|
|
@@ -3,7 +3,6 @@ import { provideRouter } from '@angular/router';
|
|
|
3
3
|
|
|
4
4
|
import { routes } from './app.routes';
|
|
5
5
|
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
|
|
6
|
-
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
|
7
6
|
import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
|
|
8
7
|
import { MatPaginatorIntl } from '@angular/material/paginator';
|
|
9
8
|
import { PaginadorPersonalizado } from './Componentes/Nucleo/tabla/paginador-personalizado';
|
|
@@ -16,10 +15,8 @@ export const appConfig: ApplicationConfig = {
|
|
|
16
15
|
{ provide: MatPaginatorIntl, useClass: PaginadorPersonalizado },
|
|
17
16
|
provideZoneChangeDetection({ eventCoalescing: true }),
|
|
18
17
|
provideRouter(routes),
|
|
19
|
-
provideClientHydration(withEventReplay()),
|
|
20
|
-
provideAnimationsAsync(),
|
|
21
18
|
provideHttpClient(withFetch()),
|
|
22
|
-
provideClientHydration(),
|
|
19
|
+
provideClientHydration(withEventReplay()),
|
|
23
20
|
provideCharts(withDefaultRegisterables()),
|
|
24
21
|
...AnalyticsModule.forRoot().providers!,
|
|
25
22
|
provideHttpClient(withInterceptors([AuthInterceptor]))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Routes } from '@angular/router';
|
|
2
|
+
import { GestionActividadComponent } from './Componentes/Nucleo/gestion-actividad/gestion-actividad.component';
|
|
2
3
|
import { GestionTablaComponent } from './Paginas/gestion-tabla/gestion-tabla.component';
|
|
3
4
|
import { ContenedorPrincipalComponent } from './Paginas/contenedor-principal/contenedor-principal.component';
|
|
4
5
|
import { GestionTablaJefeComponent } from './Paginas/gestion-tabla-jefe/gestion-tabla-jefe.component';
|
|
@@ -7,6 +8,7 @@ import { GestionDeReportesComponent } from './Paginas/gestion-de-reportes/gestio
|
|
|
7
8
|
import { GestionIframe1Component } from './Paginas/gestion-iframe1/gestion-iframe1.component';
|
|
8
9
|
|
|
9
10
|
export const routes: Routes = [
|
|
11
|
+
{ path: 'Actividad', component: GestionActividadComponent },
|
|
10
12
|
{ path: '', component: ContenedorPrincipalComponent },
|
|
11
13
|
{ path: 'tabla', component: GestionTablaComponent },
|
|
12
14
|
{ path: 'aprobaciones', component: GestionTablaJefeComponent},
|