nexabase-report 0.25.8 → 0.26.2
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/dist/{generated-DCQvzm6K.js → generated-DbO5fAwh.js} +20 -1
- package/dist/{html2pdf-DYT7GcOl.js → html2pdf-lo0OPMZo.js} +2 -2
- package/dist/{index-D73aFRdr.js → index-DRt8rzWp.js} +37154 -36401
- package/dist/{index.es-9JJkFWTH.js → index.es-CyMPKR8v.js} +2 -2
- package/dist/{jspdf.es.min-BoaSMJVw.js → jspdf.es.min-BUwNnbu8.js} +1 -1
- package/dist/lib/styles/_designer.css +89 -0
- package/dist/nexabase-report.es.js +1 -1
- package/dist/nexabase-report.umd.js +284 -265
- package/dist/{pptxgen.es-BQmRTWxX.js → pptxgen.es-DD01xTKF.js} +1 -1
- package/docs/guide/crosstab.md +157 -0
- package/docs/guide/subreport-tabs.md +166 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as rt, d as $t } from "./index-
|
|
1
|
+
import { c as rt, d as $t } from "./index-DRt8rzWp.js";
|
|
2
2
|
function nt(e) {
|
|
3
3
|
throw new Error('Could not dynamically require "' + e + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
|
|
4
4
|
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Crosstab (Tabla Dinámica)
|
|
2
|
+
|
|
3
|
+
El Crosstab permite crear **tablas con crecimiento horizontal**, similares a las matrices de Crystal Reports o las pivot tables de Excel. Las columnas se generan dinámicalemente desde los datos, mientras que las filas se definen en diseño.
|
|
4
|
+
|
|
5
|
+
## Concepto
|
|
6
|
+
|
|
7
|
+
Un Crosstab pivotea datos de filas a columnas:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Datos de entrada: Crosstab resultante:
|
|
11
|
+
┌──────────┬────────┬───────┐ ┌──────────┬────────┬────────┬────────┬───────┐
|
|
12
|
+
│ Producto │ Mes │ Venta │ │ Producto │ Ene │ Feb │ Mar │ Total │
|
|
13
|
+
├──────────┼────────┼───────┤ ├──────────┼────────┼────────┼────────┼───────┤
|
|
14
|
+
│ Laptop │ Ene │ 1000 │ ──► │ Laptop │ 1000 │ 1200 │ 950 │ 3150 │
|
|
15
|
+
│ Laptop │ Feb │ 1200 │ │ Mouse │ 200 │ 300 │ 250 │ 750 │
|
|
16
|
+
│ Laptop │ Mar │ 950 │ │ Teclado │ 150 │ 180 │ 120 │ 450 │
|
|
17
|
+
│ Mouse │ Ene │ 200 │ └──────────┴────────┴────────┴────────┴───────┘
|
|
18
|
+
│ Mouse │ Feb │ 300 │
|
|
19
|
+
│ Mouse │ Mar │ 250 │
|
|
20
|
+
│ Teclado │ Ene │ 150 │
|
|
21
|
+
│ Teclado │ Feb │ 180 │
|
|
22
|
+
│ Teclado │ Mar │ 120 │
|
|
23
|
+
└──────────┴────────┴───────┘
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Configuración en el Diseñador
|
|
27
|
+
|
|
28
|
+
### Campos de Fila (Row Fields)
|
|
29
|
+
Definen las filas del Crosstab. Puedes agregar múltiples campos para filas jerárquicas.
|
|
30
|
+
|
|
31
|
+
| Campo | Descripción |
|
|
32
|
+
|-------|-------------|
|
|
33
|
+
| **Label** | Nombre que aparece como encabezado de la columna de fila |
|
|
34
|
+
| **Binding** | Campo del dataSource que contiene el valor de la fila |
|
|
35
|
+
|
|
36
|
+
### Campo de Columna (Column Field)
|
|
37
|
+
El campo cuyos valores únicos se convierten en columnas del Crosstab. En el ejemplo anterior, `Mes` es el campo de columna.
|
|
38
|
+
|
|
39
|
+
### Campos de Valor (Value Fields)
|
|
40
|
+
Las métricas que se calculan en cada celda. Cada valor tiene:
|
|
41
|
+
|
|
42
|
+
| Campo | Descripción |
|
|
43
|
+
|-------|-------------|
|
|
44
|
+
| **Label** | Nombre de la métrica |
|
|
45
|
+
| **Binding** | Campo numérico a agregar |
|
|
46
|
+
| **Aggregation** | Función de agregación: `sum`, `count`, `avg`, `min`, `max`, `first`, `last` |
|
|
47
|
+
| **Format** | Patrón de formato (ej: `$#,##0.00`, `#,##0`, `0.00%`) |
|
|
48
|
+
|
|
49
|
+
### Totales
|
|
50
|
+
- **Mostrar Totales de Fila**: Agrega una columna "Total" al final de cada fila
|
|
51
|
+
- **Mostrar Gran Total**: Agrega una fila de totales al final
|
|
52
|
+
- **Etiqueta de Total**: Texto de la columna/fila de totales (default: "Total")
|
|
53
|
+
|
|
54
|
+
### Diseño (Layout)
|
|
55
|
+
- **Permitir salto de página**: Si el Crosstab es muy grande, se divide en múltiples páginas
|
|
56
|
+
|
|
57
|
+
## Estilo del Crosstab
|
|
58
|
+
|
|
59
|
+
El Crosstab soporta estilos personalizados:
|
|
60
|
+
|
|
61
|
+
| Propiedad | Default | Descripción |
|
|
62
|
+
|-----------|---------|-------------|
|
|
63
|
+
| `headerBackground` | `#f3f4f6` | Fondo de la fila de encabezados de columna |
|
|
64
|
+
| `headerColor` | `#111827` | Color de texto de encabezados de columna |
|
|
65
|
+
| `headerBold` | `true` | Encabezados en negrita |
|
|
66
|
+
| `rowHeaderBackground` | `#fafafa` | Fondo de las celdas de encabezado de fila |
|
|
67
|
+
| `rowHeaderColor` | `#111827` | Color de texto de encabezados de fila |
|
|
68
|
+
| `rowHeaderBold` | `true` | Encabezados de fila en negrita |
|
|
69
|
+
| `alternateRows` | `true` | Filas con colores alternados (zebra) |
|
|
70
|
+
| `alternateRowBackground` | `#f9fafb` | Color de filas alternas |
|
|
71
|
+
| `borderColor` | `#d1d5db` | Color de bordes |
|
|
72
|
+
| `borderWidth` | `1` | Ancho de borde en px |
|
|
73
|
+
| `totalsBackground` | `#e8f4fd` | Fondo de celdas de total |
|
|
74
|
+
| `totalsColor` | `#111827` | Color de texto de totales |
|
|
75
|
+
| `totalsBold` | `true` | Totales en negrita |
|
|
76
|
+
| `grandTotalBackground` | `#dbeafe` | Fondo de la fila de gran total |
|
|
77
|
+
|
|
78
|
+
## Ejemplo Completo
|
|
79
|
+
|
|
80
|
+
### Datos de entrada
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"ventas": [
|
|
85
|
+
{ "producto": "Laptop", "region": "Norte", "mes": "Ene", "cantidad": 10, "precio": 100 },
|
|
86
|
+
{ "producto": "Laptop", "region": "Norte", "mes": "Feb", "cantidad": 12, "precio": 100 },
|
|
87
|
+
{ "producto": "Laptop", "region": "Sur", "mes": "Ene", "cantidad": 5, "precio": 100 },
|
|
88
|
+
{ "producto": "Mouse", "region": "Norte", "mes": "Ene", "cantidad": 20, "precio": 15 },
|
|
89
|
+
{ "producto": "Mouse", "region": "Sur", "mes": "Feb", "cantidad": 25, "precio": 15 }
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Configuración del Crosstab
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"type": "Crosstab",
|
|
99
|
+
"x": 0, "y": 0, "width": 600, "height": 200,
|
|
100
|
+
"crosstabConfig": {
|
|
101
|
+
"rowFields": [
|
|
102
|
+
{ "binding": "producto", "label": "Producto" },
|
|
103
|
+
{ "binding": "region", "label": "Región" }
|
|
104
|
+
],
|
|
105
|
+
"columnField": "mes",
|
|
106
|
+
"valueFields": [
|
|
107
|
+
{ "binding": "cantidad", "label": "Unidades", "aggregation": "sum", "format": "#,##0" },
|
|
108
|
+
{ "binding": "precio", "label": "Precio Total", "aggregation": "sum", "format": "$#,##0.00" }
|
|
109
|
+
],
|
|
110
|
+
"showTotals": true,
|
|
111
|
+
"showGrandTotals": true,
|
|
112
|
+
"totalsLabel": "Total",
|
|
113
|
+
"dataSource": "ventas"
|
|
114
|
+
},
|
|
115
|
+
"crosstabStyle": {
|
|
116
|
+
"headerBackground": "#1e40af",
|
|
117
|
+
"headerColor": "#ffffff",
|
|
118
|
+
"alternateRows": true,
|
|
119
|
+
"totalsBackground": "#dbeafe"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Resultado
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
┌──────────┬──────────┬─────────────────┬─────────────────┬─────────────────┬─────────────────┐
|
|
128
|
+
│ Producto │ Región │ Ene │ Feb │ Total │ │
|
|
129
|
+
│ │ │ Unid. │ Precio │ Unid. │ Precio │ Unid. │ Precio │ │
|
|
130
|
+
├──────────┼──────────┼───────┼─────────┼───────┼─────────┼───────┼─────────┤─────────────────┤
|
|
131
|
+
│ Laptop │ Norte │ 10 │ $1,000 │ 12 │ $1,200 │ 22 │ $2,200 │ │
|
|
132
|
+
│ Laptop │ Sur │ 5 │ $500 │ - │ - │ 5 │ $500 │ │
|
|
133
|
+
│ Mouse │ Norte │ 20 │ $300 │ - │ - │ 20 │ $300 │ │
|
|
134
|
+
│ Mouse │ Sur │ - │ - │ 25 │ $375 │ 25 │ $375 │ │
|
|
135
|
+
├──────────┼──────────┼───────┼─────────┼───────┼─────────┼───────┼─────────┤─────────────────┤
|
|
136
|
+
│ TOTAL │ │ 35 │ $1,800 │ 37 │ $1,575 │ 72 │ $3,375 │ │
|
|
137
|
+
└──────────┴──────────┴───────┴─────────┴───────┴─────────┴───────┴─────────┴─────────────────┘
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Exportación
|
|
141
|
+
|
|
142
|
+
El Crosstab se exporta correctamente a todos los formatos:
|
|
143
|
+
|
|
144
|
+
- **PDF**: Renderizado vectorial con jsPDF, incluyendo estilos, totales y bordes
|
|
145
|
+
- **Excel**: pivotea los datos como una hoja separada en el workbook
|
|
146
|
+
- **CSV**: Datos planos con encabezados pivotados
|
|
147
|
+
- **Word**: Tabla docx con encabezados en negrita y filas de datos
|
|
148
|
+
|
|
149
|
+
## Crecimiento Horizontal vs Vertical
|
|
150
|
+
|
|
151
|
+
| Aspecto | Tabla Normal | Crosstab |
|
|
152
|
+
|---------|-------------|----------|
|
|
153
|
+
| **Columnas** | Fijas en diseño | Dinámicas (según datos) |
|
|
154
|
+
| **Filas** | Crecen verticalmente | Definidas por rowFields |
|
|
155
|
+
| **Agregación** | Manual (footer expressions) | Automática por celda |
|
|
156
|
+
| **Uso ideal** | Listados detallados | Resúmenes pivoteados |
|
|
157
|
+
| **Ejemplo** | Lista de facturas | Ventas por producto × mes |
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# SubReportes con Pestañas
|
|
2
|
+
|
|
3
|
+
NexaDesigner permite abrir y editar SubReportes en **pestañas separadas**, similar a cómo funcionan las pestañas en un navegador o en IDEs como VS Code.
|
|
4
|
+
|
|
5
|
+
## Concepto
|
|
6
|
+
|
|
7
|
+
Un SubReporte es un reporte embebido dentro de otro reporte padre. Con el sistema de pestañas, puedes:
|
|
8
|
+
|
|
9
|
+
1. **Abrir** un SubReporte en una nueva pestaña para editarlo cómodamente
|
|
10
|
+
2. **Editar** el SubReporte de forma independiente (diseño, bandas, elementos)
|
|
11
|
+
3. **Guardar** los cambios y que se reflejen automáticamente en el reporte padre
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
┌─────────────────────────────────────────────────────────┐
|
|
15
|
+
│ [📁 Reporte Principal] [📄 Historial de Ventas] [×] │ ← Pestañas
|
|
16
|
+
├─────────────────────────────────────────────────────────┤
|
|
17
|
+
│ │
|
|
18
|
+
│ ┌───────────────────────────────────────────────────┐ │
|
|
19
|
+
│ │ │ │
|
|
20
|
+
│ │ Canvas del reporte activo │ │
|
|
21
|
+
│ │ │ │
|
|
22
|
+
│ └───────────────────────────────────────────────────┘ │
|
|
23
|
+
│ │
|
|
24
|
+
└─────────────────────────────────────────────────────────┘
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Cómo Usar
|
|
28
|
+
|
|
29
|
+
### 1. Crear un SubReporte
|
|
30
|
+
|
|
31
|
+
1. Selecciona **SubReport** en la toolbox (Insert → SubReport)
|
|
32
|
+
2. Arrastra al canvas en la posición deseada
|
|
33
|
+
3. En el panel de propiedades, carga el reporte:
|
|
34
|
+
- **Desde NexaBase**: Selecciona un reporte guardado en el dropdown
|
|
35
|
+
- **Desde archivo JSON**: Carga un archivo `.json` exportado
|
|
36
|
+
|
|
37
|
+
### 2. Abrir en Pestaña
|
|
38
|
+
|
|
39
|
+
Una vez que el SubReporte tiene una definición cargada:
|
|
40
|
+
|
|
41
|
+
1. Selecciona el elemento SubReport en el canvas
|
|
42
|
+
2. En el panel de propiedades, haz clic en **"Abrir en pestaña"**
|
|
43
|
+
3. Se abre una nueva pestaña con el contenido del SubReporte
|
|
44
|
+
|
|
45
|
+
### 3. Editar
|
|
46
|
+
|
|
47
|
+
La pestaña del SubReporte funciona igual que el diseñador principal:
|
|
48
|
+
- Agrega/elimina bandas (ReportHeader, DataBand, PageFooter, etc.)
|
|
49
|
+
- Arrastra elementos desde la toolbox
|
|
50
|
+
- Configura propiedades en el panel lateral
|
|
51
|
+
- Usa el mismo motor de expresiones y binding
|
|
52
|
+
|
|
53
|
+
### 4. Guardar
|
|
54
|
+
|
|
55
|
+
Al guardar el reporte padre (NexaBase o JSON):
|
|
56
|
+
- Los cambios en la pestaña del SubReporte se **sincronizan automáticamente** al elemento SubReport dentro del padre
|
|
57
|
+
- No necesitas copiar/pegar manualmente
|
|
58
|
+
- El guardado es atómico: padre + todos los SubReportes abiertos
|
|
59
|
+
|
|
60
|
+
## Indicadores de Estado
|
|
61
|
+
|
|
62
|
+
### Pestaña Activa
|
|
63
|
+
- **Borde superior azul**: indica cuál pestaña estás viendo
|
|
64
|
+
- **Negrita**: el reporte activo
|
|
65
|
+
|
|
66
|
+
### Cambios Pendientes
|
|
67
|
+
- **Punto naranja (●)**: la pestaña tiene cambios sin guardar
|
|
68
|
+
- Aparece automáticamente cuando editas algo en el SubReporte
|
|
69
|
+
|
|
70
|
+
### Cerrar Pestaña
|
|
71
|
+
- **Botón ×**: cierra la pestaña del SubReporte
|
|
72
|
+
- **No puedes cerrar** la pestaña principal (siempre está abierta)
|
|
73
|
+
- Al cerrar, los cambios no guardados se pierden
|
|
74
|
+
|
|
75
|
+
## Arquitectura
|
|
76
|
+
|
|
77
|
+
### Modelo de Datos
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
NexaReportDefinition
|
|
81
|
+
├── layout.bands[]
|
|
82
|
+
│ ├── Band1.elements[]
|
|
83
|
+
│ │ ├── SubReport (element)
|
|
84
|
+
│ │ │ ├── subReportId: "report_123" ← ID de NexaBase (diseño)
|
|
85
|
+
│ │ │ ├── subReportDefinition: {...} ← Definición inline (render)
|
|
86
|
+
│ │ │ ├── subReportDataSource: "historico" ← Alias del dataSource padre
|
|
87
|
+
│ │ │ └── subReportBindings: [...] ← Filtros master/child
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Flujo de Sincronización
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
┌─────────────┐ openSubReportTab() ┌─────────────┐
|
|
94
|
+
│ Reporte │ ──────────────────────────► │ Pestaña │
|
|
95
|
+
│ Padre │ │ SubReporte │
|
|
96
|
+
│ │ ◄────────────────────────── │ │
|
|
97
|
+
│ (main) │ syncSubReportToParent() │ (sub_xxx) │
|
|
98
|
+
└─────────────┘ └─────────────┘
|
|
99
|
+
│ │
|
|
100
|
+
│ handleSave() │ Editar
|
|
101
|
+
▼ ▼
|
|
102
|
+
┌─────────────┐ ┌─────────────┐
|
|
103
|
+
│ NexaBase │ │ Canvas │
|
|
104
|
+
│ (guarda) │ │ WYSIWYG │
|
|
105
|
+
└─────────────┘ └─────────────┘
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Sincronización
|
|
109
|
+
|
|
110
|
+
Cuando guardas el reporte padre:
|
|
111
|
+
|
|
112
|
+
1. **Recorre todas las pestañas** abiertas
|
|
113
|
+
2. Para cada SubReporte, busca el elemento `SubReport` correspondiente en el padre
|
|
114
|
+
3. **Actualiza** `subReportDefinition` con la definición actual de la pestaña
|
|
115
|
+
4. **Guarda** el reporte padre completo (incluyendo todas las definiciones de SubReportes)
|
|
116
|
+
|
|
117
|
+
## Ejemplo: Reporte con SubReporte de Historial
|
|
118
|
+
|
|
119
|
+
### Estructura
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
Reporte Principal (Factura)
|
|
123
|
+
├── ReportHeader
|
|
124
|
+
│ ├── Text: "FACTURA #{{numero}}"
|
|
125
|
+
│ ├── Text: "Fecha: {{fecha}}"
|
|
126
|
+
│ └── Image: Logo empresa
|
|
127
|
+
├── DataBand (dataSource: "clientes")
|
|
128
|
+
│ ├── Text: "Cliente: {{nombre}}"
|
|
129
|
+
│ ├── Text: "Email: {{email}}"
|
|
130
|
+
│ └── SubReport (y: 200)
|
|
131
|
+
│ ├── subReportDataSource: "historico"
|
|
132
|
+
│ ├── subReportBindings: [{ masterField: "cliente_id", childField: "cliente_id" }]
|
|
133
|
+
│ └── subReportDefinition: { ... } ← Se edita en pestaña separada
|
|
134
|
+
└── PageFooter
|
|
135
|
+
└── Text: "Página {{Page}} de {{TotalPages}}"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### SubReporte (Historial de Ventas)
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
SubReport: Historial de Ventas
|
|
142
|
+
├── ReportHeader
|
|
143
|
+
│ └── Text: "Historial de Compras"
|
|
144
|
+
├── DataBand (dataSource: "historico") ← Recibe datos filtrados del padre
|
|
145
|
+
│ └── Table
|
|
146
|
+
│ ├── Column: Fecha ({{fecha}})
|
|
147
|
+
│ ├── Column: Producto ({{producto}})
|
|
148
|
+
│ ├── Column: Cantidad ({{cantidad}})
|
|
149
|
+
│ └── Column: Total ({{total}})
|
|
150
|
+
└── PageFooter
|
|
151
|
+
└── Text: "{{RowNumber}} de {{TotalRows}}"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Limitaciones
|
|
155
|
+
|
|
156
|
+
1. **Una sola nivel de anidación**: Un SubReporte no puede contener otro SubReporte
|
|
157
|
+
2. **Pestaña = copia**: Al abrir en pestaña, se crea una **copia independiente**. Si alguien más edita el mismo reporte, no se sincroniza en tiempo real
|
|
158
|
+
3. **Cierre sin guardar**: Al cerrar una pestaña con cambios sin guardar, los cambios se pierden
|
|
159
|
+
4. **Sin preview en vivo**: Los cambios en la pestaña del SubReporte no se reflejan en el canvas del padre hasta que guardes
|
|
160
|
+
|
|
161
|
+
## Mejores Prácticas
|
|
162
|
+
|
|
163
|
+
1. **Nombra tus SubReportes**: Usa nombres descriptivos en `metadata.name` para que las pestañas sean identificables
|
|
164
|
+
2. **Guarda frecuentemente**: Usa Ctrl+S o el botón Guardar para sincronizar cambios
|
|
165
|
+
3. **Cierra pestañas innecesarias**: Reduce la complejidad visual cerrando pestañas que no estás editando
|
|
166
|
+
4. **Usa dataSources separados**: Cada SubReporte debe tener su propio dataSource o usar el filtrado del padre
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexabase-report",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.2",
|
|
4
4
|
"description": "Professional report designer and viewer for NexaBase — drag & drop designer, PDF/Excel export, charts, crosstabs, subreports.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "NexaBase Team",
|