sf-documents 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -63
- package/fesm2022/sf-documents.mjs +240 -40
- package/fesm2022/sf-documents.mjs.map +1 -1
- package/lib/components/dialog/upload-dialog/upload-dialog.component.d.ts +15 -1
- package/lib/sf-documents.component.d.ts +3 -0
- package/lib/utils/error-message.util.d.ts +25 -0
- package/lib/utils/file-type.util.d.ts +15 -0
- package/lib/utils/toast.util.d.ts +5 -0
- package/package.json +1 -1
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Injectable, Pipe, InjectionToken, EventEmitter, ViewChild, Output, Input, Component, inject, ElementRef } from '@angular/core';
|
|
3
3
|
import { BehaviorSubject, Subject, of } from 'rxjs';
|
|
4
|
-
import * as i2
|
|
5
|
-
import { ConfirmationService } from 'primeng/api';
|
|
4
|
+
import * as i2 from 'primeng/api';
|
|
5
|
+
import { ConfirmationService, MessageService } from 'primeng/api';
|
|
6
|
+
import * as i4$2 from 'primeng/toast';
|
|
6
7
|
import { ToastModule } from 'primeng/toast';
|
|
8
|
+
import * as i15 from 'primeng/message';
|
|
9
|
+
import { MessageModule } from 'primeng/message';
|
|
7
10
|
import * as _ from 'lodash';
|
|
8
|
-
import * as
|
|
11
|
+
import * as i3 from 'primeng/button';
|
|
9
12
|
import { ButtonModule } from 'primeng/button';
|
|
10
|
-
import * as
|
|
13
|
+
import * as i6$1 from 'primeng/confirmdialog';
|
|
11
14
|
import { ConfirmDialogModule } from 'primeng/confirmdialog';
|
|
12
15
|
import { PanelModule } from 'primeng/panel';
|
|
13
|
-
import * as i4 from 'primeng/checkbox';
|
|
16
|
+
import * as i4$1 from 'primeng/checkbox';
|
|
14
17
|
import { CheckboxModule } from 'primeng/checkbox';
|
|
15
|
-
import * as
|
|
18
|
+
import * as i4 from 'primeng/dialog';
|
|
16
19
|
import { DialogModule } from 'primeng/dialog';
|
|
17
|
-
import * as
|
|
20
|
+
import * as i9 from '@angular/common';
|
|
18
21
|
import { CommonModule, registerLocaleData, DatePipe } from '@angular/common';
|
|
19
|
-
import * as i2 from '@angular/forms';
|
|
22
|
+
import * as i2$1 from '@angular/forms';
|
|
20
23
|
import { FormsModule } from '@angular/forms';
|
|
21
24
|
import * as i1 from '@angular/platform-browser';
|
|
22
25
|
import * as i5 from 'primeng/inputtext';
|
|
@@ -29,11 +32,11 @@ import { debounceTime, distinctUntilChanged, takeUntil, tap, switchMap, finalize
|
|
|
29
32
|
import * as i7 from 'primeng/select';
|
|
30
33
|
import { SelectModule } from 'primeng/select';
|
|
31
34
|
import localeEs from '@angular/common/locales/es';
|
|
32
|
-
import * as
|
|
35
|
+
import * as i12 from 'primeng/dropdown';
|
|
33
36
|
import { DropdownModule } from 'primeng/dropdown';
|
|
34
|
-
import * as
|
|
37
|
+
import * as i13 from 'primeng/datepicker';
|
|
35
38
|
import { DatePickerModule } from 'primeng/datepicker';
|
|
36
|
-
import * as
|
|
39
|
+
import * as i14 from 'primeng/skeleton';
|
|
37
40
|
import { SkeletonModule } from 'primeng/skeleton';
|
|
38
41
|
|
|
39
42
|
class SfDocumentsService {
|
|
@@ -88,10 +91,12 @@ const DOCUMENT_SERVICE = new InjectionToken('DOCUMENT_SERVICE');
|
|
|
88
91
|
* decisión de negocio (qué tipos de documento se aceptan).
|
|
89
92
|
*/
|
|
90
93
|
const DEFAULT_ALLOWED_UPLOAD_EXTENSIONS = ['.pdf', '.xls', '.xlsx'];
|
|
94
|
+
const MAX_POR_ARCHIVO = 25 * 1024 * 1024; // 25 MB
|
|
95
|
+
const MAX_POR_LOTE = 100 * 1024 * 1024; // 100 MB
|
|
91
96
|
const MIME_TYPES_BY_EXTENSION = {
|
|
92
97
|
'.pdf': 'application/pdf',
|
|
93
98
|
'.xls': 'application/vnd.ms-excel',
|
|
94
|
-
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
99
|
+
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
95
100
|
};
|
|
96
101
|
/**
|
|
97
102
|
* Extensiones que el navegador puede renderizar inline dentro de un <embed>/<iframe>.
|
|
@@ -99,7 +104,16 @@ const MIME_TYPES_BY_EXTENSION = {
|
|
|
99
104
|
* decisión de negocio, así que la librería la conoce de antemano (evita que el host
|
|
100
105
|
* marque como "previsualizable" un tipo que en realidad nunca se va a renderizar).
|
|
101
106
|
*/
|
|
102
|
-
const PREVIEWABLE_EXTENSIONS = [
|
|
107
|
+
const PREVIEWABLE_EXTENSIONS = [
|
|
108
|
+
'.pdf',
|
|
109
|
+
'.jpg',
|
|
110
|
+
'.jpeg',
|
|
111
|
+
'.png',
|
|
112
|
+
'.gif',
|
|
113
|
+
'.webp',
|
|
114
|
+
'.bmp',
|
|
115
|
+
'.svg',
|
|
116
|
+
];
|
|
103
117
|
const ICON_BY_EXTENSION = {
|
|
104
118
|
'.pdf': 'pi-file-pdf',
|
|
105
119
|
'.xls': 'pi-file-excel',
|
|
@@ -112,31 +126,55 @@ const ICON_BY_EXTENSION = {
|
|
|
112
126
|
'.gif': 'pi-image',
|
|
113
127
|
'.webp': 'pi-image',
|
|
114
128
|
'.bmp': 'pi-image',
|
|
115
|
-
'.svg': 'pi-image'
|
|
129
|
+
'.svg': 'pi-image',
|
|
116
130
|
};
|
|
117
131
|
/** Normaliza una lista de extensiones dada por el host (con o sin punto, mayúsc/minúsc). */
|
|
118
132
|
function normalizeExtensions(extensions, fallback) {
|
|
119
133
|
const list = extensions && extensions.length ? extensions : fallback;
|
|
120
134
|
return list
|
|
121
|
-
.map(ext => ext.trim().toLowerCase())
|
|
122
|
-
.filter(ext => !!ext)
|
|
123
|
-
.map(ext => (ext.startsWith('.') ? ext : `.${ext}`));
|
|
135
|
+
.map((ext) => ext.trim().toLowerCase())
|
|
136
|
+
.filter((ext) => !!ext)
|
|
137
|
+
.map((ext) => (ext.startsWith('.') ? ext : `.${ext}`));
|
|
124
138
|
}
|
|
125
139
|
/** Arma el atributo `accept` del input file a partir de las extensiones permitidas. */
|
|
126
140
|
function buildAcceptAttr(extensions) {
|
|
127
|
-
const mimeTypes = extensions
|
|
141
|
+
const mimeTypes = extensions
|
|
142
|
+
.map((ext) => MIME_TYPES_BY_EXTENSION[ext])
|
|
143
|
+
.filter((m) => !!m);
|
|
128
144
|
return [...new Set([...mimeTypes, ...extensions])].join(',');
|
|
129
145
|
}
|
|
130
146
|
function hasExtension(fileName, extensions) {
|
|
131
147
|
if (!fileName)
|
|
132
148
|
return false;
|
|
133
149
|
const lower = fileName.toLowerCase();
|
|
134
|
-
return extensions.some(ext => lower.endsWith(ext));
|
|
150
|
+
return extensions.some((ext) => lower.endsWith(ext));
|
|
135
151
|
}
|
|
136
152
|
function isAllowedUploadFile(file, extensions) {
|
|
137
|
-
const mimeTypes = extensions
|
|
153
|
+
const mimeTypes = extensions
|
|
154
|
+
.map((ext) => MIME_TYPES_BY_EXTENSION[ext])
|
|
155
|
+
.filter((m) => !!m);
|
|
138
156
|
return mimeTypes.includes(file.type) || hasExtension(file.name, extensions);
|
|
139
157
|
}
|
|
158
|
+
/** Formatea un tamaño en bytes a MB con un decimal (ej. "12.3 MB"). */
|
|
159
|
+
function formatFileSizeMB(bytes) {
|
|
160
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
161
|
+
}
|
|
162
|
+
/** Tamaño total en bytes de un conjunto de archivos. */
|
|
163
|
+
function getBatchSize(files) {
|
|
164
|
+
return files.reduce((total, file) => total + file.size, 0);
|
|
165
|
+
}
|
|
166
|
+
/** Separa los archivos según superen o no el tamaño máximo permitido por archivo. */
|
|
167
|
+
function splitFilesByMaxSize(files, maxFileSize) {
|
|
168
|
+
const allowed = [];
|
|
169
|
+
const rejected = [];
|
|
170
|
+
files.forEach((file) => {
|
|
171
|
+
if (file.size > maxFileSize)
|
|
172
|
+
rejected.push({ name: file.name, size: file.size });
|
|
173
|
+
else
|
|
174
|
+
allowed.push(file);
|
|
175
|
+
});
|
|
176
|
+
return { allowed, rejected };
|
|
177
|
+
}
|
|
140
178
|
/** true si el navegador puede mostrar este archivo inline en un <embed>/<iframe>. */
|
|
141
179
|
function canPreviewFile(name) {
|
|
142
180
|
return hasExtension(name, PREVIEWABLE_EXTENSIONS);
|
|
@@ -146,24 +184,42 @@ function getFileTypeIcon(name) {
|
|
|
146
184
|
if (!name)
|
|
147
185
|
return 'pi-file';
|
|
148
186
|
const lower = name.toLowerCase();
|
|
149
|
-
const match = Object.keys(ICON_BY_EXTENSION).find(ext => lower.endsWith(ext));
|
|
187
|
+
const match = Object.keys(ICON_BY_EXTENSION).find((ext) => lower.endsWith(ext));
|
|
150
188
|
return match ? ICON_BY_EXTENSION[match] : 'pi-file';
|
|
151
189
|
}
|
|
152
190
|
|
|
191
|
+
/**
|
|
192
|
+
* `key` de los avisos de la librería. Solo los pinta el `<p-toast>` de `SfDocumentsComponent`:
|
|
193
|
+
* un `<p-toast>` del host sin `key` (o con otra) no los muestra, así que no salen duplicados.
|
|
194
|
+
*/
|
|
195
|
+
const SF_DOCUMENTS_TOAST_KEY = 'sf-documents';
|
|
196
|
+
|
|
153
197
|
class UploadDialogComponent {
|
|
198
|
+
messageService;
|
|
154
199
|
selectedDocument;
|
|
155
200
|
/** Extensiones permitidas para subir (ej. ['.pdf', '.xlsx']). Si no se define, usa el default de la librería. */
|
|
156
201
|
allowedExtensions;
|
|
157
202
|
onUploaded = new EventEmitter();
|
|
158
203
|
loadFile = new EventEmitter();
|
|
159
204
|
fileInput;
|
|
160
|
-
|
|
205
|
+
maxFileSize = MAX_POR_ARCHIVO;
|
|
206
|
+
maxBatchSize = MAX_POR_LOTE;
|
|
207
|
+
displayOversizedDialog = false;
|
|
208
|
+
allowedFiles = [];
|
|
209
|
+
rejectedFiles = [];
|
|
210
|
+
pendingTagValue;
|
|
211
|
+
constructor(messageService) {
|
|
212
|
+
this.messageService = messageService;
|
|
213
|
+
}
|
|
161
214
|
get normalizedExtensions() {
|
|
162
215
|
return normalizeExtensions(this.allowedExtensions, DEFAULT_ALLOWED_UPLOAD_EXTENSIONS);
|
|
163
216
|
}
|
|
164
217
|
get acceptedFileTypes() {
|
|
165
218
|
return buildAcceptAttr(this.normalizedExtensions);
|
|
166
219
|
}
|
|
220
|
+
formatSize(bytes) {
|
|
221
|
+
return formatFileSizeMB(bytes);
|
|
222
|
+
}
|
|
167
223
|
loadFileClick() {
|
|
168
224
|
this.loadFile.emit();
|
|
169
225
|
this.fileInput.nativeElement.value = '';
|
|
@@ -175,17 +231,50 @@ class UploadDialogComponent {
|
|
|
175
231
|
return;
|
|
176
232
|
const files = Array.from(input.files);
|
|
177
233
|
const validFiles = files.filter(f => isAllowedUploadFile(f, this.normalizedExtensions));
|
|
178
|
-
const
|
|
179
|
-
if (validFiles
|
|
180
|
-
|
|
234
|
+
const tagValue = input.value;
|
|
235
|
+
if (!validFiles.length)
|
|
236
|
+
return;
|
|
237
|
+
if (getBatchSize(validFiles) > this.maxBatchSize) {
|
|
238
|
+
this.addMessage('error', 'Lote demasiado grande', `El lote seleccionado supera el tamaño máximo permitido de ${this.formatSize(this.maxBatchSize)}.`);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const { allowed, rejected } = splitFilesByMaxSize(validFiles, this.maxFileSize);
|
|
242
|
+
if (!rejected.length) {
|
|
243
|
+
this.onUploaded.emit({ fileList: allowed, tagValue });
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
this.allowedFiles = allowed;
|
|
247
|
+
this.rejectedFiles = rejected;
|
|
248
|
+
this.pendingTagValue = tagValue;
|
|
249
|
+
this.displayOversizedDialog = true;
|
|
250
|
+
}
|
|
251
|
+
continuarConPermitidos() {
|
|
252
|
+
this.displayOversizedDialog = false;
|
|
253
|
+
if (this.allowedFiles.length) {
|
|
254
|
+
this.onUploaded.emit({ fileList: this.allowedFiles, tagValue: this.pendingTagValue });
|
|
255
|
+
}
|
|
256
|
+
this.limpiarSeleccionRechazada();
|
|
257
|
+
}
|
|
258
|
+
cancelarEnvio() {
|
|
259
|
+
this.displayOversizedDialog = false;
|
|
260
|
+
this.limpiarSeleccionRechazada();
|
|
261
|
+
}
|
|
262
|
+
limpiarSeleccionRechazada() {
|
|
263
|
+
this.allowedFiles = [];
|
|
264
|
+
this.rejectedFiles = [];
|
|
265
|
+
this.pendingTagValue = null;
|
|
181
266
|
}
|
|
182
|
-
|
|
183
|
-
|
|
267
|
+
addMessage(severity, summary, detail) {
|
|
268
|
+
// Usa el MessageService y el <p-toast> de SfDocumentsComponent (ver SF_DOCUMENTS_TOAST_KEY).
|
|
269
|
+
this.messageService.add({ key: SF_DOCUMENTS_TOAST_KEY, severity, summary, detail, life: 4000 });
|
|
270
|
+
}
|
|
271
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: UploadDialogComponent, deps: [{ token: i2.MessageService }], target: i0.ɵɵFactoryTarget.Component });
|
|
272
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", 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 pTemplate=\"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: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { 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"] }] });
|
|
184
273
|
}
|
|
185
274
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: UploadDialogComponent, decorators: [{
|
|
186
275
|
type: Component,
|
|
187
|
-
args: [{ selector: 'lib-upload-dialog', imports: [CommonModule, ButtonModule, DialogModule], template: "<input\
|
|
188
|
-
}], ctorParameters: () => [], propDecorators: { selectedDocument: [{
|
|
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 pTemplate=\"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
|
+
}], ctorParameters: () => [{ type: i2.MessageService }], propDecorators: { selectedDocument: [{
|
|
189
278
|
type: Input
|
|
190
279
|
}], allowedExtensions: [{
|
|
191
280
|
type: Input
|
|
@@ -457,7 +546,7 @@ class FolderFilesComponent {
|
|
|
457
546
|
this.loadFiles();
|
|
458
547
|
}
|
|
459
548
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: FolderFilesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
460
|
-
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\">\r\n <!-- Header fijo -->\r\n <div class=\"ff-header\">\r\n <div class=\"ff-back-row\" *ngIf=\"!useBreadcrumb\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n icon=\"pi pi-arrow-left\"\r\n label=\"Volver\"\r\n (click)=\"goBack()\"\r\n ></button>\r\n </div>\r\n\r\n <!-- Toolbar: b\u00FAsqueda + botones de acci\u00F3n -->\r\n <div class=\"ff-toolbar\">\r\n <p-iconfield class=\"ff-toolbar__search\">\r\n <p-inputicon class=\"pi pi-search\" />\r\n <input\r\n type=\"text\"\r\n pInputText\r\n [placeholder]=\"\r\n 'Buscar en ' +\r\n carpeta.label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\r\n \"\r\n [(ngModel)]=\"searchQuery\"\r\n (input)=\"onSearchInput()\"\r\n class=\"w-full\"\r\n />\r\n </p-iconfield>\r\n\r\n <div class=\"ff-toolbar__actions\">\r\n <lib-upload-dialog\r\n *ngIf=\"carpeta?.reglas?.permisos?.cargarFront\"\r\n [selectedDocument]=\"carpeta\"\r\n [allowedExtensions]=\"allowedUploadTypes\"\r\n (onUploaded)=\"fileChange($event)\"\r\n (loadFile)=\"cargarArchivo()\"\r\n >\r\n </lib-upload-dialog>\r\n\r\n <button\r\n pButton\r\n type=\"button\"\r\n icon=\"pi pi-trash\"\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n (click)=\"emitEliminarMasivo()\"\r\n [disabled]=\"docsEliminables.length === 0\"\r\n class=\"p-button-outlined p-button-danger p-button-sm ff-btn-delete\"\r\n >\r\n <span class=\"ff-btn-label\"\r\n >Eliminar ({{ docsEliminables.length }})</span\r\n >\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Fila seleccionar todo / total archivos -->\r\n <div class=\"ff-select-row\" *ngIf=\"!loading && items.length > 0\">\r\n <div class=\"ff-select-row__left\">\r\n <p-checkbox\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n [binary]=\"true\"\r\n [(ngModel)]=\"allSelected\"\r\n (onChange)=\"toggleSelectAll()\"\r\n >\r\n </p-checkbox>\r\n <span\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n class=\"ff-select-row__label\"\r\n >Seleccionar todo</span\r\n >\r\n </div>\r\n <span class=\"ff-select-row__count\"\r\n >{{ totalRecords || items.length }}\r\n {{\r\n (totalRecords || items.length) === 1 ? \"archivo\" : \"archivos\"\r\n }}</span\r\n >\r\n </div>\r\n </div>\r\n\r\n <!-- Contenido scrollable -->\r\n <div class=\"ff-file-list-wrapper\">\r\n <!-- Loading -->\r\n <div *ngIf=\"loading\" class=\"ff-loading\">\r\n <i class=\"pi pi-spin pi-spinner\" style=\"font-size: 2rem\"></i>\r\n </div>\r\n\r\n <!-- Lista de archivos -->\r\n <div class=\"ff-file-list\" *ngIf=\"!loading\">\r\n <div\r\n class=\"ff-file-item\"\r\n *ngFor=\"let item of items\"\r\n (click)=\"openVisorDoc(item)\"\r\n >\r\n <p-checkbox\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n [binary]=\"true\"\r\n [(ngModel)]=\"item.delete\"\r\n (onChange)=\"onClickedCheckDelete($event, item)\"\r\n (click)=\"$event.stopPropagation()\"\r\n >\r\n </p-checkbox>\r\n\r\n <div class=\"ff-file-item__preview\">\r\n <i\r\n *ngIf=\"!canPreview(item.label, item.Path)\"\r\n class=\"pi ff-file-item__frame ff-file-item__icon\"\r\n [ngClass]=\"previewFallbackIcon(item.label, item.Path)\"\r\n ></i>\r\n <ng-container *ngIf=\"canPreview(item.label, item.Path)\">\r\n <embed\r\n *ngIf=\"carpeta.TipoArchivo == '2'\"\r\n class=\"ff-file-item__frame\"\r\n [src]=\"item.Path | safe\"\r\n />\r\n <img\r\n *ngIf=\"carpeta.TipoArchivo == '1' && isMobile\"\r\n class=\"ff-file-item__frame\"\r\n src=\"https://macuna.tecfinanzas.com/Imagenes/pdf_icon.png\"\r\n />\r\n <iframe\r\n *ngIf=\"carpeta.TipoArchivo == '1' && !isMobile\"\r\n class=\"ff-file-item__frame\"\r\n [src]=\"item.Path | safe\"\r\n frameborder=\"0\"\r\n ></iframe>\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"ff-file-item__info\">\r\n <span class=\"ff-file-item__name\">{{ item.label }}</span>\r\n <span class=\"ff-file-item__date\" *ngIf=\"item.FechaSubida && !isMobile\"\r\n >Fecha Subida:\r\n {{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\r\n >\r\n <span\r\n class=\"ff-file-item__date\"\r\n *ngIf=\"item.FechaSubida && isMobile\"\r\n >{{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\r\n >\r\n <i\r\n class=\"pi pi-external-link ff-file-item__open\"\r\n (click)=\"\r\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\r\n \"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n aria-label=\"Abrir en nueva ventana\"\r\n (keydown.enter)=\"\r\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\r\n \"\r\n ></i>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Sin resultados -->\r\n <div *ngIf=\"!loading && items.length === 0\" class=\"ff-empty\">\r\n Sin documentos cargados\r\n </div>\r\n </div>\r\n\r\n <!-- Footer fijo: paginaci\u00F3n compacta -->\r\n <div class=\"ff-footer\" *ngIf=\"usesApi && totalRecords > 0\">\r\n <div class=\"ff-pagination\">\r\n <p-select\r\n [options]=\"pageSizeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(ngModel)]=\"pageSize\"\r\n (ngModelChange)=\"onPageSizeChange()\"\r\n >\r\n </p-select>\r\n <p-paginator\r\n [first]=\"first\"\r\n [rows]=\"pageSize\"\r\n [totalRecords]=\"totalRecords\"\r\n (onPageChange)=\"onPageChange($event)\"\r\n [showCurrentPageReport]=\"true\"\r\n currentPageReportTemplate=\"{first} - {last} de {totalRecords}\"\r\n [showPageLinks]=\"false\"\r\n [showFirstLastIcon]=\"false\"\r\n >\r\n </p-paginator>\r\n </div>\r\n </div>\r\n</div>\r\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: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i8.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.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.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 }] });
|
|
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 }] });
|
|
461
550
|
}
|
|
462
551
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: FolderFilesComponent, decorators: [{
|
|
463
552
|
type: Component,
|
|
@@ -475,7 +564,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
475
564
|
SelectModule,
|
|
476
565
|
FlexibleDatePipe,
|
|
477
566
|
DialogModule,
|
|
478
|
-
], standalone: true, template: "<div class=\"ff-layout\">\r\n <!-- Header fijo -->\r\n <div class=\"ff-header\">\r\n <div class=\"ff-back-row\" *ngIf=\"!useBreadcrumb\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n icon=\"pi pi-arrow-left\"\r\n label=\"Volver\"\r\n (click)=\"goBack()\"\r\n ></button>\r\n </div>\r\n\r\n <!-- Toolbar: b\u00FAsqueda + botones de acci\u00F3n -->\r\n <div class=\"ff-toolbar\">\r\n <p-iconfield class=\"ff-toolbar__search\">\r\n <p-inputicon class=\"pi pi-search\" />\r\n <input\r\n type=\"text\"\r\n pInputText\r\n [placeholder]=\"\r\n 'Buscar en ' +\r\n carpeta.label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\r\n \"\r\n [(ngModel)]=\"searchQuery\"\r\n (input)=\"onSearchInput()\"\r\n class=\"w-full\"\r\n />\r\n </p-iconfield>\r\n\r\n <div class=\"ff-toolbar__actions\">\r\n <lib-upload-dialog\r\n *ngIf=\"carpeta?.reglas?.permisos?.cargarFront\"\r\n [selectedDocument]=\"carpeta\"\r\n [allowedExtensions]=\"allowedUploadTypes\"\r\n (onUploaded)=\"fileChange($event)\"\r\n (loadFile)=\"cargarArchivo()\"\r\n >\r\n </lib-upload-dialog>\r\n\r\n <button\r\n pButton\r\n type=\"button\"\r\n icon=\"pi pi-trash\"\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n (click)=\"emitEliminarMasivo()\"\r\n [disabled]=\"docsEliminables.length === 0\"\r\n class=\"p-button-outlined p-button-danger p-button-sm ff-btn-delete\"\r\n >\r\n <span class=\"ff-btn-label\"\r\n >Eliminar ({{ docsEliminables.length }})</span\r\n >\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Fila seleccionar todo / total archivos -->\r\n <div class=\"ff-select-row\" *ngIf=\"!loading && items.length > 0\">\r\n <div class=\"ff-select-row__left\">\r\n <p-checkbox\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n [binary]=\"true\"\r\n [(ngModel)]=\"allSelected\"\r\n (onChange)=\"toggleSelectAll()\"\r\n >\r\n </p-checkbox>\r\n <span\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n class=\"ff-select-row__label\"\r\n >Seleccionar todo</span\r\n >\r\n </div>\r\n <span class=\"ff-select-row__count\"\r\n >{{ totalRecords || items.length }}\r\n {{\r\n (totalRecords || items.length) === 1 ? \"archivo\" : \"archivos\"\r\n }}</span\r\n >\r\n </div>\r\n </div>\r\n\r\n <!-- Contenido scrollable -->\r\n <div class=\"ff-file-list-wrapper\">\r\n <!-- Loading -->\r\n <div *ngIf=\"loading\" class=\"ff-loading\">\r\n <i class=\"pi pi-spin pi-spinner\" style=\"font-size: 2rem\"></i>\r\n </div>\r\n\r\n <!-- Lista de archivos -->\r\n <div class=\"ff-file-list\" *ngIf=\"!loading\">\r\n <div\r\n class=\"ff-file-item\"\r\n *ngFor=\"let item of items\"\r\n (click)=\"openVisorDoc(item)\"\r\n >\r\n <p-checkbox\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n [binary]=\"true\"\r\n [(ngModel)]=\"item.delete\"\r\n (onChange)=\"onClickedCheckDelete($event, item)\"\r\n (click)=\"$event.stopPropagation()\"\r\n >\r\n </p-checkbox>\r\n\r\n <div class=\"ff-file-item__preview\">\r\n <i\r\n *ngIf=\"!canPreview(item.label, item.Path)\"\r\n class=\"pi ff-file-item__frame ff-file-item__icon\"\r\n [ngClass]=\"previewFallbackIcon(item.label, item.Path)\"\r\n ></i>\r\n <ng-container *ngIf=\"canPreview(item.label, item.Path)\">\r\n <embed\r\n *ngIf=\"carpeta.TipoArchivo == '2'\"\r\n class=\"ff-file-item__frame\"\r\n [src]=\"item.Path | safe\"\r\n />\r\n <img\r\n *ngIf=\"carpeta.TipoArchivo == '1' && isMobile\"\r\n class=\"ff-file-item__frame\"\r\n src=\"https://macuna.tecfinanzas.com/Imagenes/pdf_icon.png\"\r\n />\r\n <iframe\r\n *ngIf=\"carpeta.TipoArchivo == '1' && !isMobile\"\r\n class=\"ff-file-item__frame\"\r\n [src]=\"item.Path | safe\"\r\n frameborder=\"0\"\r\n ></iframe>\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"ff-file-item__info\">\r\n <span class=\"ff-file-item__name\">{{ item.label }}</span>\r\n <span class=\"ff-file-item__date\" *ngIf=\"item.FechaSubida && !isMobile\"\r\n >Fecha Subida:\r\n {{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\r\n >\r\n <span\r\n class=\"ff-file-item__date\"\r\n *ngIf=\"item.FechaSubida && isMobile\"\r\n >{{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\r\n >\r\n <i\r\n class=\"pi pi-external-link ff-file-item__open\"\r\n (click)=\"\r\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\r\n \"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n aria-label=\"Abrir en nueva ventana\"\r\n (keydown.enter)=\"\r\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\r\n \"\r\n ></i>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Sin resultados -->\r\n <div *ngIf=\"!loading && items.length === 0\" class=\"ff-empty\">\r\n Sin documentos cargados\r\n </div>\r\n </div>\r\n\r\n <!-- Footer fijo: paginaci\u00F3n compacta -->\r\n <div class=\"ff-footer\" *ngIf=\"usesApi && totalRecords > 0\">\r\n <div class=\"ff-pagination\">\r\n <p-select\r\n [options]=\"pageSizeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(ngModel)]=\"pageSize\"\r\n (ngModelChange)=\"onPageSizeChange()\"\r\n >\r\n </p-select>\r\n <p-paginator\r\n [first]=\"first\"\r\n [rows]=\"pageSize\"\r\n [totalRecords]=\"totalRecords\"\r\n (onPageChange)=\"onPageChange($event)\"\r\n [showCurrentPageReport]=\"true\"\r\n currentPageReportTemplate=\"{first} - {last} de {totalRecords}\"\r\n [showPageLinks]=\"false\"\r\n [showFirstLastIcon]=\"false\"\r\n >\r\n </p-paginator>\r\n </div>\r\n </div>\r\n</div>\r\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"] }]
|
|
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"] }]
|
|
479
568
|
}], ctorParameters: () => [], propDecorators: { carpeta: [{
|
|
480
569
|
type: Input
|
|
481
570
|
}], isMobile: [{
|
|
@@ -506,6 +595,102 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
506
595
|
type: Output
|
|
507
596
|
}] } });
|
|
508
597
|
|
|
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
|
+
|
|
509
694
|
class SfDocumentsComponent {
|
|
510
695
|
sanitizer;
|
|
511
696
|
snackBar;
|
|
@@ -557,6 +742,9 @@ class SfDocumentsComponent {
|
|
|
557
742
|
UsuarioTdoc;
|
|
558
743
|
idKatios;
|
|
559
744
|
displayGenerate = false;
|
|
745
|
+
/** Error de la última generación; se muestra dentro del diálogo hasta reintentar o cambiar el tipo. */
|
|
746
|
+
generateError = null;
|
|
747
|
+
toastKey = SF_DOCUMENTS_TOAST_KEY;
|
|
560
748
|
canGenerate = true;
|
|
561
749
|
documentTypes = [];
|
|
562
750
|
documentsToGenerate = [];
|
|
@@ -597,6 +785,7 @@ class SfDocumentsComponent {
|
|
|
597
785
|
this.scanFileList = new Array();
|
|
598
786
|
this.displayPDF = false;
|
|
599
787
|
this.displayGenerate = false;
|
|
788
|
+
this.generateError = null;
|
|
600
789
|
this.canGenerate = true;
|
|
601
790
|
this.documentTypes = [];
|
|
602
791
|
this.documentsToGenerate = [];
|
|
@@ -701,7 +890,7 @@ class SfDocumentsComponent {
|
|
|
701
890
|
this.documentService.loadingData = false;
|
|
702
891
|
};
|
|
703
892
|
errorCargarArbol = (iError) => {
|
|
704
|
-
this.message('error', 'Error al traer la información', iError
|
|
893
|
+
this.message('error', 'Error al traer la información', getUserErrorMessage(iError, 'getFolders'));
|
|
705
894
|
this.documentService.loadingData = false;
|
|
706
895
|
};
|
|
707
896
|
// onClickedCheckDelete($event: any, document: any) {
|
|
@@ -862,7 +1051,7 @@ class SfDocumentsComponent {
|
|
|
862
1051
|
var sIdKatios = this.idKatios;
|
|
863
1052
|
dataDocs = { data: data };
|
|
864
1053
|
formData.append('data', JSON.stringify(dataDocs));
|
|
865
|
-
formData.append('merge', '
|
|
1054
|
+
formData.append('merge', 'false');
|
|
866
1055
|
for (let _i = 0; _i < fileList.length; _i++) {
|
|
867
1056
|
formData.append('files', fileList[_i], fileList[_i].name);
|
|
868
1057
|
}
|
|
@@ -876,8 +1065,7 @@ class SfDocumentsComponent {
|
|
|
876
1065
|
},
|
|
877
1066
|
error: (err) => {
|
|
878
1067
|
this.documentService.loading = false;
|
|
879
|
-
this.message('error', 'Se presentaron inconvenientes almacenando el documento', err
|
|
880
|
-
console.error('Error : ' + err);
|
|
1068
|
+
this.message('error', 'Se presentaron inconvenientes almacenando el documento', getUserErrorMessage(err, 'uploadFiles'));
|
|
881
1069
|
},
|
|
882
1070
|
});
|
|
883
1071
|
}
|
|
@@ -941,6 +1129,7 @@ class SfDocumentsComponent {
|
|
|
941
1129
|
}
|
|
942
1130
|
message(severity, summary, message) {
|
|
943
1131
|
this.snackBar.add({
|
|
1132
|
+
key: SF_DOCUMENTS_TOAST_KEY,
|
|
944
1133
|
severity: severity,
|
|
945
1134
|
summary: summary,
|
|
946
1135
|
detail: message,
|
|
@@ -1022,11 +1211,14 @@ class SfDocumentsComponent {
|
|
|
1022
1211
|
openGenerateDialog() {
|
|
1023
1212
|
this.selectedDocType = null;
|
|
1024
1213
|
this.selectedRange = null;
|
|
1214
|
+
this.generateError = null;
|
|
1025
1215
|
this.displayGenerate = true;
|
|
1026
1216
|
}
|
|
1027
1217
|
generateDocument() {
|
|
1028
1218
|
if (!this.selectedDocType)
|
|
1029
1219
|
return;
|
|
1220
|
+
// Un error anterior no debe quedar junto al aviso de un parámetro faltante.
|
|
1221
|
+
this.generateError = null;
|
|
1030
1222
|
// Validación mínima: si hay params, exigir que no estén vacíos
|
|
1031
1223
|
for (const p of this.dynamicParams || []) {
|
|
1032
1224
|
const key = p.name;
|
|
@@ -1058,7 +1250,13 @@ class SfDocumentsComponent {
|
|
|
1058
1250
|
this.enProceso = false;
|
|
1059
1251
|
},
|
|
1060
1252
|
error: (err) => {
|
|
1061
|
-
|
|
1253
|
+
// El diálogo queda abierto con el error visible (p-message, role="alert") para
|
|
1254
|
+
// corregir o reintentar. El toast solo si el usuario ya lo cerró: así un lector de
|
|
1255
|
+
// pantalla no anuncia el mismo error dos veces.
|
|
1256
|
+
this.generateError = getUserErrorMessage(err, 'generateDocument');
|
|
1257
|
+
if (!this.displayGenerate) {
|
|
1258
|
+
this.message('error', 'No se pudo generar el documento', this.generateError);
|
|
1259
|
+
}
|
|
1062
1260
|
this.enProceso = false;
|
|
1063
1261
|
},
|
|
1064
1262
|
});
|
|
@@ -1076,6 +1274,7 @@ class SfDocumentsComponent {
|
|
|
1076
1274
|
const doc = this.selectedDocType
|
|
1077
1275
|
? this.documentsToGenerateMap[this.selectedDocType]
|
|
1078
1276
|
: null;
|
|
1277
|
+
this.generateError = null;
|
|
1079
1278
|
this.dynamicParams = doc?.params ?? [];
|
|
1080
1279
|
this.dynamicValues = {}; // reset valores
|
|
1081
1280
|
// valores default opcionales
|
|
@@ -1105,8 +1304,8 @@ class SfDocumentsComponent {
|
|
|
1105
1304
|
previewFallbackIcon(label, path) {
|
|
1106
1305
|
return getFileTypeIcon(label || this.current_label || path || this.current_path);
|
|
1107
1306
|
}
|
|
1108
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SfDocumentsComponent, deps: [{ token: i1.DomSanitizer }, { token: i2
|
|
1109
|
-
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], viewQueries: [{ propertyName: "panel", first: true, predicate: ["pdf"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"sf-doc-layout\">\r\n <div class=\"sf-doc-fixed\">\r\n <div class=\"buttons\" *ngIf=\"botones\">\r\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Atras\"\r\n icon=\"pi pi-arrow-left\"\r\n (click)=\"next(-1)\"\r\n ></button>\r\n </div>\r\n <div\r\n class=\"div-table-col50\"\r\n style=\"text-align: center\"\r\n *ngIf=\"!bFinal && botones\"\r\n >\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Siguiente\"\r\n icon=\"pi pi-arrow-right\"\r\n (click)=\"next(1)\"\r\n ></button>\r\n </div>\r\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Finalizar\"\r\n icon=\"pi pi-home\"\r\n (click)=\"next(0)\"\r\n ></button>\r\n </div>\r\n </div>\r\n <!-- Toolbar superior (solo tab 1) -->\r\n <div *ngIf=\"tab == 1\" class=\"doc-toolbar\">\r\n <div class=\"doc-toolbar-left\" *ngIf=\"aplFiltro\">\r\n <p-iconfield>\r\n <p-inputicon class=\"pi pi-search\" />\r\n <input\r\n type=\"text\"\r\n pInputText\r\n placeholder=\"Buscar carpeta...\"\r\n [(ngModel)]=\"valorFiltro\"\r\n (keyup)=\"filtrarDocumentos()\"\r\n class=\"w-full\"\r\n [disabled]=\"documentService.loadingData\"\r\n />\r\n </p-iconfield>\r\n </div>\r\n\r\n <div class=\"doc-toolbar-right\" *ngIf=\"documentTypes.length > 0\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Generar documento\"\r\n icon=\"pi pi-plus\"\r\n class=\"p-button-sm\"\r\n (click)=\"openGenerateDialog()\"\r\n [disabled]=\"enProceso || !canGenerate\"\r\n ></button>\r\n </div>\r\n </div>\r\n </div>\r\n <p-confirmDialog\r\n header=\"Atencion\"\r\n icon=\"pi pi-exclamation-triangle\"\r\n ></p-confirmDialog>\r\n <div class=\"sf-doc-scrollable\" *ngIf=\"tab == 1\">\r\n <div class=\"folder-list\">\r\n @if (!documentService.loadingData) {\r\n <ng-container *ngFor=\"let carpeta of filesFilter\">\r\n <div class=\"folder-list\">\r\n <div\r\n class=\"folder-item\"\r\n *ngFor=\"let item of carpeta.children\"\r\n (click)=\"VerDetalleTab(item)\"\r\n >\r\n <i\r\n class=\"pi pi-folder folder-item__icon\"\r\n [ngStyle]=\"{\r\n color:\r\n item.children?.length > 0 || item.fileCount > 0\r\n ? 'green'\r\n : 'red',\r\n }\"\r\n ></i>\r\n <div class=\"folder-item__info\">\r\n <span class=\"folder-item__name\">{{ item.label }}</span>\r\n <span\r\n class=\"folder-item__count\"\r\n *ngIf=\"item.children?.length > 0\"\r\n >{{ item.children.length }}\r\n {{\r\n item.children.length === 1 ? \"archivo\" : \"archivos\"\r\n }}</span\r\n >\r\n <span\r\n class=\"folder-item__count\"\r\n *ngIf=\"\r\n (!item.children || item.children.length === 0) &&\r\n item.fileCount\r\n \"\r\n >{{ item.fileCount }}\r\n {{ item.fileCount === 1 ? \"archivo\" : \"archivos\" }}</span\r\n >\r\n <span\r\n class=\"folder-item__count\"\r\n *ngIf=\"\r\n (!item.children || item.children.length === 0) &&\r\n !item.fileCount\r\n \"\r\n >0 archivos</span\r\n >\r\n </div>\r\n <i class=\"pi pi-chevron-right folder-item__arrow\"></i>\r\n </div>\r\n </div>\r\n </ng-container>\r\n } @else {\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n <ng-container *ngIf=\"botones\">\r\n <div class=\"buttons\">\r\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Atras\"\r\n icon=\"pi pi-arrow-left\"\r\n (click)=\"next(-1)\"\r\n ></button>\r\n </div>\r\n <div\r\n class=\"div-table-col50\"\r\n style=\"text-align: center\"\r\n *ngIf=\"!bFinal && botones\"\r\n >\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Siguiente\"\r\n icon=\"pi pi-arrow-right\"\r\n (click)=\"next(1)\"\r\n ></button>\r\n </div>\r\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Finalizar\"\r\n icon=\"pi pi-home\"\r\n (click)=\"next(0)\"\r\n ></button>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n <div class=\"sf-doc-scrollable sf-doc-scrollable--files\" *ngIf=\"tab == 2\">\r\n <lib-folder-files\r\n [carpeta]=\"carpetaSeleccionada\"\r\n [isMobile]=\"isMobile\"\r\n [idKatios]=\"idKatios\"\r\n [server]=\"server\"\r\n [subestado]=\"subestado\"\r\n [requestData]=\"requestData\"\r\n [useBreadcrumb]=\"useBreadcrumb\"\r\n [usesApi]=\"usesApi\"\r\n [allowedUploadTypes]=\"allowedUploadTypes\"\r\n (onFileChange)=\"fileChange($event)\"\r\n (onCargarArchivo)=\"cargarArchivo($event)\"\r\n (onEliminarMasivo)=\"eliminarMasivo($event)\"\r\n (onBack)=\"goToTab('1')\"\r\n (viewDocument)=\"openVisorDoc($event)\"\r\n >\r\n </lib-folder-files>\r\n </div>\r\n</div>\r\n\r\n<!-- <ng-template #scanContent>\r\n <div class=\"div-table\">\r\n <div class=\"div-table-row\" style=\"text-align: center\">\r\n <h4>Escanear documentos</h4>\r\n </div>\r\n <div class=\"div-table-row\" style=\"text-align: center\">\r\n Archivos cargados: <h4>{{scanFileList.length}}</h4>\r\n </div>\r\n <div class=\"div-table-row\" style=\"text-align: center\">\r\n <label (click)=\"takePhotoClick()\" class=\"btn\">\r\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">add_to_photos</mat-icon>\r\n </label>\r\n\r\n <label *ngIf=\"scanFileList.length != 0\" (click)=\"subirFotosScan()\" class=\"btn\">\r\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">share</mat-icon>\r\n </label>\r\n </div>\r\n </div>\r\n</ng-template> -->\r\n\r\n<p-dialog\r\n [(visible)]=\"displayView\"\r\n [header]=\"current_label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\"\r\n [modal]=\"true\"\r\n [style]=\"{ width: '70vw' }\"\r\n appendTo=\"body\"\r\n>\r\n <div *ngIf=\"!canPreview()\" class=\"sf-doc-preview-fallback\">\r\n <i class=\"pi\" [ngClass]=\"previewFallbackIcon()\"></i>\r\n <p>La vista previa no est\u00E1 disponible para este tipo de archivo.</p>\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Abrir en una nueva ventana\"\r\n icon=\"pi pi-external-link\"\r\n (click)=\"openCurrentInNewWindow()\"\r\n ></button>\r\n </div>\r\n <ng-container *ngIf=\"canPreview()\">\r\n <embed\r\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '2'\"\r\n [src]=\"current_path | safe\"\r\n style=\"width: 100%; min-height: 600px\"\r\n />\r\n <iframe\r\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '1'\"\r\n style=\"width: 100%; min-height: 600px\"\r\n [src]=\"current_path | safe\"\r\n ></iframe>\r\n </ng-container>\r\n</p-dialog>\r\n\r\n<p-dialog\r\n header=\"Generar documento\"\r\n [(visible)]=\"displayGenerate\"\r\n [modal]=\"true\"\r\n [closable]=\"true\"\r\n [style]=\"{ width: isMobile ? '95vw' : '520px' }\"\r\n>\r\n <div class=\"gen-form\">\r\n <!-- Tipo de documento -->\r\n <div class=\"gen-field\">\r\n <label class=\"gen-label\">Tipo de documento</label>\r\n <p-dropdown\r\n class=\"gen-control\"\r\n [options]=\"documentTypes\"\r\n optionLabel=\"label\"\r\n optionValue=\"code\"\r\n [(ngModel)]=\"selectedDocType\"\r\n placeholder=\"Seleccione un tipo\"\r\n appendTo=\"body\"\r\n (onChange)=\"onDocTypeChange()\"\r\n >\r\n </p-dropdown>\r\n </div>\r\n\r\n <!-- Par\u00E1metros din\u00E1micos -->\r\n <div class=\"gen-section\" *ngIf=\"dynamicParams.length\">\r\n <div class=\"gen-field\" *ngFor=\"let p of dynamicParams\">\r\n <label class=\"gen-label\">\r\n {{ p.description }}\r\n <span class=\"gen-required\" *ngIf=\"p.required\">*</span>\r\n </label>\r\n\r\n <!-- Date -->\r\n <p-datepicker\r\n *ngIf=\"(p.type || '').toLowerCase() === 'date'\"\r\n class=\"gen-control\"\r\n [(ngModel)]=\"dynamicValues[p.name]\"\r\n [showIcon]=\"true\"\r\n appendTo=\"body\"\r\n dateFormat=\"yy-mm-dd\"\r\n >\r\n </p-datepicker>\r\n\r\n <!-- String -->\r\n <input\r\n *ngIf=\"\r\n (p.type || '').toLowerCase() === 'nvarchar' ||\r\n (p.type || '').toLowerCase() === 'string'\r\n \"\r\n pInputText\r\n class=\"gen-control\"\r\n [(ngModel)]=\"dynamicValues[p.name]\"\r\n placeholder=\"Ingrese un valor\"\r\n />\r\n\r\n <!-- Number -->\r\n <p-inputNumber\r\n *ngIf=\"\r\n ['int', 'decimal', 'number'].includes((p.type || '').toLowerCase())\r\n \"\r\n class=\"gen-control\"\r\n [(ngModel)]=\"dynamicValues[p.name]\"\r\n >\r\n </p-inputNumber>\r\n\r\n <!-- Boolean -->\r\n <div\r\n class=\"gen-control gen-checkbox\"\r\n *ngIf=\"\r\n ['boolean', 'bit', 'bool'].includes((p.type || '').toLowerCase())\r\n \"\r\n >\r\n <p-checkbox [binary]=\"true\" [(ngModel)]=\"dynamicValues[p.name]\">\r\n </p-checkbox>\r\n <span class=\"gen-checkbox-label\">S\u00ED</span>\r\n </div>\r\n\r\n <!-- helper opcional -->\r\n <small class=\"gen-help\" *ngIf=\"p.help\">{{ p.help }}</small>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <ng-template pTemplate=\"footer\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Cancelar\"\r\n class=\"p-button-text\"\r\n (click)=\"displayGenerate = false\"\r\n ></button>\r\n\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Generar\"\r\n icon=\"pi pi-cog\"\r\n (click)=\"generateDocument()\"\r\n [disabled]=\"!selectedDocType || enProceso\"\r\n ></button>\r\n </ng-template>\r\n</p-dialog>\r\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: "directive", type: i2$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.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: i5$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.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: i7$1.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: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i8.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i8.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.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: i11.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: i12.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: i13.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "style", "shape", "animation", "borderRadius", "size", "width", "height"] }] });
|
|
1307
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SfDocumentsComponent, deps: [{ token: i1.DomSanitizer }, { token: i2.MessageService }, { token: i0.ApplicationRef }, { token: i2.ConfirmationService }, { token: SfDocumentsService }], target: i0.ɵɵFactoryTarget.Component });
|
|
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"] }] });
|
|
1110
1309
|
}
|
|
1111
1310
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SfDocumentsComponent, decorators: [{
|
|
1112
1311
|
type: Component,
|
|
@@ -1127,8 +1326,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
1127
1326
|
DropdownModule,
|
|
1128
1327
|
DatePickerModule,
|
|
1129
1328
|
SkeletonModule,
|
|
1130
|
-
], providers: [ConfirmationService], standalone: true, template: "<div class=\"sf-doc-layout\">\r\n <div class=\"sf-doc-fixed\">\r\n <div class=\"buttons\" *ngIf=\"botones\">\r\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Atras\"\r\n icon=\"pi pi-arrow-left\"\r\n (click)=\"next(-1)\"\r\n ></button>\r\n </div>\r\n <div\r\n class=\"div-table-col50\"\r\n style=\"text-align: center\"\r\n *ngIf=\"!bFinal && botones\"\r\n >\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Siguiente\"\r\n icon=\"pi pi-arrow-right\"\r\n (click)=\"next(1)\"\r\n ></button>\r\n </div>\r\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Finalizar\"\r\n icon=\"pi pi-home\"\r\n (click)=\"next(0)\"\r\n ></button>\r\n </div>\r\n </div>\r\n <!-- Toolbar superior (solo tab 1) -->\r\n <div *ngIf=\"tab == 1\" class=\"doc-toolbar\">\r\n <div class=\"doc-toolbar-left\" *ngIf=\"aplFiltro\">\r\n <p-iconfield>\r\n <p-inputicon class=\"pi pi-search\" />\r\n <input\r\n type=\"text\"\r\n pInputText\r\n placeholder=\"Buscar carpeta...\"\r\n [(ngModel)]=\"valorFiltro\"\r\n (keyup)=\"filtrarDocumentos()\"\r\n class=\"w-full\"\r\n [disabled]=\"documentService.loadingData\"\r\n />\r\n </p-iconfield>\r\n </div>\r\n\r\n <div class=\"doc-toolbar-right\" *ngIf=\"documentTypes.length > 0\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Generar documento\"\r\n icon=\"pi pi-plus\"\r\n class=\"p-button-sm\"\r\n (click)=\"openGenerateDialog()\"\r\n [disabled]=\"enProceso || !canGenerate\"\r\n ></button>\r\n </div>\r\n </div>\r\n </div>\r\n <p-confirmDialog\r\n header=\"Atencion\"\r\n icon=\"pi pi-exclamation-triangle\"\r\n ></p-confirmDialog>\r\n <div class=\"sf-doc-scrollable\" *ngIf=\"tab == 1\">\r\n <div class=\"folder-list\">\r\n @if (!documentService.loadingData) {\r\n <ng-container *ngFor=\"let carpeta of filesFilter\">\r\n <div class=\"folder-list\">\r\n <div\r\n class=\"folder-item\"\r\n *ngFor=\"let item of carpeta.children\"\r\n (click)=\"VerDetalleTab(item)\"\r\n >\r\n <i\r\n class=\"pi pi-folder folder-item__icon\"\r\n [ngStyle]=\"{\r\n color:\r\n item.children?.length > 0 || item.fileCount > 0\r\n ? 'green'\r\n : 'red',\r\n }\"\r\n ></i>\r\n <div class=\"folder-item__info\">\r\n <span class=\"folder-item__name\">{{ item.label }}</span>\r\n <span\r\n class=\"folder-item__count\"\r\n *ngIf=\"item.children?.length > 0\"\r\n >{{ item.children.length }}\r\n {{\r\n item.children.length === 1 ? \"archivo\" : \"archivos\"\r\n }}</span\r\n >\r\n <span\r\n class=\"folder-item__count\"\r\n *ngIf=\"\r\n (!item.children || item.children.length === 0) &&\r\n item.fileCount\r\n \"\r\n >{{ item.fileCount }}\r\n {{ item.fileCount === 1 ? \"archivo\" : \"archivos\" }}</span\r\n >\r\n <span\r\n class=\"folder-item__count\"\r\n *ngIf=\"\r\n (!item.children || item.children.length === 0) &&\r\n !item.fileCount\r\n \"\r\n >0 archivos</span\r\n >\r\n </div>\r\n <i class=\"pi pi-chevron-right folder-item__arrow\"></i>\r\n </div>\r\n </div>\r\n </ng-container>\r\n } @else {\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n <ng-container *ngIf=\"botones\">\r\n <div class=\"buttons\">\r\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Atras\"\r\n icon=\"pi pi-arrow-left\"\r\n (click)=\"next(-1)\"\r\n ></button>\r\n </div>\r\n <div\r\n class=\"div-table-col50\"\r\n style=\"text-align: center\"\r\n *ngIf=\"!bFinal && botones\"\r\n >\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Siguiente\"\r\n icon=\"pi pi-arrow-right\"\r\n (click)=\"next(1)\"\r\n ></button>\r\n </div>\r\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Finalizar\"\r\n icon=\"pi pi-home\"\r\n (click)=\"next(0)\"\r\n ></button>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n <div class=\"sf-doc-scrollable sf-doc-scrollable--files\" *ngIf=\"tab == 2\">\r\n <lib-folder-files\r\n [carpeta]=\"carpetaSeleccionada\"\r\n [isMobile]=\"isMobile\"\r\n [idKatios]=\"idKatios\"\r\n [server]=\"server\"\r\n [subestado]=\"subestado\"\r\n [requestData]=\"requestData\"\r\n [useBreadcrumb]=\"useBreadcrumb\"\r\n [usesApi]=\"usesApi\"\r\n [allowedUploadTypes]=\"allowedUploadTypes\"\r\n (onFileChange)=\"fileChange($event)\"\r\n (onCargarArchivo)=\"cargarArchivo($event)\"\r\n (onEliminarMasivo)=\"eliminarMasivo($event)\"\r\n (onBack)=\"goToTab('1')\"\r\n (viewDocument)=\"openVisorDoc($event)\"\r\n >\r\n </lib-folder-files>\r\n </div>\r\n</div>\r\n\r\n<!-- <ng-template #scanContent>\r\n <div class=\"div-table\">\r\n <div class=\"div-table-row\" style=\"text-align: center\">\r\n <h4>Escanear documentos</h4>\r\n </div>\r\n <div class=\"div-table-row\" style=\"text-align: center\">\r\n Archivos cargados: <h4>{{scanFileList.length}}</h4>\r\n </div>\r\n <div class=\"div-table-row\" style=\"text-align: center\">\r\n <label (click)=\"takePhotoClick()\" class=\"btn\">\r\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">add_to_photos</mat-icon>\r\n </label>\r\n\r\n <label *ngIf=\"scanFileList.length != 0\" (click)=\"subirFotosScan()\" class=\"btn\">\r\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">share</mat-icon>\r\n </label>\r\n </div>\r\n </div>\r\n</ng-template> -->\r\n\r\n<p-dialog\r\n [(visible)]=\"displayView\"\r\n [header]=\"current_label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\"\r\n [modal]=\"true\"\r\n [style]=\"{ width: '70vw' }\"\r\n appendTo=\"body\"\r\n>\r\n <div *ngIf=\"!canPreview()\" class=\"sf-doc-preview-fallback\">\r\n <i class=\"pi\" [ngClass]=\"previewFallbackIcon()\"></i>\r\n <p>La vista previa no est\u00E1 disponible para este tipo de archivo.</p>\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Abrir en una nueva ventana\"\r\n icon=\"pi pi-external-link\"\r\n (click)=\"openCurrentInNewWindow()\"\r\n ></button>\r\n </div>\r\n <ng-container *ngIf=\"canPreview()\">\r\n <embed\r\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '2'\"\r\n [src]=\"current_path | safe\"\r\n style=\"width: 100%; min-height: 600px\"\r\n />\r\n <iframe\r\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '1'\"\r\n style=\"width: 100%; min-height: 600px\"\r\n [src]=\"current_path | safe\"\r\n ></iframe>\r\n </ng-container>\r\n</p-dialog>\r\n\r\n<p-dialog\r\n header=\"Generar documento\"\r\n [(visible)]=\"displayGenerate\"\r\n [modal]=\"true\"\r\n [closable]=\"true\"\r\n [style]=\"{ width: isMobile ? '95vw' : '520px' }\"\r\n>\r\n <div class=\"gen-form\">\r\n <!-- Tipo de documento -->\r\n <div class=\"gen-field\">\r\n <label class=\"gen-label\">Tipo de documento</label>\r\n <p-dropdown\r\n class=\"gen-control\"\r\n [options]=\"documentTypes\"\r\n optionLabel=\"label\"\r\n optionValue=\"code\"\r\n [(ngModel)]=\"selectedDocType\"\r\n placeholder=\"Seleccione un tipo\"\r\n appendTo=\"body\"\r\n (onChange)=\"onDocTypeChange()\"\r\n >\r\n </p-dropdown>\r\n </div>\r\n\r\n <!-- Par\u00E1metros din\u00E1micos -->\r\n <div class=\"gen-section\" *ngIf=\"dynamicParams.length\">\r\n <div class=\"gen-field\" *ngFor=\"let p of dynamicParams\">\r\n <label class=\"gen-label\">\r\n {{ p.description }}\r\n <span class=\"gen-required\" *ngIf=\"p.required\">*</span>\r\n </label>\r\n\r\n <!-- Date -->\r\n <p-datepicker\r\n *ngIf=\"(p.type || '').toLowerCase() === 'date'\"\r\n class=\"gen-control\"\r\n [(ngModel)]=\"dynamicValues[p.name]\"\r\n [showIcon]=\"true\"\r\n appendTo=\"body\"\r\n dateFormat=\"yy-mm-dd\"\r\n >\r\n </p-datepicker>\r\n\r\n <!-- String -->\r\n <input\r\n *ngIf=\"\r\n (p.type || '').toLowerCase() === 'nvarchar' ||\r\n (p.type || '').toLowerCase() === 'string'\r\n \"\r\n pInputText\r\n class=\"gen-control\"\r\n [(ngModel)]=\"dynamicValues[p.name]\"\r\n placeholder=\"Ingrese un valor\"\r\n />\r\n\r\n <!-- Number -->\r\n <p-inputNumber\r\n *ngIf=\"\r\n ['int', 'decimal', 'number'].includes((p.type || '').toLowerCase())\r\n \"\r\n class=\"gen-control\"\r\n [(ngModel)]=\"dynamicValues[p.name]\"\r\n >\r\n </p-inputNumber>\r\n\r\n <!-- Boolean -->\r\n <div\r\n class=\"gen-control gen-checkbox\"\r\n *ngIf=\"\r\n ['boolean', 'bit', 'bool'].includes((p.type || '').toLowerCase())\r\n \"\r\n >\r\n <p-checkbox [binary]=\"true\" [(ngModel)]=\"dynamicValues[p.name]\">\r\n </p-checkbox>\r\n <span class=\"gen-checkbox-label\">S\u00ED</span>\r\n </div>\r\n\r\n <!-- helper opcional -->\r\n <small class=\"gen-help\" *ngIf=\"p.help\">{{ p.help }}</small>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <ng-template pTemplate=\"footer\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Cancelar\"\r\n class=\"p-button-text\"\r\n (click)=\"displayGenerate = false\"\r\n ></button>\r\n\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Generar\"\r\n icon=\"pi pi-cog\"\r\n (click)=\"generateDocument()\"\r\n [disabled]=\"!selectedDocType || enProceso\"\r\n ></button>\r\n </ng-template>\r\n</p-dialog>\r\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"] }]
|
|
1131
|
-
}], ctorParameters: () => [{ type: i1.DomSanitizer }, { type: i2$1.MessageService }, { type: i0.ApplicationRef }, { type: i2$1.ConfirmationService }, { type: SfDocumentsService }], propDecorators: { accion: [{
|
|
1329
|
+
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"] }]
|
|
1331
|
+
}], ctorParameters: () => [{ type: i1.DomSanitizer }, { type: i2.MessageService }, { type: i0.ApplicationRef }, { type: i2.ConfirmationService }, { type: SfDocumentsService }], propDecorators: { accion: [{
|
|
1132
1332
|
type: Input
|
|
1133
1333
|
}], entidad: [{
|
|
1134
1334
|
type: Input
|