1
0

2 Коммиты 532841a2b5 ... a631cc64e3

Автор SHA1 Сообщение Дата
  SalemRoman a631cc64e3 Merge branch 'salemDev' of http://209.50.56.224/git/JoseBrito/SAM_FRONT_V2 into salemDev 2 месяцев назад
  SalemRoman 8a02e2a20c subo cambios de estilos para el zip 2 месяцев назад

+ 2 - 0
src/app/components/initial-data-upload/individual-equipment-upload/individual-upload.component.ts

@@ -267,6 +267,8 @@ private excelFileBuffer: ArrayBuffer | null = null;
     this.loadExcelFile();
   }
 
+  
+
   cancelar(): void {
     this.dialogRef.close();
   }

+ 271 - 39
src/app/components/initial-data-upload/preview-Equipmentexcel-document/preview-excel-document.component.css

@@ -1,4 +1,3 @@
-/* preview-excel-document.component.css */
 
 .preview-excel-container {
   max-width: 100%;
@@ -7,7 +6,7 @@
   flex-direction: column;
   background: #fafafa;
   overflow: hidden;
-  position: relative; /* Agregado para contener elementos posicionados */
+  position: relative; 
 }
 
 .excel-table {
@@ -32,7 +31,7 @@
   color: #adb5bd;
 }
 
-/* Indicador visual para columnas de ID */
+
 .id-column-header {
   background: linear-gradient(to bottom, #e3f2fd, #bbdefb) !important;
   position: relative;
@@ -76,8 +75,13 @@
 }
 
 .data-cell {
-  transition: all 0.2s ease;
+  min-width: 140px;
+  max-width: 250px;
+  padding: 12px 16px;
+  border-right: 1px solid #dee2e6;
+  vertical-align: middle;
   position: relative;
+  text-align: center; 
 }
 
 .data-cell:hover {
@@ -89,25 +93,181 @@
 }
 
 .cell-input {
-  transition: all 0.2s ease;
+  width: 100%;
+  border: 1px solid #aabaca;
+  border-radius: 4px;
+  padding: 8px;
+  font-size: 13px;
+  font-family: 'Roboto', sans-serif;
+  background: white;
   outline: none;
+  box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
+  text-align: center; 
+  box-sizing: border-box; 
+  margin: 0; 
+  display: block;
+}
+
+.data-cell .cell-content {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  text-align: center;
+  
+  /* Control de overflow para contenido de celda */
+  overflow: hidden;
+  word-wrap: break-word;
+  word-break: break-word;
+  hyphens: auto;
+  
+  /* Para textos muy largos */
+  
+  /* Mejor manejo de líneas múltiples */
+  white-space: pre-wrap; /* Permitir saltos de línea */
+  
+  /* Padding interno para mejor legibilidad */
+  padding: 2px 0;
+  box-sizing: border-box;
+}
+
+.data-cell:hover .cell-content {
+  text-align: center;
+}
+
+.cell-input.disabled-cell {
+  background-color: #f8f9fa !important;
+  color: #6c757d !important;
+  cursor: not-allowed !important;
+  border-color: #e9ecef !important;
+  text-align: center !important; 
+}
+
+.disabled-cell {
+  text-align: center !important; 
+  display: flex !important;
+  align-items: center !important;
+  justify-content: center !important;
+}
+
+.excel-table td,
+.excel-table th {
+  vertical-align: middle;
+}
+
+.data-cell > * {
+  margin: 0 auto; 
+}
+
+.cell-content {
+  min-height: 20px;
+  white-space: pre-wrap;
+  word-wrap: break-word;
+  font-family: 'Roboto', sans-serif;
+  color: #424242;
+  line-height: 1.4;
+  cursor: pointer;
+  text-align: center;
+  display: flex; 
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  box-sizing: border-box;
 }
 
 .cell-input:focus {
-  border-color: #1976d2 !important;
-  box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.2);
+  border-color: #007bff !important;
+  box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25) !important;
+  text-align: center;
 }
 
 .row-number {
-  background: #f8f9fa !important;
+  width: 60px;
+  padding: 12px 8px;
+  border-right: 1px solid #dee2e6;
+  text-align: center;
   font-weight: 500;
   color: #6c757d;
-  border-right: 2px solid #dee2e6 !important;
+  font-size: 12px;
+  background: #f8f9fa !important;
+  vertical-align: middle;
+}
+.row-number > div {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 4px;
+  height: 100%;
+  min-height: 20px; 
 }
 
