utn-cli 2.1.52 → 2.1.53

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.
Files changed (36) hide show
  1. package/package.json +1 -1
  2. package/templates/backend/rutas/misc.js +105 -0
  3. package/templates/backend/servicios/Nucleo/Miscelaneas.js +107 -16
  4. package/templates/frontend/public/conozcanos1.jpg +0 -0
  5. package/templates/frontend/public/preguntasF-1.png +0 -0
  6. package/templates/frontend/public/preguntasF-2.png +0 -0
  7. package/templates/frontend/public/preguntasF-3.png +0 -0
  8. package/templates/frontend/public/preguntasF-4.png +0 -0
  9. package/templates/frontend/public/preguntasF-5.png +0 -0
  10. package/templates/frontend/public/sabias-1.png +0 -0
  11. package/templates/frontend/public/sabias-10.png +0 -0
  12. package/templates/frontend/public/sabias-11.png +0 -0
  13. package/templates/frontend/public/sabias-2.png +0 -0
  14. package/templates/frontend/public/sabias-3.png +0 -0
  15. package/templates/frontend/public/sabias-4.png +0 -0
  16. package/templates/frontend/public/sabias-5.png +0 -0
  17. package/templates/frontend/public/sabias-6.png +0 -0
  18. package/templates/frontend/public/sabias-7.png +0 -0
  19. package/templates/frontend/public/sabias-8.png +0 -0
  20. package/templates/frontend/public/sabias-9.png +0 -0
  21. package/templates/frontend/src/app/Paginas/Nucleo/acercade/acercade.component.css +65 -0
  22. package/templates/frontend/src/app/Paginas/Nucleo/acercade/acercade.component.html +49 -0
  23. package/templates/frontend/src/app/Paginas/Nucleo/acercade/acercade.component.ts +20 -0
  24. package/templates/frontend/src/app/Paginas/Nucleo/conozcanos/conozcanos.component.css +608 -0
  25. package/templates/frontend/src/app/Paginas/Nucleo/conozcanos/conozcanos.component.html +109 -0
  26. package/templates/frontend/src/app/Paginas/Nucleo/conozcanos/conozcanos.component.ts +63 -0
  27. package/templates/frontend/src/app/Paginas/Nucleo/politicas/politicas.component.css +158 -0
  28. package/templates/frontend/src/app/Paginas/Nucleo/politicas/politicas.component.html +120 -0
  29. package/templates/frontend/src/app/Paginas/Nucleo/politicas/politicas.component.ts +33 -0
  30. package/templates/frontend/src/app/Paginas/Nucleo/preguntasFrecuentes/preguntasFrecuentes.component.css +162 -0
  31. package/templates/frontend/src/app/Paginas/Nucleo/preguntasFrecuentes/preguntasFrecuentes.component.html +97 -0
  32. package/templates/frontend/src/app/Paginas/Nucleo/preguntasFrecuentes/preguntasFrecuentes.component.ts +36 -0
  33. package/templates/frontend/src/app/Paginas/Nucleo/sabiasque/sabiasque.component.css +229 -0
  34. package/templates/frontend/src/app/Paginas/Nucleo/sabiasque/sabiasque.component.html +396 -0
  35. package/templates/frontend/src/app/Paginas/Nucleo/sabiasque/sabiasque.component.ts +51 -0
  36. package/templates/frontend/src/app/app.routes.ts +20 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "utn-cli",
3
- "version": "2.1.52",
3
+ "version": "2.1.53",
4
4
  "description": "Herramienta CLI unificada para la gestión de plantillas en SIGU.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1047,4 +1047,109 @@ Router.get('/calendarioPublico/:Anio?', async (solicitud, respuesta, next) => {
1047
1047
  }
1048
1048
  });
1049
1049
 
