nexabase-report 0.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 +106 -0
- package/dist/browser-lud4wlfC.js +1473 -0
- package/dist/favicon.svg +1 -0
- package/dist/html2canvas-BXLDsEU4.js +26 -0
- package/dist/html2canvas-CSJ68r_Q.js +4877 -0
- package/dist/html2pdf-DwP6YZUu.js +4242 -0
- package/dist/icons.svg +24 -0
- package/dist/index-BJcVIdAR.js +82960 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.es-CLzdqdqQ.js +5646 -0
- package/dist/jspdf.es.min-CDx0J4wI.js +8109 -0
- package/dist/nexabase-report.es.js +7 -0
- package/dist/nexabase-report.umd.js +513 -0
- package/dist/purify.es-Bo7Q7b72.js +471 -0
- package/dist/style.css +1723 -0
- package/docs/API_REST.md +376 -0
- package/docs/EXPORT_REGRESSION.md +54 -0
- package/docs/EXTERNAL_INTEGRATION.md +211 -0
- package/docs/PUBLISHING.md +304 -0
- package/docs/QA_PLAN.md +138 -0
- package/docs/VIEWER_API.md +288 -0
- package/examples/report-agrupado-por-cliente.json +186 -0
- package/examples/report-codigos-qr-barcode.json +178 -0
- package/examples/report-crosstab-categoria-mes.json +123 -0
- package/examples/report-factura.json +287 -0
- package/examples/report-grafico-ventas-por-mes.json +127 -0
- package/examples/report-master-detail-ordenes.json +215 -0
- package/examples/report-productos.json +160 -0
- package/examples/report-ventas-logo-tabla.json +154 -0
- package/package.json +88 -0
package/docs/API_REST.md
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
# NexaBase Report - API REST
|
|
2
|
+
|
|
3
|
+
Guía de despliegue y uso de la API REST del reporteador.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📡 Endpoints Disponibles
|
|
8
|
+
|
|
9
|
+
| Método | Endpoint | Descripción |
|
|
10
|
+
|--------|----------|-------------|
|
|
11
|
+
| `GET` | `/api/reports` | Listar todos los reportes guardados |
|
|
12
|
+
| `GET` | `/api/reports/:id` | Obtener definición completa de un reporte |
|
|
13
|
+
| `POST` | `/api/reports/:id/render` | Renderizar reporte con datos y parámetros |
|
|
14
|
+
| `POST` | `/api/reports/:id/export/pdf` | Preparar exportación a PDF |
|
|
15
|
+
| `POST` | `/api/reports/:id/export/excel` | Preparar exportación a Excel |
|
|
16
|
+
| `POST` | `/api/reports/:id/export/csv` | Preparar exportación a CSV |
|
|
17
|
+
| `POST` | `/api/reports/:id/export/word` | Preparar exportación a Word (.docx) |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 🔐 Autenticación
|
|
22
|
+
|
|
23
|
+
Todos los endpoints requieren autenticación vía API Key:
|
|
24
|
+
|
|
25
|
+
### Opción 1: Header dedicado
|
|
26
|
+
```
|
|
27
|
+
X-API-Key: nb_sk_tu_api_key_aqui
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Opción 2: Bearer token
|
|
31
|
+
```
|
|
32
|
+
Authorization: Bearer nb_sk_tu_api_key_aqui
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 📋 Ejemplos de Uso
|
|
38
|
+
|
|
39
|
+
### 1. Listar Reportes
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
curl -X GET "https://tu-nexabase.url/api/reports" \
|
|
43
|
+
-H "X-API-Key: nb_sk_tu_api_key"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Respuesta:**
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"success": true,
|
|
50
|
+
"count": 3,
|
|
51
|
+
"reports": [
|
|
52
|
+
{
|
|
53
|
+
"id": "abc123",
|
|
54
|
+
"name": "Ventas Mensuales",
|
|
55
|
+
"description": "Reporte de ventas del mes",
|
|
56
|
+
"author": "Admin",
|
|
57
|
+
"createdAt": "2024-01-15T10:00:00.000Z",
|
|
58
|
+
"updatedAt": "2024-01-20T14:30:00.000Z"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### 2. Obtener Definición de Reporte
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
curl -X GET "https://tu-nexabase.url/api/reports/abc123" \
|
|
70
|
+
-H "X-API-Key: nb_sk_tu_api_key"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Respuesta:**
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"success": true,
|
|
77
|
+
"report": {
|
|
78
|
+
"id": "abc123",
|
|
79
|
+
"metadata": {
|
|
80
|
+
"version": "1.0",
|
|
81
|
+
"name": "Ventas Mensuales",
|
|
82
|
+
"author": "Admin",
|
|
83
|
+
"createdAt": "2024-01-15T10:00:00.000Z"
|
|
84
|
+
},
|
|
85
|
+
"layout": { ... },
|
|
86
|
+
"dataSources": [ ... ]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### 3. Renderizar Reporte con Parámetros
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
curl -X POST "https://tu-nexabase.url/api/reports/abc123/render" \
|
|
97
|
+
-H "X-API-Key: nb_sk_tu_api_key" \
|
|
98
|
+
-H "Content-Type: application/json" \
|
|
99
|
+
-d '{
|
|
100
|
+
"parameters": {
|
|
101
|
+
"fecha_inicio": "2024-01-01",
|
|
102
|
+
"fecha_fin": "2024-01-31"
|
|
103
|
+
},
|
|
104
|
+
"limit": 500
|
|
105
|
+
}'
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Respuesta:**
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"success": true,
|
|
112
|
+
"report": { ... },
|
|
113
|
+
"parameters": {
|
|
114
|
+
"fecha_inicio": "2024-01-01",
|
|
115
|
+
"fecha_fin": "2024-01-31"
|
|
116
|
+
},
|
|
117
|
+
"data": {
|
|
118
|
+
"main": [ ... ],
|
|
119
|
+
"detalle": [ ... ]
|
|
120
|
+
},
|
|
121
|
+
"metadata": {
|
|
122
|
+
"renderedAt": "2024-01-20T15:00:00.000Z",
|
|
123
|
+
"dataSources": 2,
|
|
124
|
+
"bands": 5
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### 4. Exportar a PDF
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
curl -X POST "https://tu-nexabase.url/api/reports/abc123/export/pdf" \
|
|
135
|
+
-H "X-API-Key: nb_sk_tu_api_key" \
|
|
136
|
+
-H "Content-Type: application/json" \
|
|
137
|
+
-d '{
|
|
138
|
+
"parameters": {
|
|
139
|
+
"fecha_inicio": "2024-01-01"
|
|
140
|
+
},
|
|
141
|
+
"limit": 1000
|
|
142
|
+
}'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Respuesta:**
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"success": true,
|
|
149
|
+
"format": "pdf",
|
|
150
|
+
"filename": "Ventas_Mensuales.pdf",
|
|
151
|
+
"report": { ... },
|
|
152
|
+
"data": { ... },
|
|
153
|
+
"parameters": { ... },
|
|
154
|
+
"exportedAt": "2024-01-20T15:00:00.000Z",
|
|
155
|
+
"note": "Para exportación completa de PDF, use el cliente con los datos devueltos"
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 🚀 Despliegue en NexaBase
|
|
162
|
+
|
|
163
|
+
### Opción 1: Usando MCP (Recomendado)
|
|
164
|
+
|
|
165
|
+
Ejecuta en Qwen Code:
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
mcp__nexabase__create_function({
|
|
169
|
+
name: "report-api",
|
|
170
|
+
code: "<contenido de src/functions/report-api.ts>",
|
|
171
|
+
trigger: "http",
|
|
172
|
+
config: {
|
|
173
|
+
path: "/api/reports/*",
|
|
174
|
+
httpMethod: ["GET", "POST", "OPTIONS"],
|
|
175
|
+
memoryLimit: 256,
|
|
176
|
+
timeout: 60
|
|
177
|
+
},
|
|
178
|
+
environment: {
|
|
179
|
+
"NEXABASE_URL": "https://api.nexabase.online",
|
|
180
|
+
"NEXABASE_API_KEY": "nb_sk_tu_api_key"
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Opción 2: Usando NexaBase Dashboard
|
|
186
|
+
|
|
187
|
+
1. Ve a **Functions** → **Nueva Función**
|
|
188
|
+
2. Nombre: `report-api`
|
|
189
|
+
3. Runtime: `typescript`
|
|
190
|
+
4. Trigger: `http`
|
|
191
|
+
5. Path: `/api/reports/*`
|
|
192
|
+
6. Pega el código de `src/functions/report-api.ts`
|
|
193
|
+
7. Agrega variables de entorno:
|
|
194
|
+
- `NEXABASE_URL`
|
|
195
|
+
- `NEXABASE_API_KEY`
|
|
196
|
+
8. Despliega
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 🔧 Uso desde Cliente (Ejemplo)
|
|
201
|
+
|
|
202
|
+
### JavaScript/TypeScript
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const API_URL = 'https://tu-nexabase.url';
|
|
206
|
+
const API_KEY = 'nb_sk_tu_api_key';
|
|
207
|
+
|
|
208
|
+
// Listar reportes
|
|
209
|
+
async function listReports() {
|
|
210
|
+
const res = await fetch(`${API_URL}/api/reports`, {
|
|
211
|
+
headers: { 'X-API-Key': API_KEY }
|
|
212
|
+
});
|
|
213
|
+
return res.json();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Renderizar reporte
|
|
217
|
+
async function renderReport(id: string, params: Record<string, any>) {
|
|
218
|
+
const res = await fetch(`${API_URL}/api/reports/${id}/render`, {
|
|
219
|
+
method: 'POST',
|
|
220
|
+
headers: {
|
|
221
|
+
'X-API-Key': API_KEY,
|
|
222
|
+
'Content-Type': 'application/json'
|
|
223
|
+
},
|
|
224
|
+
body: JSON.stringify({ parameters: params })
|
|
225
|
+
});
|
|
226
|
+
return res.json();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Exportar a PDF (requiere html2pdf.js en cliente)
|
|
230
|
+
async function exportPdf(reportDef: any, data: any) {
|
|
231
|
+
// 1. Obtener datos renderizados
|
|
232
|
+
const rendered = await renderReport(reportDef.id, {});
|
|
233
|
+
|
|
234
|
+
// 2. Usar nexabase-report viewer para exportar
|
|
235
|
+
import { registerNexaReport } from 'nexabase-report';
|
|
236
|
+
registerNexaReport();
|
|
237
|
+
|
|
238
|
+
// 3. Crear elemento viewer y llamar exportPdf
|
|
239
|
+
const viewer = document.createElement('nexa-viewer');
|
|
240
|
+
viewer.report = rendered.report;
|
|
241
|
+
viewer.data = rendered.data;
|
|
242
|
+
document.body.appendChild(viewer);
|
|
243
|
+
|
|
244
|
+
// 4. Esperar render y exportar
|
|
245
|
+
await viewer.exportPdf();
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
### Python
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
import requests
|
|
255
|
+
|
|
256
|
+
API_URL = "https://tu-nexabase.url"
|
|
257
|
+
API_KEY = "nb_sk_tu_api_key"
|
|
258
|
+
|
|
259
|
+
def list_reports():
|
|
260
|
+
res = requests.get(
|
|
261
|
+
f"{API_URL}/api/reports",
|
|
262
|
+
headers={"X-API-Key": API_KEY}
|
|
263
|
+
)
|
|
264
|
+
return res.json()
|
|
265
|
+
|
|
266
|
+
def render_report(report_id: str, params: dict = None):
|
|
267
|
+
res = requests.post(
|
|
268
|
+
f"{API_URL}/api/reports/{report_id}/render",
|
|
269
|
+
headers={
|
|
270
|
+
"X-API-Key": API_KEY,
|
|
271
|
+
"Content-Type": "application/json"
|
|
272
|
+
},
|
|
273
|
+
json={"parameters": params or {}}
|
|
274
|
+
)
|
|
275
|
+
return res.json()
|
|
276
|
+
|
|
277
|
+
# Ejemplo
|
|
278
|
+
reports = list_reports()
|
|
279
|
+
print(f"Encontrados {reports['count']} reportes")
|
|
280
|
+
|
|
281
|
+
data = render_report("abc123", {"fecha": "2024-01-01"})
|
|
282
|
+
print(f"Reporte renderizado con {len(data['data']['main'])} registros")
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## ⚠️ Notas Importantes
|
|
288
|
+
|
|
289
|
+
### Exportación PDF/Excel/Word
|
|
290
|
+
|
|
291
|
+
La API REST **prepara los datos** para exportación pero la generación final del archivo requiere ejecución en cliente (browser) debido a:
|
|
292
|
+
|
|
293
|
+
- **PDF**: Usa `html2pdf.js` que requiere DOM del navegador
|
|
294
|
+
- **Excel**: Usa `xlsx` (SheetJS) que funciona en cliente
|
|
295
|
+
- **Word**: Usa `docx` que genera archivo en memoria del cliente
|
|
296
|
+
|
|
297
|
+
**Flujo recomendado:**
|
|
298
|
+
|
|
299
|
+
1. Cliente llama `POST /api/reports/:id/export/pdf`
|
|
300
|
+
2. API devuelve `{ report, data, parameters }`
|
|
301
|
+
3. Cliente crea elemento `<nexa-viewer>` con los datos
|
|
302
|
+
4. Cliente llama `viewer.exportPdf()` (ejecuta html2pdf.js)
|
|
303
|
+
5. Archivo se descarga automáticamente
|
|
304
|
+
|
|
305
|
+
### Límites
|
|
306
|
+
|
|
307
|
+
- **Timeout**: 60 segundos (configurable en función)
|
|
308
|
+
- **Memoria**: 256MB recomendado
|
|
309
|
+
- **Registros por defecto**: 1000 (configurable con `limit`)
|
|
310
|
+
|
|
311
|
+
### CORS
|
|
312
|
+
|
|
313
|
+
Todos los endpoints incluyen headers CORS:
|
|
314
|
+
```
|
|
315
|
+
Access-Control-Allow-Origin: *
|
|
316
|
+
Access-Control-Allow-Methods: GET, POST, OPTIONS
|
|
317
|
+
Access-Control-Allow-Headers: Content-Type, Authorization, X-API-Key
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## 📊 Códigos de Error
|
|
323
|
+
|
|
324
|
+
| Código | Significado |
|
|
325
|
+
|--------|-------------|
|
|
326
|
+
| `200` | Éxito |
|
|
327
|
+
| `404` | Reporte no encontrado |
|
|
328
|
+
| `500` | Error interno del servidor |
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## 🔄 Migración de Funciones Existentes
|
|
333
|
+
|
|
334
|
+
Si ya tienes una función serverless en NexaBase, actualiza con:
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
mcp__nexabase__update_function({
|
|
338
|
+
functionId: "report-api",
|
|
339
|
+
code: "<nuevo código>"
|
|
340
|
+
})
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## 🛡️ Seguridad
|
|
346
|
+
|
|
347
|
+
### Mejores Prácticas
|
|
348
|
+
|
|
349
|
+
1. **No expongas API Keys en cliente frontend**
|
|
350
|
+
2. Usa **CORS restringido** para producción:
|
|
351
|
+
```
|
|
352
|
+
Access-Control-Allow-Origin: https://tu-dominio.com
|
|
353
|
+
```
|
|
354
|
+
3. **Rate limiting**: Configura en NexaBase dashboard
|
|
355
|
+
4. **Validación de parámetros**: Agrega middleware si es necesario
|
|
356
|
+
|
|
357
|
+
### Ejemplo con Validación
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
// Dentro de renderReport()
|
|
361
|
+
if (parameters.fecha_inicio && !isValidDate(parameters.fecha_inicio)) {
|
|
362
|
+
return jsonResponse({ error: 'Invalid date format' }, 400);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function isValidDate(dateStr: string): boolean {
|
|
366
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(dateStr) && !isNaN(Date.parse(dateStr));
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## 📞 Soporte
|
|
373
|
+
|
|
374
|
+
- **Docs**: `docs/VIEWER_API.md`, `docs/PUBLISHING.md`
|
|
375
|
+
- **Issues**: GitHub Issues
|
|
376
|
+
- **API SDK**: `@nexabase/sdk` v2.12.6+
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Export Regression Checklist
|
|
2
|
+
|
|
3
|
+
Checklist corto para validar fidelidad de export después de cada cambio.
|
|
4
|
+
|
|
5
|
+
## 1) Setup
|
|
6
|
+
|
|
7
|
+
- Ejecutar: `npm.cmd run build`
|
|
8
|
+
- En local, reiniciar dev server si cambió `vite.config.ts`: `npm.cmd run dev`
|
|
9
|
+
|
|
10
|
+
## 2) PDF (Alta prioridad)
|
|
11
|
+
|
|
12
|
+
- Caso A: imágenes same-origin (`/assets/...`)
|
|
13
|
+
- Deben verse en visor y PDF.
|
|
14
|
+
- Caso B: imágenes cross-origin (`https://...`)
|
|
15
|
+
- Deben verse en visor.
|
|
16
|
+
- En PDF deben verse vía `/api/image?url=...`.
|
|
17
|
+
- Caso C: imágenes base64 (`data:image/...`)
|
|
18
|
+
- Deben verse en visor y PDF sin depender de proxy.
|
|
19
|
+
- Validar:
|
|
20
|
+
- Sin página extra al final.
|
|
21
|
+
- Header/footer correctos por página.
|
|
22
|
+
- Tabla multipágina continua (sin huecos/saltos extraños).
|
|
23
|
+
|
|
24
|
+
## 3) Excel
|
|
25
|
+
|
|
26
|
+
- Hojas de tablas:
|
|
27
|
+
- Columnas y encabezados correctos.
|
|
28
|
+
- Filas deben coincidir con filtros/sort/joins del viewer.
|
|
29
|
+
- Hojas por datasource:
|
|
30
|
+
- Alias correcto.
|
|
31
|
+
- Datos procesados (no crudos) si aplica lógica de datasource.
|
|
32
|
+
- Validar:
|
|
33
|
+
- Celdas no vacías cuando en visor sí hay valores.
|
|
34
|
+
|
|
35
|
+
## 4) Word
|
|
36
|
+
|
|
37
|
+
- ReportHeader y PageHeader deben exportar textos correctos.
|
|
38
|
+
- DataBand:
|
|
39
|
+
- Si hay `Table`, exporta tabla con encabezados + filas.
|
|
40
|
+
- Si no hay `Table`, exporta textos por fila.
|
|
41
|
+
- Validar:
|
|
42
|
+
- Valores iguales al visor para 5-10 registros de muestra.
|
|
43
|
+
|
|
44
|
+
## 5) Casos de estrés
|
|
45
|
+
|
|
46
|
+
- Dataset mediano (200 filas) y grande (1000 filas).
|
|
47
|
+
- Con filtros (`dataSource.filter` + `band.filter`).
|
|
48
|
+
- Con `starts_with` y `regex` en formato condicional.
|
|
49
|
+
|
|
50
|
+
## 6) Criterio de OK
|
|
51
|
+
|
|
52
|
+
- PDF fiel al visor (incluyendo imágenes).
|
|
53
|
+
- Excel/Word con datos completos y coherentes con visor.
|
|
54
|
+
- Sin errores en consola durante export.
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Integración Externa con NexaReport
|
|
2
|
+
|
|
3
|
+
## Visión General
|
|
4
|
+
|
|
5
|
+
NexaReport puede usarse en cualquier aplicación externa (Vue, React, Angular, HTML puro) pasando los datos del reporte via JSON. No requiere conexión a NexaBase para funcionar.
|
|
6
|
+
|
|
7
|
+
## Uso Básico
|
|
8
|
+
|
|
9
|
+
### 1. Instalar
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install nexabase-report
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### 2. Registrar el componente
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { registerNexaReport } from 'nexabase-report';
|
|
19
|
+
import 'nexabase-report/style.css';
|
|
20
|
+
|
|
21
|
+
registerNexaReport();
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 3. Usar en tu app
|
|
25
|
+
|
|
26
|
+
```vue
|
|
27
|
+
<template>
|
|
28
|
+
<nexa-viewer
|
|
29
|
+
:definition="reportDefinition"
|
|
30
|
+
:data="reportData"
|
|
31
|
+
minimal
|
|
32
|
+
/>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup>
|
|
36
|
+
import { ref } from 'vue';
|
|
37
|
+
|
|
38
|
+
// Definición del reporte (puede venir de un archivo JSON o API)
|
|
39
|
+
const reportDefinition = ref({
|
|
40
|
+
metadata: { name: 'Mi Reporte', version: '1.0', createdAt: '2024-01-15' },
|
|
41
|
+
layout: {
|
|
42
|
+
page: { format: 'A4', orientation: 'portrait' },
|
|
43
|
+
bands: [ /* ... */ ]
|
|
44
|
+
},
|
|
45
|
+
dataSources: [{ id: 'ds1', alias: 'main', collection: '', enabled: true }]
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Datos del reporte
|
|
49
|
+
const reportData = ref([
|
|
50
|
+
{ id: 1, nombre: 'Producto A', precio: 100, cantidad: 5 },
|
|
51
|
+
{ id: 2, nombre: 'Producto B', precio: 200, cantidad: 3 }
|
|
52
|
+
]);
|
|
53
|
+
</script>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Formato de Datos
|
|
57
|
+
|
|
58
|
+
### Single DataSource (array simple)
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
[
|
|
62
|
+
{ "id": 1, "nombre": "Juan Pérez", "email": "juan@mail.com" },
|
|
63
|
+
{ "id": 2, "nombre": "María López", "email": "maria@mail.com" }
|
|
64
|
+
]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Multiple DataSources (objeto con alias)
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"clientes": [
|
|
72
|
+
{ "id": 1, "nombre": "Juan Pérez", "email": "juan@mail.com" },
|
|
73
|
+
{ "id": 2, "nombre": "María López", "email": "maria@mail.com" }
|
|
74
|
+
],
|
|
75
|
+
"pedidos": [
|
|
76
|
+
{ "id": 101, "cliente_id": 1, "monto": 1500, "fecha": "2024-03-01" },
|
|
77
|
+
{ "id": 102, "cliente_id": 2, "monto": 2300, "fecha": "2024-03-02" }
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## API del Viewer
|
|
83
|
+
|
|
84
|
+
### Métodos
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const viewer = document.querySelector('nexa-viewer');
|
|
88
|
+
|
|
89
|
+
// Exportar a diferentes formatos
|
|
90
|
+
await viewer.exportPdf();
|
|
91
|
+
await viewer.exportExcel();
|
|
92
|
+
await viewer.exportWord();
|
|
93
|
+
await viewer.exportCsv();
|
|
94
|
+
|
|
95
|
+
// Actualizar datos dinámicamente
|
|
96
|
+
viewer.updateData({
|
|
97
|
+
clientes: [ /* nuevos datos */ ],
|
|
98
|
+
pedidos: [ /* nuevos datos */ ]
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Obtener campos disponibles del diccionario
|
|
102
|
+
const fields = viewer.getDictionaryFields();
|
|
103
|
+
// [{ alias: 'clientes', fields: [{ name: 'id', type: 'number' }, ...] }]
|
|
104
|
+
|
|
105
|
+
// Navegación de páginas
|
|
106
|
+
viewer.goToPage(2);
|
|
107
|
+
console.log(viewer.currentPage); // 2
|
|
108
|
+
console.log(viewer.totalPages); // 5
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Eventos
|
|
112
|
+
|
|
113
|
+
```vue
|
|
114
|
+
<nexa-viewer
|
|
115
|
+
:definition="report"
|
|
116
|
+
@data-request="(alias) => fetch(`/api/data/${alias}`).then(r => r.json())"
|
|
117
|
+
/>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Diccionario Manual
|
|
121
|
+
|
|
122
|
+
Puedés definir la estructura de datos sin conexión a NexaBase:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"dictionary": {
|
|
127
|
+
"dataSources": [
|
|
128
|
+
{
|
|
129
|
+
"alias": "clientes",
|
|
130
|
+
"label": "Tabla de Clientes",
|
|
131
|
+
"fields": [
|
|
132
|
+
{ "name": "id", "type": "number", "label": "ID", "primaryKey": true },
|
|
133
|
+
{ "name": "nombre", "type": "string", "label": "Nombre Completo" },
|
|
134
|
+
{ "name": "email", "type": "string", "label": "Email" },
|
|
135
|
+
{ "name": "fecha_registro", "type": "date", "label": "Fecha de Registro" }
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
"relationships": [
|
|
140
|
+
{
|
|
141
|
+
"from": "pedidos.cliente_id",
|
|
142
|
+
"to": "clientes.id",
|
|
143
|
+
"type": "many-to-one"
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Variables de Sistema
|
|
151
|
+
|
|
152
|
+
Disponibles en bindings `{{...}}`:
|
|
153
|
+
|
|
154
|
+
| Variable | Descripción | Ejemplo |
|
|
155
|
+
|----------|-------------|---------|
|
|
156
|
+
| `{{Page}}` | Número de página actual | `1` |
|
|
157
|
+
| `{{TotalPages}}` | Total de páginas | `5` |
|
|
158
|
+
| `{{Now}}` | Fecha y hora actual | `2024-01-15 14:30:00` |
|
|
159
|
+
| `{{Today}}` | Fecha actual | `2024-01-15` |
|
|
160
|
+
| `{{ReportName}}` | Nombre del reporte | `Ventas Mensuales` |
|
|
161
|
+
| `{{RowNumber}}` | Número de fila | `1` |
|
|
162
|
+
|
|
163
|
+
## Ejemplo Completo
|
|
164
|
+
|
|
165
|
+
```html
|
|
166
|
+
<!DOCTYPE html>
|
|
167
|
+
<html>
|
|
168
|
+
<head>
|
|
169
|
+
<script src="https://cdn.jsdelivr.net/npm/nexabase-report/dist/nexabase-report.umd.js"></script>
|
|
170
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nexabase-report/dist/style.css">
|
|
171
|
+
</head>
|
|
172
|
+
<body>
|
|
173
|
+
<h1>Mi Reporte</h1>
|
|
174
|
+
<nexa-viewer id="viewer" minimal></nexa-viewer>
|
|
175
|
+
|
|
176
|
+
<script>
|
|
177
|
+
NexaReport.registerNexaReport();
|
|
178
|
+
|
|
179
|
+
const viewer = document.getElementById('viewer');
|
|
180
|
+
|
|
181
|
+
// Cargar definición del reporte
|
|
182
|
+
fetch('/api/reports/ventas.json')
|
|
183
|
+
.then(r => r.json())
|
|
184
|
+
.then(def => { viewer.definition = def; });
|
|
185
|
+
|
|
186
|
+
// Cargar datos
|
|
187
|
+
fetch('/api/data/ventas?desde=2024-01-01')
|
|
188
|
+
.then(r => r.json())
|
|
189
|
+
.then(data => { viewer.data = data; });
|
|
190
|
+
</script>
|
|
191
|
+
</body>
|
|
192
|
+
</html>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Tipos de Datos Soportados
|
|
196
|
+
|
|
197
|
+
| Tipo JSON | Tipo en Diccionario | Icono |
|
|
198
|
+
|-----------|---------------------|-------|
|
|
199
|
+
| `string` | `string` | 🏷️ |
|
|
200
|
+
| `number` | `number` | #️⃣ |
|
|
201
|
+
| `boolean` | `boolean` | ☑️ |
|
|
202
|
+
| `string` (formato fecha) | `date` | 📅 |
|
|
203
|
+
| `object` | `object` | 📦 |
|
|
204
|
+
| `array` | `array` | 📋 |
|
|
205
|
+
|
|
206
|
+
## Tips
|
|
207
|
+
|
|
208
|
+
1. **Datos grandes**: Usá paginación en tu API y pasá los datos por páginas
|
|
209
|
+
2. **Actualización en tiempo real**: Usá `viewer.updateData()` para refrescar sin recargar
|
|
210
|
+
3. **Validación**: Usá `viewer.getDictionaryFields()` para validar bindings antes de renderizar
|
|
211
|
+
4. **Export**: Los métodos de export funcionan sin conexión a internet
|