|
|
@@ -1,33 +1,34 @@
|
|
|
-import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
|
|
+import { MatDialogRef } from '@angular/material/dialog';
|
|
|
import { EquipmentLruUploadComponent } from '../equipment-lru-upload/equipment-lru-upload.component';
|
|
|
import { Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core';
|
|
|
import { MatDialog } from '@angular/material/dialog';
|
|
|
import { MatTableDataSource } from '@angular/material/table';
|
|
|
import { FunctionsService } from '../../../services/functions.service';
|
|
|
import { TempFileInfo } from '../../../interfaces/temp-file-info.interface';
|
|
|
-import { availableFiles } from '../../../../environments/environment.prod';
|
|
|
import { ResourcesService } from '../../../services/resources.service';
|
|
|
import { lastValueFrom } from 'rxjs';
|
|
|
import { GdelService } from '../../../services/gdel.service';
|
|
|
import { PreviewExcelDocumentComponent } from '../preview-Equipmentexcel-document/preview-excel-document.component';
|
|
|
import * as XLSX from 'xlsx';
|
|
|
-import JSZip from 'jszip';
|
|
|
+import { FormControl, Validators } from '@angular/forms';
|
|
|
+
|
|
|
+const ID_MODULE = "S002V01M15IDUP";
|
|
|
|
|
|
export interface Document {
|
|
|
nombre_del_archivo: string,
|
|
|
tamano_del_archivo: string,
|
|
|
archivo_id?: string,
|
|
|
tipo_archivo?: string,
|
|
|
- fecha_carga?: string,
|
|
|
- codigo_equipo?: string, // Nuevo campo para el código del equipo
|
|
|
- es_plantilla?: boolean // Para identificar si es la plantilla Excel
|
|
|
+ fecha_carga?: string
|
|
|
+}
|
|
|
+
|
|
|
+// Interfaz para la estructura de headers esperados
|
|
|
+interface SheetHeaderStructure {
|
|
|
+ [column: string]: string;
|
|
|
}
|
|
|
|
|
|
-// Interface para manejar los códigos extraídos del Excel
|
|
|
-export interface CodigoEquipo {
|
|
|
- codigo: string;
|
|
|
- fila: number;
|
|
|
- columnas: any[];
|
|
|
+interface TemplateStructure {
|
|
|
+ [sheetName: string]: SheetHeaderStructure;
|
|
|
}
|
|
|
|
|
|
@Component({
|
|
|
@@ -42,21 +43,47 @@ export class ZipfileUploadComponent {
|
|
|
public hasError: boolean = false;
|
|
|
public errorMessage: string = '';
|
|
|
public isUploading: boolean;
|
|
|
+
|
|
|
uploadedFile: TempFileInfo | null;
|
|
|
@ViewChild('file') private uploader?: ElementRef;
|
|
|
+
|
|
|
+ moduleControl = new FormControl('', Validators.required);
|
|
|
+
|
|
|
public dataSource: MatTableDataSource<Document>;
|
|
|
- public displayedColumns: string[] = ['nombre_del_archivo', 'tamano_del_archivo', 'tipo_archivo', 'codigo_equipo', 'acciones'];
|
|
|
+ public displayedColumns: string[] = ['nombre_del_archivo', 'tamano_del_archivo', 'acciones'];
|
|
|
|
|
|
- public files: Document[] = [];
|
|
|
- public excelDataMap: Map<string, any> = new Map();
|
|
|
- public zipContentsMap: Map<string, any[]> = new Map();
|
|
|
- public codigosEquipos: CodigoEquipo[] = [];
|
|
|
- public uploadingCount: number = 0;
|
|
|
+ // Variables para manejar archivos Excel (solo uno permitido)
|
|
|
+ public excelFile: Document | null = null;
|
|
|
+ public excelData: any = null;
|
|
|
|
|
|
+ // Variables para drag and drop
|
|
|
public isDragOver: boolean = false;
|
|
|
|
|
|
-
|
|
|
- private readonly COLUMNAS_CODIGOS = ['CÓDIGO DE EQUIPAMIENTO', 'CODIGO DE EQUIPAMIENTO', 'CÓDIGO LRU'];
|
|
|
+ // Configuración específica para archivos Excel
|
|
|
+ private readonly EXCEL_EXTENSIONS = ['xlsx', 'xls'];
|
|
|
+ private readonly MAX_FILE_SIZE_MB = 10;
|
|
|
+ private readonly HEADER_ROW = 7;
|
|
|
+
|
|
|
+ // Estructura de la plantilla esperada
|
|
|
+ private readonly TEMPLATE_STRUCTURE: TemplateStructure = {
|
|
|
+ 'CARGA DE DOCUMENTOS': {
|
|
|
+ 'B': 'CÓDIGO EQUIVALENTE',
|
|
|
+ 'D': 'CÓDIGO DE EQUIPO',
|
|
|
+ 'F': 'CÓDIGO DEL LRU',
|
|
|
+ 'H': 'FICHA DE SEGURIDAD DE PRODUCTOS QUÍMICOS',
|
|
|
+ 'J': 'FICHA TÉCNICA',
|
|
|
+ 'L': 'FOTOGRAFÍAS - DIAGRAMAS',
|
|
|
+ 'N': 'DATOS DEL PROVEEDOR',
|
|
|
+ 'P': 'MANUALES DE OPERACIÓN',
|
|
|
+ 'R': 'MANUALES DE MANTENIMIENTO PREVENTIVO',
|
|
|
+ 'T': 'MANUALES DE MANTENIMIENTO CORRECTIVO',
|
|
|
+ 'V': 'DOCUMENTOS ADICIONALES'
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ // Hojas requeridas en la plantilla
|
|
|
+ private readonly REQUIRED_SHEETS = ['CARGA DE DOCUMENTOS'];
|
|
|
|
|
|
constructor (
|
|
|
private dialogRef: MatDialogRef<EquipmentLruUploadComponent>,
|
|
|
@@ -69,11 +96,10 @@ export class ZipfileUploadComponent {
|
|
|
this.isUploading = false;
|
|
|
this.uploadedFile = null;
|
|
|
this.dataSource = new MatTableDataSource();
|
|
|
- this.uploadingCount = 0;
|
|
|
}
|
|
|
|
|
|
ngOnInit(): void {
|
|
|
- this.loadFiles();
|
|
|
+ this.loadExcelFile();
|
|
|
}
|
|
|
|
|
|
cancelar(): void {
|
|
|
@@ -84,6 +110,7 @@ export class ZipfileUploadComponent {
|
|
|
this.uploader?.nativeElement.click();
|
|
|
}
|
|
|
|
|
|
+ // Métodos para drag and drop
|
|
|
onDragOver(event: DragEvent): void {
|
|
|
event.preventDefault();
|
|
|
event.stopPropagation();
|
|
|
@@ -103,84 +130,170 @@ export class ZipfileUploadComponent {
|
|
|
|
|
|
const files = event.dataTransfer?.files;
|
|
|
if (files && files.length > 0) {
|
|
|
- this.processMultipleFiles(Array.from(files));
|
|
|
+ this.processFile(files[0]);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
checkFile(event: any): void {
|
|
|
- const files = event.target.files;
|
|
|
- if (!files || files.length === 0) return;
|
|
|
-
|
|
|
- this.processMultipleFiles(Array.from(files));
|
|
|
- event.target.value = '';
|
|
|
+ const file = event.target.files[0];
|
|
|
+ if (!file) return;
|
|
|
+ this.processFile(file);
|
|
|
}
|
|
|
|
|
|
- private processMultipleFiles(files: File[]): void {
|
|
|
- const validFiles: File[] = [];
|
|
|
- const invalidFiles: string[] = [];
|
|
|
+ private processFile(file: File): void {
|
|
|
+ // Validación específica para archivos Excel
|
|
|
+ if (!this.isValidExcelFile(file)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- //este formato está mal, porque como tal el zip no se sube
|
|
|
- files.forEach(file => {
|
|
|
- const fileName = file.name.toLowerCase();
|
|
|
- const isValidFile = fileName.endsWith('.xlsx') ||
|
|
|
- fileName.endsWith('.xls') ||
|
|
|
- fileName.endsWith('.zip');
|
|
|
-
|
|
|
- if (!isValidFile) {
|
|
|
- invalidFiles.push(`${file.name} (formato no válido - solo Excel y ZIP)`);
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (!this.isValidFileSize(file)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- const maxFileSize = 50 * 1024 * 1024;
|
|
|
- if (file.size > maxFileSize) {
|
|
|
- invalidFiles.push(`${file.name} (supera 50MB)`);
|
|
|
- return;
|
|
|
- }
|
|
|
+ this.isUploading = true;
|
|
|
+ this.uploadExcelFile(file);
|
|
|
+ }
|
|
|
|
|
|
- const existingFile = this.files.find(f => f.nombre_del_archivo === file.name);
|
|
|
- if (existingFile) {
|
|
|
- invalidFiles.push(`${file.name} (ya existe)`);
|
|
|
- return;
|
|
|
- }
|
|
|
+ private isValidExcelFile(file: File): boolean {
|
|
|
+ const fileName = file.name.toLowerCase();
|
|
|
+ const fileExtension = fileName.split('.').pop();
|
|
|
+
|
|
|
+ if (!fileExtension || !this.EXCEL_EXTENSIONS.includes(fileExtension)) {
|
|
|
+ this._resourcesService.openSnackBar('Solo se permiten archivos Excel (.xlsx, .xls)');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- validFiles.push(file);
|
|
|
- });
|
|
|
+ private isValidFileSize(file: File): boolean {
|
|
|
+ const maxFileSize = this.MAX_FILE_SIZE_MB * 1024 * 1024; // Convertir MB a bytes
|
|
|
+
|
|
|
+ if (file.size > maxFileSize) {
|
|
|
+ this._resourcesService.openSnackBar(`El tamaño del archivo supera el límite de ${this.MAX_FILE_SIZE_MB} MB`);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+// Método para validar la estructura de la plantilla Y que tenga datos
|
|
|
+private validateExcelTemplate(workbook: XLSX.WorkBook): { isValid: boolean, errors: string[] } {
|
|
|
+ const errors: string[] = [];
|
|
|
+
|
|
|
+ // Verificar que existan todas las hojas requeridas
|
|
|
+ const existingSheets = workbook.SheetNames;
|
|
|
+ const missingSheets = this.REQUIRED_SHEETS.filter(sheet => !existingSheets.includes(sheet));
|
|
|
+
|
|
|
+ if (missingSheets.length > 0) {
|
|
|
+ errors.push(`Tu documento no cumple con las hojas requeridas de la plantilla`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validar headers de cada hoja Y verificar que tengan datos
|
|
|
+ for (const sheetName of this.REQUIRED_SHEETS) {
|
|
|
+ if (existingSheets.includes(sheetName)) {
|
|
|
+ const sheetErrors = this.validateSheetHeaders(workbook.Sheets[sheetName], sheetName);
|
|
|
+ errors.push(...sheetErrors);
|
|
|
+
|
|
|
+ if (sheetName === 'CARGA DE DOCUMENTOS') {
|
|
|
+ const dataErrors = this.validateSheetHasData(workbook.Sheets[sheetName], sheetName);
|
|
|
+ errors.push(...dataErrors);
|
|
|
+ }
|
|
|
|
|
|
- if (invalidFiles.length > 0) {
|
|
|
- this._resourcesService.openSnackBar(
|
|
|
- `Archivos no válidos: ${invalidFiles.join(', ')}`
|
|
|
- );
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ isValid: errors.length === 0,
|
|
|
+ errors: errors
|
|
|
+ };
|
|
|
+}
|
|
|
|
|
|
- if (validFiles.length > 0) {
|
|
|
- this.uploadingCount = validFiles.length;
|
|
|
- this.isUploading = true;
|
|
|
+// Nuevo método para validar que una hoja tenga datos
|
|
|
+private validateSheetHasData(worksheet: XLSX.WorkSheet, sheetName: string): string[] {
|
|
|
+ const errors: string[] = [];
|
|
|
+
|
|
|
+ try {
|
|
|
+ // Obtener el rango de la hoja
|
|
|
+ const range = XLSX.utils.decode_range(worksheet['!ref'] || 'A1');
|
|
|
+
|
|
|
+ // Para MANTENIMIENTO CORRECTIVO, los datos empiezan después de la fila de headers (fila 7 en adelante)
|
|
|
+ const dataStartRow = this.HEADER_ROW + 2; // Fila 7
|
|
|
+
|
|
|
+ // Verificar si hay al menos una fila con datos después de los headers
|
|
|
+ let hasData = false;
|
|
|
+
|
|
|
+ // Revisar desde la fila de datos hasta el final del rango
|
|
|
+ if (range.e.r >= dataStartRow) {
|
|
|
+ // Revisar las columnas principales para ver si hay datos
|
|
|
+ const mainColumns = ['B', 'D', 'F', 'H']; // Las primeras columnas importantes
|
|
|
|
|
|
- validFiles.forEach(file => {
|
|
|
- const fileName = file.name.toLowerCase();
|
|
|
- if (fileName.endsWith('.xlsx') || fileName.endsWith('.xls')) {
|
|
|
- this.uploadExcelFile(file);
|
|
|
- } else if (fileName.endsWith('.zip')) {
|
|
|
- this.uploadZipFile(file);
|
|
|
+ for (let row = dataStartRow; row <= range.e.r; row++) {
|
|
|
+ for (const col of mainColumns) {
|
|
|
+ const cellAddress = `${col}${row}`;
|
|
|
+ const cell = worksheet[cellAddress];
|
|
|
+
|
|
|
+ // Si encontramos una celda con contenido (no vacía, no null, no undefined)
|
|
|
+ if (cell && cell.v !== null && cell.v !== undefined && String(cell.v).trim() !== '') {
|
|
|
+ hasData = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
- });
|
|
|
+ if (hasData) break;
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ if (!hasData) {
|
|
|
+ errors.push(`La hoja "${sheetName}" no contiene datos. Se requiere al menos un registro con información.`);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ errors.push(`Error al validar datos en la hoja "${sheetName}": No se pudo verificar el contenido.`);
|
|
|
}
|
|
|
+
|
|
|
+ return errors;
|
|
|
+}
|
|
|
|
|
|
- formatBytes(bytes: number, decimals = 2): string {
|
|
|
- if (bytes === 0) return '0 Bytes';
|
|
|
|
|
|
- const k = 1024;
|
|
|
- const dm = decimals < 0 ? 0 : decimals;
|
|
|
- const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
|
+ // Método para validar los headers de una hoja específica
|
|
|
+ private validateSheetHeaders(worksheet: XLSX.WorkSheet, sheetName: string): string[] {
|
|
|
+ const errors: string[] = [];
|
|
|
+
|
|
|
+ const expectedHeaders = this.TEMPLATE_STRUCTURE[sheetName];
|
|
|
+
|
|
|
+ if (!expectedHeaders) {
|
|
|
+ errors.push(`No se encontró la estructura esperada para la hoja: ${sheetName}`);
|
|
|
+ return errors;
|
|
|
+ }
|
|
|
|
|
|
- const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
|
+ // Obtener los headers de la fila especificada (fila 6)
|
|
|
+ const range = XLSX.utils.decode_range(worksheet['!ref'] || 'A1');
|
|
|
+
|
|
|
+ for (const [column, expectedHeader] of Object.entries(expectedHeaders)) {
|
|
|
+ const cellAddress = `${column}${this.HEADER_ROW}`;
|
|
|
+ const cell = worksheet[cellAddress];
|
|
|
+ const actualHeader = cell ? String(cell.v).trim() : '';
|
|
|
+
|
|
|
+ if (actualHeader !== expectedHeader) {
|
|
|
+ errors.push(`Hoja "${sheetName}", Columna ${column}: Se esperaba "${expectedHeader}" pero se encontró "${actualHeader}"`);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
|
|
+ return errors;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
async uploadExcelFile(fileData: File): Promise<void> {
|
|
|
try {
|
|
|
+ // Primero validar la estructura antes de subir
|
|
|
+ const validationResult = await this.validateFileStructure(fileData);
|
|
|
+
|
|
|
+ if (!validationResult.isValid) {
|
|
|
+ this._resourcesService.openSnackBar(`Debe contener al menos un registro y cumplir con la estructura requerida`);
|
|
|
+ this.isUploading = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
const idUser = localStorage.getItem('idusuario');
|
|
|
const formData = new FormData();
|
|
|
|
|
|
@@ -192,130 +305,50 @@ export class ZipfileUploadComponent {
|
|
|
const response = await lastValueFrom(this._gdelService.uploadTempFile(formData));
|
|
|
|
|
|
if (response.error) {
|
|
|
- this._resourcesService.openSnackBar(`Error al subir ${fileData.name}: ${response.msg}`);
|
|
|
+ this._resourcesService.openSnackBar(response.msg);
|
|
|
} else {
|
|
|
- await this.readExcelFile(fileData, response.response.idArchivo);
|
|
|
-
|
|
|
- const newDocument: Document = {
|
|
|
- nombre_del_archivo: fileData.name,
|
|
|
- tamano_del_archivo: this.formatBytes(fileData.size),
|
|
|
- archivo_id: response.response.idArchivo,
|
|
|
- tipo_archivo: 'excel',
|
|
|
- fecha_carga: new Date().toLocaleString(),
|
|
|
- es_plantilla: true
|
|
|
+ // Actualizar uploadedFile para compatibilidad
|
|
|
+ this.uploadedFile = {
|
|
|
+ id: response.response.idArchivo,
|
|
|
+ name: fileData.name,
|
|
|
+ size: this.formatBytes(fileData.size)
|
|
|
};
|
|
|
|
|
|
- this.files.push(newDocument);
|
|
|
- this.updateTableData();
|
|
|
-
|
|
|
- // Extraer códigos del Excel
|
|
|
- this.extractCodigosFromExcel(response.response.idArchivo);
|
|
|
+ // Leer el archivo Excel para obtener información adicional
|
|
|
+ await this.readExcelFile(fileData, response.response.idArchivo);
|
|
|
|
|
|
- this._resourcesService.openSnackBar(`${fileData.name} cargado exitosamente. Códigos de equipos extraídos.`);
|
|
|
- }
|
|
|
-
|
|
|
- this.uploadingCount--;
|
|
|
- if (this.uploadingCount === 0) {
|
|
|
- this.isUploading = false;
|
|
|
- }
|
|
|
- } catch (error: any) {
|
|
|
- this.handleUploadError(error, fileData.name);
|
|
|
- this.uploadingCount--;
|
|
|
- if (this.uploadingCount === 0) {
|
|
|
- this.isUploading = false;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- async uploadZipFile(fileData: File): Promise<void> {
|
|
|
- try {
|
|
|
- const idUser = localStorage.getItem('idusuario');
|
|
|
-
|
|
|
- // Primero procesamos el contenido del ZIP
|
|
|
- await this.processZipFile(fileData);
|
|
|
-
|
|
|
- const formData = new FormData();
|
|
|
- formData.append('file', fileData);
|
|
|
- formData.append('id_user', idUser!);
|
|
|
- formData.append('linea', "1");
|
|
|
- formData.append('tipo_archivo', 'zip');
|
|
|
-
|
|
|
- const response = await lastValueFrom(this._gdelService.uploadTempFile(formData));
|
|
|
-
|
|
|
- if (response.error) {
|
|
|
- this._resourcesService.openSnackBar(`Error al subir ${fileData.name}: ${response.msg}`);
|
|
|
- } else {
|
|
|
const newDocument: Document = {
|
|
|
nombre_del_archivo: fileData.name,
|
|
|
tamano_del_archivo: this.formatBytes(fileData.size),
|
|
|
archivo_id: response.response.idArchivo,
|
|
|
- tipo_archivo: 'zip',
|
|
|
- fecha_carga: new Date().toLocaleString(),
|
|
|
- es_plantilla: false
|
|
|
+ tipo_archivo: 'excel',
|
|
|
+ fecha_carga: new Date().toLocaleString()
|
|
|
};
|
|
|
|
|
|
- this.files.push(newDocument);
|
|
|
+ // Solo mantener un archivo
|
|
|
+ this.excelFile = newDocument;
|
|
|
this.updateTableData();
|
|
|
-
|
|
|
- this._resourcesService.openSnackBar(`${fileData.name} cargado exitosamente`);
|
|
|
+ this._resourcesService.openSnackBar('Plantilla Excel válida y cargada exitosamente');
|
|
|
}
|
|
|
|
|
|
- this.uploadingCount--;
|
|
|
- if (this.uploadingCount === 0) {
|
|
|
- this.isUploading = false;
|
|
|
- }
|
|
|
+ this.isUploading = false;
|
|
|
} catch (error: any) {
|
|
|
- this.handleUploadError(error, fileData.name);
|
|
|
- this.uploadingCount--;
|
|
|
- if (this.uploadingCount === 0) {
|
|
|
- this.isUploading = false;
|
|
|
- }
|
|
|
+ this.handleUploadError(error);
|
|
|
+ this.isUploading = false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private async processZipFile(file: File): Promise<void> {
|
|
|
+ // Método para validar la estructura del archivo antes de subirlo
|
|
|
+ private async validateFileStructure(file: File): Promise<{ isValid: boolean, errors: string[] }> {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
const reader = new FileReader();
|
|
|
- reader.onload = async (e: any) => {
|
|
|
+ reader.onload = (e: any) => {
|
|
|
try {
|
|
|
- const arrayBuffer = e.target.result;
|
|
|
- const zipContents = await JSZip.loadAsync(arrayBuffer);
|
|
|
-
|
|
|
- const fileList: any[] = [];
|
|
|
-
|
|
|
-
|
|
|
- const filePromises: Promise<void>[] = [];
|
|
|
-
|
|
|
- zipContents.forEach((relativePath, zipEntry) => {
|
|
|
- if (!zipEntry.dir) {
|
|
|
- const filePromise = zipEntry.async('uint8array').then((content) => {
|
|
|
- fileList.push({
|
|
|
- name: relativePath,
|
|
|
- originalName: relativePath,
|
|
|
- size: content.length,
|
|
|
- codigoAsignado: null
|
|
|
- });
|
|
|
- }).catch(() => {
|
|
|
-
|
|
|
- fileList.push({
|
|
|
- name: relativePath,
|
|
|
- originalName: relativePath,
|
|
|
- size: 0,
|
|
|
- codigoAsignado: null
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
- filePromises.push(filePromise);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
- await Promise.all(filePromises);
|
|
|
-
|
|
|
-
|
|
|
- this.zipContentsMap.set(file.name, fileList);
|
|
|
+ const data = new Uint8Array(e.target.result);
|
|
|
+ const workbook = XLSX.read(data, { type: 'array' });
|
|
|
|
|
|
- resolve();
|
|
|
+ const validation = this.validateExcelTemplate(workbook);
|
|
|
+ resolve(validation);
|
|
|
} catch (error) {
|
|
|
reject(error);
|
|
|
}
|
|
|
@@ -325,92 +358,6 @@ export class ZipfileUploadComponent {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
-private extractCodigosFromExcel(fileId: string): void {
|
|
|
- const excelData = this.excelDataMap.get(fileId);
|
|
|
- if (!excelData) return;
|
|
|
-
|
|
|
- this.codigosEquipos = [];
|
|
|
-
|
|
|
-
|
|
|
- const HEADER_ROW_INDEX = 0;
|
|
|
- const DATA_START_ROW = 8;
|
|
|
-
|
|
|
-
|
|
|
- Object.keys(excelData.sheets).forEach(sheetName => {
|
|
|
- const sheetData = excelData.sheets[sheetName];
|
|
|
- if (!sheetData || sheetData.length === 0) return;
|
|
|
-
|
|
|
-
|
|
|
- if (sheetData.length <= DATA_START_ROW) {
|
|
|
- console.warn(`La hoja ${sheetName} no tiene suficientes filas. Se requieren al menos ${DATA_START_ROW + 1} filas.`);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- const headerRow = sheetData[HEADER_ROW_INDEX];
|
|
|
-
|
|
|
-
|
|
|
- const columnasConCodigos: number[] = [];
|
|
|
- headerRow.forEach((header: string, index: number) => {
|
|
|
- if (header && typeof header === 'string') {
|
|
|
- const headerUpper = header.toUpperCase().trim();
|
|
|
- if (this.COLUMNAS_CODIGOS.some(col => headerUpper.includes(col))) {
|
|
|
- columnasConCodigos.push(index);
|
|
|
- console.log(`Encontrada columna de códigos: "${header}" en índice ${index}`);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- if (columnasConCodigos.length === 0) {
|
|
|
- console.warn(`No se encontraron columnas de códigos en la hoja ${sheetName}`);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- for (let i = DATA_START_ROW; i < sheetData.length; i++) {
|
|
|
- const row = sheetData[i];
|
|
|
- if (!row || row.length === 0) continue;
|
|
|
-
|
|
|
- columnasConCodigos.forEach(colIndex => {
|
|
|
- const codigo = row[colIndex];
|
|
|
- if (codigo && typeof codigo === 'string' && codigo.trim() !== '') {
|
|
|
- this.codigosEquipos.push({
|
|
|
- codigo: codigo.trim(),
|
|
|
- fila: i + 1,
|
|
|
- columnas: row
|
|
|
- });
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- console.log(`Códigos extraídos desde la fila 9:`, this.codigosEquipos);
|
|
|
-
|
|
|
-
|
|
|
- this.assignCodigosToZipFiles();
|
|
|
-}
|
|
|
-
|
|
|
- private assignCodigosToZipFiles(): void {
|
|
|
-
|
|
|
-
|
|
|
- this.zipContentsMap.forEach((fileList, zipName) => {
|
|
|
- fileList.forEach((file, index) => {
|
|
|
- if (this.codigosEquipos.length > index) {
|
|
|
- file.codigoAsignado = this.codigosEquipos[index].codigo;
|
|
|
- file.newName = `${this.codigosEquipos[index].codigo}_${file.originalName}`;
|
|
|
- }
|
|
|
- });
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- public assignCodigoManually(zipFileName: string, fileIndex: number, codigo: string): void {
|
|
|
- const fileList = this.zipContentsMap.get(zipFileName);
|
|
|
- if (fileList && fileList[fileIndex]) {
|
|
|
- fileList[fileIndex].codigoAsignado = codigo;
|
|
|
- fileList[fileIndex].newName = `${codigo}_${fileList[fileIndex].originalName}`;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
private async readExcelFile(file: File, fileId: any): Promise<void> {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
const reader = new FileReader();
|
|
|
@@ -419,6 +366,7 @@ private extractCodigosFromExcel(fileId: string): void {
|
|
|
const data = new Uint8Array(e.target.result);
|
|
|
const workbook = XLSX.read(data, { type: 'array' });
|
|
|
|
|
|
+ // Obtener información de las hojas
|
|
|
const sheetNames = workbook.SheetNames;
|
|
|
const sheetsData: any = {};
|
|
|
|
|
|
@@ -427,12 +375,13 @@ private extractCodigosFromExcel(fileId: string): void {
|
|
|
sheetsData[sheetName] = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
|
|
|
});
|
|
|
|
|
|
- this.excelDataMap.set(fileId, {
|
|
|
+ // Guardar datos del archivo para previsualización
|
|
|
+ this.excelData = {
|
|
|
fileName: file.name,
|
|
|
sheets: sheetsData,
|
|
|
sheetNames: sheetNames,
|
|
|
fileId: fileId
|
|
|
- });
|
|
|
+ };
|
|
|
|
|
|
resolve();
|
|
|
} catch (error) {
|
|
|
@@ -444,46 +393,65 @@ private extractCodigosFromExcel(fileId: string): void {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- private updateTableData(): void {
|
|
|
- this.dataSource.data = [...this.files];
|
|
|
+ // Método para eliminar archivo temporal
|
|
|
+ async deleteTempFile(): Promise<void> {
|
|
|
+ if (!this.uploadedFile) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ let idUser = localStorage.getItem('idusuario');
|
|
|
+ let formData = new FormData();
|
|
|
+
|
|
|
+ formData.append('id_user', idUser!);
|
|
|
+ formData.append('id_file', this.uploadedFile.id);
|
|
|
+ formData.append('linea', '1');
|
|
|
+
|
|
|
+ await lastValueFrom(this._gdelService.deleteTempFile(formData));
|
|
|
+
|
|
|
+ this.uploadedFile = null;
|
|
|
+ this.excelFile = null;
|
|
|
+ this.excelData = null;
|
|
|
+ this.updateTableData();
|
|
|
+ this._resourcesService.openSnackBar('Archivo eliminado exitosamente');
|
|
|
+ } catch (error: any) {
|
|
|
+ this.handleUploadError(error);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- private loadFiles(): void {
|
|
|
- this.files = [];
|
|
|
- this.excelDataMap.clear();
|
|
|
- this.zipContentsMap.clear();
|
|
|
- this.codigosEquipos = [];
|
|
|
- this.updateTableData();
|
|
|
+ formatBytes(bytes: number, decimals = 2): string {
|
|
|
+ if (bytes === 0) return '0 Bytes';
|
|
|
+
|
|
|
+ const k = 1024;
|
|
|
+ const dm = decimals < 0 ? 0 : decimals;
|
|
|
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
|
+
|
|
|
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
|
+
|
|
|
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
|
|
}
|
|
|
|
|
|
- private handleUploadError(error: any, fileName: string): void {
|
|
|
- let errorMessage = 'Ocurrió un error inesperado.';
|
|
|
-
|
|
|
- if (error.error?.msg) {
|
|
|
- errorMessage = error.error.msg;
|
|
|
- } else if (error.error) {
|
|
|
- errorMessage = 'Ocurrió un error inesperado.';
|
|
|
- }
|
|
|
-
|
|
|
- this._resourcesService.openSnackBar(`Error al subir ${fileName}: ${errorMessage}`);
|
|
|
+ private updateTableData(): void {
|
|
|
+ this.dataSource.data = this.excelFile ? [this.excelFile] : [];
|
|
|
}
|
|
|
|
|
|
- previewFile(element: Document): void {
|
|
|
- if (!element.archivo_id) {
|
|
|
- this._resourcesService.openSnackBar('No se encontró el ID del archivo');
|
|
|
- return;
|
|
|
- }
|
|
|
+ private loadExcelFile(): void {
|
|
|
+ // Inicializar con archivo vacío
|
|
|
+ this.excelFile = null;
|
|
|
+ this.updateTableData();
|
|
|
+ }
|
|
|
|
|
|
- if (element.tipo_archivo === 'excel') {
|
|
|
- this.previewExcelFile(element);
|
|
|
- } else if (element.tipo_archivo === 'zip') {
|
|
|
- this.previewZipFile(element);
|
|
|
+ private handleUploadError(error: any): void {
|
|
|
+ if (error.error == undefined) {
|
|
|
+ this._resourcesService.openSnackBar('Ocurrió un error inesperado.');
|
|
|
+ } else if (error.error.msg == undefined) {
|
|
|
+ this._resourcesService.openSnackBar('Ocurrió un error inesperado.');
|
|
|
+ } else {
|
|
|
+ this._resourcesService.openSnackBar(error.error.msg);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private previewExcelFile(element: Document): void {
|
|
|
- const excelData = this.excelDataMap.get(element.archivo_id!);
|
|
|
- if (!excelData) {
|
|
|
+ // Método para abrir previsualización del Excel
|
|
|
+ previewExcelFile(): void {
|
|
|
+ if (!this.excelData) {
|
|
|
this._resourcesService.openSnackBar('No hay datos del archivo Excel para mostrar');
|
|
|
return;
|
|
|
}
|
|
|
@@ -492,86 +460,77 @@ private extractCodigosFromExcel(fileId: string): void {
|
|
|
width: '1800px',
|
|
|
height: '900px',
|
|
|
maxWidth: '1800px',
|
|
|
- data: excelData,
|
|
|
+ data: this.excelData,
|
|
|
disableClose: true
|
|
|
});
|
|
|
|
|
|
dialogRef.afterClosed().subscribe(result => {
|
|
|
+ // Manejar el resultado si es necesario
|
|
|
if (result) {
|
|
|
console.log('Preview cerrado:', result);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- private previewZipFile(element: Document): void {
|
|
|
- const zipContents = this.zipContentsMap.get(element.nombre_del_archivo);
|
|
|
- if (!zipContents) {
|
|
|
- this._resourcesService.openSnackBar('No hay contenido del ZIP para mostrar');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- console.log('Contenido del ZIP:', zipContents);
|
|
|
- this._resourcesService.openSnackBar(`ZIP contiene ${zipContents.length} archivos`);
|
|
|
+ // Método para eliminar archivo
|
|
|
+ removeExcelFile(): void {
|
|
|
+ this.deleteTempFile();
|
|
|
}
|
|
|
|
|
|
- removeFile(element: Document): void {
|
|
|
- const index = this.files.findIndex(f => f.archivo_id === element.archivo_id);
|
|
|
- if (index > -1) {
|
|
|
- this.files.splice(index, 1);
|
|
|
-
|
|
|
- if (element.archivo_id) {
|
|
|
- this.excelDataMap.delete(element.archivo_id);
|
|
|
- }
|
|
|
-
|
|
|
- if (element.tipo_archivo === 'zip') {
|
|
|
- this.zipContentsMap.delete(element.nombre_del_archivo);
|
|
|
- }
|
|
|
-
|
|
|
- if (element.tipo_archivo === 'excel') {
|
|
|
-
|
|
|
- this.codigosEquipos = [];
|
|
|
- }
|
|
|
-
|
|
|
- this.updateTableData();
|
|
|
- this._resourcesService.openSnackBar(`${element.nombre_del_archivo} eliminado`);
|
|
|
- }
|
|
|
+ // Getter para verificar si ya hay un archivo cargado
|
|
|
+ get hasExcelFile(): boolean {
|
|
|
+ return this.excelFile !== null;
|
|
|
}
|
|
|
|
|
|
- removeAllFiles(): void {
|
|
|
- this.files = [];
|
|
|
- this.excelDataMap.clear();
|
|
|
- this.zipContentsMap.clear();
|
|
|
- this.codigosEquipos = [];
|
|
|
- this.updateTableData();
|
|
|
- this._resourcesService.openSnackBar('Todos los archivos han sido eliminados');
|
|
|
+ // Getter para obtener el array de archivos para la tabla
|
|
|
+ get excelFiles(): Document[] {
|
|
|
+ return this.excelFile ? [this.excelFile] : [];
|
|
|
}
|
|
|
|
|
|
- get hasFiles(): boolean {
|
|
|
- return this.files.length > 0;
|
|
|
- }
|
|
|
+ // Método para guardar archivo final
|
|
|
+ async saveFinalFile(): Promise<void> {
|
|
|
+ if (!this.uploadedFile) {
|
|
|
+ this._resourcesService.openSnackBar('No hay archivo cargado para guardar');
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- get filesCount(): number {
|
|
|
- return this.files.length;
|
|
|
- }
|
|
|
+ try {
|
|
|
+ this.isLoading = true;
|
|
|
+ let idUser = localStorage.getItem('idusuario');
|
|
|
+ let formData = new FormData();
|
|
|
|
|
|
- get hasExcelTemplate(): boolean {
|
|
|
- return this.files.some(f => f.tipo_archivo === 'excel' && f.es_plantilla);
|
|
|
- }
|
|
|
+ // Parámetros obligatorios
|
|
|
+ formData.append('id_user', idUser!);
|
|
|
+ formData.append('id_file', this.uploadedFile.id);
|
|
|
+ formData.append('linea', '1');
|
|
|
+
|
|
|
+ // Parámetros específicos para equipamiento
|
|
|
+ formData.append('module', 'ADSI'); // Módulo fijo para equipamiento
|
|
|
+ formData.append('clasification', 'LA'); // Clasificación fija para LRU/Equipamiento
|
|
|
+ formData.append('has_order', 'N'); // Sin orden asociada
|
|
|
+
|
|
|
+ console.log('Datos enviados al servidor:', {
|
|
|
+ id_user: idUser,
|
|
|
+ id_file: this.uploadedFile.id,
|
|
|
+ module: 'ADSI',
|
|
|
+ clasification: 'LA'
|
|
|
+ });
|
|
|
|
|
|
- get hasZipFiles(): boolean {
|
|
|
- return this.files.some(f => f.tipo_archivo === 'zip');
|
|
|
- }
|
|
|
+ const response = await lastValueFrom(this._gdelService.saveFinalFile(formData));
|
|
|
+
|
|
|
+ console.log('Respuesta del servidor:', response);
|
|
|
|
|
|
- get codigosDisponibles(): string[] {
|
|
|
- return this.codigosEquipos.map(c => c.codigo);
|
|
|
- }
|
|
|
+ if (response.error) {
|
|
|
+ throw new Error(response.msg || 'Error al guardar el archivo');
|
|
|
+ }
|
|
|
|
|
|
- get uploadingText(): string {
|
|
|
- if (this.uploadingCount === 1) {
|
|
|
- return 'Subiendo 1 archivo...';
|
|
|
- } else if (this.uploadingCount > 1) {
|
|
|
- return `Subiendo ${this.uploadingCount} archivos...`;
|
|
|
+ this._resourcesService.openSnackBar('Archivo guardado correctamente');
|
|
|
+ this.dialogRef.close(true); // Cierra el diálogo y notifica al padre
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('Error al guardar archivo:', error);
|
|
|
+ this._resourcesService.openSnackBar(error.message || 'Error al guardar el archivo');
|
|
|
+ } finally {
|
|
|
+ this.isLoading = false;
|
|
|
}
|
|
|
- return 'Subiendo archivos...';
|
|
|
}
|
|
|
}
|