1050
+ Router.get('/obtenerEquipoDeDesarrolladores', async (solicitud, respuesta, next) => {
1051
+ try {
1052
+ if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
1053
+ try {
1054
+ return respuesta.json({ body: await Miscelaneo.obtenerEquipoDeDesarrolladores(), error: undefined });
1055
+ } catch (error) {
1056
+ const MensajeDeError = 'No fue posible obtener el equipo de desarrolladores';
1057
+ console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, `Dirección IP: ${solicitud.ip}`));
1058
+ return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
1059
+ }
1060
+ }
1061
+ return respuesta.status(401).json({ body: undefined, error: ManejadorDeErrores.mensajeDeError401() });
1062
+ } catch (error) {
1063
+ next(error);
1064
+ }
1065
+ });
1066
+
1067
+ Router.get('/VistaDePoliticas', async (solicitud, respuesta, next) => {
1068
+ try {
1069
+ if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
1070
+ try {
1071
+ await Miscelaneo.registrarVistaDePoliticas(solicitud.headers.authorization);
1072
+ return respuesta.json({ body: undefined, error: undefined });
1073
+ } catch (error) {
1074
+ const MensajeDeError = 'No fue posible registrar la vista de políticas de seguridad';
1075
+ console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, `Dirección IP: ${solicitud.ip}`));
1076
+ return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
1077
+ }
1078
+ }
1079
+ return respuesta.status(401).json({ body: undefined, error: ManejadorDeErrores.mensajeDeError401() });
1080
+ } catch (error) {
1081
+ next(error);
1082
+ }
1083
+ });
1084
+ Router.get('/VistaDeAcercaDe', async (solicitud, respuesta, next) => {
1085
+ try {
1086
+ if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
1087
+ try {
1088
+ await Miscelaneo.registrarVistaDeAcercaDe(solicitud.headers.authorization);
1089
+ return respuesta.json({ body: undefined, error: undefined });
1090
+ } catch (error) {
1091
+ const MensajeDeError = 'No fue posible registrar la vista de Acerca de';
1092
+ console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, `Dirección IP: ${solicitud.ip}`));
1093
+ return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
1094
+ }
1095
+ }
1096
+ return respuesta.status(401).json({ body: undefined, error: ManejadorDeErrores.mensajeDeError401() });
1097
+ } catch (error) {
1098
+ next(error);
1099
+ }
1100
+ });
1101
+ Router.get('/VistaDeConozcanos', async (solicitud, respuesta, next) => {
1102
+ try {
1103
+ if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
1104
+ try {
1105
+ await Miscelaneo.registrarVistaDeConozcanos(solicitud.headers.authorization);
1106
+ return respuesta.json({ body: undefined, error: undefined });
1107
+ } catch (error) {
1108
+ const MensajeDeError = 'No fue posible registrar la vista de conozcanos';
1109
+ console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, `Dirección IP: ${solicitud.ip}`));
1110
+ return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
1111
+ }
1112
+ }
1113
+ return respuesta.status(401).json({ body: undefined, error: ManejadorDeErrores.mensajeDeError401() });
1114
+ } catch (error) {
1115
+ next(error);
1116
+ }
1117
+ });
1118
+
1119
+ Router.get('/VistaDeSabiasQue', async (solicitud, respuesta, next) => {
1120
+ try {
1121
+ if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
1122
+ try {
1123
+ await Miscelaneo.registrarVistaDeSabiasQue(solicitud.headers.authorization);
1124
+ return respuesta.json({ body: undefined, error: undefined });
1125
+ } catch (error) {
1126
+ const MensajeDeError = 'No fue posible registrar la vista de sabías qué';
1127
+ console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, `Dirección IP: ${solicitud.ip}`));
1128
+ return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
1129
+ }
1130
+ }
1131
+ return respuesta.status(401).json({ body: undefined, error: ManejadorDeErrores.mensajeDeError401() });
1132
+ } catch (error) {
1133
+ next(error);
1134
+ }
1135
+ });
1136
+
1137
+ Router.get('/VistaDePreguntasFrecuentes', async (solicitud, respuesta, next) => {
1138
+ try {
1139
+ if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
1140
+ try {
1141
+ await Miscelaneo.registrarVistaDePreguntasFrecuentes(solicitud.headers.authorization);
1142
+ return respuesta.json({ body: undefined, error: undefined });
1143
+ } catch (error) {
1144
+ const MensajeDeError = 'No fue posible registrar la vista de preguntas frecuentes';
1145
+ console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, `Dirección IP: ${solicitud.ip}`));
1146
+ return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
1147
+ }
1148
+ }
1149
+ return respuesta.status(401).json({ body: undefined, error: ManejadorDeErrores.mensajeDeError401() });
1150
+ } catch (error) {
1151
+ next(error);
1152
+ }
1153
+ });
1154
+
1050
1155
  module.exports = Router;
