Definição do relatório
Todo relatório Sulfite é um JSON com esta estrutura:
json
{
"reportId": "string",
"reportName": "string",
"version": "string",
"pageSettings": { ... },
"dataSources": [ ... ],
"bands": [ ... ]
}Campos
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
reportId | string | Sim | Identificador único do relatório |
reportName | string | Sim | Nome legível |
version | string | Não | Versão do relatório (ex: "1.0") |
pageSettings | object | Sim | Formato da página, margens, orientação |
dataSources | array | Sim | Fontes de dados esperadas |
bands | array | Sim | Faixas horizontais que compõem o layout |
parameters | array | Não | Parâmetros interativos preenchidos antes da impressão (ver Filtros) |
scripts | array | Não | Scripts executados em hooks do ciclo de vida (afterQuery, beforeRender) |
metadata | object | Não | Dados extras livres |
processingMode | string | Não | "strict" (padrão) ou "resilient" |
pageSettings
json
{
"format": "A4",
"width": 595.28,
"height": 841.89,
"unit": "pt",
"orientation": "portrait",
"margins": {
"left": 40,
"right": 40,
"top": 40,
"bottom": 40
}
}| Campo | Tipo | Padrão | Descrição |
|---|---|---|---|
format | string | "A4" | Nome do formato (A3, A4, A5, Carta, Legal) |
width | double | 595.28 | Largura em pontos |
height | double | 841.89 | Altura em pontos |
unit | string | "pt" | Unidade de medida |
orientation | string | "portrait" | "portrait" ou "landscape" |
margins | object | — | Margens (left, right, top, bottom) |
labelConfig | object | null | Configuração para modo etiqueta (ver Etiquetas) |
Formatos comuns
| Formato | Largura (pt) | Altura (pt) |
|---|---|---|
| A3 | 841.89 | 1190.55 |
| A4 | 595.28 | 841.89 |
| A5 | 419.53 | 595.28 |
| Carta | 612.00 | 792.00 |
| Legal | 612.00 | 1008.00 |
Modo de processamento
strict(padrão): erros de binding, data source não encontrado ou tipo inválido interrompem o processamento.resilient: registra erros emProcessedData.errorse continua com valores de fallback.
json
{
"processingMode": "resilient"
}Scripts
O campo scripts declara handlers de ciclo de vida executados pelo AdvancedScriptEngine. Cada script é identificado por um id e disparado em um dos dois hooks disponíveis:
| Hook | Quando executa |
|---|---|
afterQuery | Logo após o DataProcessor carregar os dados, antes de renderizar. Use para filtrar, enriquecer ou transformar registros. |
beforeRender | Após o processamento, antes de montar o PDF/HTML. Use para ajustar visibilidade de bands e elementos com base em regras de negócio. |
json
{
"scripts": [
{
"id": "mask_custo",
"hook": "afterQuery",
"description": "Remove coluna de custo se usuário não tiver permissão"
},
{
"id": "hide_empty_section",
"hook": "beforeRender",
"description": "Oculta band de detalhes quando não há registros"
}
]
}Os handlers são registrados em Dart via AdvancedScriptEngine.register() e associados ao relatório pelo id:
dart
final engine = AdvancedScriptEngine(
externalContext: {'permissions': userPermissions},
);
engine.register('mask_custo', (ctx) {
final podeVerCusto = ctx.context('permissions').contains('financeiro');
if (!podeVerCusto) {
ctx.setElementVisible('col_custo', false);
}
});
engine.register('hide_empty_section', (ctx) {
final rows = ctx.datasource('vendas');
ctx.setBandVisible('band_detalhe', rows.isNotEmpty);
});
final pdfBytes = await engine.generate(
report,
dataPayload: payload,
format: 'pdf',
);ScriptContext — API disponível
| Método | Descrição |
|---|---|
datasource(id) | Retorna os registros atuais de um data source |
setDatasource(id, rows) | Substitui todos os registros de um data source |
addRow(id, row) | Adiciona um registro |
removeRow(id, predicate) | Remove registros que satisfaçam a condição |
setBandVisible(id, visible) | Mostra ou oculta uma band |
setElementVisible(id, visible) | Mostra ou oculta um elemento |
setElementProperty(id, prop, value) | Altera propriedade de um elemento |
param(id) | Lê o valor de um parâmetro |
setParam(id, value) | Define o valor de um parâmetro |
context(key) | Acessa o externalContext injetado no engine |
query(sql, params) | Executa SQL via SqlBridge (opcional) |
cancel() | Aborta a geração do relatório |
log(msg) | Log de diagnóstico |
Lógica inline em elementos
Para condicionais simples sem estado, use os campos inline dos elementos:
printWhenem qualquer elemento ou band — expressão booleana que controla visibilidadevalueExpressionemFieldElement— expressão calculada no contexto do row atual
Prefira scripts quando a lógica precisar de acesso a parâmetros externos, múltiplos data sources ou estado acumulado.
Exemplo completo
Um relatório de vendas com header, 50 linhas de detalhe, agregados no summary e rodapé com paginação:
json
{
"reportId": "sales_report",
"reportName": "Relatório de Vendas",
"version": "2.0",
"pageSettings": {
"format": "A4",
"orientation": "portrait",
"margins": { "left": 30, "right": 30, "top": 30, "bottom": 30 }
},
"dataSources": [
{
"id": "sales",
"type": "list",
"schema": {
"order_id": "string",
"customer": "string",
"amount": "number",
"date": "string"
}
}
],
"bands": [
{
"type": "header", "id": "hdr", "height": 60,
"elements": [
{ "type": "text", "id": "t1", "x": 30, "y": 20, "content": "Relatório de Vendas", "fontSize": 24, "bold": true }
]
},
{
"type": "detail", "id": "det", "dataSourceId": "sales", "height": 25,
"elements": [
{ "type": "field", "id": "f1", "x": 30, "y": 5, "width": 80, "binding": "order_id" },
{ "type": "field", "id": "f2", "x": 120, "y": 5, "width": 200, "binding": "customer" },
{ "type": "field", "id": "f3", "x": 330, "y": 5, "width": 100, "binding": "amount", "format": "currency:BRL" },
{ "type": "field", "id": "f4", "x": 440, "y": 5, "width": 100, "binding": "date", "format": "date:dd/MM/yyyy" }
]
},
{
"type": "summary", "id": "sum", "height": 40,
"elements": [
{ "type": "aggregate", "id": "total", "x": 330, "y": 10, "width": 100, "verb": "SUM", "dataSourceId": "sales", "targetKey": "amount", "format": "currency:BRL", "bold": true }
]
},
{
"type": "footer", "id": "ftr", "height": 30,
"elements": [
{ "type": "text", "id": "pg", "x": 250, "y": 10, "content": "Página {page} de {totalPages}", "fontSize": 9, "color": "999999" }
]
}
]
}