Browse Source

en estos archvivos especificamente existio un conflicto de lógica, por lo mismo se conservó la de salem con necesidad de actualizarle sintaxis de A20

EmilianoOrtiz 3 weeks ago
parent
commit
67a66033f4

+ 1 - 4
src/app/app.module.ts

@@ -417,8 +417,7 @@ import { ControlPanelPreviewComponent } from './components/control-panel/graphic
 import { CorrectiveOrderFormWithoutMeasuresComponent } from './components/corrective-maintenance/operations-management/corrective-order-form-without-measures/corrective-order-form-without-measures.component';
 import { DeleteFormFieldSelectorComponent } from './components/corrective-maintenance/corrective-work-order-form-fields/delete-form-field-selector/delete-form-field-selector.component';
 import { NoMeasuresOrderValidationComponent } from './components/corrective-maintenance/operations-management/no-measures-order-validation/no-measures-order-validation.component';
-import { NoMeasuresOrderDetailsComponent } from './components/corrective-maintenance/operations-management/no-measures-order-details/no-measures-order-details.component';
-import { CloseNoMeasuresOrderComponent } from './components/corrective-maintenance/operations-management/close-no-measures-order/close-no-measures-order.component';
+//import { NoMeasuresOrderDetailsComponent } from './components/corrective-maintenance/operations-managementimport { CloseNoMeasuresOrderComponent } from './components/corrective-maintenance/operations-management/close-no-measures-order/close-no-measures-order.component';
 import { AddCloseActivityComponent } from './components/corrective-maintenance/operations-management/close-no-measures-order/add-close-activity/add-close-activity.component';
 import { NoMeasuresOrderCloseValidationComponent } from './components/corrective-maintenance/operations-management/no-measures-order-close-validation/no-measures-order-close-validation.component';
 import { NoMeasuresOrderReportComponent } from './components/corrective-maintenance/operations-management/no-measures-order-report/no-measures-order-report.component';
@@ -822,8 +821,6 @@ import { HelpDialogComponent } from './components/template/help-dialog/help-dial
     CorrectiveOrderFormWithoutMeasuresComponent,
     DeleteFormFieldSelectorComponent,
     NoMeasuresOrderValidationComponent,
-    NoMeasuresOrderDetailsComponent,
-    CloseNoMeasuresOrderComponent,
     AddCloseActivityComponent,
     NoMeasuresOrderCloseValidationComponent,
     NoMeasuresOrderReportComponent,

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

@@ -1,261 +1,481 @@
 <div class="preview-excel-container">
+  <div
+    class="preview-header"
+    style="
+      padding: 16px;
+      border-bottom: 1px solid #e0e0e0;
+      position: sticky;
+      top: 0;
+      background: white;
+      z-index: 100;
+    "
+  >
+    <div
+      class="header-top"
+      style="
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 12px;
+        width: 50%;
+      "
+    ></div>
 
