Compare commits

..

No commits in common. "1a9f74baec942c3465f0ac08d151092a35e1b126" and "f833bd464d75270357c88f29ac8b8fa721031bd1" have entirely different histories.

7 changed files with 212 additions and 942 deletions

721
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,6 @@
"@fortawesome/fontawesome-free": "^6.7.2", "@fortawesome/fontawesome-free": "^6.7.2",
"@primeng/themes": "^19.1.0", "@primeng/themes": "^19.1.0",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"primeflex": "^4.0.0", "primeflex": "^4.0.0",
"primeicons": "^7.0.0", "primeicons": "^7.0.0",

View File

@ -32,7 +32,7 @@
<!-- <div class="font-bold tituloTabla">T&iacute;tulo de la tabla:</div> --> <!-- <div class="font-bold tituloTabla">T&iacute;tulo de la tabla:</div> -->
<p-button <p-button
icon="pi pi-file-excel" icon="pi pi-file-excel"
(onClick)="exportExcelWithStyles(dt)" (onClick)="exportExcel(dt)"
styleClass="p-button-success" styleClass="p-button-success"
pTooltip="Descargar planilla Excel" pTooltip="Descargar planilla Excel"
tooltipPosition="top" tooltipPosition="top"
@ -133,7 +133,7 @@
pButton pButton
type="button" type="button"
icon="pi pi-file-excel" icon="pi pi-file-excel"
(click)="exportExcelWithStyles(dt)" (click)="exportExcel(dt)"
class="p-button-success" class="p-button-success"
label="Exportar a Excel" label="Exportar a Excel"
pTooltip="Descargar planilla Excel" pTooltip="Descargar planilla Excel"

View File

