han-excel-builder 1.0.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +769 -146
- package/dist/__vite-browser-external-d06ac358.js +5 -0
- package/dist/__vite-browser-external-d06ac358.js.map +1 -0
- package/dist/__vite-browser-external-e7aec059.cjs +2 -0
- package/dist/__vite-browser-external-e7aec059.cjs.map +1 -0
- package/dist/han-excel.cjs.js +1 -1
- package/dist/han-excel.cjs.js.map +1 -1
- package/dist/han-excel.es.js +637 -0
- package/dist/han-excel.es.js.map +1 -1
- package/dist/index.d.ts +268 -0
- package/package.json +94 -93
package/README.md
CHANGED
|
@@ -1,250 +1,866 @@
|
|
|
1
1
|
# Han Excel Builder
|
|
2
2
|
|
|
3
|
-
🚀 **
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## ✨
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
3
|
+
🚀 **Generador avanzado de archivos Excel con soporte TypeScript, estilos completos y rendimiento optimizado**
|
|
4
|
+
|
|
5
|
+
Una biblioteca moderna y completamente tipada para crear reportes Excel complejos con múltiples hojas de cálculo, estilos avanzados y alto rendimiento.
|
|
6
|
+
|
|
7
|
+
## ✨ Características
|
|
8
|
+
|
|
9
|
+
### 📊 Estructura de Datos
|
|
10
|
+
- ✅ **Múltiples Hojas de Cálculo** - Crea workbooks complejos con múltiples hojas
|
|
11
|
+
- ✅ **Múltiples Tablas por Hoja** - Crea varias tablas independientes en una sola hoja
|
|
12
|
+
- ✅ **Headers Anidados** - Soporte completo para headers con múltiples niveles de anidación
|
|
13
|
+
- ✅ **Datos Jerárquicos** - Soporte para datos con estructura de children (datos anidados)
|
|
14
|
+
|
|
15
|
+
### 📈 Tipos de Datos
|
|
16
|
+
- ✅ **STRING** - Valores de texto
|
|
17
|
+
- ✅ **NUMBER** - Valores numéricos
|
|
18
|
+
- ✅ **BOOLEAN** - Valores verdadero/falso
|
|
19
|
+
- ✅ **DATE** - Valores de fecha
|
|
20
|
+
- ✅ **PERCENTAGE** - Valores de porcentaje
|
|
21
|
+
- ✅ **CURRENCY** - Valores de moneda
|
|
22
|
+
- ✅ **LINK** - Hipervínculos con texto personalizable
|
|
23
|
+
- ✅ **FORMULA** - Fórmulas de Excel
|
|
24
|
+
|
|
25
|
+
### 🎨 Estilos Avanzados
|
|
26
|
+
- ✅ **API Fluida** - StyleBuilder con métodos encadenables
|
|
27
|
+
- ✅ **Fuentes** - Control completo sobre nombre, tamaño, color, negrita, cursiva, subrayado
|
|
28
|
+
- ✅ **Colores** - Fondos, colores de texto con soporte para hex, RGB y temas
|
|
29
|
+
- ✅ **Bordes** - Bordes personalizables en todos los lados con múltiples estilos
|
|
30
|
+
- ✅ **Alineación** - Horizontal (izquierda, centro, derecha, justificar) y vertical (arriba, medio, abajo)
|
|
31
|
+
- ✅ **Texto** - Ajuste de texto, contracción para ajustar, rotación de texto
|
|
32
|
+
- ✅ **Formatos de Número** - Múltiples formatos predefinidos y personalizados
|
|
33
|
+
- ✅ **Filas Alternadas** - Soporte para rayas alternadas en tablas
|
|
34
|
+
|
|
35
|
+
### 🔧 Funcionalidades Avanzadas
|
|
36
|
+
- ✅ **TypeScript First** - Seguridad de tipos completa con interfaces exhaustivas
|
|
37
|
+
- ✅ **Sistema de Eventos** - EventEmitter para monitorear el proceso de construcción
|
|
38
|
+
- ✅ **Validación** - Sistema robusto de validación de datos
|
|
39
|
+
- ✅ **Metadata** - Soporte completo para metadata del workbook (autor, título, descripción, etc.)
|
|
40
|
+
- ✅ **Múltiples Formatos de Exportación** - Descarga directa, Buffer, Blob
|
|
41
|
+
- ✅ **Lectura de Excel** - Lee archivos Excel y convierte a JSON
|
|
42
|
+
- ✅ **Hipervínculos** - Creación de enlaces con texto personalizable
|
|
43
|
+
- ✅ **Merge de Celdas** - Fusión horizontal y vertical de celdas
|
|
44
|
+
- ✅ **Dimensiones Personalizadas** - Ancho de columnas y alto de filas personalizables
|
|
45
|
+
|
|
46
|
+
## 📦 Instalación
|
|
19
47
|
|
|
20
48
|
```bash
|
|
21
49
|
npm install han-excel-builder
|
|
22
|
-
#
|
|
50
|
+
# o
|
|
23
51
|
yarn add han-excel-builder
|
|
24
|
-
#
|
|
52
|
+
# o
|
|
25
53
|
pnpm add han-excel-builder
|
|
26
54
|
```
|
|
27
55
|
|
|
28
|
-
## 🚀
|
|
56
|
+
## 🚀 Inicio Rápido
|
|
57
|
+
|
|
58
|
+
### Ejemplo Básico
|
|
29
59
|
|
|
30
60
|
```typescript
|
|
31
|
-
import { ExcelBuilder, CellType, NumberFormat, StyleBuilder } from 'han-excel-builder';
|
|
61
|
+
import { ExcelBuilder, CellType, NumberFormat, StyleBuilder, BorderStyle } from 'han-excel-builder';
|
|
32
62
|
|
|
33
|
-
//
|
|
34
|
-
const builder = new ExcelBuilder(
|
|
63
|
+
// Crear un reporte simple
|
|
64
|
+
const builder = new ExcelBuilder({
|
|
65
|
+
metadata: {
|
|
66
|
+
title: 'Reporte de Ventas',
|
|
67
|
+
author: 'Mi Empresa',
|
|
68
|
+
description: 'Reporte mensual de ventas'
|
|
69
|
+
}
|
|
70
|
+
});
|
|
35
71
|
|
|
36
|
-
const worksheet = builder.addWorksheet('
|
|
72
|
+
const worksheet = builder.addWorksheet('Ventas');
|
|
37
73
|
|
|
38
|
-
//
|
|
74
|
+
// Agregar header principal
|
|
39
75
|
worksheet.addHeader({
|
|
40
76
|
key: 'title',
|
|
41
|
-
value: '
|
|
77
|
+
value: 'Reporte Mensual de Ventas',
|
|
42
78
|
type: CellType.STRING,
|
|
43
79
|
mergeCell: true,
|
|
44
|
-
styles: StyleBuilder
|
|
45
|
-
.
|
|
80
|
+
styles: new StyleBuilder()
|
|
81
|
+
.fontName('Arial')
|
|
46
82
|
.fontSize(16)
|
|
83
|
+
.fontBold()
|
|
84
|
+
.backgroundColor('#4472C4')
|
|
85
|
+
.fontColor('#FFFFFF')
|
|
47
86
|
.centerAlign()
|
|
87
|
+
.border(BorderStyle.THIN, '#8EAADB')
|
|
48
88
|
.build()
|
|
49
89
|
});
|
|
50
90
|
|
|
51
|
-
//
|
|
91
|
+
// Agregar sub-headers
|
|
52
92
|
worksheet.addSubHeaders([
|
|
53
93
|
{
|
|
54
|
-
key: '
|
|
55
|
-
value: '
|
|
94
|
+
key: 'producto',
|
|
95
|
+
value: 'Producto',
|
|
56
96
|
type: CellType.STRING,
|
|
57
|
-
|
|
97
|
+
colWidth: 20,
|
|
98
|
+
styles: new StyleBuilder()
|
|
99
|
+
.fontBold()
|
|
100
|
+
.backgroundColor('#8EAADB')
|
|
101
|
+
.fontColor('#FFFFFF')
|
|
102
|
+
.centerAlign()
|
|
103
|
+
.border(BorderStyle.THIN, '#8EAADB')
|
|
104
|
+
.build()
|
|
58
105
|
},
|
|
59
106
|
{
|
|
60
|
-
key: '
|
|
61
|
-
value: '
|
|
62
|
-
type: CellType.
|
|
63
|
-
|
|
64
|
-
numberFormat:
|
|
107
|
+
key: 'ventas',
|
|
108
|
+
value: 'Ventas',
|
|
109
|
+
type: CellType.CURRENCY,
|
|
110
|
+
colWidth: 15,
|
|
111
|
+
numberFormat: '$#,##0',
|
|
112
|
+
styles: new StyleBuilder()
|
|
113
|
+
.fontBold()
|
|
114
|
+
.backgroundColor('#8EAADB')
|
|
115
|
+
.fontColor('#FFFFFF')
|
|
116
|
+
.centerAlign()
|
|
117
|
+
.border(BorderStyle.THIN, '#8EAADB')
|
|
118
|
+
.build()
|
|
65
119
|
}
|
|
66
120
|
]);
|
|
67
121
|
|
|
68
|
-
//
|
|
122
|
+
// Agregar datos
|
|
69
123
|
worksheet.addRow([
|
|
70
|
-
{
|
|
71
|
-
|
|
124
|
+
{
|
|
125
|
+
key: 'producto-1',
|
|
126
|
+
value: 'Producto A',
|
|
127
|
+
type: CellType.STRING,
|
|
128
|
+
header: 'Producto'
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
key: 'ventas-1',
|
|
132
|
+
value: 1500.50,
|
|
133
|
+
type: CellType.CURRENCY,
|
|
134
|
+
header: 'Ventas',
|
|
135
|
+
numberFormat: '$#,##0.00'
|
|
136
|
+
}
|
|
72
137
|
]);
|
|
73
138
|
|
|
74
|
-
//
|
|
75
|
-
await builder.generateAndDownload('
|
|
139
|
+
// Generar y descargar
|
|
140
|
+
await builder.generateAndDownload('reporte-ventas.xlsx');
|
|
76
141
|
```
|
|
77
142
|
|
|
78
|
-
## 📚 API
|
|
143
|
+
## 📚 Documentación de API
|
|
79
144
|
|
|
80
|
-
###
|
|
145
|
+
### Clases Principales
|
|
81
146
|
|
|
82
147
|
#### `ExcelBuilder`
|
|
83
|
-
|
|
148
|
+
|
|
149
|
+
Clase principal para crear workbooks de Excel.
|
|
84
150
|
|
|
85
151
|
```typescript
|
|
86
152
|
const builder = new ExcelBuilder({
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
153
|
+
metadata: {
|
|
154
|
+
title: 'Mi Reporte',
|
|
155
|
+
author: 'Mi Nombre',
|
|
156
|
+
company: 'Mi Empresa',
|
|
157
|
+
description: 'Descripción del reporte',
|
|
158
|
+
keywords: 'excel, reporte, datos',
|
|
159
|
+
created: new Date(),
|
|
160
|
+
modified: new Date()
|
|
161
|
+
},
|
|
162
|
+
enableValidation: true,
|
|
163
|
+
enableEvents: true,
|
|
164
|
+
maxWorksheets: 255,
|
|
165
|
+
maxRowsPerWorksheet: 1048576,
|
|
166
|
+
maxColumnsPerWorksheet: 16384
|
|
90
167
|
});
|
|
168
|
+
|
|
169
|
+
// Métodos principales
|
|
170
|
+
builder.addWorksheet(name, config); // Agregar una hoja
|
|
171
|
+
builder.getWorksheet(name); // Obtener una hoja
|
|
172
|
+
builder.removeWorksheet(name); // Eliminar una hoja
|
|
173
|
+
builder.setCurrentWorksheet(name); // Establecer hoja actual
|
|
174
|
+
builder.build(options); // Construir y obtener ArrayBuffer
|
|
175
|
+
builder.generateAndDownload(fileName); // Generar y descargar
|
|
176
|
+
builder.toBuffer(options); // Obtener como Buffer
|
|
177
|
+
builder.toBlob(options); // Obtener como Blob
|
|
178
|
+
builder.validate(); // Validar workbook
|
|
179
|
+
builder.clear(); // Limpiar todas las hojas
|
|
180
|
+
builder.getStats(); // Obtener estadísticas
|
|
181
|
+
|
|
182
|
+
// Sistema de eventos
|
|
183
|
+
builder.on(eventType, listener);
|
|
184
|
+
builder.off(eventType, listenerId);
|
|
185
|
+
builder.removeAllListeners(eventType);
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### `ExcelReader`
|
|
189
|
+
|
|
190
|
+
Clase para leer archivos Excel y convertirlos a JSON con 3 formatos de salida diferentes.
|
|
191
|
+
|
|
192
|
+
**Formatos disponibles:**
|
|
193
|
+
- `worksheet` (por defecto) - Estructura completa con hojas, filas y celdas
|
|
194
|
+
- `detailed` - Cada celda con información de posición (texto, columna, fila)
|
|
195
|
+
- `flat` - Solo los datos, sin estructura
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
import { ExcelReader, OutputFormat } from 'han-excel-builder';
|
|
199
|
+
|
|
200
|
+
// ===== FORMATO 1: WORKSHEET (por defecto) =====
|
|
201
|
+
// Estructura completa organizada por hojas
|
|
202
|
+
const result = await ExcelReader.fromFile(file, {
|
|
203
|
+
outputFormat: OutputFormat.WORKSHEET, // o 'worksheet'
|
|
204
|
+
useFirstRowAsHeaders: true
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
if (result.success) {
|
|
208
|
+
const workbook = result.data;
|
|
209
|
+
// workbook.sheets[] - Array de hojas
|
|
210
|
+
// workbook.sheets[0].rows[] - Array de filas
|
|
211
|
+
// workbook.sheets[0].rows[0].cells[] - Array de celdas
|
|
212
|
+
// workbook.sheets[0].rows[0].data - Objeto con datos (si useFirstRowAsHeaders)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ===== FORMATO 2: DETAILED =====
|
|
216
|
+
// Cada celda con información de posición
|
|
217
|
+
const result = await ExcelReader.fromFile(file, {
|
|
218
|
+
outputFormat: OutputFormat.DETAILED, // o 'detailed'
|
|
219
|
+
includeFormatting: true
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
if (result.success) {
|
|
223
|
+
const detailed = result.data;
|
|
224
|
+
// detailed.cells[] - Array de todas las celdas con:
|
|
225
|
+
// - value: valor de la celda
|
|
226
|
+
// - text: texto de la celda
|
|
227
|
+
// - column: número de columna (1-based)
|
|
228
|
+
// - columnLetter: letra de columna (A, B, C...)
|
|
229
|
+
// - row: número de fila (1-based)
|
|
230
|
+
// - reference: referencia de celda (A1, B2...)
|
|
231
|
+
// - sheet: nombre de la hoja
|
|
232
|
+
detailed.cells.forEach(cell => {
|
|
233
|
+
console.log(`${cell.sheet}!${cell.reference}: ${cell.text}`);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ===== FORMATO 3: FLAT =====
|
|
238
|
+
// Solo los datos, sin estructura
|
|
239
|
+
const result = await ExcelReader.fromFile(file, {
|
|
240
|
+
outputFormat: OutputFormat.FLAT, // o 'flat'
|
|
241
|
+
useFirstRowAsHeaders: true
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
if (result.success) {
|
|
245
|
+
const flat = result.data;
|
|
246
|
+
|
|
247
|
+
// Si es una sola hoja:
|
|
248
|
+
if ('data' in flat) {
|
|
249
|
+
// flat.data[] - Array de objetos o arrays
|
|
250
|
+
// flat.headers[] - Headers (si useFirstRowAsHeaders)
|
|
251
|
+
flat.data.forEach(row => {
|
|
252
|
+
console.log(row); // { Producto: 'A', Precio: 100 } o ['A', 100]
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Si son múltiples hojas:
|
|
257
|
+
if ('sheets' in flat) {
|
|
258
|
+
// flat.sheets['NombreHoja'].data[] - Datos por hoja
|
|
259
|
+
Object.keys(flat.sheets).forEach(sheetName => {
|
|
260
|
+
console.log(`Hoja: ${sheetName}`);
|
|
261
|
+
flat.sheets[sheetName].data.forEach(row => {
|
|
262
|
+
console.log(row);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ===== USANDO MAPPER PARA TRANSFORMAR DATOS =====
|
|
269
|
+
// El mapper permite transformar la respuesta antes de devolverla
|
|
270
|
+
const result = await ExcelReader.fromFile(file, {
|
|
271
|
+
outputFormat: OutputFormat.WORKSHEET,
|
|
272
|
+
useFirstRowAsHeaders: true,
|
|
273
|
+
// Mapper recibe el payload y devuelve la transformación
|
|
274
|
+
mapper: (data) => {
|
|
275
|
+
// Transformar datos según necesidades
|
|
276
|
+
const transformed = {
|
|
277
|
+
totalSheets: data.totalSheets,
|
|
278
|
+
sheets: data.sheets.map(sheet => ({
|
|
279
|
+
name: sheet.name,
|
|
280
|
+
// Convertir filas a objetos con datos transformados
|
|
281
|
+
rows: sheet.rows.map(row => {
|
|
282
|
+
if (row.data) {
|
|
283
|
+
// Transformar cada campo
|
|
284
|
+
return {
|
|
285
|
+
...row.data,
|
|
286
|
+
// Agregar campos calculados
|
|
287
|
+
total: Object.values(row.data).reduce((sum, val) => {
|
|
288
|
+
return sum + (typeof val === 'number' ? val : 0);
|
|
289
|
+
}, 0)
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
return row;
|
|
293
|
+
})
|
|
294
|
+
}))
|
|
295
|
+
};
|
|
296
|
+
return transformed;
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// Ejemplo con formato FLAT y mapper
|
|
301
|
+
const result = await ExcelReader.fromFile(file, {
|
|
302
|
+
outputFormat: OutputFormat.FLAT,
|
|
303
|
+
useFirstRowAsHeaders: true,
|
|
304
|
+
mapper: (data) => {
|
|
305
|
+
// Si es formato flat de una sola hoja
|
|
306
|
+
if ('data' in data && Array.isArray(data.data)) {
|
|
307
|
+
return data.data.map((row: any) => ({
|
|
308
|
+
...row,
|
|
309
|
+
// Agregar validaciones o transformaciones
|
|
310
|
+
isValid: Object.values(row).every(val => val !== null && val !== undefined)
|
|
311
|
+
}));
|
|
312
|
+
}
|
|
313
|
+
return data;
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// Ejemplo con formato DETAILED y mapper
|
|
318
|
+
const result = await ExcelReader.fromFile(file, {
|
|
319
|
+
outputFormat: OutputFormat.DETAILED,
|
|
320
|
+
mapper: (data) => {
|
|
321
|
+
// Agrupar celdas por hoja
|
|
322
|
+
const groupedBySheet: Record<string, typeof data.cells> = {};
|
|
323
|
+
data.cells.forEach(cell => {
|
|
324
|
+
if (!groupedBySheet[cell.sheet]) {
|
|
325
|
+
groupedBySheet[cell.sheet] = [];
|
|
326
|
+
}
|
|
327
|
+
groupedBySheet[cell.sheet].push(cell);
|
|
328
|
+
});
|
|
329
|
+
return {
|
|
330
|
+
sheets: Object.keys(groupedBySheet).map(sheetName => ({
|
|
331
|
+
name: sheetName,
|
|
332
|
+
cells: groupedBySheet[sheetName]
|
|
333
|
+
}))
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Opciones de lectura:**
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
interface IExcelReaderOptions {
|
|
343
|
+
outputFormat?: 'worksheet' | 'detailed' | 'flat' | OutputFormat; // Formato de salida
|
|
344
|
+
mapper?: (data: IJsonWorkbook | IDetailedFormat | IFlatFormat | IFlatFormatMultiSheet) => unknown; // Función para transformar la respuesta
|
|
345
|
+
useFirstRowAsHeaders?: boolean; // Usar primera fila como headers
|
|
346
|
+
includeEmptyRows?: boolean; // Incluir filas vacías
|
|
347
|
+
headers?: string[] | Record<number, string>; // Headers personalizados
|
|
348
|
+
sheetName?: string | number; // Nombre o índice de hoja
|
|
349
|
+
startRow?: number; // Fila inicial (1-based)
|
|
350
|
+
endRow?: number; // Fila final (1-based)
|
|
351
|
+
startColumn?: number; // Columna inicial (1-based)
|
|
352
|
+
endColumn?: number; // Columna final (1-based)
|
|
353
|
+
includeFormatting?: boolean; // Incluir información de formato
|
|
354
|
+
includeFormulas?: boolean; // Incluir fórmulas
|
|
355
|
+
datesAsISO?: boolean; // Convertir fechas a ISO string
|
|
356
|
+
}
|
|
91
357
|
```
|
|
92
358
|
|
|
359
|
+
**Formatos de salida:**
|
|
360
|
+
|
|
361
|
+
- **`worksheet`** (por defecto): Estructura completa con hojas, filas y celdas
|
|
362
|
+
- **`detailed`**: Array de celdas con información de posición (texto, columna, fila, referencia)
|
|
363
|
+
- **`flat`**: Solo los datos, sin estructura (arrays u objetos planos)
|
|
364
|
+
|
|
93
365
|
#### `Worksheet`
|
|
94
|
-
|
|
366
|
+
|
|
367
|
+
Representa una hoja de cálculo individual.
|
|
95
368
|
|
|
96
369
|
```typescript
|
|
97
|
-
const worksheet = builder.addWorksheet('
|
|
370
|
+
const worksheet = builder.addWorksheet('Mi Hoja', {
|
|
98
371
|
tabColor: '#FF0000',
|
|
99
372
|
defaultRowHeight: 20,
|
|
100
|
-
defaultColWidth: 15
|
|
373
|
+
defaultColWidth: 15,
|
|
374
|
+
pageSetup: {
|
|
375
|
+
orientation: 'portrait',
|
|
376
|
+
paperSize: 9
|
|
377
|
+
}
|
|
101
378
|
});
|
|
379
|
+
|
|
380
|
+
// Métodos principales
|
|
381
|
+
worksheet.addHeader(header); // Agregar header principal
|
|
382
|
+
worksheet.addSubHeaders(headers); // Agregar sub-headers
|
|
383
|
+
worksheet.addRow(row); // Agregar fila de datos
|
|
384
|
+
worksheet.addFooter(footer); // Agregar footer
|
|
385
|
+
worksheet.addTable(config); // Crear nueva tabla
|
|
386
|
+
worksheet.finalizeTable(); // Finalizar tabla actual
|
|
387
|
+
worksheet.getTable(name); // Obtener tabla por nombre
|
|
388
|
+
worksheet.validate(); // Validar hoja
|
|
102
389
|
```
|
|
103
390
|
|
|
104
|
-
###
|
|
391
|
+
### Tipos de Datos
|
|
105
392
|
|
|
106
393
|
#### `CellType`
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
enum CellType {
|
|
397
|
+
STRING = 'string', // Texto
|
|
398
|
+
NUMBER = 'number', // Número
|
|
399
|
+
BOOLEAN = 'boolean', // Verdadero/Falso
|
|
400
|
+
DATE = 'date', // Fecha
|
|
401
|
+
PERCENTAGE = 'percentage', // Porcentaje
|
|
402
|
+
CURRENCY = 'currency', // Moneda
|
|
403
|
+
LINK = 'link', // Hipervínculo
|
|
404
|
+
FORMULA = 'formula' // Fórmula
|
|
405
|
+
}
|
|
406
|
+
```
|
|
113
407
|
|
|
114
408
|
#### `NumberFormat`
|
|
115
|
-
- `GENERAL` - Default format
|
|
116
|
-
- `NUMBER` - Number with optional decimals
|
|
117
|
-
- `CURRENCY` - Currency format
|
|
118
|
-
- `PERCENTAGE` - Percentage format
|
|
119
|
-
- `DATE` - Date format
|
|
120
|
-
- `TIME` - Time format
|
|
121
|
-
- `CUSTOM` - Custom format string
|
|
122
409
|
|
|
123
|
-
|
|
410
|
+
```typescript
|
|
411
|
+
enum NumberFormat {
|
|
412
|
+
GENERAL = 'General',
|
|
413
|
+
NUMBER = '#,##0',
|
|
414
|
+
NUMBER_DECIMALS = '#,##0.00',
|
|
415
|
+
CURRENCY = '$#,##0.00',
|
|
416
|
+
CURRENCY_INTEGER = '$#,##0',
|
|
417
|
+
PERCENTAGE = '0%',
|
|
418
|
+
PERCENTAGE_DECIMALS = '0.00%',
|
|
419
|
+
DATE = 'dd/mm/yyyy',
|
|
420
|
+
DATE_TIME = 'dd/mm/yyyy hh:mm',
|
|
421
|
+
TIME = 'hh:mm:ss',
|
|
422
|
+
CUSTOM = 'custom'
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Estilos
|
|
124
427
|
|
|
125
428
|
#### `StyleBuilder`
|
|
126
|
-
|
|
429
|
+
|
|
430
|
+
API fluida para crear estilos de celdas.
|
|
127
431
|
|
|
128
432
|
```typescript
|
|
129
|
-
const style = StyleBuilder
|
|
130
|
-
|
|
433
|
+
const style = new StyleBuilder()
|
|
434
|
+
// Fuentes
|
|
435
|
+
.fontName('Arial')
|
|
131
436
|
.fontSize(12)
|
|
437
|
+
.fontBold()
|
|
438
|
+
.fontItalic()
|
|
439
|
+
.fontUnderline()
|
|
132
440
|
.fontColor('#FF0000')
|
|
441
|
+
|
|
442
|
+
// Fondos y bordes
|
|
133
443
|
.backgroundColor('#FFFF00')
|
|
134
|
-
.border(
|
|
444
|
+
.border(BorderStyle.THIN, '#000000')
|
|
445
|
+
.borderTop(BorderStyle.MEDIUM, '#000000')
|
|
446
|
+
.borderLeft(BorderStyle.THIN, '#000000')
|
|
447
|
+
.borderBottom(BorderStyle.THIN, '#000000')
|
|
448
|
+
.borderRight(BorderStyle.THIN, '#000000')
|
|
449
|
+
|
|
450
|
+
// Alineación
|
|
135
451
|
.centerAlign()
|
|
136
|
-
.
|
|
452
|
+
.leftAlign()
|
|
453
|
+
.rightAlign()
|
|
454
|
+
.horizontalAlign(HorizontalAlignment.CENTER)
|
|
455
|
+
.verticalAlign(VerticalAlignment.MIDDLE)
|
|
137
456
|
.wrapText()
|
|
457
|
+
|
|
458
|
+
// Formatos
|
|
459
|
+
.numberFormat('$#,##0.00')
|
|
460
|
+
.striped()
|
|
461
|
+
|
|
462
|
+
// Formato condicional
|
|
463
|
+
.conditionalFormat({
|
|
464
|
+
type: 'cellIs',
|
|
465
|
+
operator: 'greaterThan',
|
|
466
|
+
values: [1000],
|
|
467
|
+
style: StyleBuilder.create()
|
|
468
|
+
.backgroundColor('#90EE90')
|
|
469
|
+
.fontColor('#006400')
|
|
470
|
+
.build()
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
.build();
|
|
474
|
+
|
|
475
|
+
// Método estático alternativo
|
|
476
|
+
const style2 = StyleBuilder.create()
|
|
477
|
+
.fontBold()
|
|
478
|
+
.fontSize(14)
|
|
138
479
|
.build();
|
|
139
480
|
```
|
|
140
481
|
|
|
141
|
-
|
|
482
|
+
#### `BorderStyle`
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
enum BorderStyle {
|
|
486
|
+
THIN = 'thin',
|
|
487
|
+
MEDIUM = 'medium',
|
|
488
|
+
THICK = 'thick',
|
|
489
|
+
DOTTED = 'dotted',
|
|
490
|
+
DASHED = 'dashed',
|
|
491
|
+
DOUBLE = 'double',
|
|
492
|
+
HAIR = 'hair',
|
|
493
|
+
MEDIUM_DASHED = 'mediumDashed',
|
|
494
|
+
DASH_DOT = 'dashDot',
|
|
495
|
+
MEDIUM_DASH_DOT = 'mediumDashDot',
|
|
496
|
+
DASH_DOT_DOT = 'dashDotDot',
|
|
497
|
+
MEDIUM_DASH_DOT_DOT = 'mediumDashDotDot',
|
|
498
|
+
SLANT_DASH_DOT = 'slantDashDot'
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
## 🎯 Ejemplos Avanzados
|
|
142
503
|
|
|
143
|
-
###
|
|
504
|
+
### Múltiples Tablas en una Hoja
|
|
144
505
|
|
|
145
506
|
```typescript
|
|
146
|
-
import { ExcelBuilder, CellType,
|
|
507
|
+
import { ExcelBuilder, CellType, StyleBuilder, BorderStyle } from 'han-excel-builder';
|
|
147
508
|
|
|
148
|
-
const builder = new ExcelBuilder(
|
|
149
|
-
|
|
150
|
-
|
|
509
|
+
const builder = new ExcelBuilder();
|
|
510
|
+
const worksheet = builder.addWorksheet('Reporte Completo');
|
|
511
|
+
|
|
512
|
+
// ===== PRIMERA TABLA =====
|
|
513
|
+
worksheet.addTable({
|
|
514
|
+
name: 'Ventas',
|
|
515
|
+
showBorders: true,
|
|
516
|
+
showStripes: true,
|
|
517
|
+
style: 'TableStyleLight1'
|
|
151
518
|
});
|
|
152
519
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
summarySheet.addHeader({
|
|
156
|
-
key: 'title',
|
|
157
|
-
value: 'Annual Report Summary',
|
|
520
|
+
worksheet.addHeader({
|
|
521
|
+
key: 'header-ventas',
|
|
158
522
|
type: CellType.STRING,
|
|
523
|
+
value: 'RESUMEN DE VENTAS',
|
|
159
524
|
mergeCell: true,
|
|
160
|
-
styles: StyleBuilder
|
|
525
|
+
styles: new StyleBuilder()
|
|
526
|
+
.fontBold()
|
|
527
|
+
.fontSize(16)
|
|
528
|
+
.backgroundColor('#4472C4')
|
|
529
|
+
.fontColor('#FFFFFF')
|
|
530
|
+
.centerAlign()
|
|
531
|
+
.build()
|
|
161
532
|
});
|
|
162
533
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
{ key: 'date', value: 'Date', type: CellType.DATE, width: 12 },
|
|
167
|
-
{ key: 'category', value: 'Category', type: CellType.STRING, width: 15 },
|
|
168
|
-
{ key: 'amount', value: 'Amount', type: CellType.NUMBER, width: 12, numberFormat: NumberFormat.CURRENCY },
|
|
169
|
-
{ key: 'percentage', value: '%', type: CellType.PERCENTAGE, width: 8 }
|
|
534
|
+
worksheet.addSubHeaders([
|
|
535
|
+
{ key: 'producto', type: CellType.STRING, value: 'Producto' },
|
|
536
|
+
{ key: 'ventas', type: CellType.CURRENCY, value: 'Ventas' }
|
|
170
537
|
]);
|
|
171
538
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
539
|
+
worksheet.addRow([
|
|
540
|
+
{ key: 'p1', type: CellType.STRING, value: 'Producto A', header: 'Producto' },
|
|
541
|
+
{ key: 'v1', type: CellType.CURRENCY, value: 1500, header: 'Ventas' }
|
|
542
|
+
]);
|
|
543
|
+
|
|
544
|
+
worksheet.finalizeTable();
|
|
545
|
+
|
|
546
|
+
// ===== SEGUNDA TABLA =====
|
|
547
|
+
worksheet.addTable({
|
|
548
|
+
name: 'Empleados',
|
|
549
|
+
showBorders: true,
|
|
550
|
+
showStripes: true,
|
|
551
|
+
style: 'TableStyleMedium1'
|
|
184
552
|
});
|
|
185
553
|
|
|
186
|
-
|
|
554
|
+
worksheet.addHeader({
|
|
555
|
+
key: 'header-empleados',
|
|
556
|
+
type: CellType.STRING,
|
|
557
|
+
value: 'TOP EMPLEADOS',
|
|
558
|
+
mergeCell: true,
|
|
559
|
+
styles: new StyleBuilder()
|
|
560
|
+
.fontBold()
|
|
561
|
+
.fontSize(16)
|
|
562
|
+
.backgroundColor('#70AD47')
|
|
563
|
+
.fontColor('#FFFFFF')
|
|
564
|
+
.centerAlign()
|
|
565
|
+
.build()
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
worksheet.addSubHeaders([
|
|
569
|
+
{ key: 'nombre', type: CellType.STRING, value: 'Nombre' },
|
|
570
|
+
{ key: 'ventas', type: CellType.CURRENCY, value: 'Ventas' }
|
|
571
|
+
]);
|
|
572
|
+
|
|
573
|
+
worksheet.addRow([
|
|
574
|
+
{ key: 'e1', type: CellType.STRING, value: 'Juan Pérez', header: 'Nombre' },
|
|
575
|
+
{ key: 've1', type: CellType.CURRENCY, value: 150000, header: 'Ventas' }
|
|
576
|
+
]);
|
|
577
|
+
|
|
578
|
+
worksheet.finalizeTable();
|
|
579
|
+
|
|
580
|
+
await builder.generateAndDownload('multiple-tables.xlsx');
|
|
187
581
|
```
|
|
188
582
|
|
|
189
|
-
###
|
|
583
|
+
### Headers Anidados
|
|
190
584
|
|
|
191
585
|
```typescript
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
586
|
+
worksheet.addSubHeaders([
|
|
587
|
+
{
|
|
588
|
+
key: 'ventas',
|
|
589
|
+
value: 'Ventas',
|
|
590
|
+
type: CellType.STRING,
|
|
591
|
+
children: [
|
|
592
|
+
{
|
|
593
|
+
key: 'ventas-q1',
|
|
594
|
+
value: 'Q1',
|
|
595
|
+
type: CellType.STRING
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
key: 'ventas-q2',
|
|
599
|
+
value: 'Q2',
|
|
600
|
+
type: CellType.STRING
|
|
601
|
+
}
|
|
602
|
+
]
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
key: 'gastos',
|
|
606
|
+
value: 'Gastos',
|
|
607
|
+
type: CellType.STRING,
|
|
608
|
+
children: [
|
|
609
|
+
{
|
|
610
|
+
key: 'gastos-q1',
|
|
611
|
+
value: 'Q1',
|
|
612
|
+
type: CellType.STRING
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
key: 'gastos-q2',
|
|
616
|
+
value: 'Q2',
|
|
617
|
+
type: CellType.STRING
|
|
618
|
+
}
|
|
619
|
+
]
|
|
620
|
+
}
|
|
621
|
+
]);
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### Hipervínculos
|
|
625
|
+
|
|
626
|
+
```typescript
|
|
627
|
+
worksheet.addRow([
|
|
628
|
+
{
|
|
629
|
+
key: 'link-1',
|
|
630
|
+
type: CellType.LINK,
|
|
631
|
+
value: 'Visitar sitio',
|
|
632
|
+
link: 'https://example.com',
|
|
633
|
+
mask: 'Haz clic aquí', // Texto visible
|
|
634
|
+
header: 'Enlace'
|
|
635
|
+
}
|
|
636
|
+
]);
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
### Datos con Children (Estructura Jerárquica)
|
|
640
|
+
|
|
641
|
+
```typescript
|
|
642
|
+
worksheet.addRow([
|
|
643
|
+
{
|
|
644
|
+
key: 'row-1',
|
|
645
|
+
type: CellType.STRING,
|
|
646
|
+
value: 'Categoría Principal',
|
|
647
|
+
header: 'Categoría',
|
|
648
|
+
children: [
|
|
649
|
+
{
|
|
650
|
+
key: 'child-1',
|
|
651
|
+
type: CellType.STRING,
|
|
652
|
+
value: 'Subcategoría 1',
|
|
653
|
+
header: 'Subcategoría'
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
key: 'child-2',
|
|
657
|
+
type: CellType.NUMBER,
|
|
658
|
+
value: 100,
|
|
659
|
+
header: 'Valor'
|
|
660
|
+
}
|
|
661
|
+
]
|
|
662
|
+
}
|
|
663
|
+
]);
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
### Formato Condicional
|
|
667
|
+
|
|
668
|
+
```typescript
|
|
669
|
+
worksheet.addRow([
|
|
670
|
+
{
|
|
671
|
+
key: 'ventas-1',
|
|
672
|
+
type: CellType.NUMBER,
|
|
673
|
+
value: 1500,
|
|
674
|
+
header: 'Ventas',
|
|
675
|
+
styles: new StyleBuilder()
|
|
676
|
+
.conditionalFormat({
|
|
677
|
+
type: 'cellIs',
|
|
678
|
+
operator: 'greaterThan',
|
|
679
|
+
values: [1000],
|
|
680
|
+
style: StyleBuilder.create()
|
|
681
|
+
.backgroundColor('#90EE90')
|
|
682
|
+
.fontColor('#006400')
|
|
683
|
+
.build()
|
|
684
|
+
})
|
|
200
685
|
.build()
|
|
201
|
-
}
|
|
202
|
-
|
|
686
|
+
}
|
|
687
|
+
]);
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
### Múltiples Hojas de Cálculo
|
|
691
|
+
|
|
692
|
+
```typescript
|
|
693
|
+
const builder = new ExcelBuilder();
|
|
694
|
+
|
|
695
|
+
// Hoja 1: Resumen
|
|
696
|
+
const summarySheet = builder.addWorksheet('Resumen');
|
|
697
|
+
summarySheet.addHeader({
|
|
698
|
+
key: 'title',
|
|
699
|
+
value: 'Resumen Ejecutivo',
|
|
700
|
+
type: CellType.STRING,
|
|
701
|
+
mergeCell: true
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
// Hoja 2: Detalles
|
|
705
|
+
const detailsSheet = builder.addWorksheet('Detalles');
|
|
706
|
+
detailsSheet.addSubHeaders([
|
|
707
|
+
{ key: 'fecha', value: 'Fecha', type: CellType.DATE },
|
|
708
|
+
{ key: 'monto', value: 'Monto', type: CellType.CURRENCY }
|
|
709
|
+
]);
|
|
710
|
+
|
|
711
|
+
await builder.generateAndDownload('multi-sheet-report.xlsx');
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
### Exportación en Diferentes Formatos
|
|
715
|
+
|
|
716
|
+
```typescript
|
|
717
|
+
// Descarga directa (navegador)
|
|
718
|
+
await builder.generateAndDownload('reporte.xlsx');
|
|
719
|
+
|
|
720
|
+
// Obtener como Buffer
|
|
721
|
+
const bufferResult = await builder.toBuffer();
|
|
722
|
+
if (bufferResult.success) {
|
|
723
|
+
const buffer = bufferResult.data;
|
|
724
|
+
// Usar buffer...
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Obtener como Blob
|
|
728
|
+
const blobResult = await builder.toBlob();
|
|
729
|
+
if (blobResult.success) {
|
|
730
|
+
const blob = blobResult.data;
|
|
731
|
+
// Usar blob...
|
|
732
|
+
}
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
### Sistema de Eventos
|
|
736
|
+
|
|
737
|
+
```typescript
|
|
738
|
+
builder.on('build:started', (event) => {
|
|
739
|
+
console.log('Construcción iniciada');
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
builder.on('build:completed', (event) => {
|
|
743
|
+
console.log('Construcción completada', event.data);
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
builder.on('build:error', (event) => {
|
|
747
|
+
console.error('Error en construcción', event.data.error);
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
// Remover listener
|
|
751
|
+
const listenerId = builder.on('build:started', handler);
|
|
752
|
+
builder.off('build:started', listenerId);
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
### Leer Excel y Convertir a JSON
|
|
756
|
+
|
|
757
|
+
```typescript
|
|
758
|
+
import { ExcelReader } from 'han-excel-builder';
|
|
759
|
+
|
|
760
|
+
// Leer desde un archivo (navegador)
|
|
761
|
+
const fileInput = document.querySelector('input[type="file"]');
|
|
762
|
+
fileInput.addEventListener('change', async (e) => {
|
|
763
|
+
const file = (e.target as HTMLInputElement).files?.[0];
|
|
764
|
+
if (!file) return;
|
|
765
|
+
|
|
766
|
+
const result = await ExcelReader.fromFile(file, {
|
|
767
|
+
useFirstRowAsHeaders: true,
|
|
768
|
+
datesAsISO: true,
|
|
769
|
+
includeFormatting: false
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
if (result.success) {
|
|
773
|
+
const workbook = result.data;
|
|
774
|
+
|
|
775
|
+
// Procesar cada hoja
|
|
776
|
+
workbook.sheets.forEach(sheet => {
|
|
777
|
+
console.log(`Procesando hoja: ${sheet.name}`);
|
|
778
|
+
|
|
779
|
+
// Convertir a array de objetos (si usamos headers)
|
|
780
|
+
const data = sheet.rows.map(row => row.data || {});
|
|
781
|
+
console.log('Datos:', data);
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
// Leer desde ArrayBuffer (desde API)
|
|
787
|
+
async function readExcelFromAPI() {
|
|
788
|
+
const response = await fetch('/api/excel-file');
|
|
789
|
+
const buffer = await response.arrayBuffer();
|
|
790
|
+
|
|
791
|
+
const result = await ExcelReader.fromBuffer(buffer, {
|
|
792
|
+
useFirstRowAsHeaders: true,
|
|
793
|
+
sheetName: 'Ventas' // Leer solo la hoja 'Ventas'
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
if (result.success) {
|
|
797
|
+
const sheet = result.data.sheets[0];
|
|
798
|
+
const ventas = sheet.rows.map(row => row.data);
|
|
799
|
+
return ventas;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Leer desde ruta (Node.js)
|
|
804
|
+
async function readExcelFromPath() {
|
|
805
|
+
const result = await ExcelReader.fromPath('./reporte.xlsx', {
|
|
806
|
+
useFirstRowAsHeaders: true,
|
|
807
|
+
startRow: 2, // Saltar header
|
|
808
|
+
includeFormulas: true
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
if (result.success) {
|
|
812
|
+
console.log(`Tiempo de procesamiento: ${result.processingTime}ms`);
|
|
813
|
+
return result.data;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
203
816
|
```
|
|
204
817
|
|
|
205
818
|
## 🧪 Testing
|
|
206
819
|
|
|
207
820
|
```bash
|
|
208
|
-
#
|
|
821
|
+
# Ejecutar tests
|
|
209
822
|
npm test
|
|
210
823
|
|
|
211
|
-
#
|
|
824
|
+
# Ejecutar tests con cobertura
|
|
212
825
|
npm run test:coverage
|
|
213
826
|
|
|
214
|
-
#
|
|
827
|
+
# Ejecutar tests en modo watch
|
|
215
828
|
npm run test:watch
|
|
216
829
|
```
|
|
217
830
|
|
|
218
|
-
## 🛠️
|
|
831
|
+
## 🛠️ Desarrollo
|
|
219
832
|
|
|
220
833
|
```bash
|
|
221
|
-
#
|
|
834
|
+
# Instalar dependencias
|
|
222
835
|
npm install
|
|
223
836
|
|
|
224
|
-
#
|
|
837
|
+
# Iniciar servidor de desarrollo
|
|
225
838
|
npm run dev
|
|
226
839
|
|
|
227
|
-
#
|
|
840
|
+
# Construir para producción
|
|
228
841
|
npm run build
|
|
229
842
|
|
|
230
|
-
#
|
|
843
|
+
# Ejecutar linting
|
|
231
844
|
npm run lint
|
|
232
845
|
|
|
233
|
-
#
|
|
846
|
+
# Formatear código
|
|
234
847
|
npm run format
|
|
235
848
|
|
|
236
|
-
#
|
|
849
|
+
# Verificar tipos
|
|
850
|
+
npm run type-check
|
|
851
|
+
|
|
852
|
+
# Generar documentación
|
|
237
853
|
npm run docs
|
|
238
854
|
```
|
|
239
855
|
|
|
240
|
-
## 📋
|
|
856
|
+
## 📋 Migración desde legacy-excel
|
|
241
857
|
|
|
242
|
-
|
|
858
|
+
Si estás migrando desde la versión legacy, aquí hay una comparación rápida:
|
|
243
859
|
|
|
244
860
|
```typescript
|
|
245
|
-
//
|
|
861
|
+
// Forma legacy
|
|
246
862
|
const worksheets: IWorksheets[] = [{
|
|
247
|
-
name: "
|
|
863
|
+
name: "Reporte",
|
|
248
864
|
tables: [{
|
|
249
865
|
headers: [...],
|
|
250
866
|
subHeaders: [...],
|
|
@@ -252,35 +868,42 @@ const worksheets: IWorksheets[] = [{
|
|
|
252
868
|
footers: [...]
|
|
253
869
|
}]
|
|
254
870
|
}];
|
|
255
|
-
await fileBuilder(worksheets, "
|
|
871
|
+
await fileBuilder(worksheets, "reporte");
|
|
256
872
|
|
|
257
|
-
//
|
|
873
|
+
// Nueva forma
|
|
258
874
|
const builder = new ExcelBuilder();
|
|
259
|
-
const worksheet = builder.addWorksheet('
|
|
260
|
-
worksheet.
|
|
875
|
+
const worksheet = builder.addWorksheet('Reporte');
|
|
876
|
+
worksheet.addHeader({...});
|
|
261
877
|
worksheet.addSubHeaders([...]);
|
|
262
|
-
worksheet.
|
|
263
|
-
|
|
878
|
+
worksheet.addRow([...]);
|
|
879
|
+
worksheet.addFooter([...]);
|
|
880
|
+
await builder.generateAndDownload('reporte');
|
|
264
881
|
```
|
|
265
882
|
|
|
266
|
-
##
|
|
883
|
+
## 📚 Recursos Adicionales
|
|
884
|
+
|
|
885
|
+
- 📖 [Guía de Múltiples Tablas](./MULTIPLE-TABLES-GUIDE.md)
|
|
886
|
+
- 📖 [Mejoras Implementadas](./IMPROVEMENTS.md)
|
|
887
|
+
- 📖 [Resultados de Pruebas](./TEST-RESULTS.md)
|
|
888
|
+
|
|
889
|
+
## 🤝 Contribuir
|
|
267
890
|
|
|
268
|
-
1. Fork
|
|
269
|
-
2.
|
|
270
|
-
3. Commit
|
|
271
|
-
4. Push
|
|
272
|
-
5.
|
|
891
|
+
1. Fork el repositorio
|
|
892
|
+
2. Crea una rama de feature (`git checkout -b feature/mi-caracteristica`)
|
|
893
|
+
3. Commit tus cambios (`git commit -m 'Agregar mi característica'`)
|
|
894
|
+
4. Push a la rama (`git push origin feature/mi-caracteristica`)
|
|
895
|
+
5. Abre un Pull Request
|
|
273
896
|
|
|
274
|
-
## 📄
|
|
897
|
+
## 📄 Licencia
|
|
275
898
|
|
|
276
|
-
|
|
899
|
+
Este proyecto está licenciado bajo la Licencia MIT - ver el archivo [LICENSE](LICENSE) para más detalles.
|
|
277
900
|
|
|
278
|
-
## 🆘
|
|
901
|
+
## 🆘 Soporte
|
|
279
902
|
|
|
280
|
-
- 📖 [
|
|
281
|
-
- 🐛 [Issues](https://github.com/
|
|
282
|
-
- 💬 [Discussions](https://github.com/
|
|
903
|
+
- 📖 [Documentación](https://github.com/hannndler/-han-excel)
|
|
904
|
+
- 🐛 [Issues](https://github.com/hannndler/-han-excel/issues)
|
|
905
|
+
- 💬 [Discussions](https://github.com/hannndler/-han-excel/discussions)
|
|
283
906
|
|
|
284
907
|
---
|
|
285
908
|
|
|
286
|
-
|
|
909
|
+
Hecho con ❤️ por el equipo de Han Excel
|