-  <div class="preview-header" style="padding: 16px; border-bottom: 1px solid #e0e0e0; position: sticky; top: 0; background: white; z-index: 100;">
-    <div class="header-top" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; width: 50%;">
-
-      @if (hasUnsavedChanges) {
-        <div class="changes-indicator" 
-            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>
-
-    <div class="header-controls" style="display: flex; gap: 16px; width: 100%; justify-content: end; align-items: center;">
-      <div class="docu">
-        <h2 mat-dialog-title style="margin: 0; font-size: 18px; display: flex; align-items: center; gap: 8px; color: #424242; margin-bottom: 13px;" >
-          <mat-icon style="color: #19d241;">table_chart</mat-icon>
+    <div
+      class="header-controls"
+      style="
+        display: flex;
+        gap: 16px;
+        width: 100%;
+        justify-content: end;
+        align-items: center;
+      "
+    >
+      <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;
+            margin-right: 80px;
+          "
+        >
+          <mat-icon style="color: #17752b">table_chart</mat-icon>
           {{ fileName }}
         </h2>
       </div>
 
-      @if (sheetNames.length > 1) {
-        <div class="sheet-selector">
-          <mat-form-field appearance="outline" style="width: 200px;">
-            <mat-label>Hoja</mat-label>
-            <mat-select [(value)]="selectedSheet" (selectionChange)="onSheetChange($event.value)">
-              @for (sheet of sheetNames; track $index) {
-                <mat-option [value]="sheet">
-                  {{ sheet }}
-                </mat-option>
-              }
-            </mat-select>
-          </mat-form-field>
-        </div>
-      }
-      
-      <div class="edit-controls" style="display: flex; align-items: center; gap: 8px;">
-        <button mat-icon-button 
-                (click)="toggleEditMode()" 
-                [color]="editMode ? 'warn' : 'primary'"
-                [matTooltip]="editMode ? 'Salir del modo edición' : 'Activar modo edición'"
-                style="border-radius: 10px; margin-bottom: 20px;"
-                [ngClass]="editMode ? 'pink_primary_background white_font' : 'orange_primary_background white_font'">
-          <mat-icon>{{ editMode ? 'visibility' : 'edit' }}</mat-icon>
+      <div class="sheet-selector" *ngIf="sheetNames.length > 1">
+        <mat-form-field appearance="outline" style="width: 200px">
+          <mat-label>Hoja</mat-label>
+          <mat-select
+            [(value)]="selectedSheet"
+            (selectionChange)="onSheetChange($event.value)"
+          >
+            <mat-option *ngFor="let sheet of sheetNames" [value]="sheet">
+              {{ sheet }}
+            </mat-option>
+          </mat-select>
+        </mat-form-field>
+      </div>
+
+      <div
+        class="edit-controls"
+        style="display: flex; align-items: center; gap: 8px; margin-right: 20px"
+      >
+        <button
+          mat-icon-button
+          (click)="toggleEditMode()"
+          [color]="editMode ? 'warn' : 'primary'"
+          [matTooltip]="
+            editMode ? 'Salir del modo edición' : 'Activar modo edición'
+          "
+          style="border-radius: 10px; margin-bottom: 20px"
+          [ngClass]="
+            editMode
+              ? 'pink_primary_background white_font'
+              : 'orange_primary_background white_font'
+          "
+        >
+          <mat-icon>{{ editMode ? "visibility" : "edit" }}</mat-icon>
         </button>
-        
-        @if (editMode) {
-          <ng-container>
-            <button mat-icon-button 
-                    (click)="addRow()" 
-                    matTooltip="Agregar fila"
-                    color="primary"
-                    style="border-radius: 8px;">
-              <mat-icon>table_rows</mat-icon>
-            </button>
-            
-            <button mat-icon-button 
-                    (click)="addColumn()" 
-                    matTooltip="Agregar columna"
-                    color="primary"
-                    style="border-radius: 8px;">
-              <mat-icon>view_column</mat-icon>
-            </button>
-          </ng-container>
-        }
-        
-        @if (hasUnsavedChanges) {
-          <ng-container>
-            <button mat-raised-button 
-                    (click)="saveChanges()" 
-                    color="primary"
-                    style="margin-left: 8px; border-radius: 8px;">
-              <mat-icon>save</mat-icon>
-              Guardar
-            </button>
-            
-            <button mat-stroked-button 
-                    (click)="discardChanges()" 
-                    color="warn"
-                    style="border-radius: 8px;">
-              <mat-icon>undo</mat-icon>
-              Descartar
-            </button>
 
-          </ng-container>
-        }
+        <ng-container *ngIf="editMode" style="margin-bottom: 20px !important">
+          <button
+            mat-icon-button
+            (click)="addRow()"
+            matTooltip="Agregar fila"
+            style="border-radius: 8px"
+          >
+            <object data="assets/img/agregarfila.svg" width="40"></object>
+          </button>
+
+          <!-- <button mat-icon-button 
+                  disabled
+                  (click)="addColumn()" 
+                  matTooltip="Agregar columna"
+                  color="primary"
+                  style="border-radius: 8px;">
+            <mat-icon>view_column</mat-icon>
+          </button> -->
+        </ng-container>
+
+        <ng-container *ngIf="hasUnsavedChanges">
+          <button
+            mat-button
+            class="raised-button-background"
+            (click)="saveChanges()"
+            color="primary"
+            style="margin-left: 8px; border-radius: 8px"
+          >
+            <mat-icon>save</mat-icon>
+            Guardar Cambios
+          </button>
+
+          <button
+            mat-button
+            (click)="discardChanges()"
+            color="warn"
+            style="border-radius: 8px"
+          >
+            <mat-icon>undo</mat-icon>
+            Descartar
+          </button>
+        </ng-container>
       </div>
     </div>
   </div>
 
-  <div class="table-container" style="overflow: auto; background: #fafafa; position: relative;">
-    @if (currentSheetData.length > 0) {
-      <table class="excel-table" 
-            style="width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px; background: white; margin: 16px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
-        
-        <thead>
-          <tr style="background: linear-gradient(to bottom, #f8f9fa, #e9ecef); border-radius: 8px 8px 0 0;">
-            <th class="row-header" 
-                style="width: 60px; padding: 12px 8px; border-right: 1px solid #dee2e6; text-align: center; font-weight: 600; color: #495057; font-size: 12px; border-radius: 8px 0 0 0;">
-              #
-            </th>
-            
-            @for (header of getTableHeaders(); track $index; let colIndex = $index, isLast = $last) {
-              <th  
-                  class="column-header" 
-                  [style.border-radius]="isLast ? '0 8px 0 0' : '0'"
-                  style="min-width: 140px; padding: 12px 16px; border-right: 1px solid #dee2e6; text-align: left; font-weight: 600; color: #495057; font-size: 12px; position: relative;">
-                <div style="display: flex; align-items: center; justify-content: space-between;">
-                  <span>{{ header }}</span>
-                  @if (editMode && getTableHeaders().length > 1) {
-                    <button 
-                            mat-icon-button 
-                            (click)="deleteColumn(colIndex)"
-                            style="width: 24px; height: 24px; color: #dc3545; opacity: 0.7;"
-                            matTooltip="Eliminar columna">
-                      <mat-icon style="font-size: 16px;">close</mat-icon>
-                    </button>
-                  }
-                </div>
-              </th>
-            }
-          </tr>
-        </thead>
-        
-        <tbody>
-          @for (row of currentSheetData; track $index; let rowIndex = $index, isLast = $last) {
-            <tr
-                [style.background]="rowIndex % 2 === 0 ? '#ffffff' : '#f8f9fa'"
-                [style.border-radius]="isLast ? '0 0 8px 8px' : '0'"
-                style="transition: all 0.2s ease; border-bottom: 1px solid #e9ecef;">
-              
-              <td class="row-number" 
-                  [style.border-radius]="isLast ? '0 0 0 8px' : '0'"
-                  style="width: 60px; padding: 12px 8px; border-right: 1px solid #dee2e6; text-align: center; font-weight: 500; color: #6c757d; font-size: 12px; background: #f8f9fa !important;">
-                <div style="display: flex; align-items: center; justify-content: center; gap: 4px;">
-                  <span>{{ getRowNumber(rowIndex) }}</span>
-                  @if (editMode && currentSheetData.length > 1) {
-                    <button 
-                            mat-icon-button 
-                            (click)="deleteRow(rowIndex)"
-                            style="width: 20px; height: 20px; color: #dc3545;"
-                            matTooltip="Eliminar fila">
-                      <mat-icon style="font-size: 14px;">close</mat-icon>
-                    </button>
-                  }
-                </div>
-              </td>
-              
-              @for (cell of row; track $index; let colIndex = $index, isLastCol = $last) {
-                <td 
-                    class="data-cell" 
-                    [style.border-radius]="isLast && isLastCol ? '0 0 8px 0' : '0'"
-                    style="min-width: 140px; max-width: 250px; padding: 12px 16px; border-right: 1px solid #dee2e6; vertical-align: top; position: relative;">
-                  
-                  @if (!editMode) {
-                    <div 
-                        class="cell-content"
-                        style="min-height: 20px; white-space: pre-wrap; word-wrap: break-word; font-family: 'Roboto', sans-serif; color: #424242; line-height: 1.4;">
-                      {{ getCellValue(row, colIndex) }}
-                    </div>
-                  }
+  <div
+    class="table-container"
+    style="overflow: auto; background: #fafafa; position: relative"
+  >
+    <table
+      class="excel-table"
+      *ngIf="currentSheetData.length > 0"
+      style="
+        width: 100%;
+        border-collapse: separate;
+        border-spacing: 0;
+        font-size: 13px;
+        background: white;
+        margin: 16px;
+        border-radius: 10px;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+      "
+    >
+      <thead>
+        <tr
+          style="
+            background: linear-gradient(to bottom, #f8f9fa, #e9ecef);
+            border-radius: 8px 8px 0 0;
+          "
+        >
+          <th
+            class="row-header"
+            style="
+              width: 60px;
+              padding: 12px 8px;
+              border-right: 1px solid #dee2e6;
+              text-align: center;
+              font-weight: 600;
+              color: #495057;
+              font-size: 12px;
+              border-radius: 8px 0 0 0;
+            "
+          >
+            #
+          </th>
+
+          <th
+            *ngFor="
+              let header of getTableHeaders();
+              let colIndex = index;
+              let isLast = last;
+              trackBy: trackByIndex
+            "
+            class="column-header"
+            [class.id-column-header]="isIdColumn(colIndex, selectedSheet)"
+            [style.border-radius]="isLast ? '0 8px 0 0' : '0'"
+            [style.background]="
+              isIdColumn(colIndex, selectedSheet)
+                ? 'linear-gradient(to bottom, #e3f2fd, #bbdefb)'
+                : 'linear-gradient(to bottom, #f8f9fa, #e9ecef)'
+            "
+            [matTooltip]="
+              isIdColumn(colIndex, selectedSheet)
+                ? 'Columna de ID - Generada automáticamente'
+                : ''
+            "
+            style="
+              min-width: 140px;
+              padding: 12px 16px;
+              border-right: 1px solid #dee2e6;
+              text-align: left;
+              font-weight: 600;
+              color: #495057;
+              font-size: 12px;
+              position: relative;
+            "
+          >
+            <div
+              style="
+                display: flex;
+                align-items: center;
+                justify-content: space-between;
+              "
+            >
+              <span style="display: flex; align-items: center; gap: 4px">
+                {{ header }}
+              </span>
+              <button
+                *ngIf="
+                  editMode &&
+                  getTableHeaders().length > 1 &&
+                  !isIdColumn(colIndex, selectedSheet)
+                "
+                mat-icon-button
+                (click)="deleteColumn(colIndex)"
+                style="width: 24px; height: 24px; color: #dc3545; opacity: 0.7"
+                matTooltip="Eliminar columna"
+              >
+                <mat-icon style="font-size: 16px">close</mat-icon>
+              </button>
+            </div>
+          </th>
+        </tr>
+      </thead>
+
+      <tbody>
+        <tr
+          *ngFor="
+            let row of currentSheetData;
+            let rowIndex = index;
+            let isLast = last;
+            trackBy: trackByRowData
+          "
+          [style.background]="rowIndex % 2 === 0 ? '#ffffff' : '#f8f9fa'"
+          [style.border-radius]="isLast ? '0 0 8px 8px' : '0'"
+          style="transition: all 0.2s ease; border-bottom: 1px solid #e9ecef"
+        >
+          <td
+            class="row-number"
+            [style.border-radius]="isLast ? '0 0 0 8px' : '0'"
+            style="
+              width: 60px;
+              padding: 12px 8px;
+              border-right: 1px solid #dee2e6;
+              text-align: center;
+              font-weight: 500;
+              color: #6c757d;
+              font-size: 12px;
+              background: #f8f9fa !important;
+            "
+          >
+            <div
+              style="
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                gap: 4px;
+              "
+            >
+              <span>{{ getRowNumber(rowIndex) }}</span>
+              <button
+                *ngIf="editMode && currentSheetData.length > 1"
+                mat-icon-button
+                (click)="deleteRow(rowIndex)"
+                style="width: 20px; height: 20px; color: #dc3545"
+                matTooltip="Eliminar fila"
+              >
+                <mat-icon style="font-size: 14px">close</mat-icon>
+              </button>
+            </div>
+          </td>
+
+          <td
+            *ngFor="
+              let cell of row;
+              let colIndex = index;
+              let isLastCol = last;
+              trackBy: trackByIndex
+            "
+            class="data-cell"
+            [style.border-radius]="isLast && isLastCol ? '0 0 8px 0' : '0'"
+            style="
+              min-width: 140px;
+              max-width: 250px;
+              padding: 12px 16px;
+              border-right: 1px solid #dee2e6;
+              vertical-align: top;
+              position: relative;
+            "
+          >
+            <div
+              *ngIf="!isCellBeingEdited(rowIndex, colIndex)"
+              class="cell-content"
+              (click)="startEdit(rowIndex, colIndex)"
+              style="
+                min-height: 20px;
+                white-space: pre-wrap;
+                word-wrap: break-word;
+                font-family: 'Roboto', sans-serif;
+                color: #424242;
+                line-height: 1.4;
+                cursor: pointer;
+              "
+              [class.disabled-cell]="isCellDisabled(rowIndex, colIndex)"
+            >
+              {{ getDisplayCellValue(row, colIndex) }}
+            </div>
+
+            <input
+              *ngIf="isCellBeingEdited(rowIndex, colIndex)"
+              s
+              type="text"
+              class="cell-input"
+              (input)="onCellInputChange()"
+              [value]="getDisplayCellValue(row, colIndex)"
+              [attr.title]="
+                isCellDisabled(rowIndex, colIndex)
+                  ? 'Campo ID generado automáticamente'
+                  : ''
+              "
+              style="
+                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);
+              "
+              (blur)="saveCellValue(rowIndex, colIndex, $event)"
+              (keyup.enter)="saveCellValue(rowIndex, colIndex, $event)"
+              autofocus
+            />
+          </td>
+        </tr>
+      </tbody>
+    </table>
 
-                  @if (editMode) {
-                    <input
-                          type="text"
-                          class="cell-input"
-                          [value]="getCellValue(row, colIndex)"
-                          (input)="onCellInput(rowIndex, colIndex, $event)"
-                          (blur)="onCellBlur(rowIndex, colIndex, $event)"
-                          [attr.data-row]="rowIndex"
-                          [attr.data-col]="colIndex"
-                          style="width: 100%; border: 1px solid #ced4da; border-radius: 4px; padding: 8px; font-size: 13px; font-family: 'Roboto', sans-serif; background: white; transition: border-color 0.2s ease; outline: none;"
-                          onfocus="this.style.borderColor='#007bff'; this.style.boxShadow='0 0 0 2px rgba(0, 123, 255, 0.25)'"
-                          onblur="this.style.borderColor='#ced4da'; this.style.boxShadow='none'">
-                  }
-                </td>
-              }
-            </tr>
-          }
-        </tbody>
-      </table>
-    }
-    
     @if (currentSheetData.length === 0) {
-      <div 
-          class="no-data-message"
-          style="padding: 60px 20px; text-align: center; color: #6c757d; background: white; margin: 16px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
-        <mat-icon style="font-size: 64px; color: #dee2e6; margin-bottom: 16px;">table_chart</mat-icon>
-        <p style="margin: 0 0 16px 0; font-size: 16px;">No hay datos disponibles en la hoja "{{ selectedSheet }}"</p>
-        @if (editMode) {
-          <button 
-                  mat-raised-button 
-                  color="primary" 
-                  (click)="addRow()"
-                  style="border-radius: 8px;">
-            <mat-icon>add</mat-icon>
-            Agregar primera fila
-          </button>
-        }
-      </div>
+    <div
+      class="no-data-message"
+      style="
+        padding: 60px 20px;
+        text-align: center;
+        color: #6c757d;
+        background: white;
+        margin: 16px;
+        border-radius: 8px;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+      "
+    >
+      <mat-icon style="font-size: 64px; color: #dee2e6; margin-bottom: 16px"
+        >table_chart</mat-icon
+      >
+      <p style="margin: 0 0 16px 0; font-size: 16px">
+        No hay datos disponibles en la hoja "{{ selectedSheet }}"
+      </p>
+      @if (editMode) {
+      <button
+        mat-raised-button
+        color="primary"
+        (click)="addRow()"
+        style="border-radius: 8px"
+      >
+        <mat-icon>add</mat-icon>
+        Agregar primera fila
+      </button>
+      }
+    </div>
     }
   </div>
 
-  <div class="table-summary">
-    <div class="summary-info" style="display: flex; gap: 24px;">
-      <div style="display: flex; align-items: center; gap: 6px;">
-        <mat-hint style="color: #1976d2;">INFORMACIÓN:</mat-hint>
-        <mat-icon style="font-size: 16px;">layers</mat-icon>
-        <span>{{ sheetNames.length }} {{ sheetNames.length === 1 ? 'hoja' : 'hojas' }}</span>
+  <div
+    class="table-summary"
+    style="
+      padding: 16px;
+      border-top: 1px solid #e0e0e0;
+      background: #f8f9fa;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+    "
+  >
+    <div class="summary-info" style="display: flex; gap: 24px">
+      <div style="display: flex; align-items: center; gap: 6px">
+        <mat-hint style="color: #1976d2">INFORMACIÓN:</mat-hint>
+        <mat-icon style="font-size: 16px">layers</mat-icon>
+        <span
+          >{{ sheetNames.length }}
+          {{ sheetNames.length === 1 ? "hoja" : "hojas" }}</span
+        >
       </div>
-      <div style="display: flex; align-items: center; gap: 6px;">
-        <mat-icon style="font-size: 16px;">table_rows</mat-icon>
+      <div style="display: flex; align-items: center; gap: 6px">
+        <mat-icon style="font-size: 16px">table_rows</mat-icon>
         <span>{{ currentSheetData.length }} filas</span>
       </div>
-      <div style="display: flex; align-items: center; gap: 6px;">
-        <mat-icon style="font-size: 16px;">view_column</mat-icon>
+      <div style="display: flex; align-items: center; gap: 6px">
+        <mat-icon style="font-size: 16px">view_column</mat-icon>
         <span>{{ getTableHeaders().length }} columnas</span>
       </div>
     </div>
-    
+
     <div class="summary-actions">
       @if (editMode) {
-        <div style="display: flex; align-items: center; gap: 6px; color: #28a745;">
-          <mat-icon style="font-size: 16px;">edit</mat-icon>
-          <span>Edición habilitada</span>
-        </div>
-      }
-      @if (!editMode) {
-        <div style="display: flex; align-items: center; gap: 6px; color: #6c757d;">
-          <mat-icon style="font-size: 16px;">visibility</mat-icon>
-          <span>Solo lectura</span>
-        </div>
+      <div style="display: flex; align-items: center; gap: 6px; color: #28a745">
+        <mat-icon style="font-size: 16px">edit</mat-icon>
+        <span>Edición habilitada</span>
+      </div>
+      } @if (!editMode) {
+      <div style="display: flex; align-items: center; gap: 6px; color: #6c757d">
+        <mat-icon style="font-size: 16px">visibility</mat-icon>
+        <span>Solo lectura</span>
+      </div>
       }
     </div>
   </div>
 
-  <mat-dialog-actions align="end" 
-                      class="dialog-actions"
-                      style="padding: 16px; border-top: 1px solid #e0e0e0; background: white; gap: 12px;">
-
-    <div class="status-info" style="margin-right: auto; display: flex; align-items: center; gap: 8px; font-size: 13px; color: #6c757d;">
-      <mat-icon style="font-size: 16px; color: #1976d2;">info</mat-icon>
-      <span>{{ selectedSheet }} • {{ editMode ? 'Modo edición' : 'Solo lectura' }}</span>
+  <mat-dialog-actions
+    align="end"
+    class="dialog-actions"
+    style="
+      padding: 16px;
+      border-top: 1px solid #e0e0e0;
+      background: white;
+      gap: 12px;
+    "
+  >
+    <div
+      class="status-info"
+      style="
+        margin-right: auto;
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        font-size: 13px;
+        color: #6c757d;
+      "
+    >
+      <mat-icon style="font-size: 16px; color: #1976d2">info</mat-icon>
+      <span
+        >{{ selectedSheet }} •
+        {{ editMode ? "Modo edición" : "Solo lectura" }}</span
+      >
+      <span *ngIf="hasUnsavedChanges" style="color: #ff9800; margin-left: 8px"
+        >• Cambios pendientes</span
+      >
     </div>
-    
-    <div class="action-buttons" style="display: flex; gap: 12px;">
-      <button mat-button
-              (click)="closeDialog()">
-        <mat-icon>close</mat-icon>
+
+    <div class="action-buttons" style="display: flex; gap: 12px">
+      <button mat-button (click)="closeDialog()">
+        <mat-icon style="margin-top: 5px">close</mat-icon>
         Cancelar
       </button>
-     
-      <button mat-stroked-button
-              (click)="ValidateExcel()"
-              class="white_font blue_send_background">
-        <mat-icon>check</mat-icon>
-        Validar documento
+
+      <button
+        mat-button
+        class="raised-button-background"
+        color="primary"
+        (click)="ValidateExcel()"
+        [disabled]="isLoading"
+      >
+        <mat-icon *ngIf="!isLoading">check</mat-icon>
+        <mat-spinner
+          *ngIf="isLoading"
+          diameter="20"
+          style="margin-right: 8px"
+        ></mat-spinner>
+        {{ isLoading ? "Procesando..." : "Procesar equipamientos" }}
       </button>
     </div>
   </mat-dialog-actions>

+ 292 - 116
src/app/components/initial-data-upload/zipfile-upload/zipfile-upload.component.html

@@ -1,86 +1,152 @@
-<h1 mat-dialog-title class="prevent-select" style="text-align: center; margin-top: 15px;">
+<h1
+  mat-dialog-title
+  class="prevent-select"
+  style="text-align: center; margin-top: 15px"
+>
   Carga de documentos relacionados
 </h1>
 
-<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
-  </h2>
-
-  <input 
-     type="file"
-     name="file"
-     id="file"
-     #file
-     class="hidden"
-     accept=".xlsx,.xls,.zip"
-     (change)="checkFile($event)">
-  
-  @if (!isUploading) {
-    <div 
+<!-- Contenedor principal que se ocultará durante la validación -->
+<div *ngIf="!isValidating">
+  <div class="uploader">
+    <h2
+      mat-dialog-title
+      class="prevent-select"
+      style="font-size: 15px; display: flex; justify-content: center"
+    >
+      Agregue aquí sus documentos
+    </h2>
+
+    <input
+      type="file"
+      name="file"
+      id="file"
+      #file
+      class="hidden"
+      accept=".xlsx,.xls,.zip"
+      (change)="checkFile($event)"
+      [disabled]="isOperationInProgress || hasValidationResults"
+    />
+
+    <div
       class="drag-drop-area"
-      [class.drag-over]="isDragOver"
-      [class.has-file]="hasExcelFile || hasZipFile"
+      [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()">
-      
+      (click)="openFileUploader()"
+      *ngIf="!isUploading"
+    >
       <div class="drag-drop-content">
-        <mat-icon class="upload-icon">
-          {{ hasZipFile && hasExcelFile ? 'refresh' : 'folder_copy' }}
+        <mat-icon
+          class="upload-icon"
+          [style.opacity]="
+            isOperationInProgress || hasValidationResults ? '0.5' : '1'
+          "
+        >
+          {{ hasZipFile && hasExcelFile ? "refresh" : "folder_copy" }}
         </mat-icon>
-        
-        @if (!hasExcelFile || !hasZipFile) {
-          <p class="drag-drop-text">
-            <strong>Haga clic aquí o arrastre aquí los archivos requeridos</strong><br>
-            <span>Solo archivos .xlsx, .xls (máximo 10MB) y ZIP (máximo 50MB)</span>
-          </p>
-        }
-        
-        @if (hasExcelFile && hasZipFile) {
-          <p class="drag-drop-text">
-            <strong>Haga clic aquí o arrastre un nuevo archivo Excel</strong><br>
-            <span>Para reemplazar el archivo actual</span>
-          </p>
-        }
+
+        <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 &&
+            !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. </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>
-  }
-  
-  @if (isUploading) {
-    <div class="upload-progress drag-drop-area uploading">
+
+    <div *ngIf="isUploading" class="upload-progress drag-drop-area uploading">
       <mat-spinner diameter="30"></mat-spinner>
-      <p style="margin-top: 10px;">Subiendo archivo</p>
+      <p style="margin-top: 10px">
+        Subiendo archivo {{ currentFileType === "excel" ? "Excel" : "ZIP" }}...
+      </p>
     </div>
-  }
-</div>
+  </div>
 
-<div mat-dialog-content class="prevent-select">
-  @if (isLoading) {
-    <div class="is-loading animated fadeIn fast" style="text-align: center; padding: 20px;">
+  <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>
-      <h3 style="margin-top: 10px;">Procesando archivo Excel...</h3>
+      <h3 style="margin-top: 10px">Procesando archivos...</h3>
     </div>
-  }
 
-  @if (hasError) {
-    <div class="has-error animated fadeIn fast" style="text-align: center; padding: 20px;">
-      <mat-icon class="red_primary_font" style="font-size: 48px; margin-bottom: 10px;">error</mat-icon>
-      <h3 style="font-weight: bold; font-style: italic;">{{ errorMessage }}</h3>
+    <div
+      class="has-error animated fadeIn fast"
+      *ngIf="hasError"
+      style="text-align: center; padding: 20px"
+    >
+      <mat-icon
+        class="red_primary_font"
+        style="font-size: 48px; margin-bottom: 10px"
+        >error</mat-icon
+      >
+      <h3 style="font-weight: bold; font-style: italic">{{ errorMessage }}</h3>
     </div>
-  }
 
-  @if (hasZipFile || hasExcelFile && !isLoading) {
-    <div class="files-container">
-      <h3 style="margin: 20px 0; display: flex; align-items: center;">
-        <mat-icon style="margin-right: 8px; color: #2e7d32;">
-          {{ hasExcelFile ? 'table_chart' : 'folder_zip' }}
-        </mat-icon>
-        {{ hasExcelFile ? 'Archivo Excel cargado:' : 'Archivo ZIP cargado:' }}
+    <div *ngIf="hasAnyFile && !isLoading" class="files-container">
+      <h3 style="margin: 20px 0; display: flex; align-items: center">
+        <mat-icon style="margin-right: 8px; color: #2e7d32"
+          >description</mat-icon
+        >
+        Archivos cargados
       </h3>
-          
-      <table mat-table matSort class="animated fadeIn" [dataSource]="dataSource">
+
+      <table
+        mat-table
+        matSort
+        class="animated fadeIn"
+        [dataSource]="dataSource"
+      >
         <ng-container matColumnDef="nombre_del_archivo">
           <th mat-header-cell *matHeaderCellDef mat-sort-header>
             <mat-icon>description</mat-icon>
@@ -89,7 +155,11 @@
           <td mat-cell *matCellDef="let element">
             <div class="file-name-cell">
               <mat-icon color="primary">
-                {{ element.tipo_archivo === 'excel' ? 'table_chart' : 'folder_zip' }}
+                {{
+                  element.tipo_archivo === "excel"
+                    ? "table_chart"
+                    : "folder_zip"
+                }}
               </mat-icon>
               <span>{{ element.nombre_del_archivo }}</span>
             </div>
@@ -103,25 +173,23 @@
           </th>
           <td mat-cell *matCellDef="let element">
             {{ element.tamano_del_archivo }}
-            @if (element.tipo_archivo === 'zip' && zipInfo) {
-              <span style="color: #666; font-size: 12px;">
-                <br>({{ zipInfo }})
-              </span>
-            }
           </td>
         </ng-container>
 
         <ng-container matColumnDef="tipo_archivo">
           <th mat-header-cell *matHeaderCellDef mat-sort-header>
-            <mat-icon>storage</mat-icon>
+            <mat-icon>category</mat-icon>
             Tipo de archivo
           </th>
           <td mat-cell *matCellDef="let element">
-            <span class="file-type-badge" [ngClass]="{
-              'excel-badge': element.tipo_archivo === 'excel',
-              'zip-badge': element.tipo_archivo === 'zip'
-            }">
-              {{ element.tipo_archivo === 'excel' ? 'Excel' : 'ZIP' }}
+            <span
+              class="file-type-badge"
+              [ngClass]="{
+                'excel-badge': element.tipo_archivo === 'excel',
+                'zip-badge': element.tipo_archivo === 'zip'
+              }"
+            >
+              {{ element.tipo_archivo === "excel" ? "Excel" : "ZIP" }}
             </span>
           </td>
         </ng-container>
@@ -130,25 +198,43 @@
           <th mat-header-cell *matHeaderCellDef>Acciones</th>
           <td mat-cell *matCellDef="let element">
             <div class="action-buttons">
-              <button 
-                mat-icon-button 
+              <button
+                mat-icon-button
                 color="primary"
-                style="border-radius: 10px; margin-right: 5px;"
+                style="border-radius: 10px; margin-right: 5px"
                 class="pink_primary_background white_font"
-                [matTooltip]="element.tipo_archivo === 'excel' ? 'Previsualizar Excel' : 'Previsualizar ZIP'"
-                (click)="element.tipo_archivo === 'excel' ? previewExcelFile() : previewZipFile()"
-                [disabled]="isLoading || isUploading">
+                [matTooltip]="
+                  element.tipo_archivo === 'excel'
+                    ? 'Previsualizar Excel'
+                    : 'Previsualizar ZIP'
+                "
+                (click)="
+                  element.tipo_archivo === 'excel'
+                    ? previewExcelFile()
+                    : previewZipFile()
+                "
+                [disabled]="isLoading || isUploading"
+              >
                 <mat-icon>visibility</mat-icon>
               </button>
-              
-              <button 
-                mat-icon-button 
+
+              <button
+                mat-icon-button
                 color="warn"
-                style="border-radius: 10px;"
+                style="border-radius: 10px"
                 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">
+                [matTooltip]="
+                  element.tipo_archivo === 'excel'
+                    ? 'Eliminar archivo Excel'
+                    : 'Eliminar archivo ZIP'
+                "
+                (click)="
+                  element.tipo_archivo === 'excel'
+                    ? removeExcelFile()
+                    : removeZipFile()
+                "
+                [disabled]="isLoading || isUploading || hasValidationResults"
+              >
                 <mat-icon>delete</mat-icon>
               </button>
             </div>
@@ -159,43 +245,133 @@
         <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
       </table>
     </div>
-  }
-
-  <!--Para la previsualización de los documentos procesados-->
 