@ -6,7 +6,7 @@ import { SelectModule } from 'primeng/select';
import { ButtonModule } from 'primeng/button'; import { ButtonModule } from 'primeng/button';
import { TooltipModule } from 'primeng/tooltip'; import { TooltipModule } from 'primeng/tooltip';
import * as FileSaver from 'file-saver'; import * as FileSaver from 'file-saver';
import { Workbook } from 'exceljs'; import * as XLSX from 'xlsx';
@Component({ @Component({
selector: 'app-actualizacion-pd', selector: 'app-actualizacion-pd',
@ -17,6 +17,7 @@ import { Workbook } from 'exceljs';
SelectModule, SelectModule,
ButtonModule, ButtonModule,
TooltipModule TooltipModule
], ],
templateUrl: './actualizacion-pd.component.html', templateUrl: './actualizacion-pd.component.html',
styleUrl: './actualizacion-pd.component.scss', styleUrl: './actualizacion-pd.component.scss',
@ -26,7 +27,7 @@ export class ActualizacionPdComponent {
pageTitle: string = 'Cronogramas cargados:'; pageTitle: string = 'Cronogramas cargados:';
select1: any = ''; select1: any = '';
selectedCity: any = ''; selectedCity: any = '';
empresas: any[] = [{ name: 'Empresa A' }, { name: 'Empresa B' }, { name: 'Empresa C' }]; empresas: any[] = [{name: 'Empresa A'}, {name: 'Empresa B'}, {name: 'Empresa C'}];
estadoAprobacion = [ estadoAprobacion = [
{ name: 'Aprobado', value: 'Aprobado' }, { name: 'Aprobado', value: 'Aprobado' },
{ name: 'Rechazado', value: 'Rechazado' }, { name: 'Rechazado', value: 'Rechazado' },
@ -91,110 +92,84 @@ export class ActualizacionPdComponent {
dato14: '', dato14: '',
}, },
]; ];
/** /**
* Exporta la tabla a Excel usando ExcelJS * Exporta la tabla a Excel
* @param table Referencia a la tabla PrimeNG * @param table Referencia a la tabla PrimeNG
*/ */
exportExcel(table: Table) {
// Preparamos los datos para exportar
const exportData = this.prepareDataForExport(table);
exportExcelWithStyles(table: Table): void { // Creamos el libro de Excel
// Creamos un nuevo libro de trabajo const worksheet = XLSX.utils.json_to_sheet(exportData);
const workbook = new Workbook(); const workbook = { Sheets: { 'data': worksheet }, SheetNames: ['data'] };
const worksheet = workbook.addWorksheet('Datos');
// Exportamos los datos y aplicamos estilos // Aplicamos estilos a las celdas (encabezados en negrita con fondo azul)
this.addDataToWorksheet(worksheet, table); this.applyStyles(worksheet);
this.applyHeaderStyles(worksheet);
this.configureWorksheet(worksheet);
this.saveExcelFile(workbook);
// Opciones de exportación
const excelBuffer: any = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
// Guardamos el archivo
this.saveAsExcelFile(excelBuffer, 'cronogramas_exportados');
} }
/** /**
* Añade los datos de la tabla al worksheet * Prepara los datos para la exportación, filtrando según sea necesario
*/ */
private addDataToWorksheet(worksheet: any, table: Table): void { prepareDataForExport(table: Table): any[] {
// Obtenemos los datos a exportar // Si hay filtros aplicados, usamos los datos filtrados
const data = table.filteredValue || table.value; const data = table.filteredValue || table.value;
// Definimos las cabeceras // Mapeamos los datos para tener solo las propiedades que queremos exportar
const headers = [ return data.map(item => {
'Empresa', 'Código de cronograma', 'Etapa del Servicio', return {
'Nombre sistema', 'Tipo de inversión', 'Código de glosa PD', 'Empresa': item.empresa,
'Descripción glosa', 'Año de Inicio', 'Año de Término', 'Código de cronograma': item.codigoCronograma,
'Estado aprobación' 'Etapa del Servicio': item.codigoCronogramaAjuste,
]; 'Nombre sistema': item.tipoCarga,
'Tipo de inversión': item.estadoRevision,
// Añadimos cabeceras y datos 'Código de glosa PD': item.analista,
worksheet.addRow(headers); 'Descripción glosa': item.fechaIngreso,
data.forEach(item => { 'Monto Inversión Total (UF)': '',
worksheet.addRow([ 'Año de Inicio': item.dato9,
item.empresa, 'Año de Término': item.dato10,
item.codigoCronograma, 'Mes de Término': item.dato11 || '',
item.codigoCronogramaAjuste, 'Nota': item.dato12 || '',
item.tipoCarga, 'Estado aprobación': item.dato13,
item.estadoRevision, 'Observación': ''
item.analista,
item.fechaIngreso,
item.dato9,
item.dato10,
item.dato13
]);
});
}
/**
* Aplica estilos a los encabezados de la tabla
*/
private applyHeaderStyles(worksheet: any): void {
const headerRow = worksheet.getRow(1);
headerRow.height = 25;
headerRow.eachCell((cell: any) => {
cell.font = { name: 'Arial', size: 12, bold: true, color: { argb: '000000' } };
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' }
}; };
cell.alignment = { horizontal: 'center', vertical: 'middle' };
}); });
} }
/** /**
* Configura aspectos generales de la hoja de trabajo * Aplica estilos al worksheet de Excel
*/ */
private configureWorksheet(worksheet: any): void { applyStyles(worksheet: XLSX.WorkSheet) {
// Ajustamos el ancho de las columnas automáticamente // Establecemos el estilo para los encabezados
if (worksheet.columns) { const headerStyle = {
worksheet.columns.forEach((column: any) => { font: { bold: true, color: { rgb: 'FFFFFF' } },
if (column) { fill: { fgColor: { rgb: '0070C0' } },
let maxLength = 0; alignment: { horizontal: 'center' }
column.eachCell({ includeEmpty: true }, (cell: any) => { };
const columnLength = cell.value ? cell.value.toString().length : 10;
if (columnLength > maxLength) { // Aplicar estilos a los encabezados (primera fila)
maxLength = columnLength; const range = XLSX.utils.decode_range(worksheet['!ref'] || 'A1');
for (let col = range.s.c; col <= range.e.c; col++) {
const cellRef = XLSX.utils.encode_cell({ r: 0, c: col });
if (!worksheet[cellRef]) worksheet[cellRef] = { t: 's', v: '' };
worksheet[cellRef].s = headerStyle;
} }
});
column.width = maxLength < 10 ? 10 : maxLength + 2;
}
});
} }
// Congelamos la primera fila
worksheet.views = [{ state: 'frozen', xSplit: 0, ySplit: 1 }];
}
/** /**
* Guarda el archivo Excel * Guarda el buffer como un archivo Excel
*/ */
private async saveExcelFile(workbook: any): Promise<void> { saveAsExcelFile(buffer: any, fileName: string): void {
const today = new Date(); const EXCEL_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8';
const fileName = `Cronograma_temporal_por_actualización_de_PD${today.getFullYear()}${(today.getMonth() + 1).toString().padStart(2, '0')}${today.getDate().toString().padStart(2, '0')}.xlsx`; const EXCEL_EXTENSION = '.xlsx';
const data: Blob = new Blob([buffer], { type: EXCEL_TYPE });
const buffer = await workbook.xlsx.writeBuffer(); FileSaver.saveAs(data, fileName + '_' + new Date().getTime() + EXCEL_EXTENSION);
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
FileSaver.saveAs(blob, fileName);
} }
} }