@@ -45,30 +45,26 @@ class Miscelaneo {
45
45
  return await ejecutarConsultaSIGU(`SELECT * FROM \`SIGU\`.\`${NombreDeLaTabla}\``);
46
46
  }
47
47
 
48
- async PasosDeFlujoDeAprobacion(Identificador, PasoActual, Accion, Metadatos, Justificacion, LastUser) {
48
+ async PasosDeFlujoDeAprobacion(Identificador, PasoActual, Accion, Metadatos, Justificacion, LastUser, FlujoDeAprobacionId = undefined, RegistrarMovimiento = true) {
49
49
  const DatosARetornar = {};
50
50
 
51
51
  // Determina si la acción es una improbación para manejar el flujo de forma diferente
52
52
  const EsImprobacion = Accion === 'Improbacion';
53
53
 
54
54
  // Obtiene el ID del flujo de aprobación configurado para este módulo
55
- const idDelFlujoDeAprobacion = await this.idDelFlujoDeAprobacion();
56
-
55
+ const idDelFlujoDeAprobacion = FlujoDeAprobacionId ? FlujoDeAprobacionId : await this.idDelFlujoDeAprobacion();
57
56
  // Consulta cuál es el último paso del flujo, para saber si el detalle queda completamente aprobado
58
57
  const PasoMaximo = await ejecutarConsultaSIGU("SELECT MAX(`NumeroDePaso`) \
59
58
  AS `PasoMaximo` FROM `SIGU`.`SIGU_FlujosDeAprobacionPasos` WHERE \
60
59
  `FlujoDeAprobacionId` = ?"
61
60
  , [idDelFlujoDeAprobacion]);
62
-
63
61
  // En improbación el flujo retrocede, por lo que el paso siguiente se resuelve después;
64
62
  // en aprobación simplemente avanza al siguiente paso
65
63
  let PasoSiguiente = EsImprobacion ? PasoActual : PasoActual + 1;
66
-
67
64
  // Verifica que el usuario tenga permiso para actuar en el paso correspondiente
68
- const TienePermiso = await ejecutarConsultaSIGU("SELECT `NumeroDePasoPorImprobacion` FROM `SIGU`.`SIGU_FlujosDeAprobacionPasos` \
69
- WHERE `NumeroDePaso`=? AND (`Identificadores` LIKE '%?%' OR `Identificadores`='Persona usuaria')",
70
- [PasoSiguiente, Number(Identificador)]);
71
-
65
+ const TienePermiso = await ejecutarConsultaSIGU("SELECT `NumeroDePasoPorImprobacion`,`Identificadores` FROM `SIGU`.`SIGU_FlujosDeAprobacionPasos` \
66
+ WHERE `FlujoDeAprobacionId` = ? AND `NumeroDePaso` = ? AND (`Identificadores` LIKE ? OR `Identificadores`='Persona usuaria')",
67
+ [idDelFlujoDeAprobacion, PasoSiguiente, `%${Number(Identificador)}%`]);
72
68
  // Si el usuario no aparece como firmante autorizado del paso, se corta la ejecución
73
69
  if (TienePermiso.length == 0) {
74
70
  DatosARetornar.Mensaje = 'No tiene permisos para firmar este detalle';
@@ -77,11 +73,12 @@ class Miscelaneo {
77
73
  }
78
74
 
79
75
  // Registra el movimiento en el historial del flujo de aprobación
80
- await ejecutarConsultaSIGU("INSERT INTO `SIGU`.`SIGU_FlujosDeAprobacionMovimientos` VALUES (?, ?, ?, ?, ?, ?, NOW(4), ?)"
81
- , [idDelFlujoDeAprobacion, PasoActual
82
- , Identificador, Accion
83
- , Justificacion, JSON.stringify(Metadatos), LastUser]);
84
-
76
+ if (RegistrarMovimiento) {
77
+ await ejecutarConsultaSIGU("INSERT INTO `SIGU`.`SIGU_FlujosDeAprobacionMovimientos` VALUES (?, ?, ?, ?, ?, ?, NOW(4), ?)"
78
+ , [idDelFlujoDeAprobacion, PasoActual
79
+ , Identificador, Accion
80
+ , Justificacion, JSON.stringify(Metadatos), LastUser]);
81
+ }
85
82
  // En improbación, el paso destino viene definido en la configuración del flujo (retroceso configurado)
86
83
  PasoSiguiente = EsImprobacion ? TienePermiso[0].NumeroDePasoPorImprobacion : PasoSiguiente;
87
84
 
@@ -930,7 +927,12 @@ class Miscelaneo {
930
927
  }
931
928
 
932
929
  async obtenerMensajesInstitucionales() {
933
- return await ejecutarConsultaSIGU("SELECT `MensajeInstitucionalId`, `Titulo`, `Texto`, `FechaYHoraDeInicio`, `FechaYHoraDeFinalizacion` FROM `SIGU`.`SIGU_MensajesInstitucionales` WHERE NOW(4) BETWEEN `FechaYHoraDeInicio` AND `FechaYHoraDeFinalizacion`");
930
+ return await ejecutarConsultaSIGU("SELECT `MensajeInstitucionalId`, `Titulo`, `Texto`, `FechaYHoraDeInicio`, `FechaYHoraDeFinalizacion`,\
931
+ (SELECT CONCAT('https://framework-mantenimientosv2-storage.sigu.utn.ac.cr/', REPLACE(`adj`.`Ruta`, '/var/storage/public/', ''))\
932
+ FROM `SIGU`.`SIGU_Adjuntos` `adj`\
933
+ WHERE `adj`.`Modulo` = 'framework-mantenimientosv2' AND `adj`.`Etiqueta` = CONCAT('MensajeInstitucional-', `MensajeInstitucionalId`)\
934
+ ORDER BY `adj`.`LastUpdate` DESC LIMIT 1) AS `ImagenURL`\
935
+ FROM `SIGU`.`SIGU_MensajesInstitucionales` WHERE NOW(4) BETWEEN `FechaYHoraDeInicio` AND `FechaYHoraDeFinalizacion`");
934
936
  }
935
937
 
936
938
  async obtenerConsentimientoInformado(Modulo = undefined) {
@@ -997,6 +999,7 @@ class Miscelaneo {
997
999
  });
998
1000
  }
999
1001
 
1002
+
1000
1003
  async crearNotificacion(IdentificadorDelUsuario, IdentificadorDelDestinatario, Mensaje) {
1001
1004
  return await ejecutarConsultaSIGU("INSERT INTO `SIGU`.`SIGU_NotificacionesV2` VALUES (?, ?, 'Sin leer', NOW(4), NOW(4), ?)"
1002
1005
  , [IdentificadorDelDestinatario, Mensaje, IdentificadorDelUsuario]);
@@ -1689,7 +1692,7 @@ class Miscelaneo {
1689
1692
  convertirACSV(ArregloDeJSON) {
1690
1693
  if (!ArregloDeJSON || ArregloDeJSON.length === 0) return '';
1691
1694
  const intentarParsearJSON = (valor) => {
1692
- if (typeof valor === 'object' && valor !== null && !Array.isArray(valor)) return valor;
1695
+ if (typeof valor === 'object' && valor !== null && !Array.isArray(valor) && !(valor instanceof Date)) return valor;
1693
1696
  if (typeof valor === 'string' && valor.trim().startsWith('{')) {
1694
1697
  try {
1695
1698
  const objeto = JSON.parse(valor);
@@ -2768,6 +2771,94 @@ class Miscelaneo {
2768
2771
  calendario.Periodos = [...periodosMap.values()];
2769
2772
  return calendario;
2770
2773
  }
2774
+
2775
+ async obtenerEquipoDeDesarrolladores() {
2776
+ const desarrolladores = await ejecutarConsultaSIGU(`
2777
+ SELECT
2778
+ e.Identificador,
2779
+ CONCAT_WS(' ', p.Nombre, p.PrimerApellido, p.SegundoApellido) AS NombreCompleto,
2780
+ e.Biografia,
2781
+ e.Perfil
2782
+ FROM SIGU.SIGU_EquipoDeDesarrolladores e
2783
+ JOIN SIGU.SIGU_Personas p ON e.Identificador = p.Identificador
2784
+ ORDER BY NombreCompleto ASC
2785
+ `);
2786
+
2787
+ for (const desarrollador of desarrolladores) {
2788
+ const adjunto = await ejecutarConsultaSIGU(
2789
+ "SELECT `Ruta` FROM `SIGU`.`SIGU_Adjuntos`\
2790
+ WHERE `Modulo` = 'framework-mantenimientosv2' AND `Etiqueta` = ?\
2791
+ ORDER BY `LastUpdate` DESC LIMIT 1",
2792
+ [`EquipoDeDesarrolladores-${desarrollador.Identificador}`]
2793
+ );
2794
+ desarrollador.FotoURL = adjunto && adjunto.length > 0
2795
+ ? 'https://framework-mantenimientosv2-storage.sigu.utn.ac.cr/' + adjunto[0].Ruta.replace('/var/storage/public/', '')
2796
+ : null;
2797
+ }
2798
+
2799
+ return desarrolladores;
2800
+ }
2801
+
2802
+ async registrarVistaDePoliticas(Token) {
2803
+ const { uid } = await this.obtenerDatosDelUsuario(Token);
2804
+ await ejecutarConsulta(
2805
+ "INSERT INTO DatosMiscelaneos (DatoMiscelaneo, Datos, LastUser) VALUES ('VistasDePoliticas', JSON_OBJECT('Total', 1), ?) ON DUPLICATE KEY UPDATE Datos = JSON_SET(Datos, '$.Total', CAST(JSON_VALUE(Datos, '$.Total') AS UNSIGNED) + 1), LastUser = ?",
2806
+ [uid, uid]
2807
+ );
2808
+ }
2809
+
2810
+ async registrarVistaDeAcercaDe(Token) {
2811
+ const { uid } = await this.obtenerDatosDelUsuario(Token);
2812
+ await ejecutarConsulta(
2813
+ "INSERT INTO DatosMiscelaneos (DatoMiscelaneo, Datos, LastUser) VALUES ('VistasDeAcercaDe', JSON_OBJECT('Total', 1), ?) ON DUPLICATE KEY UPDATE Datos = JSON_SET(Datos, '$.Total', CAST(JSON_VALUE(Datos, '$.Total') AS UNSIGNED) + 1), LastUser = ?",
2814
+ [uid, uid]
2815
+ );
2816
+ }
2817
+
2818
+ async registrarVistaDeConozcanos(Token) {
2819
+ const { uid } = await this.obtenerDatosDelUsuario(Token);
2820
+ await ejecutarConsulta(
2821
+ "INSERT INTO DatosMiscelaneos (DatoMiscelaneo, Datos, LastUser) VALUES ('VistasDeConozcanos', JSON_OBJECT('Total', 1), ?) ON DUPLICATE KEY UPDATE Datos = JSON_SET(Datos, '$.Total', CAST(JSON_VALUE(Datos, '$.Total') AS UNSIGNED) + 1), LastUser = ?",
2822
+ [uid, uid]
2823
+ );
2824
+ }
2825
+
2826
+ async registrarVistaDeSabiasQue(Token) {
2827
+ const { uid } = await this.obtenerDatosDelUsuario(Token);
2828
+ await ejecutarConsulta(
2829
+ "INSERT INTO DatosMiscelaneos (DatoMiscelaneo, Datos, LastUser) VALUES ('VistasDeSabiasQue', JSON_OBJECT('Total', 1), ?) ON DUPLICATE KEY UPDATE Datos = JSON_SET(Datos, '$.Total', CAST(JSON_VALUE(Datos, '$.Total') AS UNSIGNED) + 1), LastUser = ?",
2830
+ [uid, uid]
2831
+ );
2832
+ }
2833
+
2834
+ async registrarVistaDePreguntasFrecuentes(Token) {
2835
+ const { uid } = await this.obtenerDatosDelUsuario(Token);
2836
+ await ejecutarConsulta(
2837
+ "INSERT INTO DatosMiscelaneos (DatoMiscelaneo, Datos, LastUser) VALUES ('VistasDePreguntasFrecuentes', JSON_OBJECT('Total', 1), ?) ON DUPLICATE KEY UPDATE Datos = JSON_SET(Datos, '$.Total', CAST(JSON_VALUE(Datos, '$.Total') AS UNSIGNED) + 1), LastUser = ?",
2838
+ [uid, uid]
2839
+ );
2840
+ }
2841
+
2842
+ async obtenerVistas() {
2843
+ const [manual, modulo, politicas, acercade, conozcanos, sabiasque, preguntasFrecuentes] = await Promise.all([
2844
+ ejecutarConsulta("SELECT CAST(JSON_VALUE(Datos, '$.Total') AS UNSIGNED) AS Total FROM DatosMiscelaneos WHERE DatoMiscelaneo = 'VistasDelManual'"),
2845
+ ejecutarConsulta("SELECT CAST(JSON_VALUE(Datos, '$.Total') AS UNSIGNED) AS Total FROM DatosMiscelaneos WHERE DatoMiscelaneo = 'VistasDelModulo'"),
2846
+ ejecutarConsulta("SELECT CAST(JSON_VALUE(Datos, '$.Total') AS UNSIGNED) AS Total FROM DatosMiscelaneos WHERE DatoMiscelaneo = 'VistasDePoliticas'"),
2847
+ ejecutarConsulta("SELECT CAST(JSON_VALUE(Datos, '$.Total') AS UNSIGNED) AS Total FROM DatosMiscelaneos WHERE DatoMiscelaneo = 'VistasDeAcercaDe'"),
2848
+ ejecutarConsulta("SELECT CAST(JSON_VALUE(Datos, '$.Total') AS UNSIGNED) AS Total FROM DatosMiscelaneos WHERE DatoMiscelaneo = 'VistasDeConozcanos'"),
2849
+ ejecutarConsulta("SELECT CAST(JSON_VALUE(Datos, '$.Total') AS UNSIGNED) AS Total FROM DatosMiscelaneos WHERE DatoMiscelaneo = 'VistasDeSabiasQue'"),
2850
+ ejecutarConsulta("SELECT CAST(JSON_VALUE(Datos, '$.Total') AS UNSIGNED) AS Total FROM DatosMiscelaneos WHERE DatoMiscelaneo = 'VistasDePreguntasFrecuentes'"),
2851
+ ]);
2852
+ return {
2853
+ VistasDelManual: manual[0]?.Total ?? 0,
2854
+ VistasDelModulo: modulo[0]?.Total ?? 0,
2855
+ VistasDePoliticas: politicas[0]?.Total ?? 0,
2856
+ VistasDeAcercaDe: acercade[0]?.Total ?? 0,
2857
+ VistasDeConozcanos: conozcanos[0]?.Total ?? 0,
2858
+ VistasDeSabiasQue: sabiasque[0]?.Total ?? 0,
2859
+ VistasDePreguntasFrecuentes: preguntasFrecuentes[0]?.Total ?? 0,
2860
+ };
2861
+ }
2771
2862
  }
2772
2863
 
2773
2864
  module.exports = new Miscelaneo();
@@ -0,0 +1,65 @@
1
+ .politicas-container {
2
+ max-width: 1000px;
3
+ padding-bottom: 20px;
4
+ font-family: 'Roboto', sans-serif;
5
+ background-color: white;
6
+ text-align: left;
7
+ margin: 0 auto;
8
+ }
9
+
10
+ .subtitle {
11
+ background-color: #0b4794;
12
+ font-size: 25px;
13
+ color: white;
14
+ padding: 18px;
15
+ margin: 20px 0;
16
+ text-align: center;
17
+ }
18
+ .subtitle p {
19
+ margin: 5px 0;
20
+ }
21
+ .description {
22
+ width: 100%;
23
+ padding-left: 30px;
24
+ padding-right: 30px;
25
+ box-sizing: border-box;
26
+ margin-top: 30px;
27
+ }
28
+
29
+ .description p {
30
+ margin: 15px 0;
31
+ font-size: 16px;
32
+ font-weight: 400;
33
+ color: #4D4D4D;
34
+ line-height: 1.6;
35
+ }
36
+
37
+ .description ul {
38
+ padding-left: 20px;
39
+ margin-top: 10px;
40
+ }
41
+
42
+ .description li {
43
+ list-style-type: disc;
44
+ margin-bottom: 10px;
45
+ color: #4D4D4D;
46
+ font-size: 16px;
47
+ }
48
+ .description li::marker {
49
+ color: #0b4794;
50
+ }
51
+ @media (max-width: 768px) {
52
+ .description {
53
+ padding-left: 20px;
54
+ padding-right: 20px;
55
+ }
56
+
57
+ .description p {
58
+ font-size: 14px;
59
+ }
60
+
61
+ .description li{
62
+ font-size: 14px;
63
+ }
64
+ }
65
+
@@ -0,0 +1,49 @@
1
+ <div class="subtitle">
2
+ <p>¿Qué es SIGU?</p>
3
+ </div>
4
+ <div class="politicas-container">
5
+
6
+ <div class="description">
7
+ <p>El Sistema Integrado de Gestión Universitaria (SIGU) es la plataforma digital de la Universidad Técnica Nacional
8
+ diseñada para centralizar y facilitar la gestión de servicios académicos, administrativos e institucionales.
9
+ </p>
10
+ <p>SIGU nace con el propósito de modernizar y optimizar los procesos institucionales que permitan a estudiantes,
11
+ docentes, personal administrativo, aspirantes, clientes y público en general acceder a distintos servicios
12
+ universitarios desde una plataforma segura, accesible y eficiente.
13
+ </p>
14
+ <P>
15
+ La plataforma integra funcionalidades relacionadas con procesos académicos, solicitudes institucionales, gestión
16
+ administrativa, autenticación de usuarios y acceso a información universitaria, permitiendo centralizar y mejorar
17
+ la experiencia digital y fortalecer la interacción entre la Universidad y sus usuarios.
18
+ </P>
19
+ <P>
20
+ Asimismo, SIGU busca ser una plataforma universitaria moderna, innovadora, accesible y en constante evolución,
21
+ comprometida con la mejora continua de los servicios digitales institucionales, el fortalecimiento de la gestión
22
+ universitaria y el uso responsable y seguro de la información, contribuyendo así a una experiencia tecnológica más
23
+ eficiente, transparente y orientada a las necesidades de la comunidad universitaria.
24
+ </P>
25
+ <P><strong>
26
+ El Sistema Integrado de Gestión Universitaria (SIGU) ofrece principios enfocados en la mejora continua de los
27
+ servicios digitales universitarios como:
28
+ </strong>
29
+ </P>
30
+ <ul>
31
+ <li>Eficiencia: SIGU busca optimizar los procesos académicos y administrativos mediante herramientas tecnológicas
32
+ que faciliten el acceso ágil y centralizado a los servicios institucionales.</li>
33
+ <li>Confiabilidad: La plataforma procura garantizar integridad y disponibilidad de la información, permitiendo a
34
+ los usuarios realizar sus gestiones dentro de un entorno confiable.
35
+ </li>
36
+ <li>Accesibilidad: SIGU facilita el acceso inmediato a la información y a los módulos de servicios, asegurando una
37
+ experiencia digital fluida para todos los usuarios registrados.</li>
38
+ <li>Seguridad: La plataforma incorpora medidas de seguridad informática y protección de datos personales, con el
39
+ fin de resguardar la información institucional y la privacidad de los usuarios.</li>
40
+ <li>Organización: SIGU centraliza distintos procesos y servicios universitarios en una única plataforma digital,
41
+ permitiendo una gestión más ordenada y eficiente de la información.</li>
42
+ </ul>
43
+
44
+ <P>La Universidad Técnica Nacional trabaja continuamente en el desarrollo y actualización de la plataforma, con el
45
+ objetivo de ofrecer servicios digitales más modernos y adaptados a las necesidades de la comunidad universitaria.
46
+ </P>
47
+ </div>
48
+
49
+ </div>
@@ -0,0 +1,20 @@
1
+ import { Component, OnInit } from '@angular/core';
2
+ import { MatIconModule } from '@angular/material/icon';
3
+ import { DatosGlobalesService } from '../../../datos-globales.service';
4
+ import { HttpClient } from '@angular/common/http';
5
+ import { takeUntil } from 'rxjs/operators';
6
+ import { Subject } from 'rxjs';
7
+ @Component({
8
+ selector: 'app-acercade',
9
+ standalone: true,
10
+ imports: [MatIconModule],
11
+ templateUrl: './acercade.component.html',
12
+ styleUrl: './acercade.component.css'
13
+ })
14
+ export class AcercadeComponent implements OnInit {
15
+ private _destroy$ = new Subject<void>();
16
+ constructor(private http: HttpClient, private datosGlobalesService: DatosGlobalesService) { }
17
+ ngOnInit(): void {
18
+ this.http.get(`${this.datosGlobalesService.ObtenerURL()}misc/VistaDeAcercaDe`).pipe(takeUntil(this._destroy$)).subscribe({ error: () => { } });
19
+ }
20
+ }