-  @if (!hasExcelFile && !isLoading && !isUploading && !hasZipFile) {
-    <div class="no-files-message" style="height: 120px; text-align: center; padding: 20px;">
-      <mat-icon style=" color: #9e9e9e; margin-bottom: 10px;">upload_file</mat-icon>
-      <p style="color: #666; font-size: 14px; margin-bottom: 5px;">
+    <div
+      *ngIf="!hasAnyFile && !isLoading && !isUploading"
+      class="no-files-message"
+      style="height: 120px; text-align: center; padding: 20px"
+    >
+      <mat-icon style="color: #9e9e9e; margin-bottom: 10px"
+        >upload_file</mat-icon
+      >
+      <p style="color: #666; font-size: 14px; margin-bottom: 5px">
         <strong>No hay archivos cargados</strong>
       </p>
-      <p style="color: #999; font-size: 12px;">
-        Use el área de arriba para cargar su archivo Excel (.xlsx o .xls) o ZIP
+      <p style="color: #999; font-size: 12px">
+        Use el área de arriba para cargar su archivo Excel (.xlsx o .xls) y ZIP
+      </p>
+    </div>
+
+    <div
+      *ngIf="hasValidationResults"
+      class="validation-results"
+      style="margin-top: 20px; padding: 15px; border-radius: 8px"
+      [ngClass]="validationClass"
+    >
+      <div
+        style="display: flex; align-items: center; margin-bottom: 10px"
+      ></div>
+
+      <p style="margin: 5px 0; color: #666">
+        {{ validationSummary }}
       </p>
+
+      <div *ngIf="!validationResult?.valid" style="margin-top: 10px">
+        <button
+          mat-button
+          color="primary"
+          (click)="showValidationDetails()"
+          style="font-size: 12px"
+        >
+          <mat-icon style="font-size: 16px; height: 16px; width: 16px"
+            >info</mat-icon
+          >
+          Ver detalles completos
+        </button>
+      </div>
+
+      <div
+        *ngIf="validationResult?.valid"
+        style="
+          margin-top: 10px;
+          padding: 10px;
+          background: rgba(76, 175, 80, 0.1);
+          border-radius: 4px;
+        "
+      >
+        <p style="margin: 0; color: #2e7d32; font-weight: 500">
+          <mat-icon
+            style="vertical-align: middle; margin-right: 5px; color: #4caf50"
+            >info</mat-icon
+          >
+          Recibirás una notificación para terminar el procesamiento de tus
+          archivos.
+        </p>
+      </div>
+    </div>
+  </div>
+</div>
+
+<!-- Gif de validación (solo se muestra durante la validación) -->
+<div class="validation-overlay" *ngIf="isValidating" [@fadeInOut]>
+  <img
+    src="/assets/img/validating.gif"
+    alt="Validando..."
+    (load)="onGifLoad()"
+    (error)="onGifError()"
+  />
+
+  <div class="validation-content">
+    <div mat-dialog-title class="validation-text">
+      {{ validationStep || "Validando archivos..." }}
     </div>
-  }
+
+    <mat-spinner diameter="40" color="primary" *ngIf="!gifLoaded">
+    </mat-spinner>
+  </div>
 </div>
 
