sf-documents 0.1.11 → 0.1.12
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.
|
@@ -5,7 +5,7 @@ import * as i2 from 'primeng/api';
|
|
|
5
5
|
import { ConfirmationService, MessageService } from 'primeng/api';
|
|
6
6
|
import * as i4$2 from 'primeng/toast';
|
|
7
7
|
import { ToastModule } from 'primeng/toast';
|
|
8
|
-
import * as
|
|
8
|
+
import * as i8 from 'primeng/message';
|
|
9
9
|
import { MessageModule } from 'primeng/message';
|
|
10
10
|
import * as _ from 'lodash';
|
|
11
11
|
import * as i3 from 'primeng/button';
|
|
@@ -19,7 +19,7 @@ import * as i4 from 'primeng/dialog';
|
|
|
19
19
|
import { DialogModule } from 'primeng/dialog';
|
|
20
20
|
import * as i9 from '@angular/common';
|
|
21
21
|
import { CommonModule, registerLocaleData, DatePipe } from '@angular/common';
|
|
22
|
-
import * as
|
|
22
|
+
import * as i10 from '@angular/forms';
|
|
23
23
|
import { FormsModule } from '@angular/forms';
|
|
24
24
|
import * as i1 from '@angular/platform-browser';
|
|
25
25
|
import * as i5 from 'primeng/inputtext';
|
|
@@ -32,11 +32,11 @@ import { debounceTime, distinctUntilChanged, takeUntil, tap, switchMap, finalize
|
|
|
32
32
|
import * as i7 from 'primeng/select';
|
|
33
33
|
import { SelectModule } from 'primeng/select';
|
|
34
34
|
import localeEs from '@angular/common/locales/es';
|
|
35
|
-
import * as i12 from 'primeng/dropdown';
|
|
36
|
-
import { DropdownModule } from 'primeng/dropdown';
|
|
37
35
|
import * as i13 from 'primeng/datepicker';
|
|
38
36
|
import { DatePickerModule } from 'primeng/datepicker';
|
|
39
|
-
import * as i14 from 'primeng/
|
|
37
|
+
import * as i14 from 'primeng/inputnumber';
|
|
38
|
+
import { InputNumberModule } from 'primeng/inputnumber';
|
|
39
|
+
import * as i15 from 'primeng/skeleton';
|
|
40
40
|
import { SkeletonModule } from 'primeng/skeleton';
|
|
41
41
|
|
|
42
42
|
class SfDocumentsService {
|
|
@@ -57,10 +57,10 @@ class SfDocumentsService {
|
|
|
57
57
|
return this._loadingData.getValue();
|
|
58
58
|
}
|
|
59
59
|
constructor() { }
|
|
60
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
|
61
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.
|
|
60
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SfDocumentsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
61
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SfDocumentsService, providedIn: 'root' });
|
|
62
62
|
}
|
|
63
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
|
63
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SfDocumentsService, decorators: [{
|
|
64
64
|
type: Injectable,
|
|
65
65
|
args: [{
|
|
66
66
|
providedIn: 'root'
|
|
@@ -75,10 +75,10 @@ class SafePipe {
|
|
|
75
75
|
transform(url) {
|
|
76
76
|
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
|
77
77
|
}
|
|
78
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
|
79
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.
|
|
78
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SafePipe, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe });
|
|
79
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.17", ngImport: i0, type: SafePipe, isStandalone: true, name: "safe" });
|
|
80
80
|
}
|
|
81
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
|
81
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SafePipe, decorators: [{
|
|
82
82
|
type: Pipe,
|
|
83
83
|
args: [{ name: 'safe' }]
|
|
84
84
|
}], ctorParameters: () => [{ type: i1.DomSanitizer }] });
|
|
@@ -268,12 +268,12 @@ class UploadDialogComponent {
|
|
|
268
268
|
// Usa el MessageService y el <p-toast> de SfDocumentsComponent (ver SF_DOCUMENTS_TOAST_KEY).
|
|
269
269
|
this.messageService.add({ key: SF_DOCUMENTS_TOAST_KEY, severity, summary, detail, life: 4000 });
|
|
270
270
|
}
|
|
271
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
|
272
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.
|
|
271
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: UploadDialogComponent, deps: [{ token: i2.MessageService }], target: i0.ɵɵFactoryTarget.Component });
|
|
272
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: UploadDialogComponent, isStandalone: true, selector: "lib-upload-dialog", inputs: { selectedDocument: "selectedDocument", allowedExtensions: "allowedExtensions" }, outputs: { onUploaded: "onUploaded", loadFile: "loadFile" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, static: true }], ngImport: i0, template: "<input\n #fileInput\n type=\"file\"\n (change)=\"fileChange($event)\"\n class=\"hidden\"\n placeholder=\"Upload file\"\n [attr.accept]=\"acceptedFileTypes\"\n multiple\n/>\n<button\n pButton\n type=\"button\"\n label=\"Subir archivo\"\n icon=\"pi pi-upload\"\n class=\"p-button-outlined ff-btn-upload\"\n (click)=\"loadFileClick()\"\n></button>\n\n<p-dialog\n header=\"Archivos que superan el tama\u00F1o permitido\"\n [(visible)]=\"displayOversizedDialog\"\n [modal]=\"true\"\n [closable]=\"false\"\n [style]=\"{ width: '32rem' }\"\n [breakpoints]=\"{ '1199px': '75vw', '575px': '90vw' }\"\n>\n <p>\n Tama\u00F1o m\u00E1ximo por archivo:\n <strong>{{ formatSize(maxFileSize) }}</strong>\n </p>\n\n <div class=\"oversized-section\">\n <p class=\"oversized-title\">Archivos rechazados:</p>\n <ul class=\"oversized-list\">\n <li *ngFor=\"let file of rejectedFiles\">\n {{ file.name }} \u2014 {{ formatSize(file.size) }}\n </li>\n </ul>\n </div>\n\n <div class=\"oversized-section\" *ngIf=\"allowedFiles.length\">\n <p class=\"oversized-title\">Archivos que s\u00ED se enviar\u00E1n:</p>\n <ul class=\"oversized-list\">\n <li *ngFor=\"let file of allowedFiles\">{{ file.name }}</li>\n </ul>\n </div>\n <p *ngIf=\"!allowedFiles.length\">No hay archivos v\u00E1lidos para enviar.</p>\n\n <ng-template #footer>\n <button\n pButton\n type=\"button\"\n label=\"Cancelar\"\n class=\"p-button-text\"\n (click)=\"cancelarEnvio()\"\n ></button>\n\n <button\n pButton\n type=\"button\"\n label=\"Continuar\"\n icon=\"pi pi-upload\"\n [disabled]=\"!allowedFiles.length\"\n (click)=\"continuarConPermitidos()\"\n ></button>\n </ng-template>\n</p-dialog>\n", styles: [".oversized-section{margin-bottom:1rem}.oversized-section .oversized-title{font-weight:600;margin-bottom:.25rem}.oversized-section .oversized-list{margin:0;padding-left:1.25rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }] });
|
|
273
273
|
}
|
|
274
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
|
274
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: UploadDialogComponent, decorators: [{
|
|
275
275
|
type: Component,
|
|
276
|
-
args: [{ selector: 'lib-upload-dialog', imports: [CommonModule, ButtonModule, DialogModule], template: "<input\n #fileInput\n type=\"file\"\n (change)=\"fileChange($event)\"\n class=\"hidden\"\n placeholder=\"Upload file\"\n [attr.accept]=\"acceptedFileTypes\"\n multiple\n/>\n<button\n pButton\n type=\"button\"\n label=\"Subir archivo\"\n icon=\"pi pi-upload\"\n class=\"p-button-outlined ff-btn-upload\"\n (click)=\"loadFileClick()\"\n></button>\n\n<p-dialog\n header=\"Archivos que superan el tama\u00F1o permitido\"\n [(visible)]=\"displayOversizedDialog\"\n [modal]=\"true\"\n [closable]=\"false\"\n [style]=\"{ width: '32rem' }\"\n [breakpoints]=\"{ '1199px': '75vw', '575px': '90vw' }\"\n>\n <p>\n Tama\u00F1o m\u00E1ximo por archivo:\n <strong>{{ formatSize(maxFileSize) }}</strong>\n </p>\n\n <div class=\"oversized-section\">\n <p class=\"oversized-title\">Archivos rechazados:</p>\n <ul class=\"oversized-list\">\n <li *ngFor=\"let file of rejectedFiles\">\n {{ file.name }} \u2014 {{ formatSize(file.size) }}\n </li>\n </ul>\n </div>\n\n <div class=\"oversized-section\" *ngIf=\"allowedFiles.length\">\n <p class=\"oversized-title\">Archivos que s\u00ED se enviar\u00E1n:</p>\n <ul class=\"oversized-list\">\n <li *ngFor=\"let file of allowedFiles\">{{ file.name }}</li>\n </ul>\n </div>\n <p *ngIf=\"!allowedFiles.length\">No hay archivos v\u00E1lidos para enviar.</p>\n\n <ng-template
|
|
276
|
+
args: [{ selector: 'lib-upload-dialog', imports: [CommonModule, ButtonModule, DialogModule], template: "<input\n #fileInput\n type=\"file\"\n (change)=\"fileChange($event)\"\n class=\"hidden\"\n placeholder=\"Upload file\"\n [attr.accept]=\"acceptedFileTypes\"\n multiple\n/>\n<button\n pButton\n type=\"button\"\n label=\"Subir archivo\"\n icon=\"pi pi-upload\"\n class=\"p-button-outlined ff-btn-upload\"\n (click)=\"loadFileClick()\"\n></button>\n\n<p-dialog\n header=\"Archivos que superan el tama\u00F1o permitido\"\n [(visible)]=\"displayOversizedDialog\"\n [modal]=\"true\"\n [closable]=\"false\"\n [style]=\"{ width: '32rem' }\"\n [breakpoints]=\"{ '1199px': '75vw', '575px': '90vw' }\"\n>\n <p>\n Tama\u00F1o m\u00E1ximo por archivo:\n <strong>{{ formatSize(maxFileSize) }}</strong>\n </p>\n\n <div class=\"oversized-section\">\n <p class=\"oversized-title\">Archivos rechazados:</p>\n <ul class=\"oversized-list\">\n <li *ngFor=\"let file of rejectedFiles\">\n {{ file.name }} \u2014 {{ formatSize(file.size) }}\n </li>\n </ul>\n </div>\n\n <div class=\"oversized-section\" *ngIf=\"allowedFiles.length\">\n <p class=\"oversized-title\">Archivos que s\u00ED se enviar\u00E1n:</p>\n <ul class=\"oversized-list\">\n <li *ngFor=\"let file of allowedFiles\">{{ file.name }}</li>\n </ul>\n </div>\n <p *ngIf=\"!allowedFiles.length\">No hay archivos v\u00E1lidos para enviar.</p>\n\n <ng-template #footer>\n <button\n pButton\n type=\"button\"\n label=\"Cancelar\"\n class=\"p-button-text\"\n (click)=\"cancelarEnvio()\"\n ></button>\n\n <button\n pButton\n type=\"button\"\n label=\"Continuar\"\n icon=\"pi pi-upload\"\n [disabled]=\"!allowedFiles.length\"\n (click)=\"continuarConPermitidos()\"\n ></button>\n </ng-template>\n</p-dialog>\n", styles: [".oversized-section{margin-bottom:1rem}.oversized-section .oversized-title{font-weight:600;margin-bottom:.25rem}.oversized-section .oversized-list{margin:0;padding-left:1.25rem}\n"] }]
|
|
277
277
|
}], ctorParameters: () => [{ type: i2.MessageService }], propDecorators: { selectedDocument: [{
|
|
278
278
|
type: Input
|
|
279
279
|
}], allowedExtensions: [{
|
|
@@ -336,14 +336,110 @@ class FlexibleDatePipe {
|
|
|
336
336
|
return d;
|
|
337
337
|
return null; // no se pudo parsear
|
|
338
338
|
}
|
|
339
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
|
340
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.
|
|
339
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FlexibleDatePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
340
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.17", ngImport: i0, type: FlexibleDatePipe, isStandalone: true, name: "flexibleDate" });
|
|
341
341
|
}
|
|
342
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
|
342
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FlexibleDatePipe, decorators: [{
|
|
343
343
|
type: Pipe,
|
|
344
344
|
args: [{ name: 'flexibleDate' }]
|
|
345
345
|
}] });
|
|
346
346
|
|
|
347
|
+
/**
|
|
348
|
+
* Traduce el error de una llamada del puerto a un texto para el usuario, en español y de usted.
|
|
349
|
+
*
|
|
350
|
+
* Nunca devuelve el mensaje del backend, `err.message`, JSON ni texto en inglés: el texto sale
|
|
351
|
+
* siempre de este archivo, según el código de error. El detalle técnico va a `console.error`
|
|
352
|
+
* con el prefijo `[sf-documents]` para soporte.
|
|
353
|
+
*
|
|
354
|
+
* Formas de error que llegan hoy:
|
|
355
|
+
* - DocumentService directo (documents-manager-ui): `err.error` es su `ApiResponse`,
|
|
356
|
+
* `{ success, statusCode, message, errors: ['CODIGO'] }`.
|
|
357
|
+
* - Vía TFAServices (TFB): la fachada lanza `new Exception(response.Content)` y responde
|
|
358
|
+
* `{ success: false, message: 'Error: {json de DocumentService}' }`. Se desenvuelve ese JSON.
|
|
359
|
+
*/
|
|
360
|
+
const GENERIC_ERROR_MESSAGE = 'Ocurrió un error inesperado. Intente de nuevo.';
|
|
361
|
+
const NETWORK_ERROR_MESSAGE = 'No hay conexión con el servidor. Revise su conexión e intente de nuevo.';
|
|
362
|
+
/**
|
|
363
|
+
* Códigos de `errors[0]` que devuelve DocumentService (`ExceptionHandlerMiddleware` y
|
|
364
|
+
* `Core/Exceptions`) → texto para el usuario. Un código que no esté aquí usa el genérico.
|
|
365
|
+
*/
|
|
366
|
+
const ERROR_CODE_MESSAGES = {
|
|
367
|
+
DOCUMENT_PART_MISSING: 'Falta un documento requerido en el gestor para esta solicitud. Revise las carpetas e intente de nuevo.',
|
|
368
|
+
DOCUMENT_TOO_LARGE: 'El documento supera el tamaño máximo permitido. Contacte a soporte.',
|
|
369
|
+
DOCUMENT_GENERATION_ERROR: 'Una parte del documento no se pudo producir. Intente de nuevo; si persiste, contacte a soporte.',
|
|
370
|
+
DOCUMENT_CONFIGURATION_ERROR: 'El documento no está configurado correctamente. Contacte a soporte.',
|
|
371
|
+
RESOURCE_NOT_FOUND: 'No se encontró la información solicitada. Recargue la pantalla e intente de nuevo.',
|
|
372
|
+
VALIDATION_ERROR: 'Revise los datos ingresados e intente de nuevo.',
|
|
373
|
+
INVALID_ARGUMENT: 'Revise los datos ingresados e intente de nuevo.',
|
|
374
|
+
BATCH_TOO_LARGE: 'Los archivos superan el tamaño máximo permitido por envío. Suba menos archivos a la vez.',
|
|
375
|
+
REQUEST_TIMEOUT: 'El servidor tardó demasiado en responder. Intente de nuevo.',
|
|
376
|
+
};
|
|
377
|
+
/** Prefijo con el que TFAServices envuelve el cuerpo de DocumentService (`$"Error: {ex.Message}"`). */
|
|
378
|
+
const TFA_WRAPPER_PREFIX = 'Error: ';
|
|
379
|
+
function tryParseObject(text) {
|
|
380
|
+
if (typeof text !== 'string')
|
|
381
|
+
return null;
|
|
382
|
+
const trimmed = text.trim();
|
|
383
|
+
if (!trimmed.startsWith('{'))
|
|
384
|
+
return null;
|
|
385
|
+
try {
|
|
386
|
+
const parsed = JSON.parse(trimmed);
|
|
387
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
388
|
+
? parsed
|
|
389
|
+
: null;
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
/** Cuerpo de la respuesta de error, ya desenvuelto si viene de TFAServices. */
|
|
396
|
+
function extractBody(err) {
|
|
397
|
+
let body = null;
|
|
398
|
+
const raw = err?.error;
|
|
399
|
+
if (raw && typeof raw === 'object') {
|
|
400
|
+
body = raw;
|
|
401
|
+
}
|
|
402
|
+
else if (typeof raw === 'string') {
|
|
403
|
+
body = tryParseObject(raw);
|
|
404
|
+
}
|
|
405
|
+
else if (err && typeof err === 'object' && Array.isArray(err.errors)) {
|
|
406
|
+
// El host ya entregó el cuerpo (p. ej. un catchError que hace throwError(() => e.error)).
|
|
407
|
+
body = err;
|
|
408
|
+
}
|
|
409
|
+
const message = body?.['message'];
|
|
410
|
+
if (typeof message === 'string' && message.startsWith(TFA_WRAPPER_PREFIX + '{')) {
|
|
411
|
+
const inner = tryParseObject(message.slice(TFA_WRAPPER_PREFIX.length));
|
|
412
|
+
if (inner)
|
|
413
|
+
body = inner;
|
|
414
|
+
}
|
|
415
|
+
return body;
|
|
416
|
+
}
|
|
417
|
+
function extractCode(body) {
|
|
418
|
+
const first = Array.isArray(body?.['errors']) ? body['errors'][0] : null;
|
|
419
|
+
return typeof first === 'string' && first.trim() ? first.trim() : null;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Texto para el usuario a partir de un error del puerto.
|
|
423
|
+
* @param context Qué se estaba haciendo, solo para el log de soporte (p. ej. 'generateDocument').
|
|
424
|
+
*/
|
|
425
|
+
function getUserErrorMessage(err, context = '') {
|
|
426
|
+
const e = err;
|
|
427
|
+
const body = extractBody(e);
|
|
428
|
+
const code = extractCode(body);
|
|
429
|
+
const status = typeof e?.status === 'number' ? e.status : null;
|
|
430
|
+
console.error(`[sf-documents]${context ? ' ' + context : ''}`, {
|
|
431
|
+
status,
|
|
432
|
+
statusCode: body?.['statusCode'] ?? null,
|
|
433
|
+
code,
|
|
434
|
+
detail: body?.['message'] ?? e?.message ?? e,
|
|
435
|
+
});
|
|
436
|
+
if (status === 0)
|
|
437
|
+
return NETWORK_ERROR_MESSAGE;
|
|
438
|
+
if (code && ERROR_CODE_MESSAGES[code])
|
|
439
|
+
return ERROR_CODE_MESSAGES[code];
|
|
440
|
+
return GENERIC_ERROR_MESSAGE;
|
|
441
|
+
}
|
|
442
|
+
|
|
347
443
|
class FolderFilesComponent {
|
|
348
444
|
documentsService = inject(DOCUMENT_SERVICE);
|
|
349
445
|
searchSubject = new Subject();
|
|
@@ -373,6 +469,9 @@ class FolderFilesComponent {
|
|
|
373
469
|
docsEliminables = [];
|
|
374
470
|
totalDocsEliminadosApi = { existoso: 0, fallido: 0 };
|
|
375
471
|
loading = false;
|
|
472
|
+
/** Error de la última carga de archivos; se muestra con "Reintentar" en lugar de la lista. */
|
|
473
|
+
loadError = null;
|
|
474
|
+
filesSub;
|
|
376
475
|
allSelected = false;
|
|
377
476
|
pageSizeOptions = [
|
|
378
477
|
{ label: '5/pág', value: 5 },
|
|
@@ -417,6 +516,7 @@ class FolderFilesComponent {
|
|
|
417
516
|
this.totalDocsEliminadosApi = { existoso: 0, fallido: 0 };
|
|
418
517
|
this.searchQuery = '';
|
|
419
518
|
this.page = 1;
|
|
519
|
+
this.loadError = null;
|
|
420
520
|
this.applyPermissions();
|
|
421
521
|
if (!this.usesApi) {
|
|
422
522
|
// Modo children pre-cargados
|
|
@@ -459,9 +559,15 @@ class FolderFilesComponent {
|
|
|
459
559
|
}
|
|
460
560
|
}
|
|
461
561
|
loadFiles() {
|
|
562
|
+
// Una carga nueva (otra carpeta, página o búsqueda) cancela la anterior: así una respuesta
|
|
563
|
+
// vieja, buena o con error, no pisa lo que el usuario está mirando.
|
|
564
|
+
this.filesSub?.unsubscribe();
|
|
462
565
|
this.loading = true;
|
|
463
|
-
|
|
566
|
+
// loadError no se limpia aquí: mientras se reintenta, el error queda visible con
|
|
567
|
+
// "Reintentar" en estado de carga, y el foco no se pierde.
|
|
568
|
+
this.filesSub = this.documentsService
|
|
464
569
|
.getFilesByFolder(this.idKatios, this.carpeta.NMCo, this.requestData, this.page, this.pageSize, this.searchQuery)
|
|
570
|
+
.pipe(takeUntil(this.destroy$))
|
|
465
571
|
.subscribe({
|
|
466
572
|
next: (response) => {
|
|
467
573
|
const res = response?.data ?? response;
|
|
@@ -471,10 +577,13 @@ class FolderFilesComponent {
|
|
|
471
577
|
this.items = res.items ?? [];
|
|
472
578
|
this.items.forEach((item) => (item.delete = false));
|
|
473
579
|
this.buildPaths(this.items);
|
|
580
|
+
this.loadError = null;
|
|
474
581
|
this.loading = false;
|
|
475
582
|
},
|
|
476
583
|
error: (error) => {
|
|
477
|
-
|
|
584
|
+
// getUserErrorMessage deja el detalle técnico en console.error para soporte.
|
|
585
|
+
this.loadError = getUserErrorMessage(error, 'getFilesByFolder');
|
|
586
|
+
this.items = [];
|
|
478
587
|
this.loading = false;
|
|
479
588
|
},
|
|
480
589
|
});
|
|
@@ -545,10 +654,10 @@ class FolderFilesComponent {
|
|
|
545
654
|
this.page = 1;
|
|
546
655
|
this.loadFiles();
|
|
547
656
|
}
|
|
548
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
|
549
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: FolderFilesComponent, isStandalone: true, selector: "lib-folder-files", inputs: { carpeta: "carpeta", isMobile: "isMobile", idKatios: "idKatios", server: "server", subestado: "subestado", requestData: "requestData", useBreadcrumb: "useBreadcrumb", usesApi: "usesApi", allowedUploadTypes: "allowedUploadTypes" }, outputs: { onFileChange: "onFileChange", onCargarArchivo: "onCargarArchivo", onEliminarMasivo: "onEliminarMasivo", onBack: "onBack", viewDocument: "viewDocument" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"ff-layout\">\n <!-- Header fijo -->\n <div class=\"ff-header\">\n <div class=\"ff-back-row\" *ngIf=\"!useBreadcrumb\">\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-arrow-left\"\n label=\"Volver\"\n (click)=\"goBack()\"\n ></button>\n </div>\n\n <!-- Toolbar: b\u00FAsqueda + botones de acci\u00F3n -->\n <div class=\"ff-toolbar\">\n <p-iconfield class=\"ff-toolbar__search\">\n <p-inputicon class=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n [placeholder]=\"\n 'Buscar en ' +\n carpeta.label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\n \"\n [(ngModel)]=\"searchQuery\"\n (input)=\"onSearchInput()\"\n class=\"w-full\"\n />\n </p-iconfield>\n\n <div class=\"ff-toolbar__actions\">\n <lib-upload-dialog\n *ngIf=\"carpeta?.reglas?.permisos?.cargarFront\"\n [selectedDocument]=\"carpeta\"\n [allowedExtensions]=\"allowedUploadTypes\"\n (onUploaded)=\"fileChange($event)\"\n (loadFile)=\"cargarArchivo()\"\n >\n </lib-upload-dialog>\n\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-trash\"\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n (click)=\"emitEliminarMasivo()\"\n [disabled]=\"docsEliminables.length === 0\"\n class=\"p-button-outlined p-button-danger p-button-sm ff-btn-delete\"\n >\n <span class=\"ff-btn-label\"\n >Eliminar ({{ docsEliminables.length }})</span\n >\n </button>\n </div>\n </div>\n\n <!-- Fila seleccionar todo / total archivos -->\n <div class=\"ff-select-row\" *ngIf=\"!loading && items.length > 0\">\n <div class=\"ff-select-row__left\">\n <p-checkbox\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n [binary]=\"true\"\n [(ngModel)]=\"allSelected\"\n (onChange)=\"toggleSelectAll()\"\n >\n </p-checkbox>\n <span\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n class=\"ff-select-row__label\"\n >Seleccionar todo</span\n >\n </div>\n <span class=\"ff-select-row__count\"\n >{{ totalRecords || items.length }}\n {{\n (totalRecords || items.length) === 1 ? \"archivo\" : \"archivos\"\n }}</span\n >\n </div>\n </div>\n\n <!-- Contenido scrollable -->\n <div class=\"ff-file-list-wrapper\">\n <!-- Loading -->\n <div *ngIf=\"loading\" class=\"ff-loading\">\n <i class=\"pi pi-spin pi-spinner\" style=\"font-size: 2rem\"></i>\n </div>\n\n <!-- Lista de archivos -->\n <div class=\"ff-file-list\" *ngIf=\"!loading\">\n <div\n class=\"ff-file-item\"\n *ngFor=\"let item of items\"\n (click)=\"openVisorDoc(item)\"\n >\n <p-checkbox\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n [binary]=\"true\"\n [(ngModel)]=\"item.delete\"\n (onChange)=\"onClickedCheckDelete($event, item)\"\n (click)=\"$event.stopPropagation()\"\n >\n </p-checkbox>\n\n <div class=\"ff-file-item__preview\">\n <i\n *ngIf=\"!canPreview(item.label, item.Path)\"\n class=\"pi ff-file-item__frame ff-file-item__icon\"\n [ngClass]=\"previewFallbackIcon(item.label, item.Path)\"\n ></i>\n <ng-container *ngIf=\"canPreview(item.label, item.Path)\">\n <embed\n *ngIf=\"carpeta.TipoArchivo == '2'\"\n class=\"ff-file-item__frame\"\n [src]=\"item.Path | safe\"\n />\n <img\n *ngIf=\"carpeta.TipoArchivo == '1' && isMobile\"\n class=\"ff-file-item__frame\"\n src=\"https://macuna.tecfinanzas.com/Imagenes/pdf_icon.png\"\n />\n <iframe\n *ngIf=\"carpeta.TipoArchivo == '1' && !isMobile\"\n class=\"ff-file-item__frame\"\n [src]=\"item.Path | safe\"\n frameborder=\"0\"\n ></iframe>\n </ng-container>\n </div>\n\n <div class=\"ff-file-item__info\">\n <span class=\"ff-file-item__name\">{{ item.label }}</span>\n <span class=\"ff-file-item__date\" *ngIf=\"item.FechaSubida && !isMobile\"\n >Fecha Subida:\n {{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\n >\n <span\n class=\"ff-file-item__date\"\n *ngIf=\"item.FechaSubida && isMobile\"\n >{{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\n >\n <i\n class=\"pi pi-external-link ff-file-item__open\"\n (click)=\"\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\n \"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Abrir en nueva ventana\"\n (keydown.enter)=\"\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\n \"\n ></i>\n </div>\n </div>\n </div>\n\n <!-- Sin resultados -->\n <div *ngIf=\"!loading && items.length === 0\" class=\"ff-empty\">\n Sin documentos cargados\n </div>\n </div>\n\n <!-- Footer fijo: paginaci\u00F3n compacta -->\n <div class=\"ff-footer\" *ngIf=\"usesApi && totalRecords > 0\">\n <div class=\"ff-pagination\">\n <p-select\n [options]=\"pageSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"pageSize\"\n (ngModelChange)=\"onPageSizeChange()\"\n >\n </p-select>\n <p-paginator\n [first]=\"first\"\n [rows]=\"pageSize\"\n [totalRecords]=\"totalRecords\"\n (onPageChange)=\"onPageChange($event)\"\n [showCurrentPageReport]=\"true\"\n currentPageReportTemplate=\"{first} - {last} de {totalRecords}\"\n [showPageLinks]=\"false\"\n [showFirstLastIcon]=\"false\"\n >\n </p-paginator>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-header{flex-shrink:0}.ff-back-row{display:flex;margin-block:15px}.ff-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:4px;padding:.5rem}.ff-toolbar__search{flex:1;min-width:0}:host ::ng-deep .ff-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.ff-toolbar__actions{display:flex;align-items:center;gap:6px;flex-shrink:0}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px;padding:.4rem .75rem}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .ff-btn-delete{white-space:nowrap;font-size:13px;padding:.4rem .75rem}.ff-select-row{display:flex;align-items:center;justify-content:space-between;padding:8px 4px;border-bottom:1px solid #e5e7eb;padding:.5rem}.ff-select-row__left{display:flex;align-items:center;gap:8px}.ff-select-row__label{font-size:13px;color:#374151}.ff-select-row__count{font-size:13px;color:#6b7280}.ff-file-list-wrapper{flex:1;min-height:0;overflow-y:auto}.ff-loading{text-align:center;padding:20px}.ff-file-list{display:flex;flex-direction:column}.ff-file-item{display:flex;align-items:center;gap:12px;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.ff-file-item:hover{background-color:#f9fafb}.ff-file-item__preview{flex-shrink:0;width:85px;height:100px;overflow:hidden;display:flex;align-items:center;justify-content:center}.ff-file-item__frame{width:85px;height:100px;border:none;pointer-events:none;object-fit:cover}.ff-file-item__icon{display:flex;align-items:center;justify-content:center;font-size:40px;color:#6b7280;background-color:#f3f4f6;border-radius:4px}.ff-file-item__icon.pi-file-excel{color:#1d6f42;background-color:#f0faf5}.ff-file-item__icon.pi-file-pdf{color:#b91c1c;background-color:#fef2f2}.ff-file-item__icon.pi-file-word{color:#1d4ed8;background-color:#eff6ff}.ff-file-item__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px;text-align:right}.ff-file-item__name{font-size:13px;font-weight:500;color:#111827;min-width:0;word-break:break-word}.ff-file-item__date{font-size:12px;color:#9ca3af;overflow:hidden}.ff-file-item__open{font-size:18px;color:#3b82f6;flex-shrink:0;padding:4px;border-radius:4px;transition:color .15s ease,background-color .15s ease;cursor:pointer;align-self:flex-end}.ff-file-item__open:hover{color:#2563eb;background-color:#eff6ff}.ff-empty{text-align:center;padding:20px;color:#999}.ff-footer{flex-shrink:0;border-top:1px solid #e5e7eb}.ff-pagination{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px;font-size:13px}:host ::ng-deep .ff-pagination .p-select{width:auto;min-width:90px}:host ::ng-deep .ff-pagination .p-select .p-select-label{font-size:12px;padding:4px 8px}:host ::ng-deep .ff-pagination .p-paginator{padding:0;background:transparent;border:none;gap:0}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-current{font-size:12px;color:#6b7280;padding:0 6px;min-width:auto;height:auto}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-prev,:host ::ng-deep .ff-pagination .p-paginator .p-paginator-next{min-width:28px;height:28px;font-size:12px}@media only screen and (max-width: 656px){.ff-toolbar{gap:6px}.ff-btn-label{display:none}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button .p-button-label{display:none}:host ::ng-deep .ff-toolbar__actions .p-button{padding:.5rem}.ff-file-item__preview,.ff-file-item__frame{width:65px;height:80px}.ff-file-item__icon{font-size:28px}.ff-file-item__name{font-size:12px}.ff-file-item__date{font-size:11px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$1.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i5.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "component", type: InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["styleClass"] }, { kind: "component", type: IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["iconPosition", "styleClass"] }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i6.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "style", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "appendTo", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first"], outputs: ["onPageChange"] }, { kind: "pipe", type: SafePipe, name: "safe" }, { kind: "component", type: UploadDialogComponent, selector: "lib-upload-dialog", inputs: ["selectedDocument", "allowedExtensions"], outputs: ["onUploaded", "loadFile"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i7.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "pipe", type: FlexibleDatePipe, name: "flexibleDate" }, { kind: "ngmodule", type: DialogModule }] });
|
|
657
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FolderFilesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
658
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FolderFilesComponent, isStandalone: true, selector: "lib-folder-files", inputs: { carpeta: "carpeta", isMobile: "isMobile", idKatios: "idKatios", server: "server", subestado: "subestado", requestData: "requestData", useBreadcrumb: "useBreadcrumb", usesApi: "usesApi", allowedUploadTypes: "allowedUploadTypes" }, outputs: { onFileChange: "onFileChange", onCargarArchivo: "onCargarArchivo", onEliminarMasivo: "onEliminarMasivo", onBack: "onBack", viewDocument: "viewDocument" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"ff-layout\">\n <!-- Header fijo -->\n <div class=\"ff-header\">\n <div class=\"ff-back-row\" *ngIf=\"!useBreadcrumb\">\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-arrow-left\"\n label=\"Volver\"\n (click)=\"goBack()\"\n ></button>\n </div>\n\n <!-- Toolbar: b\u00FAsqueda + botones de acci\u00F3n -->\n <div class=\"ff-toolbar\">\n <p-iconfield class=\"ff-toolbar__search\">\n <p-inputicon class=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n [placeholder]=\"\n 'Buscar en ' +\n carpeta.label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\n \"\n [(ngModel)]=\"searchQuery\"\n (input)=\"onSearchInput()\"\n class=\"w-full\"\n />\n </p-iconfield>\n\n <div class=\"ff-toolbar__actions\">\n <lib-upload-dialog\n *ngIf=\"carpeta?.reglas?.permisos?.cargarFront\"\n [selectedDocument]=\"carpeta\"\n [allowedExtensions]=\"allowedUploadTypes\"\n (onUploaded)=\"fileChange($event)\"\n (loadFile)=\"cargarArchivo()\"\n >\n </lib-upload-dialog>\n\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-trash\"\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n (click)=\"emitEliminarMasivo()\"\n [disabled]=\"docsEliminables.length === 0\"\n class=\"p-button-outlined p-button-danger p-button-sm ff-btn-delete\"\n >\n <span class=\"ff-btn-label\"\n >Eliminar ({{ docsEliminables.length }})</span\n >\n </button>\n </div>\n </div>\n\n <!-- Fila seleccionar todo / total archivos -->\n <div class=\"ff-select-row\" *ngIf=\"!loading && items.length > 0\">\n <div class=\"ff-select-row__left\">\n <p-checkbox\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n [binary]=\"true\"\n [(ngModel)]=\"allSelected\"\n (onChange)=\"toggleSelectAll()\"\n >\n </p-checkbox>\n <span\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n class=\"ff-select-row__label\"\n >Seleccionar todo</span\n >\n </div>\n <span class=\"ff-select-row__count\"\n >{{ totalRecords || items.length }}\n {{\n (totalRecords || items.length) === 1 ? \"archivo\" : \"archivos\"\n }}</span\n >\n </div>\n </div>\n\n <!-- Contenido scrollable -->\n <div class=\"ff-file-list-wrapper\">\n <!-- Loading -->\n <div *ngIf=\"loading && !loadError\" class=\"ff-loading\">\n <i class=\"pi pi-spin pi-spinner\" style=\"font-size: 2rem\"></i>\n </div>\n\n <!-- Error al cargar: el usuario puede volver a pedir solo esta carpeta. Mientras se\n reintenta, el error sigue a la vista y el bot\u00F3n muestra la carga. Sin [disabled]: un\n bot\u00F3n deshabilitado suelta el foco al body y quien usa teclado vuelve a empezar. -->\n <div *ngIf=\"loadError\" class=\"ff-error\">\n <p-message severity=\"error\" icon=\"pi pi-times-circle\" styleClass=\"w-full\">\n No se pudieron cargar los documentos. {{ loadError }}\n </p-message>\n <button\n pButton\n type=\"button\"\n label=\"Reintentar\"\n icon=\"pi pi-refresh\"\n [loading]=\"loading\"\n [attr.aria-disabled]=\"loading\"\n (click)=\"!loading && loadFiles()\"\n ></button>\n </div>\n\n <!-- Lista de archivos -->\n <div class=\"ff-file-list\" *ngIf=\"!loading && !loadError\">\n <div\n class=\"ff-file-item\"\n *ngFor=\"let item of items\"\n (click)=\"openVisorDoc(item)\"\n >\n <p-checkbox\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n [binary]=\"true\"\n [(ngModel)]=\"item.delete\"\n (onChange)=\"onClickedCheckDelete($event, item)\"\n (click)=\"$event.stopPropagation()\"\n >\n </p-checkbox>\n\n <div class=\"ff-file-item__preview\">\n <i\n *ngIf=\"!canPreview(item.label, item.Path)\"\n class=\"pi ff-file-item__frame ff-file-item__icon\"\n [ngClass]=\"previewFallbackIcon(item.label, item.Path)\"\n ></i>\n <ng-container *ngIf=\"canPreview(item.label, item.Path)\">\n <embed\n *ngIf=\"carpeta.TipoArchivo == '2'\"\n class=\"ff-file-item__frame\"\n [src]=\"item.Path | safe\"\n />\n <img\n *ngIf=\"carpeta.TipoArchivo == '1' && isMobile\"\n class=\"ff-file-item__frame\"\n src=\"https://macuna.tecfinanzas.com/Imagenes/pdf_icon.png\"\n />\n <iframe\n *ngIf=\"carpeta.TipoArchivo == '1' && !isMobile\"\n class=\"ff-file-item__frame\"\n [src]=\"item.Path | safe\"\n frameborder=\"0\"\n ></iframe>\n </ng-container>\n </div>\n\n <div class=\"ff-file-item__info\">\n <span class=\"ff-file-item__name\">{{ item.label }}</span>\n <span class=\"ff-file-item__date\" *ngIf=\"item.FechaSubida && !isMobile\"\n >Fecha Subida:\n {{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\n >\n <span\n class=\"ff-file-item__date\"\n *ngIf=\"item.FechaSubida && isMobile\"\n >{{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\n >\n <i\n class=\"pi pi-external-link ff-file-item__open\"\n (click)=\"\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\n \"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Abrir en nueva ventana\"\n (keydown.enter)=\"\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\n \"\n ></i>\n </div>\n </div>\n </div>\n\n <!-- Sin resultados -->\n <div *ngIf=\"!loading && !loadError && items.length === 0\" class=\"ff-empty\">\n Sin documentos cargados\n </div>\n </div>\n\n <!-- Footer fijo: paginaci\u00F3n compacta -->\n <div class=\"ff-footer\" *ngIf=\"usesApi && totalRecords > 0 && !loadError\">\n <div class=\"ff-pagination\">\n <p-select\n [options]=\"pageSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"pageSize\"\n (ngModelChange)=\"onPageSizeChange()\"\n >\n </p-select>\n <p-paginator\n [first]=\"first\"\n [rows]=\"pageSize\"\n [totalRecords]=\"totalRecords\"\n (onPageChange)=\"onPageChange($event)\"\n [showCurrentPageReport]=\"true\"\n currentPageReportTemplate=\"{first} - {last} de {totalRecords}\"\n [showPageLinks]=\"false\"\n [showFirstLastIcon]=\"false\"\n >\n </p-paginator>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-header{flex-shrink:0}.ff-back-row{display:flex;margin-block:15px}.ff-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:4px;padding:.5rem}.ff-toolbar__search{flex:1;min-width:0}:host ::ng-deep .ff-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.ff-toolbar__actions{display:flex;align-items:center;gap:6px;flex-shrink:0}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px;padding:.4rem .75rem}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .ff-btn-delete{white-space:nowrap;font-size:13px;padding:.4rem .75rem}.ff-select-row{display:flex;align-items:center;justify-content:space-between;padding:8px 4px;border-bottom:1px solid #e5e7eb;padding:.5rem}.ff-select-row__left{display:flex;align-items:center;gap:8px}.ff-select-row__label{font-size:13px;color:#374151}.ff-select-row__count{font-size:13px;color:#6b7280}.ff-file-list-wrapper{flex:1;min-height:0;overflow-y:auto}.ff-loading{text-align:center;padding:20px}.ff-file-list{display:flex;flex-direction:column}.ff-file-item{display:flex;align-items:center;gap:12px;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.ff-file-item:hover{background-color:#f9fafb}.ff-file-item__preview{flex-shrink:0;width:85px;height:100px;overflow:hidden;display:flex;align-items:center;justify-content:center}.ff-file-item__frame{width:85px;height:100px;border:none;pointer-events:none;object-fit:cover}.ff-file-item__icon{display:flex;align-items:center;justify-content:center;font-size:40px;color:#6b7280;background-color:#f3f4f6;border-radius:4px}.ff-file-item__icon.pi-file-excel{color:#1d6f42;background-color:#f0faf5}.ff-file-item__icon.pi-file-pdf{color:#b91c1c;background-color:#fef2f2}.ff-file-item__icon.pi-file-word{color:#1d4ed8;background-color:#eff6ff}.ff-file-item__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px;text-align:right}.ff-file-item__name{font-size:13px;font-weight:500;color:#111827;min-width:0;word-break:break-word}.ff-file-item__date{font-size:12px;color:#9ca3af;overflow:hidden}.ff-file-item__open{font-size:18px;color:#3b82f6;flex-shrink:0;padding:4px;border-radius:4px;transition:color .15s ease,background-color .15s ease;cursor:pointer;align-self:flex-end}.ff-file-item__open:hover{color:#2563eb;background-color:#eff6ff}.ff-empty{text-align:center;padding:20px;color:#999}.ff-error{display:flex;flex-direction:column;align-items:center;gap:12px;padding:20px}.ff-error p-message{align-self:stretch}.ff-footer{flex-shrink:0;border-top:1px solid #e5e7eb}.ff-pagination{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px;font-size:13px}:host ::ng-deep .ff-pagination .p-select{width:auto;min-width:90px}:host ::ng-deep .ff-pagination .p-select .p-select-label{font-size:12px;padding:4px 8px}:host ::ng-deep .ff-pagination .p-paginator{padding:0;background:transparent;border:none;gap:0}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-current{font-size:12px;color:#6b7280;padding:0 6px;min-width:auto;height:auto}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-prev,:host ::ng-deep .ff-pagination .p-paginator .p-paginator-next{min-width:28px;height:28px;font-size:12px}@media only screen and (max-width: 656px){.ff-toolbar{gap:6px}.ff-btn-label{display:none}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button .p-button-label{display:none}:host ::ng-deep .ff-toolbar__actions .p-button{padding:.5rem}.ff-file-item__preview,.ff-file-item__frame{width:65px;height:80px}.ff-file-item__icon{font-size:28px}.ff-file-item__name{font-size:12px}.ff-file-item__date{font-size:11px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i10.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i10.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i10.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$1.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i5.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "component", type: InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["styleClass"] }, { kind: "component", type: IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["iconPosition", "styleClass"] }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i6.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "style", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "appendTo", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first"], outputs: ["onPageChange"] }, { kind: "pipe", type: SafePipe, name: "safe" }, { kind: "component", type: UploadDialogComponent, selector: "lib-upload-dialog", inputs: ["selectedDocument", "allowedExtensions"], outputs: ["onUploaded", "loadFile"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i7.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "pipe", type: FlexibleDatePipe, name: "flexibleDate" }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i8.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] });
|
|
550
659
|
}
|
|
551
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
|
660
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FolderFilesComponent, decorators: [{
|
|
552
661
|
type: Component,
|
|
553
662
|
args: [{ selector: 'lib-folder-files', imports: [
|
|
554
663
|
CommonModule,
|
|
@@ -564,7 +673,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
564
673
|
SelectModule,
|
|
565
674
|
FlexibleDatePipe,
|
|
566
675
|
DialogModule,
|
|
567
|
-
], standalone: true, template: "<div class=\"ff-layout\">\n <!-- Header fijo -->\n <div class=\"ff-header\">\n <div class=\"ff-back-row\" *ngIf=\"!useBreadcrumb\">\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-arrow-left\"\n label=\"Volver\"\n (click)=\"goBack()\"\n ></button>\n </div>\n\n <!-- Toolbar: b\u00FAsqueda + botones de acci\u00F3n -->\n <div class=\"ff-toolbar\">\n <p-iconfield class=\"ff-toolbar__search\">\n <p-inputicon class=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n [placeholder]=\"\n 'Buscar en ' +\n carpeta.label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\n \"\n [(ngModel)]=\"searchQuery\"\n (input)=\"onSearchInput()\"\n class=\"w-full\"\n />\n </p-iconfield>\n\n <div class=\"ff-toolbar__actions\">\n <lib-upload-dialog\n *ngIf=\"carpeta?.reglas?.permisos?.cargarFront\"\n [selectedDocument]=\"carpeta\"\n [allowedExtensions]=\"allowedUploadTypes\"\n (onUploaded)=\"fileChange($event)\"\n (loadFile)=\"cargarArchivo()\"\n >\n </lib-upload-dialog>\n\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-trash\"\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n (click)=\"emitEliminarMasivo()\"\n [disabled]=\"docsEliminables.length === 0\"\n class=\"p-button-outlined p-button-danger p-button-sm ff-btn-delete\"\n >\n <span class=\"ff-btn-label\"\n >Eliminar ({{ docsEliminables.length }})</span\n >\n </button>\n </div>\n </div>\n\n <!-- Fila seleccionar todo / total archivos -->\n <div class=\"ff-select-row\" *ngIf=\"!loading && items.length > 0\">\n <div class=\"ff-select-row__left\">\n <p-checkbox\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n [binary]=\"true\"\n [(ngModel)]=\"allSelected\"\n (onChange)=\"toggleSelectAll()\"\n >\n </p-checkbox>\n <span\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n class=\"ff-select-row__label\"\n >Seleccionar todo</span\n >\n </div>\n <span class=\"ff-select-row__count\"\n >{{ totalRecords || items.length }}\n {{\n (totalRecords || items.length) === 1 ? \"archivo\" : \"archivos\"\n }}</span\n >\n </div>\n </div>\n\n <!-- Contenido scrollable -->\n <div class=\"ff-file-list-wrapper\">\n <!-- Loading -->\n <div *ngIf=\"loading\" class=\"ff-loading\">\n <i class=\"pi pi-spin pi-spinner\" style=\"font-size: 2rem\"></i>\n </div>\n\n <!-- Lista de archivos -->\n <div class=\"ff-file-list\" *ngIf=\"!loading\">\n <div\n class=\"ff-file-item\"\n *ngFor=\"let item of items\"\n (click)=\"openVisorDoc(item)\"\n >\n <p-checkbox\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n [binary]=\"true\"\n [(ngModel)]=\"item.delete\"\n (onChange)=\"onClickedCheckDelete($event, item)\"\n (click)=\"$event.stopPropagation()\"\n >\n </p-checkbox>\n\n <div class=\"ff-file-item__preview\">\n <i\n *ngIf=\"!canPreview(item.label, item.Path)\"\n class=\"pi ff-file-item__frame ff-file-item__icon\"\n [ngClass]=\"previewFallbackIcon(item.label, item.Path)\"\n ></i>\n <ng-container *ngIf=\"canPreview(item.label, item.Path)\">\n <embed\n *ngIf=\"carpeta.TipoArchivo == '2'\"\n class=\"ff-file-item__frame\"\n [src]=\"item.Path | safe\"\n />\n <img\n *ngIf=\"carpeta.TipoArchivo == '1' && isMobile\"\n class=\"ff-file-item__frame\"\n src=\"https://macuna.tecfinanzas.com/Imagenes/pdf_icon.png\"\n />\n <iframe\n *ngIf=\"carpeta.TipoArchivo == '1' && !isMobile\"\n class=\"ff-file-item__frame\"\n [src]=\"item.Path | safe\"\n frameborder=\"0\"\n ></iframe>\n </ng-container>\n </div>\n\n <div class=\"ff-file-item__info\">\n <span class=\"ff-file-item__name\">{{ item.label }}</span>\n <span class=\"ff-file-item__date\" *ngIf=\"item.FechaSubida && !isMobile\"\n >Fecha Subida:\n {{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\n >\n <span\n class=\"ff-file-item__date\"\n *ngIf=\"item.FechaSubida && isMobile\"\n >{{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\n >\n <i\n class=\"pi pi-external-link ff-file-item__open\"\n (click)=\"\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\n \"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Abrir en nueva ventana\"\n (keydown.enter)=\"\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\n \"\n ></i>\n </div>\n </div>\n </div>\n\n <!-- Sin resultados -->\n <div *ngIf=\"!loading && items.length === 0\" class=\"ff-empty\">\n Sin documentos cargados\n </div>\n </div>\n\n <!-- Footer fijo: paginaci\u00F3n compacta -->\n <div class=\"ff-footer\" *ngIf=\"usesApi && totalRecords > 0\">\n <div class=\"ff-pagination\">\n <p-select\n [options]=\"pageSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"pageSize\"\n (ngModelChange)=\"onPageSizeChange()\"\n >\n </p-select>\n <p-paginator\n [first]=\"first\"\n [rows]=\"pageSize\"\n [totalRecords]=\"totalRecords\"\n (onPageChange)=\"onPageChange($event)\"\n [showCurrentPageReport]=\"true\"\n currentPageReportTemplate=\"{first} - {last} de {totalRecords}\"\n [showPageLinks]=\"false\"\n [showFirstLastIcon]=\"false\"\n >\n </p-paginator>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-header{flex-shrink:0}.ff-back-row{display:flex;margin-block:15px}.ff-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:4px;padding:.5rem}.ff-toolbar__search{flex:1;min-width:0}:host ::ng-deep .ff-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.ff-toolbar__actions{display:flex;align-items:center;gap:6px;flex-shrink:0}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px;padding:.4rem .75rem}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .ff-btn-delete{white-space:nowrap;font-size:13px;padding:.4rem .75rem}.ff-select-row{display:flex;align-items:center;justify-content:space-between;padding:8px 4px;border-bottom:1px solid #e5e7eb;padding:.5rem}.ff-select-row__left{display:flex;align-items:center;gap:8px}.ff-select-row__label{font-size:13px;color:#374151}.ff-select-row__count{font-size:13px;color:#6b7280}.ff-file-list-wrapper{flex:1;min-height:0;overflow-y:auto}.ff-loading{text-align:center;padding:20px}.ff-file-list{display:flex;flex-direction:column}.ff-file-item{display:flex;align-items:center;gap:12px;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.ff-file-item:hover{background-color:#f9fafb}.ff-file-item__preview{flex-shrink:0;width:85px;height:100px;overflow:hidden;display:flex;align-items:center;justify-content:center}.ff-file-item__frame{width:85px;height:100px;border:none;pointer-events:none;object-fit:cover}.ff-file-item__icon{display:flex;align-items:center;justify-content:center;font-size:40px;color:#6b7280;background-color:#f3f4f6;border-radius:4px}.ff-file-item__icon.pi-file-excel{color:#1d6f42;background-color:#f0faf5}.ff-file-item__icon.pi-file-pdf{color:#b91c1c;background-color:#fef2f2}.ff-file-item__icon.pi-file-word{color:#1d4ed8;background-color:#eff6ff}.ff-file-item__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px;text-align:right}.ff-file-item__name{font-size:13px;font-weight:500;color:#111827;min-width:0;word-break:break-word}.ff-file-item__date{font-size:12px;color:#9ca3af;overflow:hidden}.ff-file-item__open{font-size:18px;color:#3b82f6;flex-shrink:0;padding:4px;border-radius:4px;transition:color .15s ease,background-color .15s ease;cursor:pointer;align-self:flex-end}.ff-file-item__open:hover{color:#2563eb;background-color:#eff6ff}.ff-empty{text-align:center;padding:20px;color:#999}.ff-footer{flex-shrink:0;border-top:1px solid #e5e7eb}.ff-pagination{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px;font-size:13px}:host ::ng-deep .ff-pagination .p-select{width:auto;min-width:90px}:host ::ng-deep .ff-pagination .p-select .p-select-label{font-size:12px;padding:4px 8px}:host ::ng-deep .ff-pagination .p-paginator{padding:0;background:transparent;border:none;gap:0}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-current{font-size:12px;color:#6b7280;padding:0 6px;min-width:auto;height:auto}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-prev,:host ::ng-deep .ff-pagination .p-paginator .p-paginator-next{min-width:28px;height:28px;font-size:12px}@media only screen and (max-width: 656px){.ff-toolbar{gap:6px}.ff-btn-label{display:none}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button .p-button-label{display:none}:host ::ng-deep .ff-toolbar__actions .p-button{padding:.5rem}.ff-file-item__preview,.ff-file-item__frame{width:65px;height:80px}.ff-file-item__icon{font-size:28px}.ff-file-item__name{font-size:12px}.ff-file-item__date{font-size:11px}}\n"] }]
|
|
676
|
+
MessageModule,
|
|
677
|
+
], standalone: true, template: "<div class=\"ff-layout\">\n <!-- Header fijo -->\n <div class=\"ff-header\">\n <div class=\"ff-back-row\" *ngIf=\"!useBreadcrumb\">\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-arrow-left\"\n label=\"Volver\"\n (click)=\"goBack()\"\n ></button>\n </div>\n\n <!-- Toolbar: b\u00FAsqueda + botones de acci\u00F3n -->\n <div class=\"ff-toolbar\">\n <p-iconfield class=\"ff-toolbar__search\">\n <p-inputicon class=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n [placeholder]=\"\n 'Buscar en ' +\n carpeta.label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\n \"\n [(ngModel)]=\"searchQuery\"\n (input)=\"onSearchInput()\"\n class=\"w-full\"\n />\n </p-iconfield>\n\n <div class=\"ff-toolbar__actions\">\n <lib-upload-dialog\n *ngIf=\"carpeta?.reglas?.permisos?.cargarFront\"\n [selectedDocument]=\"carpeta\"\n [allowedExtensions]=\"allowedUploadTypes\"\n (onUploaded)=\"fileChange($event)\"\n (loadFile)=\"cargarArchivo()\"\n >\n </lib-upload-dialog>\n\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-trash\"\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n (click)=\"emitEliminarMasivo()\"\n [disabled]=\"docsEliminables.length === 0\"\n class=\"p-button-outlined p-button-danger p-button-sm ff-btn-delete\"\n >\n <span class=\"ff-btn-label\"\n >Eliminar ({{ docsEliminables.length }})</span\n >\n </button>\n </div>\n </div>\n\n <!-- Fila seleccionar todo / total archivos -->\n <div class=\"ff-select-row\" *ngIf=\"!loading && items.length > 0\">\n <div class=\"ff-select-row__left\">\n <p-checkbox\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n [binary]=\"true\"\n [(ngModel)]=\"allSelected\"\n (onChange)=\"toggleSelectAll()\"\n >\n </p-checkbox>\n <span\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n class=\"ff-select-row__label\"\n >Seleccionar todo</span\n >\n </div>\n <span class=\"ff-select-row__count\"\n >{{ totalRecords || items.length }}\n {{\n (totalRecords || items.length) === 1 ? \"archivo\" : \"archivos\"\n }}</span\n >\n </div>\n </div>\n\n <!-- Contenido scrollable -->\n <div class=\"ff-file-list-wrapper\">\n <!-- Loading -->\n <div *ngIf=\"loading && !loadError\" class=\"ff-loading\">\n <i class=\"pi pi-spin pi-spinner\" style=\"font-size: 2rem\"></i>\n </div>\n\n <!-- Error al cargar: el usuario puede volver a pedir solo esta carpeta. Mientras se\n reintenta, el error sigue a la vista y el bot\u00F3n muestra la carga. Sin [disabled]: un\n bot\u00F3n deshabilitado suelta el foco al body y quien usa teclado vuelve a empezar. -->\n <div *ngIf=\"loadError\" class=\"ff-error\">\n <p-message severity=\"error\" icon=\"pi pi-times-circle\" styleClass=\"w-full\">\n No se pudieron cargar los documentos. {{ loadError }}\n </p-message>\n <button\n pButton\n type=\"button\"\n label=\"Reintentar\"\n icon=\"pi pi-refresh\"\n [loading]=\"loading\"\n [attr.aria-disabled]=\"loading\"\n (click)=\"!loading && loadFiles()\"\n ></button>\n </div>\n\n <!-- Lista de archivos -->\n <div class=\"ff-file-list\" *ngIf=\"!loading && !loadError\">\n <div\n class=\"ff-file-item\"\n *ngFor=\"let item of items\"\n (click)=\"openVisorDoc(item)\"\n >\n <p-checkbox\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n [binary]=\"true\"\n [(ngModel)]=\"item.delete\"\n (onChange)=\"onClickedCheckDelete($event, item)\"\n (click)=\"$event.stopPropagation()\"\n >\n </p-checkbox>\n\n <div class=\"ff-file-item__preview\">\n <i\n *ngIf=\"!canPreview(item.label, item.Path)\"\n class=\"pi ff-file-item__frame ff-file-item__icon\"\n [ngClass]=\"previewFallbackIcon(item.label, item.Path)\"\n ></i>\n <ng-container *ngIf=\"canPreview(item.label, item.Path)\">\n <embed\n *ngIf=\"carpeta.TipoArchivo == '2'\"\n class=\"ff-file-item__frame\"\n [src]=\"item.Path | safe\"\n />\n <img\n *ngIf=\"carpeta.TipoArchivo == '1' && isMobile\"\n class=\"ff-file-item__frame\"\n src=\"https://macuna.tecfinanzas.com/Imagenes/pdf_icon.png\"\n />\n <iframe\n *ngIf=\"carpeta.TipoArchivo == '1' && !isMobile\"\n class=\"ff-file-item__frame\"\n [src]=\"item.Path | safe\"\n frameborder=\"0\"\n ></iframe>\n </ng-container>\n </div>\n\n <div class=\"ff-file-item__info\">\n <span class=\"ff-file-item__name\">{{ item.label }}</span>\n <span class=\"ff-file-item__date\" *ngIf=\"item.FechaSubida && !isMobile\"\n >Fecha Subida:\n {{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\n >\n <span\n class=\"ff-file-item__date\"\n *ngIf=\"item.FechaSubida && isMobile\"\n >{{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\n >\n <i\n class=\"pi pi-external-link ff-file-item__open\"\n (click)=\"\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\n \"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Abrir en nueva ventana\"\n (keydown.enter)=\"\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\n \"\n ></i>\n </div>\n </div>\n </div>\n\n <!-- Sin resultados -->\n <div *ngIf=\"!loading && !loadError && items.length === 0\" class=\"ff-empty\">\n Sin documentos cargados\n </div>\n </div>\n\n <!-- Footer fijo: paginaci\u00F3n compacta -->\n <div class=\"ff-footer\" *ngIf=\"usesApi && totalRecords > 0 && !loadError\">\n <div class=\"ff-pagination\">\n <p-select\n [options]=\"pageSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"pageSize\"\n (ngModelChange)=\"onPageSizeChange()\"\n >\n </p-select>\n <p-paginator\n [first]=\"first\"\n [rows]=\"pageSize\"\n [totalRecords]=\"totalRecords\"\n (onPageChange)=\"onPageChange($event)\"\n [showCurrentPageReport]=\"true\"\n currentPageReportTemplate=\"{first} - {last} de {totalRecords}\"\n [showPageLinks]=\"false\"\n [showFirstLastIcon]=\"false\"\n >\n </p-paginator>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-header{flex-shrink:0}.ff-back-row{display:flex;margin-block:15px}.ff-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:4px;padding:.5rem}.ff-toolbar__search{flex:1;min-width:0}:host ::ng-deep .ff-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.ff-toolbar__actions{display:flex;align-items:center;gap:6px;flex-shrink:0}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px;padding:.4rem .75rem}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .ff-btn-delete{white-space:nowrap;font-size:13px;padding:.4rem .75rem}.ff-select-row{display:flex;align-items:center;justify-content:space-between;padding:8px 4px;border-bottom:1px solid #e5e7eb;padding:.5rem}.ff-select-row__left{display:flex;align-items:center;gap:8px}.ff-select-row__label{font-size:13px;color:#374151}.ff-select-row__count{font-size:13px;color:#6b7280}.ff-file-list-wrapper{flex:1;min-height:0;overflow-y:auto}.ff-loading{text-align:center;padding:20px}.ff-file-list{display:flex;flex-direction:column}.ff-file-item{display:flex;align-items:center;gap:12px;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.ff-file-item:hover{background-color:#f9fafb}.ff-file-item__preview{flex-shrink:0;width:85px;height:100px;overflow:hidden;display:flex;align-items:center;justify-content:center}.ff-file-item__frame{width:85px;height:100px;border:none;pointer-events:none;object-fit:cover}.ff-file-item__icon{display:flex;align-items:center;justify-content:center;font-size:40px;color:#6b7280;background-color:#f3f4f6;border-radius:4px}.ff-file-item__icon.pi-file-excel{color:#1d6f42;background-color:#f0faf5}.ff-file-item__icon.pi-file-pdf{color:#b91c1c;background-color:#fef2f2}.ff-file-item__icon.pi-file-word{color:#1d4ed8;background-color:#eff6ff}.ff-file-item__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px;text-align:right}.ff-file-item__name{font-size:13px;font-weight:500;color:#111827;min-width:0;word-break:break-word}.ff-file-item__date{font-size:12px;color:#9ca3af;overflow:hidden}.ff-file-item__open{font-size:18px;color:#3b82f6;flex-shrink:0;padding:4px;border-radius:4px;transition:color .15s ease,background-color .15s ease;cursor:pointer;align-self:flex-end}.ff-file-item__open:hover{color:#2563eb;background-color:#eff6ff}.ff-empty{text-align:center;padding:20px;color:#999}.ff-error{display:flex;flex-direction:column;align-items:center;gap:12px;padding:20px}.ff-error p-message{align-self:stretch}.ff-footer{flex-shrink:0;border-top:1px solid #e5e7eb}.ff-pagination{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px;font-size:13px}:host ::ng-deep .ff-pagination .p-select{width:auto;min-width:90px}:host ::ng-deep .ff-pagination .p-select .p-select-label{font-size:12px;padding:4px 8px}:host ::ng-deep .ff-pagination .p-paginator{padding:0;background:transparent;border:none;gap:0}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-current{font-size:12px;color:#6b7280;padding:0 6px;min-width:auto;height:auto}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-prev,:host ::ng-deep .ff-pagination .p-paginator .p-paginator-next{min-width:28px;height:28px;font-size:12px}@media only screen and (max-width: 656px){.ff-toolbar{gap:6px}.ff-btn-label{display:none}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button .p-button-label{display:none}:host ::ng-deep .ff-toolbar__actions .p-button{padding:.5rem}.ff-file-item__preview,.ff-file-item__frame{width:65px;height:80px}.ff-file-item__icon{font-size:28px}.ff-file-item__name{font-size:12px}.ff-file-item__date{font-size:11px}}\n"] }]
|
|
568
678
|
}], ctorParameters: () => [], propDecorators: { carpeta: [{
|
|
569
679
|
type: Input
|
|
570
680
|
}], isMobile: [{
|
|
@@ -595,102 +705,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
595
705
|
type: Output
|
|
596
706
|
}] } });
|
|
597
707
|
|
|
598
|
-
/**
|
|
599
|
-
* Traduce el error de una llamada del puerto a un texto para el usuario, en español y de usted.
|
|
600
|
-
*
|
|
601
|
-
* Nunca devuelve el mensaje del backend, `err.message`, JSON ni texto en inglés: el texto sale
|
|
602
|
-
* siempre de este archivo, según el código de error. El detalle técnico va a `console.error`
|
|
603
|
-
* con el prefijo `[sf-documents]` para soporte.
|
|
604
|
-
*
|
|
605
|
-
* Formas de error que llegan hoy:
|
|
606
|
-
* - DocumentService directo (documents-manager-ui): `err.error` es su `ApiResponse`,
|
|
607
|
-
* `{ success, statusCode, message, errors: ['CODIGO'] }`.
|
|
608
|
-
* - Vía TFAServices (TFB): la fachada lanza `new Exception(response.Content)` y responde
|
|
609
|
-
* `{ success: false, message: 'Error: {json de DocumentService}' }`. Se desenvuelve ese JSON.
|
|
610
|
-
*/
|
|
611
|
-
const GENERIC_ERROR_MESSAGE = 'Ocurrió un error inesperado. Intente de nuevo.';
|
|
612
|
-
const NETWORK_ERROR_MESSAGE = 'No hay conexión con el servidor. Revise su conexión e intente de nuevo.';
|
|
613
|
-
/**
|
|
614
|
-
* Códigos de `errors[0]` que devuelve DocumentService (`ExceptionHandlerMiddleware` y
|
|
615
|
-
* `Core/Exceptions`) → texto para el usuario. Un código que no esté aquí usa el genérico.
|
|
616
|
-
*/
|
|
617
|
-
const ERROR_CODE_MESSAGES = {
|
|
618
|
-
DOCUMENT_PART_MISSING: 'Falta un documento requerido en el gestor para esta solicitud. Revise las carpetas e intente de nuevo.',
|
|
619
|
-
DOCUMENT_TOO_LARGE: 'El documento supera el tamaño máximo permitido. Contacte a soporte.',
|
|
620
|
-
DOCUMENT_GENERATION_ERROR: 'Una parte del documento no se pudo producir. Intente de nuevo; si persiste, contacte a soporte.',
|
|
621
|
-
DOCUMENT_CONFIGURATION_ERROR: 'El documento no está configurado correctamente. Contacte a soporte.',
|
|
622
|
-
RESOURCE_NOT_FOUND: 'No se encontró la información solicitada. Recargue la pantalla e intente de nuevo.',
|
|
623
|
-
VALIDATION_ERROR: 'Revise los datos ingresados e intente de nuevo.',
|
|
624
|
-
INVALID_ARGUMENT: 'Revise los datos ingresados e intente de nuevo.',
|
|
625
|
-
BATCH_TOO_LARGE: 'Los archivos superan el tamaño máximo permitido por envío. Suba menos archivos a la vez.',
|
|
626
|
-
REQUEST_TIMEOUT: 'El servidor tardó demasiado en responder. Intente de nuevo.',
|
|
627
|
-
};
|
|
628
|
-
/** Prefijo con el que TFAServices envuelve el cuerpo de DocumentService (`$"Error: {ex.Message}"`). */
|
|
629
|
-
const TFA_WRAPPER_PREFIX = 'Error: ';
|
|
630
|
-
function tryParseObject(text) {
|
|
631
|
-
if (typeof text !== 'string')
|
|
632
|
-
return null;
|
|
633
|
-
const trimmed = text.trim();
|
|
634
|
-
if (!trimmed.startsWith('{'))
|
|
635
|
-
return null;
|
|
636
|
-
try {
|
|
637
|
-
const parsed = JSON.parse(trimmed);
|
|
638
|
-
return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
639
|
-
? parsed
|
|
640
|
-
: null;
|
|
641
|
-
}
|
|
642
|
-
catch {
|
|
643
|
-
return null;
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
/** Cuerpo de la respuesta de error, ya desenvuelto si viene de TFAServices. */
|
|
647
|
-
function extractBody(err) {
|
|
648
|
-
let body = null;
|
|
649
|
-
const raw = err?.error;
|
|
650
|
-
if (raw && typeof raw === 'object') {
|
|
651
|
-
body = raw;
|
|
652
|
-
}
|
|
653
|
-
else if (typeof raw === 'string') {
|
|
654
|
-
body = tryParseObject(raw);
|
|
655
|
-
}
|
|
656
|
-
else if (err && typeof err === 'object' && Array.isArray(err.errors)) {
|
|
657
|
-
// El host ya entregó el cuerpo (p. ej. un catchError que hace throwError(() => e.error)).
|
|
658
|
-
body = err;
|
|
659
|
-
}
|
|
660
|
-
const message = body?.['message'];
|
|
661
|
-
if (typeof message === 'string' && message.startsWith(TFA_WRAPPER_PREFIX + '{')) {
|
|
662
|
-
const inner = tryParseObject(message.slice(TFA_WRAPPER_PREFIX.length));
|
|
663
|
-
if (inner)
|
|
664
|
-
body = inner;
|
|
665
|
-
}
|
|
666
|
-
return body;
|
|
667
|
-
}
|
|
668
|
-
function extractCode(body) {
|
|
669
|
-
const first = Array.isArray(body?.['errors']) ? body['errors'][0] : null;
|
|
670
|
-
return typeof first === 'string' && first.trim() ? first.trim() : null;
|
|
671
|
-
}
|
|
672
|
-
/**
|
|
673
|
-
* Texto para el usuario a partir de un error del puerto.
|
|
674
|
-
* @param context Qué se estaba haciendo, solo para el log de soporte (p. ej. 'generateDocument').
|
|
675
|
-
*/
|
|
676
|
-
function getUserErrorMessage(err, context = '') {
|
|
677
|
-
const e = err;
|
|
678
|
-
const body = extractBody(e);
|
|
679
|
-
const code = extractCode(body);
|
|
680
|
-
const status = typeof e?.status === 'number' ? e.status : null;
|
|
681
|
-
console.error(`[sf-documents]${context ? ' ' + context : ''}`, {
|
|
682
|
-
status,
|
|
683
|
-
statusCode: body?.['statusCode'] ?? null,
|
|
684
|
-
code,
|
|
685
|
-
detail: body?.['message'] ?? e?.message ?? e,
|
|
686
|
-
});
|
|
687
|
-
if (status === 0)
|
|
688
|
-
return NETWORK_ERROR_MESSAGE;
|
|
689
|
-
if (code && ERROR_CODE_MESSAGES[code])
|
|
690
|
-
return ERROR_CODE_MESSAGES[code];
|
|
691
|
-
return GENERIC_ERROR_MESSAGE;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
708
|
class SfDocumentsComponent {
|
|
695
709
|
sanitizer;
|
|
696
710
|
snackBar;
|
|
@@ -1219,22 +1233,20 @@ class SfDocumentsComponent {
|
|
|
1219
1233
|
return;
|
|
1220
1234
|
// Un error anterior no debe quedar junto al aviso de un parámetro faltante.
|
|
1221
1235
|
this.generateError = null;
|
|
1222
|
-
//
|
|
1236
|
+
// Solo los obligatorios deben tener valor
|
|
1223
1237
|
for (const p of this.dynamicParams || []) {
|
|
1224
|
-
|
|
1225
|
-
const v = this.dynamicValues?.[key];
|
|
1226
|
-
if (v === null || v === undefined || v === '') {
|
|
1238
|
+
if (this.isRequired(p) && this.isEmpty(this.dynamicValues?.[p.name])) {
|
|
1227
1239
|
this.message('warn', '', `Falta el parámetro ${p.description}`);
|
|
1228
1240
|
return;
|
|
1229
1241
|
}
|
|
1230
1242
|
}
|
|
1231
|
-
// construir params
|
|
1243
|
+
// construir params: van todos, porque DocumentService exige cada parámetro de la
|
|
1244
|
+
// configuración; un opcional vacío viaja como null (DBNull en el SP).
|
|
1232
1245
|
const paramsToSend = {};
|
|
1233
1246
|
for (const p of this.dynamicParams || []) {
|
|
1234
|
-
const
|
|
1235
|
-
const
|
|
1236
|
-
paramsToSend[p.name] =
|
|
1237
|
-
(p.type || '').toLowerCase() === 'date' ? this.toYYYYMMDD(raw) : raw;
|
|
1247
|
+
const raw = this.dynamicValues?.[p.name];
|
|
1248
|
+
const value = (p.type || '').toLowerCase() === 'date' ? this.toYYYYMMDD(raw) : raw;
|
|
1249
|
+
paramsToSend[p.name] = this.isEmpty(value) ? null : value;
|
|
1238
1250
|
}
|
|
1239
1251
|
this.enProceso = true;
|
|
1240
1252
|
const payload = {
|
|
@@ -1277,11 +1289,31 @@ class SfDocumentsComponent {
|
|
|
1277
1289
|
this.generateError = null;
|
|
1278
1290
|
this.dynamicParams = doc?.params ?? [];
|
|
1279
1291
|
this.dynamicValues = {}; // reset valores
|
|
1280
|
-
//
|
|
1292
|
+
// Valores iniciales: un bit arranca en false (sin marcar ya es un valor); el resto, vacío.
|
|
1281
1293
|
for (const p of this.dynamicParams) {
|
|
1282
|
-
|
|
1283
|
-
|
|
1294
|
+
this.dynamicValues[p.name] = this.isBoolean(p) ? false : null;
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1298
|
+
* `required` viene de JCONFIGURACION (query.params) sin esquema: se acepta true, 1 y
|
|
1299
|
+
* "true"/"1"/"s"/"si"/"sí" en texto; cualquier otra cosa (false, "false", ausente) es
|
|
1300
|
+
* opcional. No aplica a los bit: arrancan en false, que ya es un valor.
|
|
1301
|
+
*/
|
|
1302
|
+
isRequired(p) {
|
|
1303
|
+
if (this.isBoolean(p))
|
|
1304
|
+
return false;
|
|
1305
|
+
const r = p?.required;
|
|
1306
|
+
if (typeof r === 'string') {
|
|
1307
|
+
return ['true', '1', 's', 'si', 'sí'].includes(r.trim().toLowerCase());
|
|
1284
1308
|
}
|
|
1309
|
+
return r === true || r === 1;
|
|
1310
|
+
}
|
|
1311
|
+
/** Vacío para la validación y el envío: null, undefined o texto en blanco (0 y false no). */
|
|
1312
|
+
isEmpty(v) {
|
|
1313
|
+
return v === null || v === undefined || (typeof v === 'string' && v.trim() === '');
|
|
1314
|
+
}
|
|
1315
|
+
isBoolean(p) {
|
|
1316
|
+
return ['boolean', 'bit', 'bool'].includes((p?.type || '').toLowerCase());
|
|
1285
1317
|
}
|
|
1286
1318
|
openVisorDoc(item) {
|
|
1287
1319
|
if (this.carpetaSeleccionada.TipoArchivo == '1' && this.isMobile) {
|
|
@@ -1304,10 +1336,10 @@ class SfDocumentsComponent {
|
|
|
1304
1336
|
previewFallbackIcon(label, path) {
|
|
1305
1337
|
return getFileTypeIcon(label || this.current_label || path || this.current_path);
|
|
1306
1338
|
}
|
|
1307
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
|
1308
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: SfDocumentsComponent, isStandalone: true, selector: "app-sf-documents", inputs: { accion: "accion", entidad: "entidad", ndoc: "ndoc", tdoc: "tdoc", tipo: "tipo", Kasociada: "Kasociada", Producto: "Producto", Solicitud: "Solicitud", oSession: "oSession", perfilDocumentos: "perfilDocumentos", subestado: "subestado", isMobile: "isMobile", bAtras: "bAtras", bFinal: "bFinal", botones: "botones", aplFiltro: "aplFiltro", nmco: "nmco", useBreadcrumb: "useBreadcrumb", usesApi: "usesApi", allowedUploadTypes: "allowedUploadTypes", server: "server", idKatios: "idKatios" }, outputs: { nextTabPapa: "nextTabPapa", onNavigationChange: "onNavigationChange" }, providers: [ConfirmationService, MessageService], viewQueries: [{ propertyName: "panel", first: true, predicate: ["pdf"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"sf-doc-layout\">\n <div class=\"sf-doc-fixed\">\n <div class=\"buttons\" *ngIf=\"botones\">\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\n <button\n pButton\n type=\"button\"\n label=\"Atras\"\n icon=\"pi pi-arrow-left\"\n (click)=\"next(-1)\"\n ></button>\n </div>\n <div\n class=\"div-table-col50\"\n style=\"text-align: center\"\n *ngIf=\"!bFinal && botones\"\n >\n <button\n pButton\n type=\"button\"\n label=\"Siguiente\"\n icon=\"pi pi-arrow-right\"\n (click)=\"next(1)\"\n ></button>\n </div>\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\n <button\n pButton\n type=\"button\"\n label=\"Finalizar\"\n icon=\"pi pi-home\"\n (click)=\"next(0)\"\n ></button>\n </div>\n </div>\n <!-- Toolbar superior (solo tab 1) -->\n <div *ngIf=\"tab == 1\" class=\"doc-toolbar\">\n <div class=\"doc-toolbar-left\" *ngIf=\"aplFiltro\">\n <p-iconfield>\n <p-inputicon class=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n placeholder=\"Buscar carpeta...\"\n [(ngModel)]=\"valorFiltro\"\n (keyup)=\"filtrarDocumentos()\"\n class=\"w-full\"\n [disabled]=\"documentService.loadingData\"\n />\n </p-iconfield>\n </div>\n\n <div class=\"doc-toolbar-right\" *ngIf=\"documentTypes.length > 0\">\n <button\n pButton\n type=\"button\"\n label=\"Generar documento\"\n icon=\"pi pi-plus\"\n class=\"p-button-sm\"\n (click)=\"openGenerateDialog()\"\n [disabled]=\"enProceso || !canGenerate\"\n ></button>\n </div>\n </div>\n </div>\n <p-confirmDialog\n header=\"Atencion\"\n icon=\"pi pi-exclamation-triangle\"\n ></p-confirmDialog>\n <!-- Avisos de la librer\u00EDa: solo los de su key, as\u00ED el toast del host no los duplica. -->\n <p-toast\n [key]=\"toastKey\"\n [breakpoints]=\"{ '576px': { width: 'calc(100vw - 40px)' } }\"\n ></p-toast>\n <div class=\"sf-doc-scrollable\" *ngIf=\"tab == 1\">\n <div class=\"folder-list\">\n @if (!documentService.loadingData) {\n <ng-container *ngFor=\"let carpeta of filesFilter\">\n <div class=\"folder-list\">\n <div\n class=\"folder-item\"\n *ngFor=\"let item of carpeta.children\"\n (click)=\"VerDetalleTab(item)\"\n >\n <i\n class=\"pi pi-folder folder-item__icon\"\n [ngStyle]=\"{\n color:\n item.children?.length > 0 || item.fileCount > 0\n ? 'green'\n : 'red',\n }\"\n ></i>\n <div class=\"folder-item__info\">\n <span class=\"folder-item__name\">{{ item.label }}</span>\n <span\n class=\"folder-item__count\"\n *ngIf=\"item.children?.length > 0\"\n >{{ item.children.length }}\n {{\n item.children.length === 1 ? \"archivo\" : \"archivos\"\n }}</span\n >\n <span\n class=\"folder-item__count\"\n *ngIf=\"\n (!item.children || item.children.length === 0) &&\n item.fileCount\n \"\n >{{ item.fileCount }}\n {{ item.fileCount === 1 ? \"archivo\" : \"archivos\" }}</span\n >\n <span\n class=\"folder-item__count\"\n *ngIf=\"\n (!item.children || item.children.length === 0) &&\n !item.fileCount\n \"\n >0 archivos</span\n >\n </div>\n <i class=\"pi pi-chevron-right folder-item__arrow\"></i>\n </div>\n </div>\n </ng-container>\n } @else {\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n }\n </div>\n <ng-container *ngIf=\"botones\">\n <div class=\"buttons\">\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\n <button\n pButton\n type=\"button\"\n label=\"Atras\"\n icon=\"pi pi-arrow-left\"\n (click)=\"next(-1)\"\n ></button>\n </div>\n <div\n class=\"div-table-col50\"\n style=\"text-align: center\"\n *ngIf=\"!bFinal && botones\"\n >\n <button\n pButton\n type=\"button\"\n label=\"Siguiente\"\n icon=\"pi pi-arrow-right\"\n (click)=\"next(1)\"\n ></button>\n </div>\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\n <button\n pButton\n type=\"button\"\n label=\"Finalizar\"\n icon=\"pi pi-home\"\n (click)=\"next(0)\"\n ></button>\n </div>\n </div>\n </ng-container>\n </div>\n <div class=\"sf-doc-scrollable sf-doc-scrollable--files\" *ngIf=\"tab == 2\">\n <lib-folder-files\n [carpeta]=\"carpetaSeleccionada\"\n [isMobile]=\"isMobile\"\n [idKatios]=\"idKatios\"\n [server]=\"server\"\n [subestado]=\"subestado\"\n [requestData]=\"requestData\"\n [useBreadcrumb]=\"useBreadcrumb\"\n [usesApi]=\"usesApi\"\n [allowedUploadTypes]=\"allowedUploadTypes\"\n (onFileChange)=\"fileChange($event)\"\n (onCargarArchivo)=\"cargarArchivo($event)\"\n (onEliminarMasivo)=\"eliminarMasivo($event)\"\n (onBack)=\"goToTab('1')\"\n (viewDocument)=\"openVisorDoc($event)\"\n >\n </lib-folder-files>\n </div>\n</div>\n\n<!-- <ng-template #scanContent>\n <div class=\"div-table\">\n <div class=\"div-table-row\" style=\"text-align: center\">\n <h4>Escanear documentos</h4>\n </div>\n <div class=\"div-table-row\" style=\"text-align: center\">\n Archivos cargados: <h4>{{scanFileList.length}}</h4>\n </div>\n <div class=\"div-table-row\" style=\"text-align: center\">\n <label (click)=\"takePhotoClick()\" class=\"btn\">\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">add_to_photos</mat-icon>\n </label>\n\n <label *ngIf=\"scanFileList.length != 0\" (click)=\"subirFotosScan()\" class=\"btn\">\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">share</mat-icon>\n </label>\n </div>\n </div>\n</ng-template> -->\n\n<p-dialog\n [(visible)]=\"displayView\"\n [header]=\"current_label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\"\n [modal]=\"true\"\n [style]=\"{ width: '70vw' }\"\n appendTo=\"body\"\n>\n <div *ngIf=\"!canPreview()\" class=\"sf-doc-preview-fallback\">\n <i class=\"pi\" [ngClass]=\"previewFallbackIcon()\"></i>\n <p>La vista previa no est\u00E1 disponible para este tipo de archivo.</p>\n <button\n pButton\n type=\"button\"\n label=\"Abrir en una nueva ventana\"\n icon=\"pi pi-external-link\"\n (click)=\"openCurrentInNewWindow()\"\n ></button>\n </div>\n <ng-container *ngIf=\"canPreview()\">\n <embed\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '2'\"\n [src]=\"current_path | safe\"\n style=\"width: 100%; min-height: 600px\"\n />\n <iframe\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '1'\"\n style=\"width: 100%; min-height: 600px\"\n [src]=\"current_path | safe\"\n ></iframe>\n </ng-container>\n</p-dialog>\n\n<p-dialog\n header=\"Generar documento\"\n [(visible)]=\"displayGenerate\"\n [modal]=\"true\"\n [closable]=\"true\"\n [style]=\"{ width: isMobile ? '95vw' : '520px' }\"\n>\n <div class=\"gen-form\">\n <!-- Error de la \u00FAltima generaci\u00F3n: el di\u00E1logo queda abierto para corregir o reintentar -->\n <p-message\n *ngIf=\"generateError\"\n severity=\"error\"\n icon=\"pi pi-times-circle\"\n styleClass=\"w-full\"\n >\n No se pudo generar el documento. {{ generateError }}\n </p-message>\n\n <!-- Tipo de documento -->\n <div class=\"gen-field\">\n <label class=\"gen-label\">Tipo de documento</label>\n <p-dropdown\n class=\"gen-control\"\n [options]=\"documentTypes\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [(ngModel)]=\"selectedDocType\"\n placeholder=\"Seleccione un tipo\"\n appendTo=\"body\"\n (onChange)=\"onDocTypeChange()\"\n >\n </p-dropdown>\n </div>\n\n <!-- Par\u00E1metros din\u00E1micos -->\n <div class=\"gen-section\" *ngIf=\"dynamicParams.length\">\n <div class=\"gen-field\" *ngFor=\"let p of dynamicParams\">\n <label class=\"gen-label\">\n {{ p.description }}\n <span class=\"gen-required\" *ngIf=\"p.required\">*</span>\n </label>\n\n <!-- Date -->\n <p-datepicker\n *ngIf=\"(p.type || '').toLowerCase() === 'date'\"\n class=\"gen-control\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n [showIcon]=\"true\"\n appendTo=\"body\"\n dateFormat=\"yy-mm-dd\"\n >\n </p-datepicker>\n\n <!-- String -->\n <input\n *ngIf=\"\n (p.type || '').toLowerCase() === 'nvarchar' ||\n (p.type || '').toLowerCase() === 'string'\n \"\n pInputText\n class=\"gen-control\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n placeholder=\"Ingrese un valor\"\n />\n\n <!-- Number -->\n <p-inputNumber\n *ngIf=\"\n ['int', 'decimal', 'number'].includes((p.type || '').toLowerCase())\n \"\n class=\"gen-control\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n >\n </p-inputNumber>\n\n <!-- Boolean -->\n <div\n class=\"gen-control gen-checkbox\"\n *ngIf=\"\n ['boolean', 'bit', 'bool'].includes((p.type || '').toLowerCase())\n \"\n >\n <p-checkbox [binary]=\"true\" [(ngModel)]=\"dynamicValues[p.name]\">\n </p-checkbox>\n <span class=\"gen-checkbox-label\">S\u00ED</span>\n </div>\n\n <!-- helper opcional -->\n <small class=\"gen-help\" *ngIf=\"p.help\">{{ p.help }}</small>\n </div>\n </div>\n </div>\n\n <ng-template pTemplate=\"footer\">\n <button\n pButton\n type=\"button\"\n label=\"Cancelar\"\n class=\"p-button-text\"\n (click)=\"displayGenerate = false\"\n ></button>\n\n <button\n pButton\n type=\"button\"\n [label]=\"generateError ? 'Reintentar' : 'Generar'\"\n [icon]=\"generateError ? 'pi pi-refresh' : 'pi pi-cog'\"\n (click)=\"generateDocument()\"\n [loading]=\"enProceso\"\n [disabled]=\"!selectedDocType || enProceso\"\n ></button>\n </ng-template>\n</p-dialog>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-fixed{flex-shrink:0}.sf-doc-scrollable{flex:1;min-height:0;overflow-y:auto}.sf-doc-scrollable--files{overflow:hidden;display:flex;flex-direction:column}:host ::ng-deep .sf-doc-scrollable--files>lib-folder-files{flex:1;min-height:0}.iconWhatsApp{font-size:40px;color:#6495ed}.doc-toolbar{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:.5rem}:host ::ng-deep .doc-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.doc-toolbar-left{flex:1;min-width:180px}.doc-toolbar-right{display:flex;justify-content:flex-end}:host ::ng-deep .doc-toolbar-right .p-button-outlined{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px}:host ::ng-deep .doc-toolbar-right .p-button-outlined:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .doc-toolbar-right .p-button-outlined:disabled{opacity:.5}@media only screen and (max-width: 656px),(max-device-width: 656px){.doc-toolbar{flex-direction:column;align-items:stretch}.doc-toolbar-right{justify-content:stretch}.doc-toolbar-right button{width:100%}}.folder-list{display:flex;flex-direction:column}.folder-item{display:flex;align-items:center;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.folder-item:hover{background-color:#f9fafb}.folder-item:last-child{border-bottom:1px solid #e5e7eb}.folder-item__icon{font-size:18px;color:#6b7280;margin-right:12px;flex-shrink:0}.folder-item__info{display:flex;flex-direction:column;flex:1;min-width:0}.folder-item__name{font-size:13.5px;font-weight:500;color:#111827;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.folder-item__count{font-size:12px;color:#9ca3af;margin-top:1px}.folder-item__arrow{font-size:13px;color:#9ca3af;margin-left:12px;flex-shrink:0}.buttons{display:flex;justify-content:space-around;margin-block:15px}.buttonResponsive,buttonResponsiveBotonFinal{display:inline-block;border-radius:4px;background-color:#00f;border:none;color:#fff;text-align:center;font-size:12px;padding:10px;width:200px;transition:all .5s;cursor:pointer;margin:20px 5px 5px}.gen-form{display:flex;flex-direction:column;gap:14px}.gen-section{display:flex;flex-direction:column;gap:12px}.gen-field{display:flex;flex-direction:column;gap:6px}.gen-label{font-size:13px;font-weight:600;color:#111827}.gen-required{color:#ef4444;margin-left:4px}.gen-control{width:100%}:host ::ng-deep .gen-control .p-dropdown,:host ::ng-deep .gen-control .p-inputtext,:host ::ng-deep .gen-control .p-inputnumber,:host ::ng-deep .gen-control .p-datepicker{width:100%}:host ::ng-deep .gen-control .p-inputnumber-input{width:100%}.gen-checkbox{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid #e5e7eb;border-radius:8px}.gen-checkbox-label{font-size:14px;color:#374151}.gen-help{color:#6b7280}.sf-doc-preview-fallback{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:300px;text-align:center;color:#374151}.sf-doc-preview-fallback i{font-size:48px;color:#6b7280}.sf-doc-preview-fallback i.pi-file-excel{color:#1d6f42}.sf-doc-preview-fallback i.pi-file-pdf{color:#b91c1c}.sf-doc-preview-fallback i.pi-file-word{color:#1d4ed8}.frameDoc{overflow:hidden;border:none}\n"], dependencies: [{ kind: "ngmodule", type: ToastModule }, { kind: "component", type: i4$2.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }, { kind: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: ConfirmDialogModule }, { kind: "component", type: i6$1.ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "ngmodule", type: PanelModule }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$1.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i9.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: SafePipe, name: "safe" }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i5.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "component", type: InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["styleClass"] }, { kind: "component", type: IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["iconPosition", "styleClass"] }, { kind: "component", type: FolderFilesComponent, selector: "lib-folder-files", inputs: ["carpeta", "isMobile", "idKatios", "server", "subestado", "requestData", "useBreadcrumb", "usesApi", "allowedUploadTypes"], outputs: ["onFileChange", "onCargarArchivo", "onEliminarMasivo", "onBack", "viewDocument"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i12.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i13.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "size", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i14.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "style", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i15.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] });
|
|
1339
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SfDocumentsComponent, deps: [{ token: i1.DomSanitizer }, { token: i2.MessageService }, { token: i0.ApplicationRef }, { token: i2.ConfirmationService }, { token: SfDocumentsService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1340
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SfDocumentsComponent, isStandalone: true, selector: "app-sf-documents", inputs: { accion: "accion", entidad: "entidad", ndoc: "ndoc", tdoc: "tdoc", tipo: "tipo", Kasociada: "Kasociada", Producto: "Producto", Solicitud: "Solicitud", oSession: "oSession", perfilDocumentos: "perfilDocumentos", subestado: "subestado", isMobile: "isMobile", bAtras: "bAtras", bFinal: "bFinal", botones: "botones", aplFiltro: "aplFiltro", nmco: "nmco", useBreadcrumb: "useBreadcrumb", usesApi: "usesApi", allowedUploadTypes: "allowedUploadTypes", server: "server", idKatios: "idKatios" }, outputs: { nextTabPapa: "nextTabPapa", onNavigationChange: "onNavigationChange" }, providers: [ConfirmationService, MessageService], viewQueries: [{ propertyName: "panel", first: true, predicate: ["pdf"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"sf-doc-layout\">\n <div class=\"sf-doc-fixed\">\n <div class=\"buttons\" *ngIf=\"botones\">\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\n <button\n pButton\n type=\"button\"\n label=\"Atras\"\n icon=\"pi pi-arrow-left\"\n (click)=\"next(-1)\"\n ></button>\n </div>\n <div\n class=\"div-table-col50\"\n style=\"text-align: center\"\n *ngIf=\"!bFinal && botones\"\n >\n <button\n pButton\n type=\"button\"\n label=\"Siguiente\"\n icon=\"pi pi-arrow-right\"\n (click)=\"next(1)\"\n ></button>\n </div>\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\n <button\n pButton\n type=\"button\"\n label=\"Finalizar\"\n icon=\"pi pi-home\"\n (click)=\"next(0)\"\n ></button>\n </div>\n </div>\n <!-- Toolbar superior (solo tab 1) -->\n <div *ngIf=\"tab == 1\" class=\"doc-toolbar\">\n <div class=\"doc-toolbar-left\" *ngIf=\"aplFiltro\">\n <p-iconfield>\n <p-inputicon class=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n placeholder=\"Buscar carpeta...\"\n [(ngModel)]=\"valorFiltro\"\n (keyup)=\"filtrarDocumentos()\"\n class=\"w-full\"\n [disabled]=\"documentService.loadingData\"\n />\n </p-iconfield>\n </div>\n\n <div class=\"doc-toolbar-right\" *ngIf=\"documentTypes.length > 0\">\n <button\n pButton\n type=\"button\"\n label=\"Generar documento\"\n icon=\"pi pi-plus\"\n class=\"p-button-sm\"\n (click)=\"openGenerateDialog()\"\n [disabled]=\"enProceso || !canGenerate\"\n ></button>\n </div>\n </div>\n </div>\n <p-confirmDialog\n header=\"Atenci\u00F3n\"\n icon=\"pi pi-exclamation-triangle\"\n ></p-confirmDialog>\n <!-- Avisos de la librer\u00EDa: solo los de su key, as\u00ED el toast del host no los duplica. -->\n <p-toast\n [key]=\"toastKey\"\n [breakpoints]=\"{ '576px': { width: 'calc(100vw - 40px)' } }\"\n ></p-toast>\n <div class=\"sf-doc-scrollable\" *ngIf=\"tab == 1\">\n <div class=\"folder-list\">\n @if (!documentService.loadingData) {\n <ng-container *ngFor=\"let carpeta of filesFilter\">\n <div class=\"folder-list\">\n <div\n class=\"folder-item\"\n *ngFor=\"let item of carpeta.children\"\n (click)=\"VerDetalleTab(item)\"\n >\n <i\n class=\"pi pi-folder folder-item__icon\"\n [ngStyle]=\"{\n color:\n item.children?.length > 0 || item.fileCount > 0\n ? 'green'\n : 'red',\n }\"\n ></i>\n <div class=\"folder-item__info\">\n <span class=\"folder-item__name\">{{ item.label }}</span>\n <span\n class=\"folder-item__count\"\n *ngIf=\"item.children?.length > 0\"\n >{{ item.children.length }}\n {{\n item.children.length === 1 ? \"archivo\" : \"archivos\"\n }}</span\n >\n <span\n class=\"folder-item__count\"\n *ngIf=\"\n (!item.children || item.children.length === 0) &&\n item.fileCount\n \"\n >{{ item.fileCount }}\n {{ item.fileCount === 1 ? \"archivo\" : \"archivos\" }}</span\n >\n <span\n class=\"folder-item__count\"\n *ngIf=\"\n (!item.children || item.children.length === 0) &&\n !item.fileCount\n \"\n >0 archivos</span\n >\n </div>\n <i class=\"pi pi-chevron-right folder-item__arrow\"></i>\n </div>\n </div>\n </ng-container>\n } @else {\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n }\n </div>\n <ng-container *ngIf=\"botones\">\n <div class=\"buttons\">\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\n <button\n pButton\n type=\"button\"\n label=\"Atras\"\n icon=\"pi pi-arrow-left\"\n (click)=\"next(-1)\"\n ></button>\n </div>\n <div\n class=\"div-table-col50\"\n style=\"text-align: center\"\n *ngIf=\"!bFinal && botones\"\n >\n <button\n pButton\n type=\"button\"\n label=\"Siguiente\"\n icon=\"pi pi-arrow-right\"\n (click)=\"next(1)\"\n ></button>\n </div>\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\n <button\n pButton\n type=\"button\"\n label=\"Finalizar\"\n icon=\"pi pi-home\"\n (click)=\"next(0)\"\n ></button>\n </div>\n </div>\n </ng-container>\n </div>\n <div class=\"sf-doc-scrollable sf-doc-scrollable--files\" *ngIf=\"tab == 2\">\n <lib-folder-files\n [carpeta]=\"carpetaSeleccionada\"\n [isMobile]=\"isMobile\"\n [idKatios]=\"idKatios\"\n [server]=\"server\"\n [subestado]=\"subestado\"\n [requestData]=\"requestData\"\n [useBreadcrumb]=\"useBreadcrumb\"\n [usesApi]=\"usesApi\"\n [allowedUploadTypes]=\"allowedUploadTypes\"\n (onFileChange)=\"fileChange($event)\"\n (onCargarArchivo)=\"cargarArchivo($event)\"\n (onEliminarMasivo)=\"eliminarMasivo($event)\"\n (onBack)=\"goToTab('1')\"\n (viewDocument)=\"openVisorDoc($event)\"\n >\n </lib-folder-files>\n </div>\n</div>\n\n<!-- <ng-template #scanContent>\n <div class=\"div-table\">\n <div class=\"div-table-row\" style=\"text-align: center\">\n <h4>Escanear documentos</h4>\n </div>\n <div class=\"div-table-row\" style=\"text-align: center\">\n Archivos cargados: <h4>{{scanFileList.length}}</h4>\n </div>\n <div class=\"div-table-row\" style=\"text-align: center\">\n <label (click)=\"takePhotoClick()\" class=\"btn\">\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">add_to_photos</mat-icon>\n </label>\n\n <label *ngIf=\"scanFileList.length != 0\" (click)=\"subirFotosScan()\" class=\"btn\">\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">share</mat-icon>\n </label>\n </div>\n </div>\n</ng-template> -->\n\n<p-dialog\n [(visible)]=\"displayView\"\n [header]=\"current_label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\"\n [modal]=\"true\"\n [style]=\"{ width: '70vw' }\"\n appendTo=\"body\"\n>\n <div *ngIf=\"!canPreview()\" class=\"sf-doc-preview-fallback\">\n <i class=\"pi\" [ngClass]=\"previewFallbackIcon()\"></i>\n <p>La vista previa no est\u00E1 disponible para este tipo de archivo.</p>\n <button\n pButton\n type=\"button\"\n label=\"Abrir en una nueva ventana\"\n icon=\"pi pi-external-link\"\n (click)=\"openCurrentInNewWindow()\"\n ></button>\n </div>\n <ng-container *ngIf=\"canPreview()\">\n <embed\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '2'\"\n [src]=\"current_path | safe\"\n style=\"width: 100%; min-height: 600px\"\n />\n <iframe\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '1'\"\n style=\"width: 100%; min-height: 600px\"\n [src]=\"current_path | safe\"\n ></iframe>\n </ng-container>\n</p-dialog>\n\n<p-dialog\n header=\"Generar documento\"\n [(visible)]=\"displayGenerate\"\n [modal]=\"true\"\n [closable]=\"true\"\n [style]=\"{ width: isMobile ? '95vw' : '520px' }\"\n>\n <div class=\"gen-form\">\n <!-- Error de la \u00FAltima generaci\u00F3n: el di\u00E1logo queda abierto para corregir o reintentar -->\n <p-message\n *ngIf=\"generateError\"\n severity=\"error\"\n icon=\"pi pi-times-circle\"\n styleClass=\"w-full\"\n >\n No se pudo generar el documento. {{ generateError }}\n </p-message>\n\n <!-- Tipo de documento -->\n <div class=\"gen-field\">\n <!-- p-select pone el inputId en un span (combobox): el nombre le llega por aria-labelledby -->\n <label class=\"gen-label\" id=\"gen-doc-type-label\" for=\"gen-doc-type\">Tipo de documento</label>\n <p-select\n class=\"gen-control\"\n inputId=\"gen-doc-type\"\n ariaLabelledBy=\"gen-doc-type-label\"\n [options]=\"documentTypes\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [(ngModel)]=\"selectedDocType\"\n placeholder=\"Seleccione un tipo\"\n appendTo=\"body\"\n (onChange)=\"onDocTypeChange()\"\n >\n </p-select>\n </div>\n\n <!-- Par\u00E1metros din\u00E1micos: cada label apunta al id de su control, gen-param-{\u00EDndice}\n (el name puede traer caracteres que no sirven en un id) -->\n <div class=\"gen-section\" *ngIf=\"dynamicParams.length\">\n <div class=\"gen-field\" *ngFor=\"let p of dynamicParams; let i = index\">\n <label class=\"gen-label\" [attr.for]=\"'gen-param-' + i\">\n {{ p.description }}\n <span class=\"gen-required\" *ngIf=\"isRequired(p)\" aria-hidden=\"true\">*</span>\n </label>\n\n <!-- Date -->\n <p-datepicker\n *ngIf=\"(p.type || '').toLowerCase() === 'date'\"\n class=\"gen-control\"\n [inputId]=\"'gen-param-' + i\"\n [required]=\"isRequired(p)\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n [showIcon]=\"true\"\n appendTo=\"body\"\n dateFormat=\"yy-mm-dd\"\n >\n </p-datepicker>\n\n <!-- String -->\n <input\n *ngIf=\"\n (p.type || '').toLowerCase() === 'nvarchar' ||\n (p.type || '').toLowerCase() === 'string'\n \"\n pInputText\n class=\"gen-control\"\n [id]=\"'gen-param-' + i\"\n [attr.aria-required]=\"isRequired(p)\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n placeholder=\"Ingrese un valor\"\n />\n\n <!-- Number: los int van sin decimales ni separador de miles (suelen ser ids o a\u00F1os) -->\n <p-inputNumber\n *ngIf=\"\n ['int', 'decimal', 'number'].includes((p.type || '').toLowerCase())\n \"\n class=\"gen-control\"\n [inputId]=\"'gen-param-' + i\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n locale=\"es-CO\"\n [maxFractionDigits]=\"(p.type || '').toLowerCase() === 'int' ? 0 : 4\"\n [useGrouping]=\"(p.type || '').toLowerCase() !== 'int'\"\n [max]=\"(p.type || '').toLowerCase() === 'int' ? 2147483647 : null\"\n [ariaRequired]=\"isRequired(p)\"\n placeholder=\"Ingrese un valor\"\n >\n </p-inputNumber>\n\n <!-- Boolean -->\n <div\n class=\"gen-control gen-checkbox\"\n *ngIf=\"isBoolean(p)\"\n >\n <p-checkbox\n [binary]=\"true\"\n [inputId]=\"'gen-param-' + i\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n >\n </p-checkbox>\n <span class=\"gen-checkbox-label\" aria-hidden=\"true\">S\u00ED</span>\n </div>\n\n <!-- helper opcional -->\n <small class=\"gen-help\" *ngIf=\"p.help\">{{ p.help }}</small>\n </div>\n </div>\n </div>\n\n <ng-template #footer>\n <button\n pButton\n type=\"button\"\n label=\"Cancelar\"\n class=\"p-button-text\"\n (click)=\"displayGenerate = false\"\n ></button>\n\n <button\n pButton\n type=\"button\"\n [label]=\"generateError ? 'Reintentar' : 'Generar'\"\n [icon]=\"generateError ? 'pi pi-refresh' : 'pi pi-cog'\"\n (click)=\"generateDocument()\"\n [loading]=\"enProceso\"\n [disabled]=\"!selectedDocType || enProceso\"\n ></button>\n </ng-template>\n</p-dialog>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-fixed{flex-shrink:0}.sf-doc-scrollable{flex:1;min-height:0;overflow-y:auto}.sf-doc-scrollable--files{overflow:hidden;display:flex;flex-direction:column}:host ::ng-deep .sf-doc-scrollable--files>lib-folder-files{flex:1;min-height:0}.iconWhatsApp{font-size:40px;color:#6495ed}.doc-toolbar{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:.5rem}:host ::ng-deep .doc-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.doc-toolbar-left{flex:1;min-width:180px}.doc-toolbar-right{display:flex;justify-content:flex-end}:host ::ng-deep .doc-toolbar-right .p-button-outlined{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px}:host ::ng-deep .doc-toolbar-right .p-button-outlined:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .doc-toolbar-right .p-button-outlined:disabled{opacity:.5}@media only screen and (max-width: 656px),(max-device-width: 656px){.doc-toolbar{flex-direction:column;align-items:stretch}.doc-toolbar-right{justify-content:stretch}.doc-toolbar-right button{width:100%}}.folder-list{display:flex;flex-direction:column}.folder-item{display:flex;align-items:center;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.folder-item:hover{background-color:#f9fafb}.folder-item:last-child{border-bottom:1px solid #e5e7eb}.folder-item__icon{font-size:18px;color:#6b7280;margin-right:12px;flex-shrink:0}.folder-item__info{display:flex;flex-direction:column;flex:1;min-width:0}.folder-item__name{font-size:13.5px;font-weight:500;color:#111827;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.folder-item__count{font-size:12px;color:#9ca3af;margin-top:1px}.folder-item__arrow{font-size:13px;color:#9ca3af;margin-left:12px;flex-shrink:0}.buttons{display:flex;justify-content:space-around;margin-block:15px}.buttonResponsive,buttonResponsiveBotonFinal{display:inline-block;border-radius:4px;background-color:#00f;border:none;color:#fff;text-align:center;font-size:12px;padding:10px;width:200px;transition:all .5s;cursor:pointer;margin:20px 5px 5px}.gen-form{display:flex;flex-direction:column;gap:14px}.gen-section{display:flex;flex-direction:column;gap:12px}.gen-field{display:flex;flex-direction:column;gap:6px}.gen-label{font-size:13px;font-weight:600;color:var(--p-text-color)}.gen-required{color:var(--p-form-field-invalid-border-color);margin-left:4px}.gen-control{width:100%}:host ::ng-deep .gen-control .p-inputtext,:host ::ng-deep .gen-control .p-inputnumber,:host ::ng-deep .gen-control .p-datepicker{width:100%}:host ::ng-deep .gen-control .p-inputnumber-input{width:100%}.gen-checkbox{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--p-content-border-color);border-radius:8px}.gen-checkbox-label{font-size:14px;color:var(--p-text-color)}.gen-help{color:var(--p-text-muted-color)}.sf-doc-preview-fallback{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:300px;text-align:center;color:#374151}.sf-doc-preview-fallback i{font-size:48px;color:#6b7280}.sf-doc-preview-fallback i.pi-file-excel{color:#1d6f42}.sf-doc-preview-fallback i.pi-file-pdf{color:#b91c1c}.sf-doc-preview-fallback i.pi-file-word{color:#1d4ed8}.frameDoc{overflow:hidden;border:none}\n"], dependencies: [{ kind: "ngmodule", type: ToastModule }, { kind: "component", type: i4$2.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: ConfirmDialogModule }, { kind: "component", type: i6$1.ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "ngmodule", type: PanelModule }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$1.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i9.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i10.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i10.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i10.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i10.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: SafePipe, name: "safe" }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i5.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "component", type: InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["styleClass"] }, { kind: "component", type: IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["iconPosition", "styleClass"] }, { kind: "component", type: FolderFilesComponent, selector: "lib-folder-files", inputs: ["carpeta", "isMobile", "idKatios", "server", "subestado", "requestData", "useBreadcrumb", "usesApi", "allowedUploadTypes"], outputs: ["onFileChange", "onCargarArchivo", "onEliminarMasivo", "onBack", "viewDocument"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i7.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i13.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "size", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i14.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "style", "placeholder", "size", "maxlength", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "name", "required", "autocomplete", "min", "max", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "step", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "variant", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus", "disabled", "fluid"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i15.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "style", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i8.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] });
|
|
1309
1341
|
}
|
|
1310
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
|
1342
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SfDocumentsComponent, decorators: [{
|
|
1311
1343
|
type: Component,
|
|
1312
1344
|
args: [{ selector: 'app-sf-documents', imports: [
|
|
1313
1345
|
ToastModule,
|
|
@@ -1323,11 +1355,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
1323
1355
|
InputIcon,
|
|
1324
1356
|
IconField,
|
|
1325
1357
|
FolderFilesComponent,
|
|
1326
|
-
|
|
1358
|
+
SelectModule,
|
|
1327
1359
|
DatePickerModule,
|
|
1360
|
+
InputNumberModule,
|
|
1328
1361
|
SkeletonModule,
|
|
1329
1362
|
MessageModule,
|
|
1330
|
-
], providers: [ConfirmationService, MessageService], standalone: true, template: "<div class=\"sf-doc-layout\">\n <div class=\"sf-doc-fixed\">\n <div class=\"buttons\" *ngIf=\"botones\">\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\n <button\n pButton\n type=\"button\"\n label=\"Atras\"\n icon=\"pi pi-arrow-left\"\n (click)=\"next(-1)\"\n ></button>\n </div>\n <div\n class=\"div-table-col50\"\n style=\"text-align: center\"\n *ngIf=\"!bFinal && botones\"\n >\n <button\n pButton\n type=\"button\"\n label=\"Siguiente\"\n icon=\"pi pi-arrow-right\"\n (click)=\"next(1)\"\n ></button>\n </div>\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\n <button\n pButton\n type=\"button\"\n label=\"Finalizar\"\n icon=\"pi pi-home\"\n (click)=\"next(0)\"\n ></button>\n </div>\n </div>\n <!-- Toolbar superior (solo tab 1) -->\n <div *ngIf=\"tab == 1\" class=\"doc-toolbar\">\n <div class=\"doc-toolbar-left\" *ngIf=\"aplFiltro\">\n <p-iconfield>\n <p-inputicon class=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n placeholder=\"Buscar carpeta...\"\n [(ngModel)]=\"valorFiltro\"\n (keyup)=\"filtrarDocumentos()\"\n class=\"w-full\"\n [disabled]=\"documentService.loadingData\"\n />\n </p-iconfield>\n </div>\n\n <div class=\"doc-toolbar-right\" *ngIf=\"documentTypes.length > 0\">\n <button\n pButton\n type=\"button\"\n label=\"Generar documento\"\n icon=\"pi pi-plus\"\n class=\"p-button-sm\"\n (click)=\"openGenerateDialog()\"\n [disabled]=\"enProceso || !canGenerate\"\n ></button>\n </div>\n </div>\n </div>\n <p-confirmDialog\n header=\"Atencion\"\n icon=\"pi pi-exclamation-triangle\"\n ></p-confirmDialog>\n <!-- Avisos de la librer\u00EDa: solo los de su key, as\u00ED el toast del host no los duplica. -->\n <p-toast\n [key]=\"toastKey\"\n [breakpoints]=\"{ '576px': { width: 'calc(100vw - 40px)' } }\"\n ></p-toast>\n <div class=\"sf-doc-scrollable\" *ngIf=\"tab == 1\">\n <div class=\"folder-list\">\n @if (!documentService.loadingData) {\n <ng-container *ngFor=\"let carpeta of filesFilter\">\n <div class=\"folder-list\">\n <div\n class=\"folder-item\"\n *ngFor=\"let item of carpeta.children\"\n (click)=\"VerDetalleTab(item)\"\n >\n <i\n class=\"pi pi-folder folder-item__icon\"\n [ngStyle]=\"{\n color:\n item.children?.length > 0 || item.fileCount > 0\n ? 'green'\n : 'red',\n }\"\n ></i>\n <div class=\"folder-item__info\">\n <span class=\"folder-item__name\">{{ item.label }}</span>\n <span\n class=\"folder-item__count\"\n *ngIf=\"item.children?.length > 0\"\n >{{ item.children.length }}\n {{\n item.children.length === 1 ? \"archivo\" : \"archivos\"\n }}</span\n >\n <span\n class=\"folder-item__count\"\n *ngIf=\"\n (!item.children || item.children.length === 0) &&\n item.fileCount\n \"\n >{{ item.fileCount }}\n {{ item.fileCount === 1 ? \"archivo\" : \"archivos\" }}</span\n >\n <span\n class=\"folder-item__count\"\n *ngIf=\"\n (!item.children || item.children.length === 0) &&\n !item.fileCount\n \"\n >0 archivos</span\n >\n </div>\n <i class=\"pi pi-chevron-right folder-item__arrow\"></i>\n </div>\n </div>\n </ng-container>\n } @else {\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n }\n </div>\n <ng-container *ngIf=\"botones\">\n <div class=\"buttons\">\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\n <button\n pButton\n type=\"button\"\n label=\"Atras\"\n icon=\"pi pi-arrow-left\"\n (click)=\"next(-1)\"\n ></button>\n </div>\n <div\n class=\"div-table-col50\"\n style=\"text-align: center\"\n *ngIf=\"!bFinal && botones\"\n >\n <button\n pButton\n type=\"button\"\n label=\"Siguiente\"\n icon=\"pi pi-arrow-right\"\n (click)=\"next(1)\"\n ></button>\n </div>\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\n <button\n pButton\n type=\"button\"\n label=\"Finalizar\"\n icon=\"pi pi-home\"\n (click)=\"next(0)\"\n ></button>\n </div>\n </div>\n </ng-container>\n </div>\n <div class=\"sf-doc-scrollable sf-doc-scrollable--files\" *ngIf=\"tab == 2\">\n <lib-folder-files\n [carpeta]=\"carpetaSeleccionada\"\n [isMobile]=\"isMobile\"\n [idKatios]=\"idKatios\"\n [server]=\"server\"\n [subestado]=\"subestado\"\n [requestData]=\"requestData\"\n [useBreadcrumb]=\"useBreadcrumb\"\n [usesApi]=\"usesApi\"\n [allowedUploadTypes]=\"allowedUploadTypes\"\n (onFileChange)=\"fileChange($event)\"\n (onCargarArchivo)=\"cargarArchivo($event)\"\n (onEliminarMasivo)=\"eliminarMasivo($event)\"\n (onBack)=\"goToTab('1')\"\n (viewDocument)=\"openVisorDoc($event)\"\n >\n </lib-folder-files>\n </div>\n</div>\n\n<!-- <ng-template #scanContent>\n <div class=\"div-table\">\n <div class=\"div-table-row\" style=\"text-align: center\">\n <h4>Escanear documentos</h4>\n </div>\n <div class=\"div-table-row\" style=\"text-align: center\">\n Archivos cargados: <h4>{{scanFileList.length}}</h4>\n </div>\n <div class=\"div-table-row\" style=\"text-align: center\">\n <label (click)=\"takePhotoClick()\" class=\"btn\">\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">add_to_photos</mat-icon>\n </label>\n\n <label *ngIf=\"scanFileList.length != 0\" (click)=\"subirFotosScan()\" class=\"btn\">\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">share</mat-icon>\n </label>\n </div>\n </div>\n</ng-template> -->\n\n<p-dialog\n [(visible)]=\"displayView\"\n [header]=\"current_label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\"\n [modal]=\"true\"\n [style]=\"{ width: '70vw' }\"\n appendTo=\"body\"\n>\n <div *ngIf=\"!canPreview()\" class=\"sf-doc-preview-fallback\">\n <i class=\"pi\" [ngClass]=\"previewFallbackIcon()\"></i>\n <p>La vista previa no est\u00E1 disponible para este tipo de archivo.</p>\n <button\n pButton\n type=\"button\"\n label=\"Abrir en una nueva ventana\"\n icon=\"pi pi-external-link\"\n (click)=\"openCurrentInNewWindow()\"\n ></button>\n </div>\n <ng-container *ngIf=\"canPreview()\">\n <embed\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '2'\"\n [src]=\"current_path | safe\"\n style=\"width: 100%; min-height: 600px\"\n />\n <iframe\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '1'\"\n style=\"width: 100%; min-height: 600px\"\n [src]=\"current_path | safe\"\n ></iframe>\n </ng-container>\n</p-dialog>\n\n<p-dialog\n header=\"Generar documento\"\n [(visible)]=\"displayGenerate\"\n [modal]=\"true\"\n [closable]=\"true\"\n [style]=\"{ width: isMobile ? '95vw' : '520px' }\"\n>\n <div class=\"gen-form\">\n <!-- Error de la \u00FAltima generaci\u00F3n: el di\u00E1logo queda abierto para corregir o reintentar -->\n <p-message\n *ngIf=\"generateError\"\n severity=\"error\"\n icon=\"pi pi-times-circle\"\n styleClass=\"w-full\"\n >\n No se pudo generar el documento. {{ generateError }}\n </p-message>\n\n <!-- Tipo de documento -->\n <div class=\"gen-field\">\n <label class=\"gen-label\">Tipo de documento</label>\n <p-dropdown\n class=\"gen-control\"\n [options]=\"documentTypes\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [(ngModel)]=\"selectedDocType\"\n placeholder=\"Seleccione un tipo\"\n appendTo=\"body\"\n (onChange)=\"onDocTypeChange()\"\n >\n </p-dropdown>\n </div>\n\n <!-- Par\u00E1metros din\u00E1micos -->\n <div class=\"gen-section\" *ngIf=\"dynamicParams.length\">\n <div class=\"gen-field\" *ngFor=\"let p of dynamicParams\">\n <label class=\"gen-label\">\n {{ p.description }}\n <span class=\"gen-required\" *ngIf=\"p.required\">*</span>\n </label>\n\n <!-- Date -->\n <p-datepicker\n *ngIf=\"(p.type || '').toLowerCase() === 'date'\"\n class=\"gen-control\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n [showIcon]=\"true\"\n appendTo=\"body\"\n dateFormat=\"yy-mm-dd\"\n >\n </p-datepicker>\n\n <!-- String -->\n <input\n *ngIf=\"\n (p.type || '').toLowerCase() === 'nvarchar' ||\n (p.type || '').toLowerCase() === 'string'\n \"\n pInputText\n class=\"gen-control\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n placeholder=\"Ingrese un valor\"\n />\n\n <!-- Number -->\n <p-inputNumber\n *ngIf=\"\n ['int', 'decimal', 'number'].includes((p.type || '').toLowerCase())\n \"\n class=\"gen-control\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n >\n </p-inputNumber>\n\n <!-- Boolean -->\n <div\n class=\"gen-control gen-checkbox\"\n *ngIf=\"\n ['boolean', 'bit', 'bool'].includes((p.type || '').toLowerCase())\n \"\n >\n <p-checkbox [binary]=\"true\" [(ngModel)]=\"dynamicValues[p.name]\">\n </p-checkbox>\n <span class=\"gen-checkbox-label\">S\u00ED</span>\n </div>\n\n <!-- helper opcional -->\n <small class=\"gen-help\" *ngIf=\"p.help\">{{ p.help }}</small>\n </div>\n </div>\n </div>\n\n <ng-template pTemplate=\"footer\">\n <button\n pButton\n type=\"button\"\n label=\"Cancelar\"\n class=\"p-button-text\"\n (click)=\"displayGenerate = false\"\n ></button>\n\n <button\n pButton\n type=\"button\"\n [label]=\"generateError ? 'Reintentar' : 'Generar'\"\n [icon]=\"generateError ? 'pi pi-refresh' : 'pi pi-cog'\"\n (click)=\"generateDocument()\"\n [loading]=\"enProceso\"\n [disabled]=\"!selectedDocType || enProceso\"\n ></button>\n </ng-template>\n</p-dialog>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-fixed{flex-shrink:0}.sf-doc-scrollable{flex:1;min-height:0;overflow-y:auto}.sf-doc-scrollable--files{overflow:hidden;display:flex;flex-direction:column}:host ::ng-deep .sf-doc-scrollable--files>lib-folder-files{flex:1;min-height:0}.iconWhatsApp{font-size:40px;color:#6495ed}.doc-toolbar{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:.5rem}:host ::ng-deep .doc-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.doc-toolbar-left{flex:1;min-width:180px}.doc-toolbar-right{display:flex;justify-content:flex-end}:host ::ng-deep .doc-toolbar-right .p-button-outlined{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px}:host ::ng-deep .doc-toolbar-right .p-button-outlined:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .doc-toolbar-right .p-button-outlined:disabled{opacity:.5}@media only screen and (max-width: 656px),(max-device-width: 656px){.doc-toolbar{flex-direction:column;align-items:stretch}.doc-toolbar-right{justify-content:stretch}.doc-toolbar-right button{width:100%}}.folder-list{display:flex;flex-direction:column}.folder-item{display:flex;align-items:center;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.folder-item:hover{background-color:#f9fafb}.folder-item:last-child{border-bottom:1px solid #e5e7eb}.folder-item__icon{font-size:18px;color:#6b7280;margin-right:12px;flex-shrink:0}.folder-item__info{display:flex;flex-direction:column;flex:1;min-width:0}.folder-item__name{font-size:13.5px;font-weight:500;color:#111827;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.folder-item__count{font-size:12px;color:#9ca3af;margin-top:1px}.folder-item__arrow{font-size:13px;color:#9ca3af;margin-left:12px;flex-shrink:0}.buttons{display:flex;justify-content:space-around;margin-block:15px}.buttonResponsive,buttonResponsiveBotonFinal{display:inline-block;border-radius:4px;background-color:#00f;border:none;color:#fff;text-align:center;font-size:12px;padding:10px;width:200px;transition:all .5s;cursor:pointer;margin:20px 5px 5px}.gen-form{display:flex;flex-direction:column;gap:14px}.gen-section{display:flex;flex-direction:column;gap:12px}.gen-field{display:flex;flex-direction:column;gap:6px}.gen-label{font-size:13px;font-weight:600;color:#111827}.gen-required{color:#ef4444;margin-left:4px}.gen-control{width:100%}:host ::ng-deep .gen-control .p-dropdown,:host ::ng-deep .gen-control .p-inputtext,:host ::ng-deep .gen-control .p-inputnumber,:host ::ng-deep .gen-control .p-datepicker{width:100%}:host ::ng-deep .gen-control .p-inputnumber-input{width:100%}.gen-checkbox{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid #e5e7eb;border-radius:8px}.gen-checkbox-label{font-size:14px;color:#374151}.gen-help{color:#6b7280}.sf-doc-preview-fallback{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:300px;text-align:center;color:#374151}.sf-doc-preview-fallback i{font-size:48px;color:#6b7280}.sf-doc-preview-fallback i.pi-file-excel{color:#1d6f42}.sf-doc-preview-fallback i.pi-file-pdf{color:#b91c1c}.sf-doc-preview-fallback i.pi-file-word{color:#1d4ed8}.frameDoc{overflow:hidden;border:none}\n"] }]
|
|
1363
|
+
], providers: [ConfirmationService, MessageService], standalone: true, template: "<div class=\"sf-doc-layout\">\n <div class=\"sf-doc-fixed\">\n <div class=\"buttons\" *ngIf=\"botones\">\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\n <button\n pButton\n type=\"button\"\n label=\"Atras\"\n icon=\"pi pi-arrow-left\"\n (click)=\"next(-1)\"\n ></button>\n </div>\n <div\n class=\"div-table-col50\"\n style=\"text-align: center\"\n *ngIf=\"!bFinal && botones\"\n >\n <button\n pButton\n type=\"button\"\n label=\"Siguiente\"\n icon=\"pi pi-arrow-right\"\n (click)=\"next(1)\"\n ></button>\n </div>\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\n <button\n pButton\n type=\"button\"\n label=\"Finalizar\"\n icon=\"pi pi-home\"\n (click)=\"next(0)\"\n ></button>\n </div>\n </div>\n <!-- Toolbar superior (solo tab 1) -->\n <div *ngIf=\"tab == 1\" class=\"doc-toolbar\">\n <div class=\"doc-toolbar-left\" *ngIf=\"aplFiltro\">\n <p-iconfield>\n <p-inputicon class=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n placeholder=\"Buscar carpeta...\"\n [(ngModel)]=\"valorFiltro\"\n (keyup)=\"filtrarDocumentos()\"\n class=\"w-full\"\n [disabled]=\"documentService.loadingData\"\n />\n </p-iconfield>\n </div>\n\n <div class=\"doc-toolbar-right\" *ngIf=\"documentTypes.length > 0\">\n <button\n pButton\n type=\"button\"\n label=\"Generar documento\"\n icon=\"pi pi-plus\"\n class=\"p-button-sm\"\n (click)=\"openGenerateDialog()\"\n [disabled]=\"enProceso || !canGenerate\"\n ></button>\n </div>\n </div>\n </div>\n <p-confirmDialog\n header=\"Atenci\u00F3n\"\n icon=\"pi pi-exclamation-triangle\"\n ></p-confirmDialog>\n <!-- Avisos de la librer\u00EDa: solo los de su key, as\u00ED el toast del host no los duplica. -->\n <p-toast\n [key]=\"toastKey\"\n [breakpoints]=\"{ '576px': { width: 'calc(100vw - 40px)' } }\"\n ></p-toast>\n <div class=\"sf-doc-scrollable\" *ngIf=\"tab == 1\">\n <div class=\"folder-list\">\n @if (!documentService.loadingData) {\n <ng-container *ngFor=\"let carpeta of filesFilter\">\n <div class=\"folder-list\">\n <div\n class=\"folder-item\"\n *ngFor=\"let item of carpeta.children\"\n (click)=\"VerDetalleTab(item)\"\n >\n <i\n class=\"pi pi-folder folder-item__icon\"\n [ngStyle]=\"{\n color:\n item.children?.length > 0 || item.fileCount > 0\n ? 'green'\n : 'red',\n }\"\n ></i>\n <div class=\"folder-item__info\">\n <span class=\"folder-item__name\">{{ item.label }}</span>\n <span\n class=\"folder-item__count\"\n *ngIf=\"item.children?.length > 0\"\n >{{ item.children.length }}\n {{\n item.children.length === 1 ? \"archivo\" : \"archivos\"\n }}</span\n >\n <span\n class=\"folder-item__count\"\n *ngIf=\"\n (!item.children || item.children.length === 0) &&\n item.fileCount\n \"\n >{{ item.fileCount }}\n {{ item.fileCount === 1 ? \"archivo\" : \"archivos\" }}</span\n >\n <span\n class=\"folder-item__count\"\n *ngIf=\"\n (!item.children || item.children.length === 0) &&\n !item.fileCount\n \"\n >0 archivos</span\n >\n </div>\n <i class=\"pi pi-chevron-right folder-item__arrow\"></i>\n </div>\n </div>\n </ng-container>\n } @else {\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n }\n </div>\n <ng-container *ngIf=\"botones\">\n <div class=\"buttons\">\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\n <button\n pButton\n type=\"button\"\n label=\"Atras\"\n icon=\"pi pi-arrow-left\"\n (click)=\"next(-1)\"\n ></button>\n </div>\n <div\n class=\"div-table-col50\"\n style=\"text-align: center\"\n *ngIf=\"!bFinal && botones\"\n >\n <button\n pButton\n type=\"button\"\n label=\"Siguiente\"\n icon=\"pi pi-arrow-right\"\n (click)=\"next(1)\"\n ></button>\n </div>\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\n <button\n pButton\n type=\"button\"\n label=\"Finalizar\"\n icon=\"pi pi-home\"\n (click)=\"next(0)\"\n ></button>\n </div>\n </div>\n </ng-container>\n </div>\n <div class=\"sf-doc-scrollable sf-doc-scrollable--files\" *ngIf=\"tab == 2\">\n <lib-folder-files\n [carpeta]=\"carpetaSeleccionada\"\n [isMobile]=\"isMobile\"\n [idKatios]=\"idKatios\"\n [server]=\"server\"\n [subestado]=\"subestado\"\n [requestData]=\"requestData\"\n [useBreadcrumb]=\"useBreadcrumb\"\n [usesApi]=\"usesApi\"\n [allowedUploadTypes]=\"allowedUploadTypes\"\n (onFileChange)=\"fileChange($event)\"\n (onCargarArchivo)=\"cargarArchivo($event)\"\n (onEliminarMasivo)=\"eliminarMasivo($event)\"\n (onBack)=\"goToTab('1')\"\n (viewDocument)=\"openVisorDoc($event)\"\n >\n </lib-folder-files>\n </div>\n</div>\n\n<!-- <ng-template #scanContent>\n <div class=\"div-table\">\n <div class=\"div-table-row\" style=\"text-align: center\">\n <h4>Escanear documentos</h4>\n </div>\n <div class=\"div-table-row\" style=\"text-align: center\">\n Archivos cargados: <h4>{{scanFileList.length}}</h4>\n </div>\n <div class=\"div-table-row\" style=\"text-align: center\">\n <label (click)=\"takePhotoClick()\" class=\"btn\">\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">add_to_photos</mat-icon>\n </label>\n\n <label *ngIf=\"scanFileList.length != 0\" (click)=\"subirFotosScan()\" class=\"btn\">\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">share</mat-icon>\n </label>\n </div>\n </div>\n</ng-template> -->\n\n<p-dialog\n [(visible)]=\"displayView\"\n [header]=\"current_label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\"\n [modal]=\"true\"\n [style]=\"{ width: '70vw' }\"\n appendTo=\"body\"\n>\n <div *ngIf=\"!canPreview()\" class=\"sf-doc-preview-fallback\">\n <i class=\"pi\" [ngClass]=\"previewFallbackIcon()\"></i>\n <p>La vista previa no est\u00E1 disponible para este tipo de archivo.</p>\n <button\n pButton\n type=\"button\"\n label=\"Abrir en una nueva ventana\"\n icon=\"pi pi-external-link\"\n (click)=\"openCurrentInNewWindow()\"\n ></button>\n </div>\n <ng-container *ngIf=\"canPreview()\">\n <embed\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '2'\"\n [src]=\"current_path | safe\"\n style=\"width: 100%; min-height: 600px\"\n />\n <iframe\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '1'\"\n style=\"width: 100%; min-height: 600px\"\n [src]=\"current_path | safe\"\n ></iframe>\n </ng-container>\n</p-dialog>\n\n<p-dialog\n header=\"Generar documento\"\n [(visible)]=\"displayGenerate\"\n [modal]=\"true\"\n [closable]=\"true\"\n [style]=\"{ width: isMobile ? '95vw' : '520px' }\"\n>\n <div class=\"gen-form\">\n <!-- Error de la \u00FAltima generaci\u00F3n: el di\u00E1logo queda abierto para corregir o reintentar -->\n <p-message\n *ngIf=\"generateError\"\n severity=\"error\"\n icon=\"pi pi-times-circle\"\n styleClass=\"w-full\"\n >\n No se pudo generar el documento. {{ generateError }}\n </p-message>\n\n <!-- Tipo de documento -->\n <div class=\"gen-field\">\n <!-- p-select pone el inputId en un span (combobox): el nombre le llega por aria-labelledby -->\n <label class=\"gen-label\" id=\"gen-doc-type-label\" for=\"gen-doc-type\">Tipo de documento</label>\n <p-select\n class=\"gen-control\"\n inputId=\"gen-doc-type\"\n ariaLabelledBy=\"gen-doc-type-label\"\n [options]=\"documentTypes\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [(ngModel)]=\"selectedDocType\"\n placeholder=\"Seleccione un tipo\"\n appendTo=\"body\"\n (onChange)=\"onDocTypeChange()\"\n >\n </p-select>\n </div>\n\n <!-- Par\u00E1metros din\u00E1micos: cada label apunta al id de su control, gen-param-{\u00EDndice}\n (el name puede traer caracteres que no sirven en un id) -->\n <div class=\"gen-section\" *ngIf=\"dynamicParams.length\">\n <div class=\"gen-field\" *ngFor=\"let p of dynamicParams; let i = index\">\n <label class=\"gen-label\" [attr.for]=\"'gen-param-' + i\">\n {{ p.description }}\n <span class=\"gen-required\" *ngIf=\"isRequired(p)\" aria-hidden=\"true\">*</span>\n </label>\n\n <!-- Date -->\n <p-datepicker\n *ngIf=\"(p.type || '').toLowerCase() === 'date'\"\n class=\"gen-control\"\n [inputId]=\"'gen-param-' + i\"\n [required]=\"isRequired(p)\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n [showIcon]=\"true\"\n appendTo=\"body\"\n dateFormat=\"yy-mm-dd\"\n >\n </p-datepicker>\n\n <!-- String -->\n <input\n *ngIf=\"\n (p.type || '').toLowerCase() === 'nvarchar' ||\n (p.type || '').toLowerCase() === 'string'\n \"\n pInputText\n class=\"gen-control\"\n [id]=\"'gen-param-' + i\"\n [attr.aria-required]=\"isRequired(p)\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n placeholder=\"Ingrese un valor\"\n />\n\n <!-- Number: los int van sin decimales ni separador de miles (suelen ser ids o a\u00F1os) -->\n <p-inputNumber\n *ngIf=\"\n ['int', 'decimal', 'number'].includes((p.type || '').toLowerCase())\n \"\n class=\"gen-control\"\n [inputId]=\"'gen-param-' + i\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n locale=\"es-CO\"\n [maxFractionDigits]=\"(p.type || '').toLowerCase() === 'int' ? 0 : 4\"\n [useGrouping]=\"(p.type || '').toLowerCase() !== 'int'\"\n [max]=\"(p.type || '').toLowerCase() === 'int' ? 2147483647 : null\"\n [ariaRequired]=\"isRequired(p)\"\n placeholder=\"Ingrese un valor\"\n >\n </p-inputNumber>\n\n <!-- Boolean -->\n <div\n class=\"gen-control gen-checkbox\"\n *ngIf=\"isBoolean(p)\"\n >\n <p-checkbox\n [binary]=\"true\"\n [inputId]=\"'gen-param-' + i\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n >\n </p-checkbox>\n <span class=\"gen-checkbox-label\" aria-hidden=\"true\">S\u00ED</span>\n </div>\n\n <!-- helper opcional -->\n <small class=\"gen-help\" *ngIf=\"p.help\">{{ p.help }}</small>\n </div>\n </div>\n </div>\n\n <ng-template #footer>\n <button\n pButton\n type=\"button\"\n label=\"Cancelar\"\n class=\"p-button-text\"\n (click)=\"displayGenerate = false\"\n ></button>\n\n <button\n pButton\n type=\"button\"\n [label]=\"generateError ? 'Reintentar' : 'Generar'\"\n [icon]=\"generateError ? 'pi pi-refresh' : 'pi pi-cog'\"\n (click)=\"generateDocument()\"\n [loading]=\"enProceso\"\n [disabled]=\"!selectedDocType || enProceso\"\n ></button>\n </ng-template>\n</p-dialog>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-fixed{flex-shrink:0}.sf-doc-scrollable{flex:1;min-height:0;overflow-y:auto}.sf-doc-scrollable--files{overflow:hidden;display:flex;flex-direction:column}:host ::ng-deep .sf-doc-scrollable--files>lib-folder-files{flex:1;min-height:0}.iconWhatsApp{font-size:40px;color:#6495ed}.doc-toolbar{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:.5rem}:host ::ng-deep .doc-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.doc-toolbar-left{flex:1;min-width:180px}.doc-toolbar-right{display:flex;justify-content:flex-end}:host ::ng-deep .doc-toolbar-right .p-button-outlined{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px}:host ::ng-deep .doc-toolbar-right .p-button-outlined:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .doc-toolbar-right .p-button-outlined:disabled{opacity:.5}@media only screen and (max-width: 656px),(max-device-width: 656px){.doc-toolbar{flex-direction:column;align-items:stretch}.doc-toolbar-right{justify-content:stretch}.doc-toolbar-right button{width:100%}}.folder-list{display:flex;flex-direction:column}.folder-item{display:flex;align-items:center;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.folder-item:hover{background-color:#f9fafb}.folder-item:last-child{border-bottom:1px solid #e5e7eb}.folder-item__icon{font-size:18px;color:#6b7280;margin-right:12px;flex-shrink:0}.folder-item__info{display:flex;flex-direction:column;flex:1;min-width:0}.folder-item__name{font-size:13.5px;font-weight:500;color:#111827;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.folder-item__count{font-size:12px;color:#9ca3af;margin-top:1px}.folder-item__arrow{font-size:13px;color:#9ca3af;margin-left:12px;flex-shrink:0}.buttons{display:flex;justify-content:space-around;margin-block:15px}.buttonResponsive,buttonResponsiveBotonFinal{display:inline-block;border-radius:4px;background-color:#00f;border:none;color:#fff;text-align:center;font-size:12px;padding:10px;width:200px;transition:all .5s;cursor:pointer;margin:20px 5px 5px}.gen-form{display:flex;flex-direction:column;gap:14px}.gen-section{display:flex;flex-direction:column;gap:12px}.gen-field{display:flex;flex-direction:column;gap:6px}.gen-label{font-size:13px;font-weight:600;color:var(--p-text-color)}.gen-required{color:var(--p-form-field-invalid-border-color);margin-left:4px}.gen-control{width:100%}:host ::ng-deep .gen-control .p-inputtext,:host ::ng-deep .gen-control .p-inputnumber,:host ::ng-deep .gen-control .p-datepicker{width:100%}:host ::ng-deep .gen-control .p-inputnumber-input{width:100%}.gen-checkbox{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--p-content-border-color);border-radius:8px}.gen-checkbox-label{font-size:14px;color:var(--p-text-color)}.gen-help{color:var(--p-text-muted-color)}.sf-doc-preview-fallback{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:300px;text-align:center;color:#374151}.sf-doc-preview-fallback i{font-size:48px;color:#6b7280}.sf-doc-preview-fallback i.pi-file-excel{color:#1d6f42}.sf-doc-preview-fallback i.pi-file-pdf{color:#b91c1c}.sf-doc-preview-fallback i.pi-file-word{color:#1d4ed8}.frameDoc{overflow:hidden;border:none}\n"] }]
|
|
1331
1364
|
}], ctorParameters: () => [{ type: i1.DomSanitizer }, { type: i2.MessageService }, { type: i0.ApplicationRef }, { type: i2.ConfirmationService }, { type: SfDocumentsService }], propDecorators: { accion: [{
|
|
1332
1365
|
type: Input
|
|
1333
1366
|
}], entidad: [{
|