View File

@ -123,7 +123,7 @@
<button <button
pButton pButton
type="button" type="button"
(click)="exportExcelWithStyles(dt)" (click)="exportExcel(dt)"
icon="pi pi-file-excel" icon="pi pi-file-excel"
class="p-button-success" class="p-button-success"
label="Exportar a Excel" label="Exportar a Excel"

View File

@ -1,12 +1,12 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { TableModule, Table } from 'primeng/table'; import { TableModule ,Table} from 'primeng/table';
import { InputTextModule } from 'primeng/inputtext'; import { InputTextModule } from 'primeng/inputtext';
import { SelectModule } from 'primeng/select'; import { SelectModule } from 'primeng/select';
import { TooltipModule } from 'primeng/tooltip'; import { TooltipModule } from 'primeng/tooltip';
import { ButtonModule } from 'primeng/button'; import { ButtonModule } from 'primeng/button';
import * as FileSaver from 'file-saver'; import * as FileSaver from 'file-saver';
import { Workbook } from 'exceljs'; import * as XLSX from 'xlsx';
@Component({ @Component({
selector: 'app-ajuste-pd', selector: 'app-ajuste-pd',
@ -23,9 +23,9 @@ import { Workbook } from 'exceljs';
}) })
export class AjustePdComponent { export class AjustePdComponent {
selectedCity: any = ''; selectedCity: any = '';
empresas: any[] = [{ name: 'Empresa A' }, { name: 'Empresa B' }, { name: 'Empresa C' }]; empresas: any[] = [{name: 'Empresa A'}, {name: 'Empresa B'}, {name: 'Empresa C'}];
select1: any = ''; select1: any = '';
estadoAprobacion: any[] = [{ name: 'Rechazado' }, { name: 'Aprobado' }]; estadoAprobacion: any[] = [{name:'Rechazado'}, {name:'Aprobado'}];
products: any[] = [ products: any[] = [
{ {
empresa: 'Empresa A', empresa: 'Empresa A',
@ -100,152 +100,115 @@ export class AjustePdComponent {
dato14: 'green', dato14: 'green',
}, },
]; ];
/**
* Exporta los datos de la tabla a Excel con estilos en los encabezados
* @param table Tabla PrimeNG a exportar
*/
exportExcelWithStyles(table: Table): void {
// Creamos un nuevo libro de trabajo
const workbook = new Workbook();
const worksheet = workbook.addWorksheet('Datos');
// Obtenemos los datos y los cabeceros /**
* Exporta los datos de la tabla a un archivo Excel
* @param table Referencia a la tabla PrimeNG
*/
exportExcel(table: Table) {
try {
// Obtenemos los datos a exportar (usamos los datos filtrados si existen)
const dataToExport = this.prepareDataForExport(table);
// Creamos el libro de Excel
const worksheet = XLSX.utils.json_to_sheet(dataToExport);
const workbook = { Sheets: { 'data': worksheet }, SheetNames: ['data'] };
// Aplicamos estilos a las celdas
this.applyExcelStyles(worksheet);
// Opciones de exportación
const excelBuffer: any = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
// Guardamos el archivo
this.saveAsExcelFile(excelBuffer, 'ajuste_pd');
console.log('Exportación a Excel completada con éxito');
} catch (error) {
console.error('Error al exportar a Excel:', error);
}
}
/**
* Prepara los datos para la exportación, traduciendo los nombres de columnas
* @param table Referencia a la tabla PrimeNG
* @returns Array de objetos con los datos formateados para exportar
*/
private prepareDataForExport(table: Table): any[] {
// Si hay filtros aplicados, usamos los datos filtrados, de lo contrario todos los datos
const data = table.filteredValue || table.value; const data = table.filteredValue || table.value;
const headers = this.getHeaders();
// Añadimos los datos a la hoja // Mapeamos los datos para tener nombres de columnas en español y legibles
this.populateWorksheet(worksheet, headers, data); return data.map(item => {
return {
// Aplicamos estilos a los encabezados 'Empresa': item.empresa,
this.styleHeaders(worksheet); 'Código de cronograma': item.codigoCronograma,
'Etapa del Servicio': item.codigoCronogramaAjuste,
// Configuramos propiedades generales de la hoja 'Nombre sistema': item.tipoCarga,
this.configureWorksheet(worksheet, data.length); 'Tipo de inversión': item.estadoRevision,
'Código de glosa PD': item.analista,
// Exportamos el archivo 'Descripción glosa': item.fechaIngreso,
this.saveExcelFile(workbook); 'Año de Inicio': item.dato9,
} 'Año de Término': item.dato10,
'Estado aprobación': item.dato13
/**
* Devuelve los cabeceros para el archivo Excel
*/
private getHeaders(): string[] {
return [
'Empresa',
'Código de cronograma',
'Etapa del Servicio',
'Nombre sistema',
'Tipo de inversión',
'Código de glosa PD',
'Descripción glosa',
'Año de Inicio',
'Año de Término',
'Estado aprobación'
];
}
/**
* Rellena la hoja con los datos de la tabla
*/
private populateWorksheet(worksheet: any, headers: string[], data: any[]): void {
// Añadimos las cabeceras
worksheet.addRow(headers);
// Añadimos los datos
data.forEach(item => {
worksheet.addRow([
item.empresa,
item.codigoCronograma,
item.codigoCronogramaAjuste,
item.tipoCarga,
item.estadoRevision,
item.analista,
item.fechaIngreso,
item.dato9,
item.dato10,
item.dato13
]);
});
}
/**
* Aplica estilos a los encabezados
*/
private styleHeaders(worksheet: any): void {
const headerRow = worksheet.getRow(1);
headerRow.height = 25;
headerRow.eachCell(cell => {
// Estilo de texto Encabezado
cell.font = {
name: 'Arial',
size: 12,
bold: true,
color: { argb: '000000' }
};
// Bordes
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' }
};
// Alineación
cell.alignment = {
horizontal: 'center',
vertical: 'middle'
}; };
}); });
} }
/** /**
* Configura propiedades generales de la hoja de trabajo * Aplica estilos al worksheet de Excel para mejorar la presentación
* @param worksheet Hoja de Excel a la que aplicar estilos
*/ */
private configureWorksheet(worksheet: any, dataLength: number): void { private applyExcelStyles(worksheet: XLSX.WorkSheet) {
// Configuramos altura de fila predeterminada // Definimos estilos para los encabezados
worksheet.properties.defaultRowHeight = 20; const headerStyle = {
font: { bold: true, color: { rgb: 'FFFFFF' } },
fill: { fgColor: { rgb: '007ACC' } }, // Color azul para los encabezados
alignment: { horizontal: 'center', vertical: 'center' }
};
// Aplicamos estilos a los encabezados (primera fila)
const range = XLSX.utils.decode_range(worksheet['!ref'] || 'A1');
for (let col = range.s.c; col <= range.e.c; col++) {
const cellRef = XLSX.utils.encode_cell({ r: 0, c: col });
if (!worksheet[cellRef]) worksheet[cellRef] = { t: 's', v: '' };
// Asignamos el estilo al encabezado
worksheet[cellRef].s = headerStyle;
}
// Ajustamos el ancho de las columnas automáticamente // Ajustamos el ancho de las columnas automáticamente
this.adjustColumnWidths(worksheet); const colWidths = [];
for (let col = range.s.c; col <= range.e.c; col++) {
// Congelamos la primera fila colWidths.push({ wch: 15 }); // Ancho predeterminado
worksheet.views = [{ state: 'frozen', xSplit: 0, ySplit: 1 }]; }
worksheet['!cols'] = colWidths;
} }
/** /**
* Ajusta el ancho de las columnas según el contenido * Guarda el buffer como un archivo Excel
* @param buffer Datos del archivo Excel
* @param fileName Nombre base del archivo
*/ */
private adjustColumnWidths(worksheet: any): void { private saveAsExcelFile(buffer: any, fileName: string): void {
if (worksheet.columns) { // Definimos el tipo MIME para archivos Excel
worksheet.columns.forEach(column => { const EXCEL_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8';
if (column) { const EXCEL_EXTENSION = '.xlsx';
let maxLength = 0;
column.eachCell({ includeEmpty: true }, cell => {
const columnLength = cell.value ? cell.value.toString().length : 10;
if (columnLength > maxLength) {
maxLength = columnLength;
}
});
column.width = maxLength < 10 ? 10 : maxLength + 2;
}
});
}
}
/** // Creamos un Blob con los datos
* Guarda el archivo Excel generado const data: Blob = new Blob([buffer], { type: EXCEL_TYPE });
*/
private saveExcelFile(workbook: any): void { // Generamos un nombre de archivo con timestamp para evitar duplicados
const today = new Date(); const today = new Date();
const fileName = `Cronograma_temporal_por_ajuste_de_PD${today.getFullYear()}${(today.getMonth() + 1).toString().padStart(2, '0')}${today.getDate().toString().padStart(2, '0')}.xlsx`; const formattedDate =
today.getFullYear().toString() +
(today.getMonth() + 1).toString().padStart(2, '0') +
today.getDate().toString().padStart(2, '0') +
'_' +
today.getHours().toString().padStart(2, '0') +
today.getMinutes().toString().padStart(2, '0');
workbook.xlsx.writeBuffer() // Guardamos el archivo
.then(buffer => { FileSaver.saveAs(data, `${fileName}_${formattedDate}${EXCEL_EXTENSION}`);
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
FileSaver.saveAs(blob, fileName);
})
.catch(error => console.error('Error al exportar a Excel:', error));
} }
} }

View File

@ -4,7 +4,7 @@
"compileOnSave": false, "compileOnSave": false,
"compilerOptions": { "compilerOptions": {
"outDir": "./dist/out-tsc", "outDir": "./dist/out-tsc",
"strict": false, "strict": true,
"noImplicitOverride": true, "noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true, "noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true, "noImplicitReturns": true,