-<mat-dialog-actions align="end" style="padding: 16px;">
-  <button 
-     mat-button
+<!-- Dialog actions -->
+<mat-dialog-actions
+  align="end"
+  style="padding: 16px; border-top: 1px solid #eee"
+>
+  <button
+    mat-button
     (click)="cancelar()"
-    style="margin-right: 8px;"
-    [disabled]="isLoading || isUploading">
+    style="margin-right: 8px"
+    [disabled]="
+      isLoading || isUploading || isValidating || hasValidationResults
+    "
+  >
     <mat-icon>close</mat-icon>
     Cancelar
   </button>
-  
-  @if (hasAnyFile) {
-    <button 
-      mat-raised-button
-      color="primary"
-      class="blue_send_background white_font"
-      (click)="saveFinalFile()"
-      [disabled]="isLoading || isUploading">
-      <mat-icon>{{ hasExcelFile ? 'table_chart' : 'folder_zip' }}</mat-icon>
-      {{ hasExcelFile ? 'Procesar Excel' : 'Procesar ZIP' }}
-    </button>
-  }
-</mat-dialog-actions>
 
+  <!-- Botón de validar (solo si no hay resultados de validación) -->
+  <button
+    mat-raised-button
+    color="primary"
+    class="blue_send_background white_font"
+    (click)="validateAndProcessDocuments()"
+    style="margin-right: 8px"
+    *ngIf="!hasValidationResults"
+    [disabled]="!canValidate || isLoading || isUploading"
+  >
+    <mat-icon>{{ isValidating ? "hourglass_empty" : "verified" }}</mat-icon>
+    {{ isValidating ? "Validando..." : "Validar archivos" }}
+  </button>
+
+  <!-- Botón de Aceptar (solo si ya se validaron los documentos) -->
+  <button
+    mat-raised-button
+    color="primary"
+    class="blue_send_background white_font"
+    (click)="dialogRef.close({ success: true })"
+    *ngIf="hasValidationResults"
+    [disabled]="isLoading || isUploading || isValidating"
+  >
+    <mat-icon>check_circle</mat-icon>
+    Aceptar
+  </button>
+</mat-dialog-actions>

File diff suppressed because it is too large
+ 566 - 251
src/app/components/initial-data-upload/zipfile-upload/zipfile-upload.component.ts


Some files were not shown because too many files changed in this diff