utn-cli 2.1.1 → 2.1.3
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/.claude/settings.local.json +7 -0
- package/commands/commit.js +14 -1
- package/commands/frontend.js +1 -1
- package/package.json +1 -1
- package/templates/backend/package.json +3 -3
- package/templates/backend/rutas/misc.js +69 -0
- package/templates/backend/servicios/Nucleo/Miscelaneas.js +188 -22
- package/templates/backend/servicios/Nucleo/ReportePDF.js +1 -1
- package/templates/bd/docker-scripts/1-crear estructura.sql +8 -0
- package/templates/frontend/package.json +9 -8
- package/templates/frontend/public/Manual.md +1 -0
- package/templates/frontend/src/app/Componentes/Nucleo/gestion-actividad/gestion-actividad.component.ts +11 -3
- package/templates/frontend/src/app/Componentes/Nucleo/graficos/graficos.component.ts +2 -4
- package/templates/frontend/src/app/Componentes/Nucleo/manual/manual.component.css +318 -0
- package/templates/frontend/src/app/Componentes/Nucleo/manual/manual.component.html +43 -0
- package/templates/frontend/src/app/Componentes/Nucleo/manual/manual.component.ts +77 -0
- package/templates/frontend/src/app/Componentes/Nucleo/mensajes/mensajes.component.ts +5 -3
- package/templates/frontend/src/app/Componentes/Nucleo/reporte-de-incidencias/reporte-de-incidencias.component.ts +12 -4
- package/templates/frontend/src/app/Componentes/Nucleo/reporte-de-sugerencias/reporte-de-sugerencias.component.ts +12 -3
- package/templates/frontend/src/app/Componentes/Nucleo/subir-archivo/subir-archivo.component.html +13 -10
- package/templates/frontend/src/app/Componentes/Nucleo/subir-archivo/subir-archivo.component.ts +18 -6
- package/templates/frontend/src/app/Componentes/Nucleo/tarjeta/tarjeta.component.html +2 -2
- package/templates/frontend/src/app/Componentes/Nucleo/tarjeta/tarjeta.component.ts +9 -13
- package/templates/frontend/src/app/Componentes/Nucleo/tarjeta-personalizada/tarjeta-personalizada.component.ts +7 -9
- package/templates/frontend/src/app/Componentes/Nucleo/tarjeta-reporte/tarjeta-reporte.component.ts +1 -6
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.css +72 -0
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.html +17 -4
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.ts +45 -57
- package/templates/frontend/src/app/Paginas/contenedor-principal/contenedor-principal.component.css +11 -0
- package/templates/frontend/src/app/Paginas/contenedor-principal/contenedor-principal.component.html +4 -4
- package/templates/frontend/src/app/Paginas/contenedor-principal/contenedor-principal.component.ts +65 -69
- package/templates/frontend/src/app/Paginas/gestion-de-reportes/gestion-de-reportes.component.html +14 -3
- package/templates/frontend/src/app/Paginas/gestion-de-reportes/gestion-de-reportes.component.ts +52 -14
- package/templates/frontend/src/app/app.routes.ts +4 -0
- package/templates/frontend/src/app/datos-globales.service.ts +4 -1
package/commands/commit.js
CHANGED
|
@@ -20,6 +20,8 @@ export async function runCommit() {
|
|
|
20
20
|
'¿Ya realizó el update de los módulos de UTN?',
|
|
21
21
|
'¿Ya revisó la visualización en móvil?',
|
|
22
22
|
'¿Ya hizo el stage de todos los cambios?',
|
|
23
|
+
'¿Ya hizo la actualización del manual?',
|
|
24
|
+
'¿Ya actualizó la función de monitoreo?',
|
|
23
25
|
'¿El archivo app.routes.ts hace uso de la estrategia de "Lazy Loading"?'
|
|
24
26
|
];
|
|
25
27
|
|
|
@@ -29,8 +31,19 @@ export async function runCommit() {
|
|
|
29
31
|
[preguntas[i], preguntas[j]] = [preguntas[j], preguntas[i]];
|
|
30
32
|
}
|
|
31
33
|
|
|
34
|
+
const PREGUNTA_MANUAL = '¿Ya hizo la actualización del manual?';
|
|
35
|
+
const PROMPT_MANUAL = `Necesito actualizar el manual Manual.md que se encuentra en la carpeta public, en donde se aborden todas las secciones nuevas que se contemplan en el frontend, el nivel de detalle del manual debe de ser alto, ya que no va a contener imágenes para guiar al usuario en la forma de ejecutar las diferentes acciones, debe ser compatible con las reglas de accesibilidad y para que sea leío programas lectores de pantalla, en el archivo app.routes.ts están las rutas disponibles que se deben incluir en el manual omitiendo las que estén comentadas.`;
|
|
36
|
+
|
|
32
37
|
for (const pregunta of preguntas) {
|
|
33
|
-
if (!await confirmarPaso(pregunta))
|
|
38
|
+
if (!await confirmarPaso(pregunta)) {
|
|
39
|
+
if (pregunta === PREGUNTA_MANUAL) {
|
|
40
|
+
console.log('\nPuede usar el siguiente prompt con Claude para actualizar el manual:\n');
|
|
41
|
+
console.log('─'.repeat(60));
|
|
42
|
+
console.log(PROMPT_MANUAL);
|
|
43
|
+
console.log('─'.repeat(60));
|
|
44
|
+
}
|
|
45
|
+
return closeReadLine();
|
|
46
|
+
}
|
|
34
47
|
}
|
|
35
48
|
|
|
36
49
|
try {
|
package/commands/frontend.js
CHANGED
|
@@ -42,7 +42,7 @@ export async function initFrontend() {
|
|
|
42
42
|
|
|
43
43
|
export async function updateFrontend(opciones = { cerrarAlFinalizar: true }) {
|
|
44
44
|
console.log('Actualizando el proyecto de frontend...');
|
|
45
|
-
const archivosAExcluir = ['app.routes.ts', 'contenedor-principal.component.ts', '.vscode', 'dist'];
|
|
45
|
+
const archivosAExcluir = ['app.routes.ts', 'contenedor-principal.component.ts', '.vscode', 'dist', 'Manual.md'];
|
|
46
46
|
const directoriodePlantillas = path.join(__dirname, '../templates/frontend');
|
|
47
47
|
const directorioDestino = process.cwd();
|
|
48
48
|
|
package/package.json
CHANGED
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"bcryptjs": "^2.4.3",
|
|
22
22
|
"cors": "^2.8.6",
|
|
23
23
|
"express": "^4.22.1",
|
|
24
|
-
"helmet": "^7.2.0",
|
|
25
24
|
"google-auth-library": "^9.15.1",
|
|
25
|
+
"helmet": "^7.2.0",
|
|
26
26
|
"jsonwebtoken": "^9.0.3",
|
|
27
|
-
"mysql2": "^3.
|
|
28
|
-
"nodemailer": "^8.0.
|
|
27
|
+
"mysql2": "^3.22.3",
|
|
28
|
+
"nodemailer": "^8.0.7",
|
|
29
29
|
"pdf-lib": "^1.17.1",
|
|
30
30
|
"pdfkit": "^0.15.2"
|
|
31
31
|
}
|
|
@@ -209,6 +209,24 @@ Router.get('/obtenerDetalleDelModulo', async (solicitud, respuesta, next) => {
|
|
|
209
209
|
}
|
|
210
210
|
});
|
|
211
211
|
|
|
212
|
+
Router.get('/VistaDelManual', async (solicitud, respuesta, next) => {
|
|
213
|
+
try {
|
|
214
|
+
if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
|
|
215
|
+
try {
|
|
216
|
+
await Miscelaneo.registrarVistaDelManual(solicitud.headers.authorization);
|
|
217
|
+
return respuesta.json({ body: undefined, error: undefined });
|
|
218
|
+
} catch (error) {
|
|
219
|
+
const MensajeDeError = 'No fue posible registrar la vista del manual';
|
|
220
|
+
console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, `Dirección IP: ${solicitud.ip}`));
|
|
221
|
+
return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return respuesta.status(401).json({ body: undefined, error: ManejadorDeErrores.mensajeDeError401() });
|
|
225
|
+
} catch (error) {
|
|
226
|
+
next(error);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
212
230
|
Router.get('/obtenerDatosDelUsuario', async (solicitud, respuesta, next) => {
|
|
213
231
|
try {
|
|
214
232
|
if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
|
|
@@ -486,6 +504,23 @@ Router.get('/validarToken', async (solicitud, respuesta, next) => {
|
|
|
486
504
|
return respuesta.json({ body: await Miscelaneo.validarTokenV2(solicitud.headers.authorization), error: undefined });
|
|
487
505
|
});
|
|
488
506
|
|
|
507
|
+
Router.get('/inicializar', async (solicitud, respuesta, next) => {
|
|
508
|
+
try {
|
|
509
|
+
if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
|
|
510
|
+
try {
|
|
511
|
+
return respuesta.json({ body: await Miscelaneo.inicializar(solicitud), error: undefined });
|
|
512
|
+
} catch (error) {
|
|
513
|
+
const MensajeDeError = 'No fue posible inicializar el módulo';
|
|
514
|
+
console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, `Dirección IP: ${solicitud.ip}`));
|
|
515
|
+
return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return respuesta.status(401).json({ body: undefined, error: ManejadorDeErrores.mensajeDeError401() });
|
|
519
|
+
} catch (error) {
|
|
520
|
+
next(error);
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
|
|
489
524
|
Router.get('/descargarArchivo/:ArchivoId', async (solicitud, respuesta, next) => {
|
|
490
525
|
try {
|
|
491
526
|
if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
|
|
@@ -777,4 +812,38 @@ Router.get('/obtenerIdentificacion/:Identificador', async (solicitud, respuesta,
|
|
|
777
812
|
}
|
|
778
813
|
});
|
|
779
814
|
|
|
815
|
+
Router.get('/obtenerTarjetasDelContenedor', async (solicitud, respuesta, next) => {
|
|
816
|
+
try {
|
|
817
|
+
if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
|
|
818
|
+
try {
|
|
819
|
+
return respuesta.json({ body: await Miscelaneo.obtenerTarjetasDelContenedor(solicitud.headers.authorization), error: undefined });
|
|
820
|
+
} catch (error) {
|
|
821
|
+
const MensajeDeError = 'No fue posible obtener las tarjetas del contenedor';
|
|
822
|
+
console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, `Dirección IP: ${solicitud.ip}`));
|
|
823
|
+
return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
return respuesta.status(401).json({ body: undefined, error: ManejadorDeErrores.mensajeDeError401() });
|
|
827
|
+
} catch (error) {
|
|
828
|
+
next(error);
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
Router.get('/obtenerTarjetas', async (solicitud, respuesta, next) => {
|
|
833
|
+
try {
|
|
834
|
+
if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
|
|
835
|
+
try {
|
|
836
|
+
return respuesta.json({ body: await Miscelaneo.obtenerTarjetas(), error: undefined });
|
|
837
|
+
} catch (error) {
|
|
838
|
+
const MensajeDeError = 'No fue posible obtener las tarjetas';
|
|
839
|
+
console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, `Dirección IP: ${solicitud.ip}`));
|
|
840
|
+
return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
return respuesta.status(401).json({ body: undefined, error: ManejadorDeErrores.mensajeDeError401() });
|
|
844
|
+
} catch (error) {
|
|
845
|
+
next(error);
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
|
|
780
849
|
module.exports = Router;
|
|
@@ -250,7 +250,8 @@ class Miscelaneo {
|
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
async RegistrarElServicio(Servicio) {
|
|
253
|
+
async RegistrarElServicio(Servicio, Tarjetas = null) {
|
|
254
|
+
const archivo = this._archivoFuenteActual;
|
|
254
255
|
try {
|
|
255
256
|
await ejecutarConsultaSIGU("REPLACE INTO `SIGU`.`SIGU_ModulosV2Secciones` (`Modulo`, `Descripcion`) VALUES (?, ?)"
|
|
256
257
|
, [this.NombreCanonicoDelModulo, Servicio]);
|
|
@@ -258,6 +259,70 @@ class Miscelaneo {
|
|
|
258
259
|
} catch (error) {
|
|
259
260
|
console.error(error.message);
|
|
260
261
|
}
|
|
262
|
+
|
|
263
|
+
if (!Tarjetas) return;
|
|
264
|
+
|
|
265
|
+
const listaTarjetas = Array.isArray(Tarjetas) ? Tarjetas : [Tarjetas];
|
|
266
|
+
|
|
267
|
+
for (const tarjeta of listaTarjetas) {
|
|
268
|
+
try {
|
|
269
|
+
const titulo = tarjeta['Título'];
|
|
270
|
+
const existentes = await ejecutarConsultaSIGU(
|
|
271
|
+
`SELECT CAST(JSON_VALUE(\`Datos\`, '$."Posición"') AS UNSIGNED) AS Posicion, JSON_VALUE(\`Datos\`, '$."Título"') AS Titulo, JSON_VALUE(\`Datos\`, '$."Descripción"') AS Descripcion FROM \`SIGU\`.\`ModulosV2Tarjetas\` WHERE \`Modulo\` = ? AND JSON_VALUE(\`Datos\`, '$."Título"') = ?`,
|
|
272
|
+
[this.NombreCanonicoDelModulo, titulo]
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
let datosFinales;
|
|
276
|
+
if (existentes.length > 0) {
|
|
277
|
+
datosFinales = { ...tarjeta, 'Posición': existentes[0].Posicion, 'Título': existentes[0].Titulo, 'Descripción': existentes[0].Descripcion, 'Archivo': archivo };
|
|
278
|
+
await ejecutarConsultaSIGU(
|
|
279
|
+
`UPDATE \`SIGU\`.\`ModulosV2Tarjetas\` SET \`Datos\` = ?, \`LastUser\` = 'Sistema' WHERE \`Modulo\` = ? AND JSON_VALUE(\`Datos\`, '$."Título"') = ?`,
|
|
280
|
+
[JSON.stringify(datosFinales), this.NombreCanonicoDelModulo, titulo]
|
|
281
|
+
);
|
|
282
|
+
} else {
|
|
283
|
+
let posicion = tarjeta['Posición'];
|
|
284
|
+
if (posicion === undefined) {
|
|
285
|
+
const [{ NuevaPosicion }] = await ejecutarConsultaSIGU(
|
|
286
|
+
`SELECT COALESCE(MAX(CAST(JSON_VALUE(\`Datos\`, '$."Posición"') AS UNSIGNED)), 0) + 10 AS NuevaPosicion FROM \`SIGU\`.\`ModulosV2Tarjetas\` WHERE \`Modulo\` = ?`,
|
|
287
|
+
[this.NombreCanonicoDelModulo]
|
|
288
|
+
);
|
|
289
|
+
posicion = NuevaPosicion;
|
|
290
|
+
}
|
|
291
|
+
datosFinales = { ...tarjeta, 'Posición': posicion, 'Archivo': archivo };
|
|
292
|
+
await ejecutarConsultaSIGU(
|
|
293
|
+
`INSERT INTO \`SIGU\`.\`ModulosV2Tarjetas\` (\`Modulo\`, \`Datos\`, \`LastUser\`) VALUES (?, ?, 'Sistema')`,
|
|
294
|
+
[this.NombreCanonicoDelModulo, JSON.stringify(datosFinales)]
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
console.log(`Tarjeta "${titulo}" registrada correctamente`);
|
|
298
|
+
} catch (error) {
|
|
299
|
+
console.error(`Error al registrar tarjeta "${tarjeta['Título']}":`, error.message);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
_archivoFuenteActual = null;
|
|
305
|
+
_archivoCache = new Map();
|
|
306
|
+
|
|
307
|
+
_buscarArchivoRecursivo(dir, nombre) {
|
|
308
|
+
if (this._archivoCache.has(nombre)) return this._archivoCache.get(nombre);
|
|
309
|
+
const fs = require('fs');
|
|
310
|
+
const path = require('path');
|
|
311
|
+
const buscar = (directorio) => {
|
|
312
|
+
for (const entrada of fs.readdirSync(directorio, { withFileTypes: true })) {
|
|
313
|
+
const ruta = path.join(directorio, entrada.name);
|
|
314
|
+
if (entrada.isDirectory()) {
|
|
315
|
+
const resultado = buscar(ruta);
|
|
316
|
+
if (resultado) return resultado;
|
|
317
|
+
} else if (entrada.name === nombre) {
|
|
318
|
+
return ruta;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return null;
|
|
322
|
+
};
|
|
323
|
+
const resultado = buscar(dir);
|
|
324
|
+
this._archivoCache.set(nombre, resultado);
|
|
325
|
+
return resultado;
|
|
261
326
|
}
|
|
262
327
|
|
|
263
328
|
async DatosParaReporteCSV() {
|
|
@@ -381,7 +446,7 @@ class Miscelaneo {
|
|
|
381
446
|
// }
|
|
382
447
|
let LastUser = '';
|
|
383
448
|
if (Resultado) {
|
|
384
|
-
LastUser = Resultado.
|
|
449
|
+
LastUser = Resultado.Identificador;
|
|
385
450
|
}
|
|
386
451
|
LastUser = LastUser + '@' + Solicitud.headers.host.trim()
|
|
387
452
|
+ '@' + Solicitud.headers["user-agent"].trim()
|
|
@@ -815,6 +880,14 @@ class Miscelaneo {
|
|
|
815
880
|
});
|
|
816
881
|
}
|
|
817
882
|
|
|
883
|
+
async registrarVistaDelManual(Token) {
|
|
884
|
+
const { uid } = await this.obtenerDatosDelUsuario(Token);
|
|
885
|
+
await ejecutarConsulta(
|
|
886
|
+
"INSERT INTO `DatosMiscelaneos` (`DatoMiscelaneo`, `Datos`, `LastUser`) VALUES ('VistasDelManual', JSON_OBJECT('Total', 1), ?) ON DUPLICATE KEY UPDATE `Datos` = JSON_SET(`Datos`, '$.Total', CAST(JSON_VALUE(`Datos`, '$.Total') AS UNSIGNED) + 1), `LastUser` = ?",
|
|
887
|
+
[uid, uid]
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
|
|
818
891
|
async obtenerMensajesModulares() {
|
|
819
892
|
return await ejecutarConsultaSIGU("SELECT `MensajeModularId`, `Titulo`, `Texto`, `FechaYHoraDeInicio`, `FechaYHoraDeFinalizacion` FROM `SIGU`.`SIGU_MensajesModulares` WHERE NOW(4) BETWEEN `FechaYHoraDeInicio` AND `FechaYHoraDeFinalizacion` AND `Modulo` = ?"
|
|
820
893
|
, [this.NombreCanonicoDelModulo]);
|
|
@@ -867,7 +940,7 @@ class Miscelaneo {
|
|
|
867
940
|
return;
|
|
868
941
|
}
|
|
869
942
|
const Permisos = await ejecutarConsultaSIGU("SELECT `PermisoId` FROM `SIGU`.`SIGU_PermisosPersonasV2` WHERE `Identificador` = ?"
|
|
870
|
-
, [Resultado.
|
|
943
|
+
, [Resultado.Identificador]);
|
|
871
944
|
const Modulos = await ejecutarConsultaSIGU("SELECT `a`.`Nombre`, `a`.`Padre`, `a`.`Descripcion`, `a`.`Detalle`,\
|
|
872
945
|
`a`.`Tipo`, IF(`a`.`Icono` <> '', CONCAT('https://storage.sigu.utn.ac.cr/images/cards/', `a`.`Icono`), '') AS `Icono`, `a`.`Color`, `a`.`Correo`,\
|
|
873
946
|
`a`.`Version`, `a`.`FechaDePublicacion`, `a`.`AcuerdoDeNivelDeServicio`, `a`.`DiccionarioDeDatos`, `a`.`Repositorios`,\
|
|
@@ -902,7 +975,7 @@ class Miscelaneo {
|
|
|
902
975
|
return;
|
|
903
976
|
}
|
|
904
977
|
return await ejecutarConsultaSIGU("UPDATE `SIGU`.`SIGU_NotificacionesV2` SET `Estado` = 'Leída' WHERE `Identificador` = ? AND `FechaYHoraDeCreacion` = ?"
|
|
905
|
-
, [Resultado.
|
|
978
|
+
, [Resultado.Identificador, FechaYHoraDeCreacion]);
|
|
906
979
|
}
|
|
907
980
|
|
|
908
981
|
async obtenerNotificaciones(Token) {
|
|
@@ -916,7 +989,7 @@ class Miscelaneo {
|
|
|
916
989
|
console.log(error);
|
|
917
990
|
return;
|
|
918
991
|
}
|
|
919
|
-
return await ejecutarConsultaSIGU("SELECT `Notificacion` AS `valor`, CONCAT(`FechaYHoraDeCreacion`) AS `llave`, false AS `tachado` FROM `SIGU`.`SIGU_NotificacionesV2` WHERE `Identificador` = ? AND `Estado` = 'Sin leer' ORDER BY `FechaYHoraDeCreacion` DESC LIMIT 10", [Resultado.
|
|
992
|
+
return await ejecutarConsultaSIGU("SELECT `Notificacion` AS `valor`, CONCAT(`FechaYHoraDeCreacion`) AS `llave`, false AS `tachado` FROM `SIGU`.`SIGU_NotificacionesV2` WHERE `Identificador` = ? AND `Estado` = 'Sin leer' ORDER BY `FechaYHoraDeCreacion` DESC LIMIT 10", [Resultado.Identificador]);
|
|
920
993
|
}
|
|
921
994
|
|
|
922
995
|
async reporteDeIncidencia(Solicitud, Datos) {
|
|
@@ -1373,7 +1446,7 @@ class Miscelaneo {
|
|
|
1373
1446
|
, `a`.`Nombre`, `a`.`PrimerApellido`, `a`.`SegundoApellido`\
|
|
1374
1447
|
, (SELECT GROUP_CONCAT(`b`.`CuentaIBAN`) FROM `SIGU`.`SIGU_CuentasBancariasPersonas` `b` WHERE `b`.`Estado` = TRUE AND `a`.`Identificador` = `b`.`Identificador`) AS `CuentasIBAN`\
|
|
1375
1448
|
FROM `SIGU`.`SIGU_Personas` `a` WHERE `a`.`Identificador` = ?"
|
|
1376
|
-
, [Resultado.
|
|
1449
|
+
, [Resultado.Identificador]);
|
|
1377
1450
|
}
|
|
1378
1451
|
|
|
1379
1452
|
async obtenerDatosDeLaPersonaPorIdentificacion(Identificacion) {
|
|
@@ -1465,7 +1538,7 @@ class Miscelaneo {
|
|
|
1465
1538
|
Resultado.token = token;
|
|
1466
1539
|
const DatosDeLaPersona = await ejecutarConsultaSIGU("SELECT `Identificacion`, `Nombre`, `PrimerApellido`,\
|
|
1467
1540
|
`SegundoApellido`, CONCAT(`FechaNacimiento`) AS `FechaDeNacimiento`\
|
|
1468
|
-
FROM `SIGU`.`SIGU_Personas` WHERE `Identificador` = ?", [Resultado.
|
|
1541
|
+
FROM `SIGU`.`SIGU_Personas` WHERE `Identificador` = ?", [Resultado.Identificador]);
|
|
1469
1542
|
Resultado.Identificacion = DatosDeLaPersona[0]['Identificacion'];
|
|
1470
1543
|
Resultado.Nombre = DatosDeLaPersona[0]['Nombre'];
|
|
1471
1544
|
Resultado.PrimerApellido = DatosDeLaPersona[0]['PrimerApellido'];
|
|
@@ -1490,16 +1563,16 @@ class Miscelaneo {
|
|
|
1490
1563
|
try {
|
|
1491
1564
|
// Validación del token en la sesión
|
|
1492
1565
|
const tokenAlmacenado = await ejecutarConsultaSIGU("SELECT COUNT(*) AS `Total` FROM `SIGU`.`SIGU_Sesiones`\
|
|
1493
|
-
WHERE `Identificador` = ? AND `Token` = ?", [Resultado.
|
|
1566
|
+
WHERE `Identificador` = ? AND `Token` = ?", [Resultado.Identificador, Resultado.token]);
|
|
1494
1567
|
if (tokenAlmacenado[0]['Total'] >= 1) {
|
|
1495
1568
|
// Validación de permisos
|
|
1496
1569
|
const rolPermisoId = await this.permisoIdV2();
|
|
1497
1570
|
const permisos = await ejecutarConsultaSIGU("SELECT COUNT(*) AS `Total` FROM `SIGU`.`SIGU_PermisosPersonasV2`\
|
|
1498
|
-
WHERE `PermisoId` = ? AND `Identificador` = ?", [rolPermisoId, Resultado.
|
|
1571
|
+
WHERE `PermisoId` = ? AND `Identificador` = ?", [rolPermisoId, Resultado.Identificador]);
|
|
1499
1572
|
if (permisos[0]['Total'] === 1) {
|
|
1500
1573
|
if (permisoExtraId) {
|
|
1501
1574
|
const ValidacionPermisoExtra = await ejecutarConsultaSIGU("SELECT COUNT(*) AS `Total` FROM `SIGU`.`SIGU_PermisosExtraPersonasV2`\
|
|
1502
|
-
WHERE `PermisoExtraId` = ? AND `Identificador` = ?", [permisoExtraId, Resultado.
|
|
1575
|
+
WHERE `PermisoExtraId` = ? AND `Identificador` = ?", [permisoExtraId, Resultado.Identificador]);
|
|
1503
1576
|
if (ValidacionPermisoExtra[0]['Total'] === 1) {
|
|
1504
1577
|
return true;
|
|
1505
1578
|
}
|
|
@@ -1533,13 +1606,13 @@ class Miscelaneo {
|
|
|
1533
1606
|
// try {
|
|
1534
1607
|
// // Validación del token en la sesión
|
|
1535
1608
|
// const tokenAlmacenado = await ejecutarConsultaSIGU("SELECT COUNT(*) AS `Total` FROM `SIGU`.`SIGU_Sesiones`\
|
|
1536
|
-
// WHERE `Identificador` = ? AND `Token` = ?", [Resultado.
|
|
1609
|
+
// WHERE `Identificador` = ? AND `Token` = ?", [Resultado.Identificador, Resultado.token]);
|
|
1537
1610
|
// if (tokenAlmacenado[0]['Total'] >= 1) { // Se compara con >= para preveer multisesiones
|
|
1538
1611
|
// // Validación de permisos
|
|
1539
1612
|
// const perfilGeneralId = await this.perfilGeneralId();
|
|
1540
1613
|
// const rolPermisoId = await this.rolPermisoIdDelModulo();
|
|
1541
1614
|
// const permisos = await ejecutarConsultaSIGU("SELECT COUNT(*) AS `Total` FROM `SIGU`.`SIGU_RolesPersonas`\
|
|
1542
|
-
// WHERE `RolPermisoId` = ? AND `Identificador` = ? AND `PerfilGeneralId` = ?", [rolPermisoId, Resultado.
|
|
1615
|
+
// WHERE `RolPermisoId` = ? AND `Identificador` = ? AND `PerfilGeneralId` = ?", [rolPermisoId, Resultado.Identificador, perfilGeneralId]);
|
|
1543
1616
|
// if (permisos[0]['Total'] === 1) {
|
|
1544
1617
|
// return true;
|
|
1545
1618
|
// } else {
|
|
@@ -1855,16 +1928,16 @@ class Miscelaneo {
|
|
|
1855
1928
|
const informacionDelArchivo = await this.almacenarArchivoEnDisco(Solicitud, Resultado['uid']);
|
|
1856
1929
|
const Respuesta = await ejecutarConsultaSIGU("INSERT INTO `SIGU`.`SIGU_Adjuntos` (`AdjuntosId`, `Identificador`, `Modulo`, `Seccion`, `Nombre`,\
|
|
1857
1930
|
`NombreOriginal`, `Ruta`, `Tipo`, `Tamanio`, `Etiqueta`, `LastUpdate`, `LastUser`)\
|
|
1858
|
-
VALUES (NULL, ?, ?, 'No aplica', ?, ?, ?, ?, ?,
|
|
1931
|
+
VALUES (NULL, ?, ?, 'No aplica', ?, ?, ?, ?, ?, ?, NOW(4), ?)"
|
|
1859
1932
|
, [Resultado['uid'], this.NombreCanonicoDelModulo, informacionDelArchivo.nombreDeArchivo, informacionDelArchivo.nombreDeArchivo
|
|
1860
1933
|
, informacionDelArchivo.rutaDeArchivo, informacionDelArchivo.tipoDeContenido, informacionDelArchivo.tamanioTotal
|
|
1861
|
-
, Resultado['uid']]);
|
|
1934
|
+
, Etiquetas, Resultado['uid']]);
|
|
1862
1935
|
informacionDelArchivo.insertId = Respuesta.insertId;
|
|
1863
1936
|
informacionDelArchivo.Etiquetas = Etiquetas;
|
|
1864
1937
|
await ejecutarConsulta("INSERT INTO `" + this.NombreDelRepositorioDeLaBaseDeDatos.slice(0, -3) + "`.`Archivos`\
|
|
1865
1938
|
VALUES (?, ?, ?, ?, ?, NOW(4), ?)"
|
|
1866
|
-
, [Respuesta.insertId, Resultado.
|
|
1867
|
-
, Etiquetas, Resultado.
|
|
1939
|
+
, [Respuesta.insertId, Resultado.Identificador, informacionDelArchivo.rutaDeArchivo, informacionDelArchivo.nombreDeArchivo
|
|
1940
|
+
, Etiquetas, Resultado.Identificador]);
|
|
1868
1941
|
return informacionDelArchivo;
|
|
1869
1942
|
}
|
|
1870
1943
|
return;
|
|
@@ -2148,7 +2221,7 @@ class Miscelaneo {
|
|
|
2148
2221
|
let Token = undefined;
|
|
2149
2222
|
if (this.NombresParalocalhost().includes(process.env.HOST) && (typeof process.env.DB_HOST_SIGU === "undefined")) {
|
|
2150
2223
|
const jwt = require('jsonwebtoken');
|
|
2151
|
-
Token = await jwt.sign({ uid: Identificador }, await this.palabraSecretaParaTokens(), { expiresIn: '10h' });
|
|
2224
|
+
Token = await jwt.sign({ uid: Identificador, Identificador }, await this.palabraSecretaParaTokens(), { expiresIn: '10h' });
|
|
2152
2225
|
await ejecutarConsultaSIGU("DELETE FROM `SIGU`.`SIGU_Sesiones` WHERE `Identificador` = ?", [Identificador]);
|
|
2153
2226
|
await ejecutarConsultaSIGU("INSERT INTO `SIGU`.`SIGU_Sesiones` VALUES (?, 'Backend', ?, NOW(4), USER())", [Identificador, Token]);
|
|
2154
2227
|
}
|
|
@@ -2198,7 +2271,7 @@ class Miscelaneo {
|
|
|
2198
2271
|
return await ejecutarConsulta("SELECT `ArchivoId`, `Identificador`, `Ruta`, CONCAT(`Nombre`, ' (', DATE_FORMAT(`LastUpdate`, '%Y-%M-%d %H:%i'), ')') AS `Nombre`, `Etiquetas`\
|
|
2199
2272
|
FROM `" + this.NombreDelRepositorioDeLaBaseDeDatos.slice(0, -3) + "`.`Archivos`\
|
|
2200
2273
|
WHERE `Identificador` = ? AND `Etiquetas` = ?"
|
|
2201
|
-
, [Resultado.
|
|
2274
|
+
, [Resultado.Identificador, Etiquetas]);
|
|
2202
2275
|
}
|
|
2203
2276
|
if (ultimaParte === 'Servicio') {
|
|
2204
2277
|
return await ejecutarConsulta("SELECT `ArchivoId`, `Identificador`, `Ruta`, CONCAT(`Nombre`, ' (', DATE_FORMAT(`LastUpdate`, '%Y-%M-%d %H:%i'), ')') AS `Nombre`, `Etiquetas`\
|
|
@@ -2258,14 +2331,14 @@ class Miscelaneo {
|
|
|
2258
2331
|
const Archivo = await ejecutarConsulta("SELECT `Ruta`\
|
|
2259
2332
|
FROM `" + this.NombreDelRepositorioDeLaBaseDeDatos.slice(0, -3) + "`.`Archivos`\
|
|
2260
2333
|
WHERE `Identificador` = ? AND `ArchivoId` = ?"
|
|
2261
|
-
, [Resultado.
|
|
2334
|
+
, [Resultado.Identificador, Datos.ArchivoId]);
|
|
2262
2335
|
fs.unlinkSync(Archivo[0]['Ruta']);
|
|
2263
2336
|
await ejecutarConsulta("DELETE FROM `" + this.NombreDelRepositorioDeLaBaseDeDatos.slice(0, -3) + "`.`Archivos`\
|
|
2264
2337
|
WHERE `Identificador` = ? AND `ArchivoId` = ?"
|
|
2265
|
-
, [Resultado.
|
|
2338
|
+
, [Resultado.Identificador, Datos.ArchivoId]);
|
|
2266
2339
|
await ejecutarConsultaSIGU("DELETE FROM `SIGU`.`SIGU_Adjuntos`\
|
|
2267
2340
|
WHERE `Identificador` = ? AND `AdjuntosId` = ?"
|
|
2268
|
-
, [Resultado.
|
|
2341
|
+
, [Resultado.Identificador, Datos.ArchivoId]);
|
|
2269
2342
|
return;
|
|
2270
2343
|
}
|
|
2271
2344
|
|
|
@@ -2288,7 +2361,7 @@ class Miscelaneo {
|
|
|
2288
2361
|
RutaDelArchivo = await ejecutarConsulta("SELECT `Ruta`\
|
|
2289
2362
|
FROM `" + this.NombreDelRepositorioDeLaBaseDeDatos.slice(0, -3) + "`.`Archivos`\
|
|
2290
2363
|
WHERE `Identificador` = ? AND `ArchivoId` = ?"
|
|
2291
|
-
, [Resultado.
|
|
2364
|
+
, [Resultado.Identificador, ArchivoId]);
|
|
2292
2365
|
}
|
|
2293
2366
|
if (ultimaParte === 'Servicio') {
|
|
2294
2367
|
RutaDelArchivo = await ejecutarConsulta("SELECT `Ruta`\
|
|
@@ -2388,8 +2461,14 @@ class Miscelaneo {
|
|
|
2388
2461
|
}
|
|
2389
2462
|
|
|
2390
2463
|
async ejecucionDiferida(callback) {
|
|
2464
|
+
const stackLines = new Error().stack.split('\n');
|
|
2465
|
+
const lineaCaller = stackLines[2] ?? '';
|
|
2466
|
+
const match = lineaCaller.match(/\((.+?):\d+:\d+\)/) ?? lineaCaller.match(/at (.+?):\d+:\d+/);
|
|
2467
|
+
const archivo = match ? require('path').basename(match[1]) : null;
|
|
2468
|
+
|
|
2391
2469
|
while (true) {
|
|
2392
2470
|
try {
|
|
2471
|
+
this._archivoFuenteActual = archivo;
|
|
2393
2472
|
await callback();
|
|
2394
2473
|
break;
|
|
2395
2474
|
} catch (error) {
|
|
@@ -2398,6 +2477,7 @@ class Miscelaneo {
|
|
|
2398
2477
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
2399
2478
|
}
|
|
2400
2479
|
}
|
|
2480
|
+
this._archivoFuenteActual = null;
|
|
2401
2481
|
}
|
|
2402
2482
|
|
|
2403
2483
|
// async obtenerEnlaceDelModuloPadre() {
|
|
@@ -2414,6 +2494,92 @@ class Miscelaneo {
|
|
|
2414
2494
|
async obtenerEnlaceDePerfil() {
|
|
2415
2495
|
return this.EnlaceDePerfil;
|
|
2416
2496
|
}
|
|
2497
|
+
|
|
2498
|
+
async obtenerTarjetas() {
|
|
2499
|
+
const resultados = await ejecutarConsultaSIGU(
|
|
2500
|
+
"SELECT `Datos` FROM `SIGU`.`ModulosV2Tarjetas` WHERE `Modulo` = ? AND JSON_EXTRACT(`Datos`, '$.Activa') = TRUE",
|
|
2501
|
+
[this.NombreCanonicoDelModulo]
|
|
2502
|
+
);
|
|
2503
|
+
return resultados.map(fila => typeof fila.Datos === 'string' ? JSON.parse(fila.Datos) : fila.Datos);
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
async inicializar(solicitud) {
|
|
2507
|
+
const ConsentimientoInformado = require('./ConsentimientoInformado.js');
|
|
2508
|
+
const LastUser = await this.generarLastUser(solicitud);
|
|
2509
|
+
const [configuracion, detalleDelModulo, notificaciones, mensajesModulares, consentimiento] = await Promise.all([
|
|
2510
|
+
this.configurarFrontend(solicitud.headers.authorization),
|
|
2511
|
+
this.obtenerDetalleDelModulo(),
|
|
2512
|
+
this.obtenerNotificaciones(solicitud.headers.authorization),
|
|
2513
|
+
this.obtenerMensajesModulares(),
|
|
2514
|
+
ConsentimientoInformado.ConsentimientoInformado({ LastUser })
|
|
2515
|
+
]);
|
|
2516
|
+
return {
|
|
2517
|
+
TienePermiso: true,
|
|
2518
|
+
...configuracion,
|
|
2519
|
+
Descripcion: detalleDelModulo[0]?.Descripcion ?? configuracion.Descripcion,
|
|
2520
|
+
Detalle: detalleDelModulo[0]?.Detalle ?? configuracion.Detalle,
|
|
2521
|
+
EnlaceDelManual: detalleDelModulo[0]?.EnlaceDelManual ?? '-',
|
|
2522
|
+
EnlaceDelVideo: detalleDelModulo[0]?.EnlaceDelVideo ?? '-',
|
|
2523
|
+
Notificaciones: notificaciones,
|
|
2524
|
+
MensajesModulares: mensajesModulares,
|
|
2525
|
+
Consentimiento: consentimiento
|
|
2526
|
+
};
|
|
2527
|
+
}
|
|
2528
|
+
|
|
2529
|
+
async obtenerTarjetasDelContenedor(token) {
|
|
2530
|
+
const ConfiguracionDeTarjetas = require('./ConfiguracionDeTarjetas.js');
|
|
2531
|
+
const Personas = require('../Personas.js');
|
|
2532
|
+
const path = require('path');
|
|
2533
|
+
const serviciosDir = path.join(__dirname, '..');
|
|
2534
|
+
|
|
2535
|
+
const usuario = await this.obtenerDatosDelUsuario(token);
|
|
2536
|
+
const [tarjetas, configuracion, tienePermisoExtra] = await Promise.all([
|
|
2537
|
+
this.obtenerTarjetas(),
|
|
2538
|
+
ConfiguracionDeTarjetas.obtener({ Identificador: usuario.uid }),
|
|
2539
|
+
Personas.PermisoExtra(token)
|
|
2540
|
+
]);
|
|
2541
|
+
|
|
2542
|
+
const cantidadesEntradas = await Promise.all(
|
|
2543
|
+
tarjetas
|
|
2544
|
+
.filter(t => t.Archivo)
|
|
2545
|
+
.map(async t => {
|
|
2546
|
+
try {
|
|
2547
|
+
const rutaArchivo = this._buscarArchivoRecursivo(serviciosDir, t.Archivo);
|
|
2548
|
+
if (!rutaArchivo) return null;
|
|
2549
|
+
const servicio = require(rutaArchivo);
|
|
2550
|
+
if (typeof servicio.Cantidades !== 'function') return null;
|
|
2551
|
+
const cantidades = await servicio.Cantidades(token);
|
|
2552
|
+
return [t['Título'], cantidades];
|
|
2553
|
+
} catch { return null; }
|
|
2554
|
+
})
|
|
2555
|
+
);
|
|
2556
|
+
|
|
2557
|
+
const cantidadesPorTitulo = Object.fromEntries(cantidadesEntradas.filter(Boolean));
|
|
2558
|
+
|
|
2559
|
+
const titulosAExcluir = new Set(
|
|
2560
|
+
Object.entries(cantidadesPorTitulo)
|
|
2561
|
+
.filter(([, c]) => !(c.cantidadMaxima > 0))
|
|
2562
|
+
.map(([titulo]) => titulo)
|
|
2563
|
+
);
|
|
2564
|
+
|
|
2565
|
+
return tarjetas
|
|
2566
|
+
.filter(t => !t.RequierePermisoExtra || tienePermisoExtra)
|
|
2567
|
+
.filter(t => !titulosAExcluir.has(t['Título']))
|
|
2568
|
+
.map(t => {
|
|
2569
|
+
const config = configuracion.find(c => c.Titulo === t['Título']);
|
|
2570
|
+
if (config) {
|
|
2571
|
+
t['Posición'] = config.Posicion;
|
|
2572
|
+
if (config.ColorDeBorde) t.ColorDeBorde = config.ColorDeBorde;
|
|
2573
|
+
}
|
|
2574
|
+
const cantidades = cantidadesPorTitulo[t['Título']];
|
|
2575
|
+
if (cantidades) {
|
|
2576
|
+
t['Cantidad'] = cantidades.cantidad;
|
|
2577
|
+
t['CantidadMaxima'] = cantidades.cantidadMaxima;
|
|
2578
|
+
}
|
|
2579
|
+
return t;
|
|
2580
|
+
})
|
|
2581
|
+
.sort((a, b) => a['Posición'] - b['Posición']);
|
|
2582
|
+
}
|
|
2417
2583
|
}
|
|
2418
2584
|
|
|
2419
2585
|
module.exports = new Miscelaneo();
|
|
@@ -661,7 +661,7 @@ class ReportePDF {
|
|
|
661
661
|
|
|
662
662
|
// Función auxiliar para aplicar el formato y escribir el buffer
|
|
663
663
|
const flushText = (token, isLast) => {
|
|
664
|
-
if (token
|
|
664
|
+
if (!token) return;
|
|
665
665
|
|
|
666
666
|
let fontName = this.config.fuenteBase;
|
|
667
667
|
if (isBold && isItalic) fontName = this.config.fuenteNegritaCursiva;
|
|
@@ -37,3 +37,11 @@ CREATE OR REPLACE TABLE `NOMBRE_DEL_REPOSITORIO_DE_BASE_DE_DATOS`.`Configuracion
|
|
|
37
37
|
`LastUser` VARCHAR(1000) NOT NULL DEFAULT '-' COMMENT 'Último usuario que modificó la fila',
|
|
38
38
|
PRIMARY KEY (`Identificador`, `Titulo`)
|
|
39
39
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_spanish_ci COMMENT = 'Almacena la configuración de las tarjetas del contenedor principal por usuario';
|
|
40
|
+
|
|
41
|
+
CREATE OR REPLACE TABLE `NOMBRE_DEL_REPOSITORIO_DE_BASE_DE_DATOS`.`DatosMiscelaneos` (
|
|
42
|
+
`DatoMiscelaneo` VARCHAR(200) NOT NULL COMMENT 'Nombre del datos misceláneo que se desea almacenar',
|
|
43
|
+
`Datos` JSON NOT NULL COMMENT 'Configuración completa de la tarjeta: Tipo, Posición, Título, Descripción, Ícono, RutaASeguir, Rutas, ColorDeBorde, RequierePermisoExtra, Activo',
|
|
44
|
+
`LastUpdate` DATETIME(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4) ON UPDATE CURRENT_TIMESTAMP(4) COMMENT 'Fecha de la última actualización de la fila',
|
|
45
|
+
`LastUser` VARCHAR(1000) NOT NULL DEFAULT '-' COMMENT 'Último usuario que modificó la fila',
|
|
46
|
+
PRIMARY KEY (`DatoMiscelaneo`)
|
|
47
|
+
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_spanish_ci COMMENT = 'Datos misceláneos sobre el módulo';
|
|
@@ -16,22 +16,23 @@
|
|
|
16
16
|
"@angular/common": "^21.0.0",
|
|
17
17
|
"@angular/compiler": "^21.0.0",
|
|
18
18
|
"@angular/core": "^21.0.0",
|
|
19
|
-
"@angular/forms": "^21.2.
|
|
20
|
-
"@angular/material": "^21.2.
|
|
19
|
+
"@angular/forms": "^21.2.11",
|
|
20
|
+
"@angular/material": "^21.2.9",
|
|
21
21
|
"@angular/platform-browser": "^21.0.0",
|
|
22
|
-
"@angular/platform-browser-dynamic": "^21.2.
|
|
23
|
-
"@angular/router": "^21.2.
|
|
22
|
+
"@angular/platform-browser-dynamic": "^21.2.11",
|
|
23
|
+
"@angular/router": "^21.2.11",
|
|
24
24
|
"chart.js": "^4.5.1",
|
|
25
|
+
"marked": "^18.0.3",
|
|
25
26
|
"ng2-charts": "^8.0.0",
|
|
26
27
|
"rxjs": "~7.8.0",
|
|
27
28
|
"tslib": "^2.3.0",
|
|
28
29
|
"zone.js": "^0.16.1"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
|
-
"@angular-devkit/build-angular": "^21.2.
|
|
32
|
+
"@angular-devkit/build-angular": "^21.2.9",
|
|
32
33
|
"@angular/build": "^21.0.3",
|
|
33
|
-
"@angular/cli": "^21.2.
|
|
34
|
-
"@angular/compiler-cli": "^21.2.
|
|
34
|
+
"@angular/cli": "^21.2.9",
|
|
35
|
+
"@angular/compiler-cli": "^21.2.11",
|
|
35
36
|
"@types/jasmine": "^5.1.15",
|
|
36
37
|
"jasmine-core": "^5.13.0",
|
|
37
38
|
"jsdom": "^27.4.0",
|
|
@@ -41,6 +42,6 @@
|
|
|
41
42
|
"karma-jasmine": "^5.1.0",
|
|
42
43
|
"karma-jasmine-html-reporter": "^2.2.0",
|
|
43
44
|
"typescript": "~5.9.2",
|
|
44
|
-
"vitest": "^4.1.
|
|
45
|
+
"vitest": "^4.1.5"
|
|
45
46
|
}
|
|
46
47
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Manual de Usuario — Módulo de Mantenimientos V2
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component, OnInit } from '@angular/core';
|
|
1
|
+
import { Component, OnDestroy, OnInit } from '@angular/core';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import { HttpClient } from '@angular/common/http';
|
|
4
4
|
import { MatIconModule } from '@angular/material/icon';
|
|
@@ -8,6 +8,8 @@ import { MatButtonModule } from '@angular/material/button';
|
|
|
8
8
|
import { MatDialog } from '@angular/material/dialog';
|
|
9
9
|
import { MensajeConfirmacionComponent } from '../mensaje-confirmacion/mensaje-confirmacion';
|
|
10
10
|
import { DatosGlobalesService } from '../../../datos-globales.service';
|
|
11
|
+
import { Subject } from 'rxjs';
|
|
12
|
+
import { takeUntil } from 'rxjs/operators';
|
|
11
13
|
|
|
12
14
|
@Component({
|
|
13
15
|
selector: 'app-gestion-actividad',
|
|
@@ -16,10 +18,11 @@ import { DatosGlobalesService } from '../../../datos-globales.service';
|
|
|
16
18
|
templateUrl: './gestion-actividad.component.html',
|
|
17
19
|
styleUrls: ['./gestion-actividad.component.css']
|
|
18
20
|
})
|
|
19
|
-
export class GestionActividadComponent implements OnInit {
|
|
21
|
+
export class GestionActividadComponent implements OnInit, OnDestroy {
|
|
20
22
|
public actividad: any[] = [];
|
|
21
23
|
public cargando = false;
|
|
22
24
|
private tokenActual = '';
|
|
25
|
+
private _destroy$ = new Subject<void>();
|
|
23
26
|
|
|
24
27
|
constructor(private http: HttpClient, private datosGlobalesService: DatosGlobalesService, private dialog: MatDialog) { }
|
|
25
28
|
|
|
@@ -30,7 +33,7 @@ export class GestionActividadComponent implements OnInit {
|
|
|
30
33
|
|
|
31
34
|
obtenerActividad(): void {
|
|
32
35
|
this.cargando = true;
|
|
33
|
-
this.http.get(`${this.datosGlobalesService.ObtenerURL()}misc/ListarActividades`).subscribe({
|
|
36
|
+
this.http.get(`${this.datosGlobalesService.ObtenerURL()}misc/ListarActividades`).pipe(takeUntil(this._destroy$)).subscribe({
|
|
34
37
|
next: (datos: any) => {
|
|
35
38
|
this.actividad = datos.body;
|
|
36
39
|
},
|
|
@@ -69,6 +72,11 @@ export class GestionActividadComponent implements OnInit {
|
|
|
69
72
|
},
|
|
70
73
|
});
|
|
71
74
|
}
|
|
75
|
+
ngOnDestroy(): void {
|
|
76
|
+
this._destroy$.next();
|
|
77
|
+
this._destroy$.complete();
|
|
78
|
+
}
|
|
79
|
+
|
|
72
80
|
esSesionActual(token: string): boolean {
|
|
73
81
|
|
|
74
82
|
return token === this.tokenActual;
|