+.row-number .mat-icon-button {
+  width: 20px;
+  height: 20px;
+  color: #dc3545;
+  display: flex; /* Usar flexbox para centrar el ícono */
+  align-items: center; /* Centrar verticalmente el ícono */
+  justify-content: center; /* Centrar horizontalmente el ícono */
+  padding: 0; /* Eliminar padding por defecto */
+  margin: 0; /* Eliminar margen por defecto */
+}
+
+.row-number .mat-icon-button .mat-icon {
+  font-size: 14px;
+  line-height: 1; /* Eliminar espacio extra */
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+
 .column-header {
-  background: linear-gradient(to bottom, #f8f9fa, #e9ecef);
-  border-bottom: 2px solid #dee2e6;
+  min-width: 140px;
+  padding: 12px 16px;
+  border-right: 1px solid #dee2e6;
+  text-align: center; /* Centrar el texto del header */
+  font-weight: 600;
+  color: #495057;
+  font-size: 12px;
+  position: relative;
+  vertical-align: middle; /* Centrar verticalmente */
+}
+
+.column-header > div {
+  display: flex;
+  align-items: center; /* Centrar verticalmente */
+  justify-content: space-between; /* Distribuir espacio entre texto e ícono */
+  height: 100%;
+  min-height: 20px;
+}
+
+.column-header > div > span {
+  display: flex;
+  align-items: center;
+  justify-content: center; /* Centrar el texto del header */
+  gap: 4px;
+  flex-grow: 1; /* Ocupar el espacio disponible */
+}
+
+.column-header .mat-icon-button {
+  width: 24px;
+  height: 24px;
+  color: #dc3545;
+  opacity: 0.7;
+  display: flex; 
+  align-items: center;
+  justify-content: center;
+  padding: 0; 
+  margin: 0; 
+  flex-shrink: 0;
+}
+
+.column-header .mat-icon-button .mat-icon {
+  font-size: 16px;
+  line-height: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
 }
 
 .table-container {
@@ -117,8 +277,8 @@
   border-radius: 8px;
   margin: 0 16px;
   overflow: auto;
-  margin-bottom: 0; /* Removido el margen inferior */
-  min-height: 0; /* Permite que el flex funcione correctamente */
+  margin-bottom: 0;
+  min-height: 0;
 }
 
 .table-container::-webkit-scrollbar {
@@ -144,7 +304,7 @@
   background: linear-gradient(to bottom, #ffffff, #f8f9fa);
   border-bottom: 1px solid #e0e0e0;
   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
-  flex-shrink: 0; /* Evita que el header se encoja */
+  flex-shrink: 0; 
 }
 
 .table-summary {
@@ -157,8 +317,7 @@
   font-size: 13px;
   color: #6c757d;
   min-height: 48px;
-  /* Removido position: fixed y propiedades relacionadas */
-  flex-shrink: 0; /* Evita que se encoja */
+  flex-shrink: 0; 
   box-sizing: border-box;
 }
 
@@ -166,8 +325,7 @@
   background: linear-gradient(to bottom, #ffffff, #f8f9fa);
   border-top: 1px solid #e0e0e0;
   box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.05);
-  /* Removido position: fixed y propiedades relacionadas */
-  flex-shrink: 0; /* Evita que se encoja */
+  flex-shrink: 0; 
   box-sizing: border-box;
 }
 
@@ -175,6 +333,10 @@
   animation: pulse 2s infinite;
 }
 
+.sheet-selector{
+  margin-top: 15px;
+}
+
 @keyframes pulse {
   0% { opacity: 1; }
   50% { opacity: 0.7; }
@@ -191,34 +353,27 @@
   color: #6c757d;
 }
 
-/* Responsive */
 @media (max-width: 768px) {
-  .excel-table {
-    font-size: 12px;
+  .cell-input {
+    text-align: center;
+    padding: 6px;
+  }
+  
+  .cell-content {
+    text-align: center;
+    justify-content: center;
   }
   
   .column-header,
   .data-cell {
-    min-width: 100px;
-    padding: 8px 12px;
+    text-align: center;
   }
   
   .row-number {
-    width: 40px;
-    padding: 8px 4px;
-  }
-  
-  .header-controls {
-    flex-direction: column;
-    gap: 12px;
-  }
-  
-  .edit-controls {
-    justify-content: center;
+    text-align: center;
   }
 }
 
-/* Mejoras de accesibilidad */
 .excel-table:focus-within {
   outline: 2px solid #1976d2;
   outline-offset: 2px;
@@ -229,7 +384,6 @@ button:focus {
   outline-offset: 2px;
 }
 
-/* Estados de carga */
 .loading-state {
   opacity: 0.6;
   pointer-events: none;
@@ -255,7 +409,6 @@ button:focus {
 
 
 
-/* Estilos adicionales para mejorar la experiencia de edición */
 .cell-input:focus {
   border-color: #007bff !important;
   box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25) !important;
@@ -281,11 +434,90 @@ button:focus {
   opacity: 1;
 }
 
-/* Animaciones suaves */
 .preview-excel-container {
   animation: fadeIn 0.3s ease-in-out;
 }
 
+.edit-controls {
+  display: flex;
+  align-items: center; 
+  gap: 8px;
+  margin-right: 20px;
+}
+
+.edit-controls > button[mat-icon-button] {
+  border-radius: 10px;
+  margin-bottom: 0 !important; 
+  display: flex;
+  align-items: center; 
+  justify-content: center;
+  width: 40px; 
+  height: 40px;
+  padding: 0; 
+}
+
+.edit-controls > button[mat-icon-button] .mat-icon {
+  margin: 0 !important; 
+  line-height: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.edit-controls ng-container {
+  display: flex;
+  align-items: center; 
+  gap: 8px;
+  margin-bottom: 0 !important; 
+}
+
+.edit-controls ng-container button[mat-icon-button] {
+  border-radius: 8px;
+  margin-bottom: 0 !important; 
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 40px; 
+  height: 40px;
+  padding: 0; 
+  vertical-align: middle; 
+}
+
+.edit-controls ng-container button[mat-icon-button] object {
+  width: 24px !important; 
+  height: 24px !important;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  vertical-align: middle;
+  margin: 0; 
+}
+
+.edit-controls * {
+  vertical-align: middle;
+}
+
+.header-controls {
+  display: flex;
+  gap: 16px;
+  width: 100%;
+  justify-content: end;
+  align-items: center; 
+  min-height: 48px;
+}
+
+.header-controls > * {
+  margin-bottom: 0 !important;
+}
+
+button[mat-icon-button][color="warn"],
+button[mat-icon-button][color="primary"] {
+  margin-bottom: 0 !important;
+  align-self: center; 
+}
+
+
+
 @keyframes fadeIn {
   from {
     opacity: 0;
@@ -297,7 +529,7 @@ button:focus {
   }
 }
 
-/* Responsive design */
+
 @media (max-width: 768px) {
   .header-controls {
     flex-direction: column;

+ 5 - 9
src/app/components/initial-data-upload/preview-Equipmentexcel-document/preview-excel-document.component.html

@@ -7,13 +7,8 @@
     </div>
 
     <div class="header-controls" style="display: flex; gap: 16px; width: 100%; justify-content: end; align-items: center;">
-      <div class="changes-indicator" *ngIf="hasUnsavedChanges" 
-           style="display: flex; align-items: center; gap: 6px; padding: 6px 12px; background: #fff3cd; border-radius: 20px; font-size: 12px; color: #856404; border: 1px solid #ffeaa7;">
-        <mat-icon style="font-size: 14px;">edit</mat-icon>
-        <span>Cambios sin guardar</span>
-      </div>
       <div class="docu" style="margin-right: 100 !important;">
-        <h2 mat-dialog-title class="dialog-title" style=" font-size: 18px; display: flex; align-items: center; gap: 8px; color: #424242; margin-bottom: 13px;" >
+        <h2 mat-dialog-title class="dialog-title" style=" font-size: 18px; display: flex; align-items: center; gap: 8px; color: #424242; margin-bottom: 13px; margin-right: 80px;" >
           <mat-icon style="color: #17752b;">table_chart</mat-icon>
           {{ fileName }}
         </h2>
@@ -62,7 +57,8 @@
         </ng-container>
         
         <ng-container *ngIf="hasUnsavedChanges">
-          <button mat-raised-button 
+          <button mat-button 
+                  class="raised-button-background"
                   (click)="saveChanges()" 
                   color="primary"
                   style="margin-left: 8px; border-radius: 8px;">
@@ -70,7 +66,7 @@
             Guardar Cambios
           </button>
           
-          <button mat-stroked-button 
+          <button mat-button 
                   (click)="discardChanges()" 
                   color="warn"
                   style="border-radius: 8px;">
@@ -237,7 +233,7 @@
           [disabled]="isLoading">
     <mat-icon *ngIf="!isLoading">check</mat-icon>
     <mat-spinner *ngIf="isLoading" diameter="20" style="margin-right: 8px;"></mat-spinner>
-    {{ isLoading ? 'Validando...' : 'Validar documento' }}
+    {{ isLoading ? 'Procesando...' : 'Procesar equipamientos' }}
   </button>
 </div>
   </mat-dialog-actions>

+ 5 - 4
src/app/components/initial-data-upload/preview-Equipmentexcel-document/preview-excel-document.component.ts

@@ -61,6 +61,7 @@ export class PreviewExcelDocumentComponent implements OnInit {
   ) {}
 
   ngOnInit(): void {
+    
     if (this.data) {
       this.fileName = this.data.fileName;
       this.sheetNames = this.data.sheetNames;
@@ -556,7 +557,7 @@ private getSheetDataAsMatrix(worksheet: XLSX.WorkSheet): any[][] {
       });
       
       const originalName = this.fileName.replace(/\.[^/.]+$/, "");
-      const modifiedFileName = `${originalName}_modificado.xlsx`;
+      const modifiedFileName = `${originalName}.xlsx`;
       
       return new File([blob], modifiedFileName, {
         type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
@@ -1179,7 +1180,7 @@ private uploadModifiedFileAndValidate(): void {
 // 5. Método para subir archivo modificado como temporal
 private async uploadModifiedFileToTemp(modifiedFile: File): Promise<string | null> {
   try {
-    console.log('📤 Subiendo archivo modificado:', modifiedFile.name, 'Tamaño:', (modifiedFile.size / 1024).toFixed(2), 'KB');
+    console.log(' Subiendo archivo modificado:', modifiedFile.name, 'Tamaño:', (modifiedFile.size / 1024).toFixed(2), 'KB');
     
     const idUser = this.data.userId || localStorage.getItem('idusuario');
     const formData = new FormData();
@@ -1197,7 +1198,7 @@ private async uploadModifiedFileToTemp(modifiedFile: File): Promise<string | nul
       return null;
     } else {
       console.log(' Archivo modificado subido exitosamente');
-      console.log('🆔 Nuevo ID de archivo:', response.response.idArchivo);
+      console.log(' Nuevo ID de archivo:', response.response.idArchivo);
       return response.response.idArchivo;
     }
 
@@ -1732,7 +1733,7 @@ private handleValidationSuccess(response: any): void {
   console.log(' Validación exitosa:', response);
   
   // Mostrar mensaje de éxito
-  const message = response.message || 'Documento validado exitosamente';
+  const message = response.message || 'Equipamientos procesados exitosamente';
   this._resourcesService?.openSnackBar(message);
   
   // CERRAR EL COMPONENTE después de validación exitosa

+ 1 - 8
src/app/components/initial-data-upload/preview-file-content/preview-file-content.component.html

@@ -205,14 +205,7 @@
         <span>{{ isValidating ? 'Validando...' : 'Validar ZIP' }}</span>
       </button>
 
-      <button *ngIf="!canValidate" 
-              mat-button 
-              color="primary" 
-              class="raised-button-background"
-              disabled>
-        <mat-icon>info</mat-icon>
-        <span>Sin datos de Excel para validar</span>
-      </button>
+
     </div>
   </mat-dialog-actions>
 </div>

+ 42 - 0
src/app/components/initial-data-upload/zipfile-upload/zipfile-upload.component.css

@@ -174,3 +174,45 @@
     align-self: flex-end;
   }
 }
+
+
+/* Estilos para el área drag-drop deshabilitada */
+.drag-drop-area.disabled {
+  background-color: #f5f5f5 !important;
+  border: 2px dashed #ccc !important;
+  cursor: not-allowed !important;
+  opacity: 0.6;
+}
+
+.drag-drop-area.disabled:hover {
+  border-color: #ccc !important;
+  background-color: #f5f5f5 !important;
+}
+
+.drag-drop-area.disabled .drag-drop-content {
+  pointer-events: none;
+}
+
+.drag-drop-area.disabled .upload-icon {
+  color: #999 !important;
+}
+
+.drag-drop-area.disabled .drag-drop-text {
+  color: #999 !important;
+}
+
+.drag-drop-area.disabled .drag-drop-text strong {
+  color: #777 !important;
+}
+
+/* Evitar el efecto hover cuando está deshabilitado */
+.drag-drop-area.disabled:not(.drag-over):hover {
+  transform: none !important;
+  box-shadow: none !important;
+}
+
+/* Asegurar que el drag-over no se aplique cuando está deshabilitado */
+.drag-drop-area.disabled.drag-over {
+  border-color: #ccc !important;
+  background-color: #f5f5f5 !important;
+}

+ 48 - 12
src/app/components/initial-data-upload/zipfile-upload/zipfile-upload.component.html

@@ -4,7 +4,7 @@
 
 <div class="uploader">
   <h2 mat-dialog-title class="prevent-select" style="font-size: 15px; display: flex; justify-content: center;">
-    Agregue sus documentos en las secciones requeridas
+    Agregue aquí sus documentos
   </h2>
   
   <input 
@@ -14,32 +14,46 @@
     #file
     class="hidden"
     accept=".xlsx,.xls,.zip"
-    (change)="checkFile($event)">
+    (change)="checkFile($event)"
+    [disabled]="isOperationInProgress || hasValidationResults">
   
   <div 
     class="drag-drop-area"
-    [class.drag-over]="isDragOver"
+    [class.drag-over]="isDragOver && !isOperationInProgress && !hasValidationResults"
     [class.has-file]="hasAnyFile"
+    [class.disabled]="isOperationInProgress || hasValidationResults"
     (dragover)="onDragOver($event)"
     (dragleave)="onDragLeave($event)"
     (drop)="onDrop($event)"
     (click)="openFileUploader()"
     *ngIf="!isUploading">
     
-    <div class="drag-drop-content">
-      <mat-icon class="upload-icon">
+    <div class="drag-drop-content" >
+      <mat-icon class="upload-icon" [style.opacity]="isOperationInProgress || hasValidationResults ? '0.5' : '1'">
         {{ hasZipFile && hasExcelFile ? 'refresh' : 'folder_copy' }}
       </mat-icon>
       
-      <p class="drag-drop-text" *ngIf="!hasExcelFile || !hasZipFile">
+      <p class="drag-drop-text" *ngIf="(!hasExcelFile || !hasZipFile) && !isOperationInProgress && !hasValidationResults">
         <strong>Haga clic aquí o arrastre aquí los archivos requeridos</strong><br>
         <span>Solo archivos .xlsx, .xls (máximo {{MAX_FILE_SIZE_MB}}MB) y ZIP (máximo {{MAX_ZIP_SIZE_MB}}MB)</span>
       </p>
       
-      <p class="drag-drop-text" *ngIf="hasExcelFile && hasZipFile">
+      <p class="drag-drop-text" *ngIf="hasExcelFile && hasZipFile && !isOperationInProgress && !hasValidationResults">
         <strong>Haga clic aquí o arrastre nuevos archivos</strong><br>
         <span>Para reemplazar los archivos actuales</span>
       </p>
+
+      <!-- Mensaje cuando está deshabilitado por validación -->
+      <p class="drag-drop-text" *ngIf="hasValidationResults" style="opacity: 0.7;">
+        <strong>Área de carga deshabilitada</strong><br>
+        <span>Los archivos ya han sido validados. Use "Limpiar todo" para cargar nuevos archivos.</span>
+      </p>
+
+      <!-- Mensaje cuando está en progreso -->
+      <p class="drag-drop-text" *ngIf="isOperationInProgress && !hasValidationResults " style="opacity: 0.7;">
+        <strong>Operación en progreso...</strong><br>
+        <span>Espere a que termine la operación actual</span>
+      </p>
     </div>
   </div>
   
@@ -49,6 +63,28 @@
   </div>
 </div>
 
+
+<div class="validation-overlay" *ngIf="isValidating" [@fadeInOut]>
+  <img 
+  src="/assets/img/validating.gif"
+  alt="Validando..." 
+    (load)="onGifLoad()"
+    (error)="onGifError()">
+  
+  <div class="validation-content">
+    <div class="validation-text">
+      {{ validationStep || 'Validando archivos...' }}
+    </div>
+    
+    <mat-spinner 
+      diameter="40" 
+      color="primary" 
+      style="margin-top: 20px;"
+      *ngIf="!gifLoaded">
+    </mat-spinner>
+  </div>
+</div>
+
 <div mat-dialog-content class="prevent-select">
   <div class="is-loading animated fadeIn fast" *ngIf="isLoading" style="text-align: center; padding: 20px;">
     <mat-spinner></mat-spinner>
@@ -129,7 +165,7 @@
               class="red_primary_background white_font"
               [matTooltip]="element.tipo_archivo === 'excel' ? 'Eliminar archivo Excel' : 'Eliminar archivo ZIP'"
               (click)="element.tipo_archivo === 'excel' ? removeExcelFile() : removeZipFile()"
-              [disabled]="isLoading || isUploading">
+              [disabled]="isLoading || isUploading || hasValidationResults">
               <mat-icon>delete</mat-icon>
             </button>
           </div>
@@ -210,7 +246,7 @@
     Cancelar
   </button>
   
-  <button 
+  <!-- <button 
     mat-button
     color="primary"
     (click)="clearAllData()"
@@ -218,10 +254,10 @@
     [disabled]="!hasAnyFile || isLoading || isUploading || isValidating || isProcessing">
     <mat-icon>delete_sweep</mat-icon>
     Limpiar todo
-  </button>
+  </button> -->
 
   <!-- Botón para reiniciar validación (solo si ya hay resultados) -->
-  <button 
+  <!-- <button 
     mat-button
     color="warn"
     (click)="resetValidation()"
@@ -230,7 +266,7 @@
     [disabled]="isLoading || isUploading || isValidating || isProcessing">
     <mat-icon>refresh</mat-icon>
     Nueva validación
-  </button>
+  </button> -->
   
   <!-- Botón de validar (solo si no hay resultados de validación) -->
   <button 

+ 106 - 28
src/app/components/initial-data-upload/zipfile-upload/zipfile-upload.component.ts

@@ -12,6 +12,8 @@ import { FormControl, Validators } from '@angular/forms';
 import JSZip from 'jszip';
 import { PreviewDocumentsComponent } from '../preview-documents/preview-documents.component';
 import { PreviewFileContentComponent } from '../preview-file-content/preview-file-content.component';
+import { trigger, state, style, transition, animate } from '@angular/animations';
+
 import { firstValueFrom } from 'rxjs';
 const ID_MODULE = "S002V01M15IDUP";
 
@@ -90,7 +92,18 @@ interface TemplateStructure {
   selector: 'app-zipfile-upload',
   templateUrl: './zipfile-upload.component.html',
   styleUrls: ['./zipfile-upload.component.css'],
-  standalone: false
+  standalone: false,
+  animations: [
+    trigger('fadeInOut', [
+      transition(':enter', [
+        style({ opacity: 0 }),
+        animate('300ms ease-in', style({ opacity: 1 }))
+      ]),
+      transition(':leave', [
+        animate('300ms ease-out', style({ opacity: 0 }))
+      ])
+    ])
+  ]
 })
 export class ZipfileUploadComponent implements OnInit {
 
@@ -104,7 +117,7 @@ export class ZipfileUploadComponent implements OnInit {
   public errorMessage: string = '';
   public isUploading: boolean = false;
   public currentFileType: 'excel' | 'zip' | null = null;
-
+  public gifLoaded: boolean = false;
   // Variables para validación y procesamiento
   public validationResult: ValidationResult | null = null;
   public isValidating: boolean = false;
@@ -184,22 +197,42 @@ export class ZipfileUploadComponent implements OnInit {
   }
 
   openFileUploader(): void {
+    if (this.isOperationInProgress || this.hasValidationResults) {
+      return;
+    }
     this.uploader?.nativeElement.click();
   }
 
   onDragOver(event: DragEvent): void {
+    // Prevenir drag-over si está deshabilitado
+    if (this.isOperationInProgress || this.hasValidationResults) {
+      return;
+    }
+    
     event.preventDefault();
     event.stopPropagation();
     this.isDragOver = true;
   }
 
-  onDragLeave(event: DragEvent): void {                           
+  onDragLeave(event: DragEvent): void {
+    // Solo procesar si no está deshabilitado                           
+    if (this.isOperationInProgress || this.hasValidationResults) {
+      return;
+    }
+    
     event.preventDefault();
     event.stopPropagation();
     this.isDragOver = false;
   }
 
   onDrop(event: DragEvent): void {
+    // Prevenir drop si está deshabilitado
+    if (this.isOperationInProgress || this.hasValidationResults) {
+      event.preventDefault();
+      event.stopPropagation();
+      return;
+    }
+    
     event.preventDefault();
     event.stopPropagation();
     this.isDragOver = false;
@@ -211,6 +244,11 @@ export class ZipfileUploadComponent implements OnInit {
   }
 
   checkFile(event: any): void {
+    // Prevenir procesamiento si está deshabilitado
+    if (this.isOperationInProgress || this.hasValidationResults) {
+      return;
+    }
+    
     const file = event.target.files[0];
     if (!file) return;
     this.processFile(file);
@@ -367,31 +405,42 @@ public async validateAndProcessDocuments(): Promise<void> {
     }
 
     this.isValidating = true;
-    this.validationStep = 'Validando archivos con el servidor...';
+    this.validationStep = 'Iniciando validación...';
     
     try {
-
       const idUser = localStorage.getItem('idusuario');
       if (!idUser) {
         throw new Error('No se encontró ID de usuario');
       }
 
+      // Actualizar pasos de validación con más detalle
+      this.validationStep = 'Preparando archivos para validación...';
+      await this.delay(500);
+
       const formData = new FormData();
       formData.append('excel_file', this.originalExcelFile, this.originalExcelFile.name);
       formData.append('zip_file', this.originalZipFile, this.originalZipFile.name);
       formData.append('id_user', idUser);
       formData.append('linea', '1');
 
-    const response = await firstValueFrom(
-      this._gdelService.validateZipFile(formData)
-    );
+      this.validationStep = 'Enviando archivos al servidor...';
+      await this.delay(500);
+
+      this.validationStep = 'Procesando validación en el servidor...';
+
+      const response = await firstValueFrom(
+        this._gdelService.validateZipFile(formData)
+      );
       
       if (response.error) {
         throw new Error(response.msg || 'Error en validación del servidor');
       }
 
-    this.validationResult = response.response; 
-    return true;
+      this.validationStep = 'Finalizando validación...';
+      await this.delay(500);
+
+      this.validationResult = response.response; 
+      return true;
 
     } catch (error: any) {
       console.error('Error en validación:', error);
@@ -399,11 +448,25 @@ public async validateAndProcessDocuments(): Promise<void> {
       this.validationResult = null;
       return false;
     } finally {
+      // Pequeño delay para que el usuario vea el mensaje final
+      await this.delay(500);
       this.isValidating = false;
       this.validationStep = '';
     }
   }
 
+    private delay(ms: number): Promise<void> {
+    return new Promise(resolve => setTimeout(resolve, ms));
+  }
+  
+onGifLoad(): void {
+    this.gifLoaded = true;
+  }
+
+  onGifError(): void {
+    this.gifLoaded = false;
+  }
+
  private async processValidatedFiles(): Promise<void> {
   if (!this.validationResult?.temp_files) {
     this._resourcesService.openSnackBar('No hay archivos temporales para procesar');
@@ -863,25 +926,40 @@ public async validateAndProcessDocuments(): Promise<void> {
     this._resourcesService.openSnackBar('Archivo ZIP eliminado');
   }
 
-public clearAllData(): void {
-  this.originalExcelFile = null;
-  this.originalZipFile = null;
-  this.excelFile = null;
-  this.excelData = null;
-  this.zipFile = null;
-  this.zipData = null;
-  this.validationResult = null;
-  this.processedDocuments = [];
-  this.currentFileType = null;
-  
-  // Limpiar input de archivos
-  if (this.uploader && this.uploader.nativeElement) {
-    this.uploader.nativeElement.value = '';
+  public clearAllData(): void {
+    this.originalExcelFile = null;
+    this.originalZipFile = null;
+    this.excelFile = null;
+    this.excelData = null;
+    this.zipFile = null;
+    this.zipData = null;
+    this.validationResult = null;
+    this.processedDocuments = [];
+    this.currentFileType = null;
+    this.isDragOver = false; // Resetear estado de drag
+    
+    // Limpiar input de archivos
+    if (this.uploader && this.uploader.nativeElement) {
+      this.uploader.nativeElement.value = '';
+    }
+    
+    this.updateTableData();
+    this._resourcesService.openSnackBar('Todos los datos han sido limpiados');
   }
-  
-  this.updateTableData();
-  this._resourcesService.openSnackBar('Todos los datos han sido limpiados');
-}
+
+ get isDragDropDisabled(): boolean {
+    return this.isOperationInProgress || this.hasValidationResults;
+  }
+
+  get dragDropStatusMessage(): string {
+    if (this.hasValidationResults) {
+      return 'Los archivos ya han sido validados. Use "Limpiar todo" para cargar nuevos archivos.';
+    }
+    if (this.isOperationInProgress) {
+      return 'Espere a que termine la operación actual';
+    }
+    return '';
+  }  
 
   get hasExcelFile(): boolean {
     return this.excelFile !== null && this.originalExcelFile !== null;