wm-menu 1.2.9 → 1.4.0

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 (32) hide show
  1. package/bundles/wm-menu.umd.js +368 -31
  2. package/bundles/wm-menu.umd.js.map +1 -1
  3. package/bundles/wm-menu.umd.min.js +2 -2
  4. package/bundles/wm-menu.umd.min.js.map +1 -1
  5. package/esm2015/lib/wm-menu/asistente-datos/asistente-datos-api.service.js +52 -0
  6. package/esm2015/lib/wm-menu/asistente-datos/asistente-datos.component.js +178 -0
  7. package/esm2015/lib/wm-menu/asistente-datos/reconocimiento-voz.service.js +77 -0
  8. package/esm2015/lib/wm-menu/services/wm-menu-alerta-panico.service.js +4 -21
  9. package/esm2015/lib/wm-menu/services/wm-menu-servicio.service.js +9 -1
  10. package/esm2015/lib/wm-menu/wm-menu.component.js +35 -7
  11. package/esm2015/lib/wm-menu.module.js +9 -2
  12. package/esm2015/wm-menu.js +4 -1
  13. package/esm5/lib/wm-menu/asistente-datos/asistente-datos-api.service.js +53 -0
  14. package/esm5/lib/wm-menu/asistente-datos/asistente-datos.component.js +194 -0
  15. package/esm5/lib/wm-menu/asistente-datos/reconocimiento-voz.service.js +79 -0
  16. package/esm5/lib/wm-menu/services/wm-menu-alerta-panico.service.js +4 -21
  17. package/esm5/lib/wm-menu/services/wm-menu-servicio.service.js +9 -1
  18. package/esm5/lib/wm-menu/wm-menu.component.js +39 -7
  19. package/esm5/lib/wm-menu.module.js +9 -2
  20. package/esm5/wm-menu.js +4 -1
  21. package/fesm2015/wm-menu.js +343 -29
  22. package/fesm2015/wm-menu.js.map +1 -1
  23. package/fesm5/wm-menu.js +366 -29
  24. package/fesm5/wm-menu.js.map +1 -1
  25. package/lib/wm-menu/asistente-datos/asistente-datos-api.service.d.ts +26 -0
  26. package/lib/wm-menu/asistente-datos/asistente-datos.component.d.ts +39 -0
  27. package/lib/wm-menu/asistente-datos/reconocimiento-voz.service.d.ts +7 -0
  28. package/lib/wm-menu/services/wm-menu-servicio.service.d.ts +1 -0
  29. package/lib/wm-menu/wm-menu.component.d.ts +10 -3
  30. package/package.json +1 -1
  31. package/wm-menu.d.ts +3 -0
  32. package/wm-menu.metadata.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { __decorate } from 'tslib';
2
- import { ɵɵdefineInjectable, ɵɵinject, Injectable, Input, Component, NgModule } from '@angular/core';
2
+ import { ɵɵdefineInjectable, ɵɵinject, Injectable, Input, Component, EventEmitter, ViewChild, Output, NgModule } from '@angular/core';
3
3
  import { HttpHeaders, HttpParams, HttpClient, HttpClientModule } from '@angular/common/http';
4
4
  import { map, catchError } from 'rxjs/operators';
5
5
  import { throwError } from 'rxjs';
@@ -11,7 +11,10 @@ import { MatSidenavModule } from '@angular/material/sidenav';
11
11
  import { MatListModule } from '@angular/material/list';
12
12
  import { MatButtonModule } from '@angular/material/button';
13
13
  import { MatMenuModule } from '@angular/material/menu';
14
+ import { MatTableModule } from '@angular/material/table';
15
+ import { MatTooltipModule } from '@angular/material/tooltip';
14
16
  import { MatRippleModule } from '@angular/material/core';
17
+ import { FormsModule } from '@angular/forms';
15
18
 
16
19
  class MenuSecundario {
17
20
  constructor() {
@@ -95,6 +98,14 @@ let WmMenuServicioService = class WmMenuServicioService {
95
98
  return throwError(error.error);
96
99
  }));
97
100
  }
101
+ // Funciones (permisos) del usuario autenticado, para gatear features del menú como el
102
+ // asistente "Pregúntale a tus datos" (CodigoLogica === 'WebChatConsultaIA').
103
+ funcionesObtener(url, token) {
104
+ const headers = new HttpHeaders({
105
+ 'Authorization': `Bearer ${token}`
106
+ });
107
+ return this.http.get(url, { headers }).pipe(map(resp => resp), catchError(error => throwError(error.error)));
108
+ }
98
109
  };
99
110
  WmMenuServicioService.ctorParameters = () => [
100
111
  { type: HttpClient },
@@ -117,27 +128,22 @@ let WmMenuAlertaPanicoService = class WmMenuAlertaPanicoService {
117
128
  this.IdsAlertasPanicoActivas = new Set(); // Almacena los IDs de las alertas ya manejadas
118
129
  this.soundTimeout = null; // Controla el temporizador del sonido
119
130
  this.isRunning = false;
120
- console.log('WmMenuAlertaPanicoService inicializado.');
121
131
  }
122
132
  iniciarProceso(intervalMs, callback, urlObtenerParametro, token, rutaAudio) {
123
- console.log('iniciarProceso llamado con parámetros:', { intervalMs, urlObtenerParametro, token, rutaAudio });
124
133
  this.rutaAudio = rutaAudio;
125
134
  const iniciarConInteraccion = () => {
126
- console.log('iniciarConInteraccion ejecutado.');
127
135
  this.wmMenuServicioService
128
136
  .menuApiObtener(urlObtenerParametro, null, token, 'ReporteAlertasPanico')
129
137
  .subscribe((resp) => {
130
- console.log('Respuesta obtenida de menuApiObtener:', resp);
138
+ // validar si el parametro ReporteAlertasPanico esta encendido
131
139
  if (resp && resp.length > 0 && resp[0].Valor == 1) {
132
140
  if (this.isRunning) {
133
- console.log('Proceso ya está corriendo.');
134
141
  return;
135
142
  }
143
+ // Inicializar la variable desde localStorage
136
144
  const storedIds = localStorage.getItem('ALERTAS_PANICO_ACTIVAS_WM');
137
145
  this.IdsAlertasPanicoActivas = storedIds ? new Set(JSON.parse(storedIds)) : new Set();
138
- console.log('IdsAlertasPanicoActivas inicializado:', this.IdsAlertasPanicoActivas);
139
146
  const ejecutarProceso = () => {
140
- console.log('ejecutarProceso iniciado.');
141
147
  this.isRunning = true;
142
148
  callback();
143
149
  setTimeout(() => {
@@ -150,48 +156,41 @@ let WmMenuAlertaPanicoService = class WmMenuAlertaPanicoService {
150
156
  });
151
157
  };
152
158
  ['drag', 'click'].forEach(evento => {
153
- console.log(`Evento ${evento} registrado para iniciar proceso.`);
154
159
  document.addEventListener(evento, () => {
155
160
  iniciarConInteraccion();
156
161
  }, { once: true });
157
162
  });
158
163
  }
159
164
  stopProcess() {
160
- console.log('stopProcess ejecutado.');
161
165
  this.isRunning = false;
162
166
  if (this.subscription) {
163
167
  this.subscription.unsubscribe();
164
168
  }
165
169
  }
166
170
  ngOnDestroy() {
167
- console.log('ngOnDestroy ejecutado.');
168
171
  this.stopSound();
169
172
  this.stopFlashingTitle();
170
173
  }
171
174
  playSound() {
172
- console.log('playSound llamado.');
173
175
  if (this.isPlaying)
174
176
  return; // Evita reproducir si ya está sonando
175
177
  this.isPlaying = true;
176
178
  if (!this.audio) {
177
179
  this.audio = new Audio(this.rutaAudio); // Ruta al archivo de sonido
178
180
  }
179
- console.log("Audio cargado: ", this.audio);
180
181
  this.audio.loop = true; // Reproducir en bucle
181
182
  this.audio.play()
182
183
  .then(() => {
183
- console.log('Sonido reproduciéndose.');
184
184
  // Detener el sonido después de 10 segundos
185
185
  this.soundTimeout = setTimeout(() => {
186
186
  this.stopSound();
187
187
  }, 10000); // Detener después de 10 segundos
188
188
  })
189
189
  .catch(error => {
190
- console.error('Error al reproducir el sonido:', error);
190
+ console.log('Error al reproducir el sonido:', error);
191
191
  });
192
192
  }
193
193
  stopSound() {
194
- console.log('stopSound llamado.');
195
194
  if (this.audio) {
196
195
  this.audio.pause();
197
196
  this.audio.currentTime = 0; // Reinicia el sonido
@@ -203,7 +202,6 @@ let WmMenuAlertaPanicoService = class WmMenuAlertaPanicoService {
203
202
  }
204
203
  }
205
204
  startFlashingTitle() {
206
- console.log('startFlashingTitle llamado.');
207
205
  let toggle = false;
208
206
  // Almacenar el título original si aún no se ha guardado
209
207
  if (!this.originalTitle) {
@@ -218,7 +216,6 @@ let WmMenuAlertaPanicoService = class WmMenuAlertaPanicoService {
218
216
  }
219
217
  }
220
218
  stopFlashingTitle() {
221
- console.log('stopFlashingTitle llamado.');
222
219
  if (this.intervalId) {
223
220
  clearInterval(this.intervalId);
224
221
  this.intervalId = null;
@@ -226,16 +223,13 @@ let WmMenuAlertaPanicoService = class WmMenuAlertaPanicoService {
226
223
  }
227
224
  }
228
225
  revisarAlertasPendientes(urlObtenerAlertasPanico, token) {
229
- console.log('revisarAlertasPendientes llamado con parámetros:', { urlObtenerAlertasPanico, token });
230
226
  const helper = new JwtHelperService();
231
227
  const decodedToken = helper.decodeToken(token);
232
228
  this.wmMenuServicioService
233
229
  .menuApiObtener(urlObtenerAlertasPanico, decodedToken['id_usuario'], token)
234
230
  .subscribe((resp) => {
235
- console.log('Respuesta obtenida de revisarAlertasPendientes:', resp);
236
231
  if (resp && resp.length > 0) {
237
232
  const alertasIds = resp.map(alerta => alerta.IdAlertaPanico);
238
- console.log('IDs de alertas obtenidas:', alertasIds);
239
233
  // Eliminar IDs que no están en la respuesta del servicio
240
234
  this.IdsAlertasPanicoActivas.forEach((id) => {
241
235
  if (!alertasIds.includes(id)) {
@@ -275,17 +269,33 @@ WmMenuAlertaPanicoService = __decorate([
275
269
  ], WmMenuAlertaPanicoService);
276
270
 
277
271
  let WmMenuComponent = class WmMenuComponent {
278
- constructor(wmMenuServicioService, wmMenuAlertaPanicoService) {
272
+ constructor(wmMenuServicioService, alertaPanicoService) {
279
273
  this.wmMenuServicioService = wmMenuServicioService;
280
- this.wmMenuAlertaPanicoService = wmMenuAlertaPanicoService;
281
- this.intervaloPeticionesMs = 60000;
274
+ this.alertaPanicoService = alertaPanicoService;
275
+ this.mostrarAsistente = false;
276
+ this.idiomaAsistente = 'es-CO';
277
+ this.asistenteAbierto = false;
278
+ this.funcionesUsuario = [];
282
279
  this.menuSecundarioSel = new MenuSecundario();
283
280
  this.menuLateralAbierto = false;
284
281
  this.menuIdioma = [];
282
+ this.intervaloPeticionesMs = 60000;
283
+ }
284
+ get puedeAsistente() {
285
+ const forzado = this.mostrarAsistente === true || this.mostrarAsistente === 'true' || this.mostrarAsistente === '1';
286
+ const tienePermiso = this.funcionesUsuario.some((f) => f.CodigoLogica === 'WebChatConsultaIA');
287
+ return forzado || tienePermiso;
285
288
  }
286
289
  ngOnInit() {
287
- this.wmMenuAlertaPanicoService.iniciarProceso(this.intervaloPeticionesMs, () => this.wmMenuAlertaPanicoService.revisarAlertasPendientes(this.urlObtenerAlertasPanico, this.token), this.urlObtenerParametro, this.token, this.rutaAudio);
288
290
  this.cargarMenuCuenta();
291
+ this.alertaPanicoService.iniciarProceso(this.intervaloPeticionesMs, () => this.alertaPanicoService.revisarAlertasPendientes(this.urlObtenerAlertasPanico, this.token), this.urlObtenerParametro, this.token, this.rutaAudio);
292
+ // Carga las funciones del usuario para gatear el asistente (puedeAsistente / WebChatConsultaIA).
293
+ // Si falla (ej. 401), queda vacía y el asistente no se muestra.
294
+ if (this.urlObtenerFunciones && this.token) {
295
+ this.wmMenuServicioService
296
+ .funcionesObtener(this.urlObtenerFunciones, this.token)
297
+ .subscribe((resp) => { this.funcionesUsuario = (resp !== null && resp !== void 0 ? resp : []); }, () => { this.funcionesUsuario = []; });
298
+ }
289
299
  if (this.urlMenu && this.token) {
290
300
  var helper = new JwtHelperService();
291
301
  const decodedToken = helper.decodeToken(this.token);
@@ -408,27 +418,331 @@ __decorate([
408
418
  __decorate([
409
419
  Input()
410
420
  ], WmMenuComponent.prototype, "urlIdiomas", void 0);
421
+ __decorate([
422
+ Input()
423
+ ], WmMenuComponent.prototype, "urlObtenerFunciones", void 0);
424
+ __decorate([
425
+ Input()
426
+ ], WmMenuComponent.prototype, "mostrarAsistente", void 0);
427
+ __decorate([
428
+ Input()
429
+ ], WmMenuComponent.prototype, "urlAsistenteConsultar", void 0);
430
+ __decorate([
431
+ Input()
432
+ ], WmMenuComponent.prototype, "idiomaAsistente", void 0);
411
433
  WmMenuComponent = __decorate([
412
434
  Component({
413
435
  selector: 'wm-menu',
414
- template: "<div class=\"menu\" [ngStyle]=\"{'background-color': colorFondo, 'color': colorTexto}\">\r\n <div class=\"d-lg-none\">\r\n <button mat-icon-button (click)=\"menuLateralAbierto=!menuLateralAbierto; menuPrincipalSel = null\">\r\n <mat-icon *ngIf=\"!menuLateralAbierto\" class=\"animate__animated animate__fadeInRight animate__faster\">menu\r\n </mat-icon>\r\n <mat-icon *ngIf=\"menuLateralAbierto\" class=\"animate__animated animate__fadeInLeft animate__faster\">close\r\n </mat-icon>\r\n </button>\r\n </div>\r\n <div class=\"d-lg-none logo-menu-principal\">\r\n <img class=\"logo\" src=\"{{logo}}\">\r\n </div>\r\n <div class=\"d-none d-lg-block\">\r\n <img class=\"logo\" src=\"{{logo}}\">\r\n <div *ngFor=\"let menuItem of menuPrincipal; let i=index\" class=\"d-inline-block\">\r\n\r\n <a *ngIf=\"menuItem.url\" mat-button [href]=\"menuItem.url\" (click)=\"clickMenuPrincipal(i)\">\r\n {{menuItem.titulo}}\r\n </a>\r\n <button *ngIf=\"!menuItem.url\" mat-button (click)=\"clickMenuPrincipal(i)\">\r\n {{menuItem.titulo}}\r\n </button>\r\n </div>\r\n </div>\r\n <div class=\"info-adicional\">\r\n <div class=\"datos border-r mt-1\" *ngIf=\"nombreCliente\">{{nombreCliente}}<mat-icon>people</mat-icon></div>\r\n <div class=\"datos border-r mt-1\" *ngIf=\"nombreUsuario\">{{nombreUsuario}}<mat-icon>person_outline</mat-icon></div>\r\n <div class=\"version\" *ngIf=\"versionWeb\">{{versionWeb}}</div>\r\n <div class=\"content-idioma\" *ngIf=\"urlIdiomas\">\r\n <mat-menu #menuIdiomas=\"matMenu\">\r\n <a mat-menu-item *ngFor=\"let menuItem of menuIdioma.Culturas\" href=\"{{urlCuentaSeguridad}}CambiarIdioma?culture={{menuItem.Name}}&ReturnUrl=/\">\r\n {{menuItem.NativeName}}\r\n </a>\r\n </mat-menu>\r\n <button mat-button [matMenuTriggerFor]=\"menuIdiomas\"><label class=\"mt-1\">{{menuIdioma.Lenguaje}}</label><mat-icon class=\"icon-idioma\">language</mat-icon></button>\r\n </div>\r\n\r\n </div>\r\n <div>\r\n <mat-menu #submenu=\"matMenu\">\r\n <a mat-menu-item *ngFor=\"let menuItem of menuSecundarioSel.hijos\" href=\"{{menuItem.url}}\"\r\n [disabled]=\"!menuItem.url\">\r\n <mat-icon *ngIf=\"menuItem.icono\">{{menuItem.icono}}</mat-icon>\r\n {{menuItem.titulo}}\r\n </a>\r\n </mat-menu>\r\n <button *ngFor=\"let menuItem of menuSecundario; let i = index\" mat-icon-button [matMenuTriggerFor]=\"submenu\"\r\n (click)=\"clickMenuSecundario(i)\">\r\n <mat-icon>{{menuItem.icono}}</mat-icon>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<div class=\"menu-lateral d-lg-none animate__animated animate__fadeInRight animate__faster\" *ngIf=\"menuLateralAbierto\">\r\n <div class=\"row\">\r\n <div *ngFor=\"let menuItem of menuPrincipal; let i=index\" class=\"col-sm-6 col-md-4\">\r\n <a *ngIf=\"menuItem.url\" [href]=\"menuItem.url\" (click)=\"clickMenuPrincipal(i)\">\r\n <div>\r\n <mat-icon svgIcon=\"{{menuItem.icono}}\">{{menuItem.icono}}</mat-icon>\r\n <p>{{menuItem.titulo}}</p>\r\n </div>\r\n </a>\r\n <span *ngIf=\"!menuItem.url\" (click)=\"clickMenuPrincipal(i)\">\r\n <div>\r\n <mat-icon svgIcon=\"{{menuItem.icono}}\">{{menuItem.icono}}</mat-icon>\r\n <p>{{menuItem.titulo}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div class=\"sub-menu-fondo animate__animated animate__fadeIn animate__faster\" (click)=\"menuPrincipalSel=null\"\r\n *ngIf=\"menuPrincipalSel\"></div>\r\n\r\n<div class=\"sub-menu animate__animated animate__fadeIn animate__faster\" *ngIf=\"menuPrincipalSel\">\r\n <div class=\"container-fluid\">\r\n <div class=\"row\">\r\n <div class=\"col-12 col-lg-5\">\r\n <div class=\"px-3 px-sm-5 pt-5 pb-lg-5 text-center descripcion-menu\">\r\n <mat-icon [ngStyle]=\"{'color': colorFondo}\" svgIcon=\"{{menuPrincipalSel.icono}}\">\r\n {{menuPrincipalSel.icono}}</mat-icon>\r\n <p>{{menuPrincipalSel.titulo}}</p>\r\n <p class=\"text-secondary\">{{menuPrincipalSel.descripcion}}</p>\r\n </div>\r\n </div>\r\n <div class=\"col-12 col-lg-7 my-4\">\r\n <div class=\"px-3 px-md-4 py-2 py-md-2\">\r\n <ul class=\"list-unstyled\">\r\n\r\n <li class=\"mb-3 d-flex\" *ngFor=\"let menuItem of menuPrincipalSel.hijos\">\r\n <mat-icon>{{menuItem.icono}}</mat-icon>\r\n <div class=\"ml-2 flex-fill\">\r\n <a href=\"{{menuItem.url}}\" *ngIf=\"menuItem.url\">\r\n <div class=\"lead mb-2\">{{menuItem.titulo}}</div>\r\n </a>\r\n <div class=\"lead mb-2\" *ngIf=\"!menuItem.url\">{{menuItem.titulo}}</div>\r\n\r\n <a href=\"{{menuSubItem.url}}\" class=\"pl-2 my-2\" *ngFor=\"let menuSubItem of menuItem.hijos\">\r\n <div class=\"text-secondary\">{{menuSubItem.titulo}}</div>\r\n </a>\r\n </div>\r\n </li>\r\n </ul>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <button mat-icon-button class=\"close-icon d-lg-none\" (click)=\"menuPrincipalSel=null\">\r\n <mat-icon>arrow_back</mat-icon>\r\n </button>\r\n</div>\r\n<div class=\"alerta-almacenamiento\" *ngIf=\"porcentajeUtilizado >= 100\">Su capacidad de almacenamiento ha llegado al {{porcentajeUtilizado}}% , libere espacio o adquiera mayor capacidad</div>",
415
- styles: [".menu{height:46px;display:flex;justify-content:space-between;align-items:center;top:0;left:0;right:0;background-color:#1c98a4;color:#fff;padding:0 4px}.menu .d-lg-block .mat-button{font-weight:400;height:46px;line-height:46px}.menu .logo{display:inline-block;height:40px}.menu .logo-menu-principal{position:absolute;display:block;left:65px}.menu .logo-menu-principal>img{display:block;margin:0 -50%}.menu .info-adicional{color:#fff;display:flex;justify-content:end;font-size:13px;position:absolute;right:47px}.menu .info-adicional .border-r{border-right:1px solid #fff}.menu .info-adicional .version{margin:7px 0 0 7px}.menu .info-adicional div.datos{margin:0 2px 0 5px;height:28px}.menu .info-adicional .mat-icon{vertical-align:middle;font-size:17px;color:#fff;line-height:21px;margin-left:2px}.menu .info-adicional button{padding:0 0 0 15px}.menu .info-adicional .content-idioma{margin:-5px 2px 0 5px;display:block;cursor:pointer}.menu .info-adicional .icon-idioma{font-size:17px!important;vertical-align:text-top!important;color:#fffc}.sub-menu{width:100%;position:absolute;top:46px;z-index:1000;background-color:#fff;display:flex;overflow-y:auto;box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}.sub-menu .close-icon{position:absolute;left:4px;top:4px}.sub-menu .descripcion-menu .mat-icon{color:#1c98a4;width:100px;height:100px}.sub-menu .descripcion-menu p:first-of-type{font-weight:300;font-size:30px;margin:16px 0}.sub-menu .descripcion-menu p:last-of-type{color:#6c757d}.sub-menu li{float:left;width:50%}.sub-menu li>.mat-icon{color:#444}.sub-menu li:nth-child(even){float:right}.sub-menu li a{transition:.5s;display:block}.sub-menu li a:hover{margin-left:8px}.sub-menu li .lead{line-height:24px;color:#212529;font-size:17px}.sub-menu-fondo{background:#272d3357;position:absolute;top:46px;bottom:0;left:0;right:0;z-index:1000}.menu-lateral{width:100%;position:absolute;top:46px;bottom:0;left:0;right:0;z-index:1000;display:flex;flex-direction:column;overflow-y:auto;background:#f7f7f7;padding:20px}.menu-lateral>div>div>*>div{text-align:center;padding:16px;background-color:#fff;margin:0 0 16px;color:#333;cursor:pointer;box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}.menu-lateral>div>div>*>div>.mat-icon{width:50px;height:50px}.menu-lateral>div>div>*>div>p{padding:0;margin:8px 0 0}a.mat-menu-item{color:#444!important}.alerta-almacenamiento{background:#ffffec;border-bottom:1px solid #efff00;min-height:39px;line-height:36px;font-size:12px;padding:0 0 0 25px}@media (max-width:767.98px){.sub-menu ul{margin:auto;padding:0 10px}.sub-menu ul li{float:none;width:100%}.sub-menu ul li:nth-child(even){float:none}}@media (max-width:991.98px){.sub-menu{bottom:0}}@media (min-width:600px){.logo-menu-principal{left:50%!important}}* :focus,:active{outline:0!important}"]
436
+ template: "<div class=\"menu\" [ngStyle]=\"{'background-color': colorFondo, 'color': colorTexto}\">\r\n <div class=\"d-lg-none\">\r\n <button mat-icon-button (click)=\"menuLateralAbierto=!menuLateralAbierto; menuPrincipalSel = null\">\r\n <mat-icon *ngIf=\"!menuLateralAbierto\" class=\"animate__animated animate__fadeInRight animate__faster\">menu\r\n </mat-icon>\r\n <mat-icon *ngIf=\"menuLateralAbierto\" class=\"animate__animated animate__fadeInLeft animate__faster\">close\r\n </mat-icon>\r\n </button>\r\n </div>\r\n <div class=\"d-lg-none logo-menu-principal\">\r\n <img class=\"logo\" src=\"{{logo}}\">\r\n </div>\r\n <div class=\"d-none d-lg-block\">\r\n <img class=\"logo\" src=\"{{logo}}\">\r\n <div *ngFor=\"let menuItem of menuPrincipal; let i=index\" class=\"d-inline-block\">\r\n\r\n <a *ngIf=\"menuItem.url\" mat-button [href]=\"menuItem.url\" (click)=\"clickMenuPrincipal(i)\">\r\n {{menuItem.titulo}}\r\n </a>\r\n <button *ngIf=\"!menuItem.url\" mat-button (click)=\"clickMenuPrincipal(i)\">\r\n {{menuItem.titulo}}\r\n </button>\r\n </div>\r\n </div>\r\n <div class=\"info-adicional\">\r\n <div class=\"datos border-r mt-1 boton-asistente-datos\" *ngIf=\"puedeAsistente\" matTooltip=\"Preg\u00FAntale a tus datos\" (click)=\"asistenteAbierto = !asistenteAbierto\">\r\n <span class=\"icono-asistente-fab\"></span>\r\n </div>\r\n <div class=\"datos border-r mt-1\" *ngIf=\"nombreCliente\">{{nombreCliente}}<mat-icon>people</mat-icon></div>\r\n <div class=\"datos border-r mt-1\" *ngIf=\"nombreUsuario\">{{nombreUsuario}}<mat-icon>person_outline</mat-icon></div>\r\n <div class=\"version\" *ngIf=\"versionWeb\">{{versionWeb}}</div>\r\n <div class=\"content-idioma\" *ngIf=\"urlIdiomas\">\r\n <mat-menu #menuIdiomas=\"matMenu\">\r\n <a mat-menu-item *ngFor=\"let menuItem of menuIdioma.Culturas\" href=\"{{urlCuentaSeguridad}}CambiarIdioma?culture={{menuItem.Name}}&ReturnUrl=/\">\r\n {{menuItem.NativeName}}\r\n </a>\r\n </mat-menu>\r\n <button mat-button [matMenuTriggerFor]=\"menuIdiomas\"><label class=\"mt-1\">{{menuIdioma.Lenguaje}}</label><mat-icon class=\"icon-idioma\">language</mat-icon></button>\r\n </div>\r\n\r\n </div>\r\n <div>\r\n <mat-menu #submenu=\"matMenu\">\r\n <a mat-menu-item *ngFor=\"let menuItem of menuSecundarioSel.hijos\" href=\"{{menuItem.url}}\"\r\n [disabled]=\"!menuItem.url\">\r\n <mat-icon *ngIf=\"menuItem.icono\">{{menuItem.icono}}</mat-icon>\r\n {{menuItem.titulo}}\r\n </a>\r\n </mat-menu>\r\n <button *ngFor=\"let menuItem of menuSecundario; let i = index\" mat-icon-button [matMenuTriggerFor]=\"submenu\"\r\n (click)=\"clickMenuSecundario(i)\">\r\n <mat-icon>{{menuItem.icono}}</mat-icon>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<div class=\"menu-lateral d-lg-none animate__animated animate__fadeInRight animate__faster\" *ngIf=\"menuLateralAbierto\">\r\n <div class=\"row\">\r\n <div *ngFor=\"let menuItem of menuPrincipal; let i=index\" class=\"col-sm-6 col-md-4\">\r\n <a *ngIf=\"menuItem.url\" [href]=\"menuItem.url\" (click)=\"clickMenuPrincipal(i)\">\r\n <div>\r\n <mat-icon svgIcon=\"{{menuItem.icono}}\">{{menuItem.icono}}</mat-icon>\r\n <p>{{menuItem.titulo}}</p>\r\n </div>\r\n </a>\r\n <span *ngIf=\"!menuItem.url\" (click)=\"clickMenuPrincipal(i)\">\r\n <div>\r\n <mat-icon svgIcon=\"{{menuItem.icono}}\">{{menuItem.icono}}</mat-icon>\r\n <p>{{menuItem.titulo}}</p>\r\n </div>\r\n </span>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div class=\"sub-menu-fondo animate__animated animate__fadeIn animate__faster\" (click)=\"menuPrincipalSel=null\"\r\n *ngIf=\"menuPrincipalSel\"></div>\r\n\r\n<div class=\"sub-menu animate__animated animate__fadeIn animate__faster\" *ngIf=\"menuPrincipalSel\">\r\n <div class=\"container-fluid\">\r\n <div class=\"row\">\r\n <div class=\"col-12 col-lg-5\">\r\n <div class=\"px-3 px-sm-5 pt-5 pb-lg-5 text-center descripcion-menu\">\r\n <mat-icon [ngStyle]=\"{'color': colorFondo}\" svgIcon=\"{{menuPrincipalSel.icono}}\">\r\n {{menuPrincipalSel.icono}}</mat-icon>\r\n <p>{{menuPrincipalSel.titulo}}</p>\r\n <p class=\"text-secondary\">{{menuPrincipalSel.descripcion}}</p>\r\n </div>\r\n </div>\r\n <div class=\"col-12 col-lg-7 my-4\">\r\n <div class=\"px-3 px-md-4 py-2 py-md-2\">\r\n <ul class=\"list-unstyled\">\r\n\r\n <li class=\"mb-3 d-flex\" *ngFor=\"let menuItem of menuPrincipalSel.hijos\">\r\n <mat-icon>{{menuItem.icono}}</mat-icon>\r\n <div class=\"ml-2 flex-fill\">\r\n <a href=\"{{menuItem.url}}\" *ngIf=\"menuItem.url\">\r\n <div class=\"lead mb-2\">{{menuItem.titulo}}</div>\r\n </a>\r\n <div class=\"lead mb-2\" *ngIf=\"!menuItem.url\">{{menuItem.titulo}}</div>\r\n\r\n <a href=\"{{menuSubItem.url}}\" class=\"pl-2 my-2\" *ngFor=\"let menuSubItem of menuItem.hijos\">\r\n <div class=\"text-secondary\">{{menuSubItem.titulo}}</div>\r\n </a>\r\n </div>\r\n </li>\r\n </ul>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <button mat-icon-button class=\"close-icon d-lg-none\" (click)=\"menuPrincipalSel=null\">\r\n <mat-icon>arrow_back</mat-icon>\r\n </button>\r\n</div>\r\n<div class=\"alerta-almacenamiento\" *ngIf=\"porcentajeUtilizado >= 100\">Su capacidad de almacenamiento ha llegado al {{porcentajeUtilizado}}% , libere espacio o adquiera mayor capacidad</div>\r\n\r\n<!-- Asistente \"Preg\u00FAntale a tus datos\": panel flotante que se abre desde el bot\u00F3n del men\u00FA. -->\r\n<wm-asistente-datos *ngIf=\"puedeAsistente\" [abierto]=\"asistenteAbierto\" [urlConsultar]=\"urlAsistenteConsultar\"\r\n [idioma]=\"idiomaAsistente\" (cerrarChange)=\"asistenteAbierto = false\"></wm-asistente-datos>",
437
+ styles: [".menu{height:46px;display:flex;justify-content:space-between;align-items:center;top:0;left:0;right:0;background-color:#1c98a4;color:#fff;padding:0 4px}.menu .d-lg-block .mat-button{font-weight:400;height:46px;line-height:46px}.menu .logo{display:inline-block;height:40px}.menu .logo-menu-principal{position:absolute;display:block;left:65px}.menu .logo-menu-principal>img{display:block;margin:0 -50%}.menu .info-adicional{color:#fff;display:flex;justify-content:end;font-size:13px;position:absolute;right:47px}.menu .info-adicional .border-r{border-right:1px solid #fff}.menu .info-adicional .version{margin:7px 0 0 7px}.menu .info-adicional div.datos{margin:0 2px 0 5px;height:28px}.menu .info-adicional .boton-asistente-datos{cursor:pointer;padding-right:10px}.menu .info-adicional .mat-icon{vertical-align:middle;font-size:17px;color:#fff;line-height:21px;margin-left:2px}.menu .info-adicional button{padding:0 0 0 15px}.menu .info-adicional .content-idioma{margin:-5px 2px 0 5px;display:block;cursor:pointer}.menu .info-adicional .icon-idioma{font-size:17px!important;vertical-align:text-top!important;color:#fffc}.sub-menu{width:100%;position:absolute;top:46px;z-index:1000;background-color:#fff;display:flex;overflow-y:auto;box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}.sub-menu .close-icon{position:absolute;left:4px;top:4px}.sub-menu .descripcion-menu .mat-icon{color:#1c98a4;width:100px;height:100px}.sub-menu .descripcion-menu p:first-of-type{font-weight:300;font-size:30px;margin:16px 0}.sub-menu .descripcion-menu p:last-of-type{color:#6c757d}.sub-menu li{float:left;width:50%}.sub-menu li>.mat-icon{color:#444}.sub-menu li:nth-child(even){float:right}.sub-menu li a{transition:.5s;display:block}.sub-menu li a:hover{margin-left:8px}.sub-menu li .lead{line-height:24px;color:#212529;font-size:17px}.sub-menu-fondo{background:#272d3357;position:absolute;top:46px;bottom:0;left:0;right:0;z-index:1000}.menu-lateral{width:100%;position:absolute;top:46px;bottom:0;left:0;right:0;z-index:1000;display:flex;flex-direction:column;overflow-y:auto;background:#f7f7f7;padding:20px}.menu-lateral>div>div>*>div{text-align:center;padding:16px;background-color:#fff;margin:0 0 16px;color:#333;cursor:pointer;box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}.menu-lateral>div>div>*>div>.mat-icon{width:50px;height:50px}.menu-lateral>div>div>*>div>p{padding:0;margin:8px 0 0}a.mat-menu-item{color:#444!important}.alerta-almacenamiento{background:#ffffec;border-bottom:1px solid #efff00;min-height:39px;line-height:36px;font-size:12px;padding:0 0 0 25px}@media (max-width:767.98px){.sub-menu ul{margin:auto;padding:0 10px}.sub-menu ul li{float:none;width:100%}.sub-menu ul li:nth-child(even){float:none}}@media (max-width:991.98px){.sub-menu{bottom:0}}@media (min-width:600px){.logo-menu-principal{left:50%!important}}* :focus,:active{outline:0!important}.icono-asistente-fab{display:inline-block;width:32px;height:32px;vertical-align:middle;background:url(data:image/png;base64,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) center/contain no-repeat}"]
416
438
  })
417
439
  ], WmMenuComponent);
418
440
 
441
+ // Envoltorio de la Web Speech API (SpeechRecognition) del navegador — dictado de voz a texto,
442
+ // 100% cliente, sin backend. Soportado en Chrome/Edge; SIN soporte en Firefox y de forma
443
+ // inconsistente en Safari (limitación real del navegador, no de esta implementación).
444
+ let ReconocimientoVozService = class ReconocimientoVozService {
445
+ constructor() {
446
+ this.reconocimiento = null;
447
+ }
448
+ estaSoportado() {
449
+ return !!(this.obtenerConstructor());
450
+ }
451
+ // onResultado se llama con el texto reconocido hasta el momento (incluye resultados
452
+ // provisionales — interimResults: true — para que el cuadro de texto se vea llenar en vivo).
453
+ // onFin se llama cuando el reconocimiento termina, ya sea porque el navegador detectó una
454
+ // pausa (continuous: false) o porque se llamó a detener().
455
+ iniciar(idioma, onResultado, onFin) {
456
+ const SpeechRecognitionCtor = this.obtenerConstructor();
457
+ if (!SpeechRecognitionCtor) {
458
+ onFin();
459
+ return;
460
+ }
461
+ this.detener();
462
+ this.reconocimiento = new SpeechRecognitionCtor();
463
+ this.reconocimiento.lang = idioma;
464
+ this.reconocimiento.continuous = false;
465
+ this.reconocimiento.interimResults = true;
466
+ this.reconocimiento.onresult = (evento) => {
467
+ const texto = Array.from(evento.results)
468
+ .map((resultado) => resultado[0].transcript)
469
+ .join(' ');
470
+ onResultado(texto);
471
+ };
472
+ this.reconocimiento.onerror = (evento) => {
473
+ var _a;
474
+ // Motivos típicos (event.error de SpeechRecognitionErrorEvent): "not-allowed" (permiso de
475
+ // micrófono denegado o sitio sin HTTPS/localhost), "no-speech", "audio-capture" (sin
476
+ // micrófono), "network". Se deja en consola porque no hay backend que lo registre y el
477
+ // navegador no explica el motivo en la UI.
478
+ console.error('Reconocimiento de voz: error -', (_a = evento) === null || _a === void 0 ? void 0 : _a.error);
479
+ this.reconocimiento = null;
480
+ onFin();
481
+ };
482
+ this.reconocimiento.onend = () => {
483
+ this.reconocimiento = null;
484
+ onFin();
485
+ };
486
+ try {
487
+ this.reconocimiento.start();
488
+ }
489
+ catch (e) {
490
+ console.error('Reconocimiento de voz: no se pudo iniciar -', e);
491
+ this.reconocimiento = null;
492
+ onFin();
493
+ }
494
+ }
495
+ detener() {
496
+ if (this.reconocimiento) {
497
+ this.reconocimiento.onend = null;
498
+ this.reconocimiento.onerror = null;
499
+ this.reconocimiento.stop();
500
+ this.reconocimiento = null;
501
+ }
502
+ }
503
+ obtenerConstructor() {
504
+ return window.SpeechRecognition || window.webkitSpeechRecognition || null;
505
+ }
506
+ };
507
+ ReconocimientoVozService.ɵprov = ɵɵdefineInjectable({ factory: function ReconocimientoVozService_Factory() { return new ReconocimientoVozService(); }, token: ReconocimientoVozService, providedIn: "root" });
508
+ ReconocimientoVozService = __decorate([
509
+ Injectable({
510
+ providedIn: 'root',
511
+ })
512
+ ], ReconocimientoVozService);
513
+
514
+ let AsistenteDatosApiService = class AsistenteDatosApiService {
515
+ constructor(http) {
516
+ this.http = http;
517
+ // La fija el componente desde su @Input urlConsultar (reemplaza WmChatConfigService.urlConsultar).
518
+ this.url = '';
519
+ // Mismo origen del JWT que WmSeguridadService.getJWT() en wm-chat: localStorage['WMTKN'],
520
+ // descartado si está vencido. Se replica aquí para que el header Authorization sea idéntico
521
+ // al del chat original sin depender de un servicio de config externo.
522
+ this.TOKEN_KEY = 'WMTKN';
523
+ this.jwtHelper = new JwtHelperService();
524
+ }
525
+ consultar(pregunta, proveedor) {
526
+ const headers = new HttpHeaders({
527
+ Authorization: `Bearer ${this.obtenerJWT()}`,
528
+ 'Content-Type': 'application/json; charset=utf-8',
529
+ });
530
+ return this.http
531
+ .post(this.url, { Pregunta: pregunta, Proveedor: proveedor }, { headers })
532
+ .pipe(catchError((error) => {
533
+ return throwError(error.error);
534
+ }));
535
+ }
536
+ obtenerJWT() {
537
+ const jwt = localStorage.getItem(this.TOKEN_KEY);
538
+ if (jwt) {
539
+ try {
540
+ return this.jwtHelper.isTokenExpired(jwt) ? null : jwt;
541
+ }
542
+ catch (_a) { }
543
+ }
544
+ return null;
545
+ }
546
+ };
547
+ AsistenteDatosApiService.ctorParameters = () => [
548
+ { type: HttpClient }
549
+ ];
550
+ AsistenteDatosApiService.ɵprov = ɵɵdefineInjectable({ factory: function AsistenteDatosApiService_Factory() { return new AsistenteDatosApiService(ɵɵinject(HttpClient)); }, token: AsistenteDatosApiService, providedIn: "root" });
551
+ AsistenteDatosApiService = __decorate([
552
+ Injectable({
553
+ providedIn: 'root',
554
+ })
555
+ ], AsistenteDatosApiService);
556
+
557
+ let AsistenteDatosComponent = class AsistenteDatosComponent {
558
+ constructor(asistenteDatosApiService, reconocimientoVoz) {
559
+ this.asistenteDatosApiService = asistenteDatosApiService;
560
+ this.reconocimientoVoz = reconocimientoVoz;
561
+ // La apertura/cierre del panel la controla el padre (el menú). El panel solo se renderiza
562
+ // cuando `abierto` es true y avisa, vía `cerrarChange`, cuando el usuario toca la X.
563
+ this.abierto = false;
564
+ // Idioma para el reconocimiento de voz (Web Speech API).
565
+ this.idioma = 'es-CO';
566
+ this.cerrarChange = new EventEmitter();
567
+ this.mensajes = [];
568
+ this.borrador = '';
569
+ // Alterna el alto de la caja del mensaje (compacta ↔ expandida), igual que el "pedir cambios"
570
+ // del asistente de IA del generador de formularios (ver filasBorrador / onClickExpandirBorrador).
571
+ this.borradorExpandido = false;
572
+ this.consultando = false;
573
+ // "Gemini" o "Groq" — mismo selector que el asistente de generación de formularios
574
+ // (ver ProveedorIAServicio en el backend).
575
+ this.proveedorSeleccionado = 'Gemini';
576
+ // Dictado por voz (Web Speech API) — sin soporte en Firefox, inconsistente en Safari.
577
+ this.escuchando = false;
578
+ // Preguntas ya verificadas como respondibles hoy (whitelist + contrato de la IA — ver
579
+ // ChatConsultaWhitelistServicio/ChatConsultaPromptServicio en el backend), mostradas como chips
580
+ // de sugerencia en el estado vacío del chat.
581
+ this.chipsSugeridos = [
582
+ '¿Cuántos formularios se diligenciaron hoy?',
583
+ '¿Cuántos formularios se diligenciaron esta semana?',
584
+ 'Muéstrame los últimos 10 formularios diligenciados',
585
+ ];
586
+ }
587
+ // URL del POST de consulta. Se refleja en el api service (propiedad `url`), que es donde se usa.
588
+ set urlConsultar(valor) {
589
+ if (valor) {
590
+ this.asistenteDatosApiService.url = valor;
591
+ }
592
+ }
593
+ // El padre abre/cierra el panel; aquí solo se avisa que el usuario pidió cerrarlo (botón X).
594
+ cerrar() {
595
+ this.cerrarChange.emit();
596
+ }
597
+ // Caja del mensaje compacta (1 fila, como era el chat originalmente) ↔ expandida (6 filas).
598
+ // El botón de expandir es el mismo patrón del "pedir cambios" del generador.
599
+ get filasBorrador() {
600
+ return this.borradorExpandido ? 6 : 1;
601
+ }
602
+ onClickExpandirBorrador() {
603
+ this.borradorExpandido = !this.borradorExpandido;
604
+ }
605
+ get micDisponible() {
606
+ return this.reconocimientoVoz.estaSoportado();
607
+ }
608
+ onClickMicrofono() {
609
+ if (this.escuchando) {
610
+ this.reconocimientoVoz.detener();
611
+ this.escuchando = false;
612
+ return;
613
+ }
614
+ if (!this.reconocimientoVoz.estaSoportado()) {
615
+ return;
616
+ }
617
+ // El resultado del reconocimiento no incluye lo que ya estaba escrito — se guarda antes de
618
+ // empezar y se antepone en cada actualización (que llega con la transcripción COMPLETA de
619
+ // esta sesión de escucha, no un incremento) para no perder lo que ya había en el campo.
620
+ const textoPrevio = this.borrador.trim();
621
+ this.escuchando = true;
622
+ this.reconocimientoVoz.iniciar(this.idioma, (texto) => (this.borrador = textoPrevio ? `${textoPrevio} ${texto}` : texto), () => (this.escuchando = false));
623
+ }
624
+ onClickEnviar(textoPreset) {
625
+ const pregunta = ((textoPreset !== null && textoPreset !== void 0 ? textoPreset : this.borrador)).trim();
626
+ if (!pregunta || this.consultando) {
627
+ return;
628
+ }
629
+ this.mensajes.push({ deUsuario: true, texto: pregunta });
630
+ this.borrador = '';
631
+ // Sin url de consulta no se hace la petición: el usuario ve el mismo error genérico que
632
+ // cuando la API falla.
633
+ if (!this.asistenteDatosApiService.url) {
634
+ this.mensajes.push({
635
+ deUsuario: false,
636
+ texto: 'No se pudo procesar la consulta.',
637
+ esError: true,
638
+ });
639
+ this.scrollAlFinal();
640
+ return;
641
+ }
642
+ this.consultando = true;
643
+ this.scrollAlFinal();
644
+ this.asistenteDatosApiService.consultar(pregunta, this.proveedorSeleccionado).subscribe({
645
+ // El tipo (RespuestaAsistenteDatos) se infiere del Observable: importar la interfaz
646
+ // dejaba un import a un símbolo inexistente en el JS de la librería (aviso de rollup).
647
+ next: (respuesta) => {
648
+ var _a;
649
+ this.consultando = false;
650
+ this.mensajes.push({
651
+ deUsuario: false,
652
+ descripcion: respuesta.Descripcion,
653
+ resultado: (_a = respuesta.Resultado, (_a !== null && _a !== void 0 ? _a : [])),
654
+ proveedor: respuesta.Proveedor,
655
+ });
656
+ this.scrollAlFinal();
657
+ },
658
+ error: (error) => {
659
+ var _a;
660
+ this.consultando = false;
661
+ this.mensajes.push({
662
+ deUsuario: false,
663
+ texto: ((_a = error) === null || _a === void 0 ? void 0 : _a.Mensaje) || 'No se pudo procesar la consulta.',
664
+ esError: true,
665
+ });
666
+ this.scrollAlFinal();
667
+ },
668
+ });
669
+ }
670
+ // El nuevo mensaje recién se refleja en el DOM después del siguiente ciclo de detección de
671
+ // cambios — por eso el scrollTop se ajusta en un setTimeout(0), no inmediatamente después del
672
+ // push, para que scrollHeight ya incluya el mensaje agregado.
673
+ scrollAlFinal() {
674
+ setTimeout(() => {
675
+ var _a;
676
+ const elemento = (_a = this.mensajesContainer) === null || _a === void 0 ? void 0 : _a.nativeElement;
677
+ if (elemento) {
678
+ elemento.scrollTop = elemento.scrollHeight;
679
+ }
680
+ });
681
+ }
682
+ columnasDe(resultado) {
683
+ return resultado.length ? Object.keys(resultado[0]) : [];
684
+ }
685
+ // El backend devuelve un conteo (ChatConsultaIAServicio.EjecutarConteo) como una sola fila con
686
+ // una sola columna llamada literalmente "Resultado" — se muestra como número grande en vez de
687
+ // como tabla de una celda.
688
+ esConteo(resultado) {
689
+ var _a;
690
+ return ((_a = resultado) === null || _a === void 0 ? void 0 : _a.length) === 1 && Object.keys(resultado[0]).length === 1 && 'Resultado' in resultado[0];
691
+ }
692
+ // Listado con una sola columna (ej. una lista de nombres/ids) — se muestra como texto simple
693
+ // en vez de una tabla de una sola columna repetida.
694
+ esListaSimple(resultado) {
695
+ var _a;
696
+ return ((_a = resultado) === null || _a === void 0 ? void 0 : _a.length) > 0 && !this.esConteo(resultado) && this.columnasDe(resultado).length === 1;
697
+ }
698
+ textoListaSimple(resultado) {
699
+ const columna = this.columnasDe(resultado)[0];
700
+ return resultado.map((fila) => fila[columna]).join(', ');
701
+ }
702
+ };
703
+ AsistenteDatosComponent.ctorParameters = () => [
704
+ { type: AsistenteDatosApiService },
705
+ { type: ReconocimientoVozService }
706
+ ];
707
+ __decorate([
708
+ ViewChild('mensajesContainer')
709
+ ], AsistenteDatosComponent.prototype, "mensajesContainer", void 0);
710
+ __decorate([
711
+ Input()
712
+ ], AsistenteDatosComponent.prototype, "abierto", void 0);
713
+ __decorate([
714
+ Input()
715
+ ], AsistenteDatosComponent.prototype, "urlConsultar", null);
716
+ __decorate([
717
+ Input()
718
+ ], AsistenteDatosComponent.prototype, "idioma", void 0);
719
+ __decorate([
720
+ Output()
721
+ ], AsistenteDatosComponent.prototype, "cerrarChange", void 0);
722
+ AsistenteDatosComponent = __decorate([
723
+ Component({
724
+ selector: 'wm-asistente-datos',
725
+ template: "<!-- Panel (abierto) -->\r\n<div class=\"chat-ia-panel\" *ngIf=\"abierto\">\r\n <div class=\"chat-ia-header\">\r\n <div class=\"chat-ia-header-info\">\r\n <div class=\"chat-ia-header-icono\">\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"1.8\">\r\n <path d=\"M4 5h16v10H9l-4 4V15H4z\"></path>\r\n </svg>\r\n </div>\r\n <div>\r\n <div class=\"chat-ia-titulo\">Preg\u00FAntale a tus Datos</div>\r\n <div class=\"chat-ia-subtitulo\">Consulta tus reportes en lenguaje natural</div>\r\n </div>\r\n </div>\r\n <div class=\"chat-ia-cerrar\" (click)=\"cerrar()\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" stroke=\"#fff\" stroke-width=\"2\" fill=\"none\" stroke-linecap=\"round\">\r\n <path d=\"M6 6l12 12M18 6L6 18\"></path>\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <div class=\"chat-ia-mensajes\" #mensajesContainer>\r\n <div class=\"chat-ia-bienvenida-texto\">Hola, soy tu asistente de datos de Snap Forms. Preg\u00FAntame lo que quieras saber sobre tu operaci\u00F3n.</div>\r\n\r\n <div class=\"chat-ia-mensaje\" *ngFor=\"let mensaje of mensajes\" [class.chat-ia-mensaje-usuario]=\"mensaje.deUsuario\">\r\n <div class=\"chat-ia-burbuja\" [class.chat-ia-burbuja-error]=\"mensaje.esError\">\r\n <span *ngIf=\"mensaje.texto\">{{ mensaje.texto }}</span>\r\n\r\n <ng-container *ngIf=\"mensaje.resultado\">\r\n <div class=\"chat-ia-descripcion\" *ngIf=\"mensaje.descripcion\">{{ mensaje.descripcion }}</div>\r\n\r\n <div class=\"chat-ia-sin-resultados\" *ngIf=\"mensaje.resultado.length === 0\">La consulta no encontr\u00F3 resultados.</div>\r\n\r\n <div class=\"chat-ia-stat\" *ngIf=\"esConteo(mensaje.resultado)\">\r\n <div class=\"chat-ia-stat-valor\">{{ mensaje.resultado[0].Resultado | number }}</div>\r\n </div>\r\n\r\n <div class=\"chat-ia-lista-simple\" *ngIf=\"esListaSimple(mensaje.resultado)\">{{ textoListaSimple(mensaje.resultado) }}</div>\r\n\r\n <div class=\"chat-ia-tabla-resultado\" *ngIf=\"mensaje.resultado.length > 0 && !esConteo(mensaje.resultado) && !esListaSimple(mensaje.resultado)\">\r\n <table mat-table [dataSource]=\"mensaje.resultado\">\r\n <ng-container *ngFor=\"let columna of columnasDe(mensaje.resultado)\" [matColumnDef]=\"columna\">\r\n <th mat-header-cell *matHeaderCellDef>{{ columna }}</th>\r\n <td mat-cell *matCellDef=\"let fila\">{{ fila[columna] }}</td>\r\n </ng-container>\r\n <tr mat-header-row *matHeaderRowDef=\"columnasDe(mensaje.resultado)\"></tr>\r\n <tr mat-row *matRowDef=\"let fila; columns: columnasDe(mensaje.resultado);\"></tr>\r\n </table>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <div class=\"chat-ia-pensando\" *ngIf=\"consultando\">\r\n <span class=\"chat-ia-dot\"></span><span class=\"chat-ia-dot\"></span><span class=\"chat-ia-dot\"></span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"chips-chat-ia\">\r\n <span class=\"chip-chat-ia\" *ngFor=\"let chip of chipsSugeridos\"\r\n (click)=\"onClickEnviar(chip)\">{{ chip }}</span>\r\n </div>\r\n\r\n <div class=\"chat-ia-entrada\">\r\n <div class=\"chat-ia-caja-entrada\">\r\n <mat-icon class=\"chat-ia-expandir\" (click)=\"onClickExpandirBorrador()\">{{ borradorExpandido ? 'close_fullscreen' : 'open_in_full' }}</mat-icon>\r\n <textarea [rows]=\"filasBorrador\" [(ngModel)]=\"borrador\" (keydown.enter)=\"$event.preventDefault(); onClickEnviar()\"\r\n [class.chat-ia-textarea-expandido]=\"borradorExpandido\"\r\n placeholder=\"Escribe tu pregunta...\"></textarea>\r\n <div class=\"chat-ia-pie-entrada\">\r\n <button class=\"chat-ia-selector-modelo\" [matMenuTriggerFor]=\"menuModeloChatIA\" type=\"button\">\r\n <span *ngIf=\"proveedorSeleccionado === 'Gemini'\">Gemini</span>\r\n <span *ngIf=\"proveedorSeleccionado === 'Groq'\">Groq</span>\r\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M6 9l6 6 6-6\"></path>\r\n </svg>\r\n </button>\r\n <button class=\"chat-ia-microfono\" [class.chat-ia-microfono-activo]=\"escuchando\" *ngIf=\"micDisponible\"\r\n (click)=\"onClickMicrofono()\" type=\"button\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\"></path>\r\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"></path>\r\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"></line>\r\n </svg>\r\n </button>\r\n <button class=\"chat-ia-enviar\" [disabled]=\"!borrador.trim() || consultando\" (click)=\"onClickEnviar()\" type=\"button\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M12 19V6\"></path>\r\n <path d=\"M5 13l7-7 7 7\"></path>\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<mat-menu #menuModeloChatIA=\"matMenu\" class=\"menu-modelo-chat-ia\">\r\n <button mat-menu-item [class.opcion-activa]=\"proveedorSeleccionado === 'Gemini'\"\r\n (click)=\"proveedorSeleccionado = 'Gemini'\">\r\n <span>Gemini</span>\r\n <svg *ngIf=\"proveedorSeleccionado === 'Gemini'\" class=\"chat-ia-check\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M20 6L9 17l-5-5\"></path>\r\n </svg>\r\n </button>\r\n <button mat-menu-item [class.opcion-activa]=\"proveedorSeleccionado === 'Groq'\"\r\n (click)=\"proveedorSeleccionado = 'Groq'\">\r\n <span>Groq</span>\r\n <svg *ngIf=\"proveedorSeleccionado === 'Groq'\" class=\"chat-ia-check\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M20 6L9 17l-5-5\"></path>\r\n </svg>\r\n </button>\r\n</mat-menu>\r\n",
726
+ styles: [":host{position:fixed;right:32px;bottom:32px;z-index:1000;font-family:Roboto,sans-serif}.chat-ia-panel{width:450px;height:650px;max-width:calc(100vw - 48px);max-height:calc(100vh - 96px);background:#fff;border-radius:18px;box-shadow:0 24px 60px rgba(20,25,30,.28);display:flex;flex-direction:column;overflow:hidden}.chat-ia-header{background:linear-gradient(135deg,#7c5ce0,#5f42bd);padding:16px 18px;display:flex;align-items:center;justify-content:space-between;flex-shrink:0}.chat-ia-header-info{display:flex;align-items:center;gap:10px;min-width:0}.chat-ia-header-icono{width:32px;height:32px;border-radius:50%;background:rgba(255,255,255,.22);display:flex;align-items:center;justify-content:center;flex:none}.chat-ia-titulo{color:#fff;font-size:14px;font-weight:500}.chat-ia-subtitulo{color:rgba(255,255,255,.75);font-size:11px;margin-top:1px}.chat-ia-cerrar{width:24px;height:24px;display:flex;align-items:center;justify-content:center;cursor:pointer;opacity:.85;flex:none}.chat-ia-cerrar:hover{opacity:1}.chat-ia-mensajes{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:12px;padding:16px;background:#fbfafc}.chat-ia-mensaje{display:flex}.chat-ia-mensaje .chat-ia-burbuja{max-width:88%;background:#f2eefb;color:#26313a;border-radius:14px 14px 14px 3px;padding:10px 13px;font-size:13px;line-height:1.5}.chat-ia-mensaje .chat-ia-burbuja-error{background:#fdecea;color:#7a1f14}.chat-ia-mensaje.chat-ia-mensaje-usuario{justify-content:flex-end}.chat-ia-mensaje.chat-ia-mensaje-usuario .chat-ia-burbuja{background:#7c5ce0;color:#fff;border-radius:14px 14px 3px}.chat-ia-bienvenida-texto{align-self:flex-start;max-width:88%;background:#f2eefb;color:#26313a;border-radius:14px 14px 14px 3px;padding:10px 13px;font-size:13px;line-height:1.5}.chips-chat-ia{flex:none;display:flex;flex-wrap:wrap;gap:6px;padding:0 16px 10px}.chip-chat-ia{border:1px solid #e7e2f5;background:#f2eefb;color:#5f42bd;border-radius:14px;padding:5px 10px;font-size:11px;cursor:pointer}.chip-chat-ia:hover{background:#e7ddfa}.chat-ia-descripcion{font-size:13px;line-height:1.5;margin-bottom:6px}.chat-ia-sin-resultados{color:#5a5a5a;font-style:italic}.chat-ia-stat{margin-top:4px}.chat-ia-stat-valor{font-size:30px;font-weight:600;color:#5f42bd;line-height:1.15;font-variant-numeric:proportional-nums}.chat-ia-lista-simple,.chat-ia-tabla-resultado{margin-top:4px;background:#fff;border-radius:10px;padding:8px 10px}.chat-ia-lista-simple{font-size:13px;line-height:1.5}.chat-ia-tabla-resultado{overflow-x:auto;max-width:100%;padding:4px 10px}.chat-ia-tabla-resultado table{font-size:12px;background:0 0}.chat-ia-tabla-resultado th.mat-header-cell{color:#6b6478;font-weight:600;padding:0 14px 5px 0;border-bottom:1px solid #f0edf7;white-space:nowrap}.chat-ia-tabla-resultado td.mat-cell{padding:7px 14px 0 0;white-space:nowrap;font-variant-numeric:tabular-nums}.chat-ia-pensando{align-self:flex-start;background:#f2eefb;padding:12px 16px;border-radius:14px 14px 14px 3px;display:flex;gap:5px;flex-shrink:0}.chat-ia-dot{width:6px;height:6px;border-radius:50%;background:#9a93ae;-webkit-animation:1.1s ease-in-out infinite chatIaBlink;animation:1.1s ease-in-out infinite chatIaBlink}.chat-ia-dot:nth-child(2){-webkit-animation-delay:.15s;animation-delay:.15s}.chat-ia-dot:nth-child(3){-webkit-animation-delay:.3s;animation-delay:.3s}@-webkit-keyframes chatIaBlink{0%,100%,80%{opacity:.25}40%{opacity:1}}@keyframes chatIaBlink{0%,100%,80%{opacity:.25}40%{opacity:1}}.chat-ia-entrada{padding:10px 14px 14px;border-top:1px solid #e9f2ee;flex-shrink:0}.chat-ia-caja-entrada{position:relative;background:#f2f7f5;border:1px solid #e6efea;border-radius:18px;padding:10px 12px 8px}.chat-ia-caja-entrada textarea{border:none;outline:0;background:0 0;width:100%;font:inherit;font-size:13.5px;color:#26313a;resize:none;line-height:1.45;max-height:110px;overflow-y:auto;display:block;padding:0 28px 0 0}.chat-ia-caja-entrada textarea.chat-ia-textarea-expandido{max-height:160px}.chat-ia-caja-entrada textarea::-webkit-input-placeholder{color:#9a93ae}.chat-ia-caja-entrada textarea::-moz-placeholder{color:#9a93ae}.chat-ia-caja-entrada textarea:-ms-input-placeholder{color:#9a93ae}.chat-ia-caja-entrada textarea::-ms-input-placeholder{color:#9a93ae}.chat-ia-caja-entrada textarea::placeholder{color:#9a93ae}.chat-ia-expandir{position:absolute;top:8px;right:10px;font-size:17px;height:17px;width:17px;color:#9a9a9a;cursor:pointer}.chat-ia-pie-entrada{display:flex;align-items:center;justify-content:flex-end;gap:8px;margin-top:8px}.chat-ia-selector-modelo{display:inline-flex;align-items:center;gap:4px;border:none;background:0 0;color:#4e5d57;border-radius:14px;padding:5px 9px;font-size:11.5px;font-weight:600;cursor:pointer}.chat-ia-enviar{width:32px;height:32px;border-radius:50%;border:none;background:#7c5ce0;color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;flex:none}.chat-ia-enviar:disabled{background:#dce6e1;color:#a9bab3;cursor:default}.chat-ia-microfono{width:28px;height:28px;border-radius:50%;border:none;background:0 0;color:#6b6478;display:flex;align-items:center;justify-content:center;cursor:pointer;flex:none}.chat-ia-microfono:hover{background:#f2eefb}.chat-ia-microfono.chat-ia-microfono-activo{color:#fff;background:#e05a5a;-webkit-animation:1.1s ease-in-out infinite chatIaBlink;animation:1.1s ease-in-out infinite chatIaBlink}::ng-deep .mat-menu-panel.menu-modelo-chat-ia{min-width:132px;border:1px solid #e6efea;border-radius:10px;box-shadow:0 12px 26px rgba(20,25,30,.16)}::ng-deep .mat-menu-panel.menu-modelo-chat-ia .mat-menu-content{padding:4px}::ng-deep .mat-menu-panel.menu-modelo-chat-ia .mat-menu-item{display:flex;align-items:center;justify-content:space-between;gap:8px;height:auto;line-height:normal;padding:7px 10px;font-size:12px;color:#26313a;border-radius:7px}::ng-deep .mat-menu-panel.menu-modelo-chat-ia .mat-menu-item.opcion-activa{background:#f2f7f5}::ng-deep .mat-menu-panel.menu-modelo-chat-ia .mat-menu-item .chat-ia-check{color:#7c5ce0}"]
727
+ })
728
+ ], AsistenteDatosComponent);
729
+
419
730
  let WmMenuModule = class WmMenuModule {
420
731
  };
421
732
  WmMenuModule = __decorate([
422
733
  NgModule({
423
- declarations: [WmMenuComponent],
734
+ declarations: [WmMenuComponent, AsistenteDatosComponent],
424
735
  imports: [
425
736
  BrowserModule,
737
+ FormsModule,
426
738
  MatToolbarModule,
427
739
  MatSidenavModule,
428
740
  MatListModule,
429
741
  MatButtonModule,
430
742
  MatIconModule,
431
743
  MatMenuModule,
744
+ MatTableModule,
745
+ MatTooltipModule,
432
746
  MatRippleModule,
433
747
  HttpClientModule,
434
748
  JwtModule
@@ -445,5 +759,5 @@ WmMenuModule = __decorate([
445
759
  * Generated bundle index. Do not edit.
446
760
  */
447
761
 
448
- export { WmMenuAlertaPanicoService, WmMenuComponent, WmMenuModule, WmMenuServicioService };
762
+ export { WmMenuAlertaPanicoService, WmMenuComponent, WmMenuModule, WmMenuServicioService, AsistenteDatosComponent as ɵa, AsistenteDatosApiService as ɵb, ReconocimientoVozService as ɵc };
449
763
  //# sourceMappingURL=wm-menu.js.map