Skip to content

Tutorial: Relatório com parâmetros

Neste tutorial você vai construir um relatório de RH parametrizado onde o usuário pode filtrar por departamento, salário mínimo e data de admissão. Combina Print Parameters, validação, GroupBands e RichText para exibir os filtros aplicados.

Exemplo completo: examples/08-hr-report

O que você vai aprender

  • Definir parâmetros com tipos select, number e date
  • Adicionar validação (min, required)
  • Injetar parâmetros no ScriptEngine para filtragem
  • Exibir os filtros aplicados via richText
  • Combinar parâmetros com groupHeader/groupFooter

1. Definir os parâmetros

Os parâmetros são declarados no nível raiz do relatório:

json
{
  "parameters": [
    {
      "id": "department",
      "label": "Departamento",
      "type": "select",
      "defaultValue": "Todos",
      "options": ["Todos", "Engenharia", "Marketing", "Vendas", "RH", "Financeiro"]
    },
    {
      "id": "min_salary",
      "label": "Salário mínimo",
      "type": "number",
      "defaultValue": "0",
      "validation": {
        "rule": "min",
        "value": "0",
        "message": "O salário mínimo não pode ser negativo"
      }
    },
    {
      "id": "hire_date_from",
      "label": "Admitido a partir de",
      "type": "date",
      "defaultValue": "2020-01-01"
    }
  ]
}

Tipos de parâmetro

TipoWidget geradoUso
textCampo de texto livreBuscas, nomes
numberCampo numéricoFaixas de valor
dateDate pickerPeríodos
selectDropdown / radioListas fixas

Validação

Cada parâmetro aceita um objeto validation com:

CampoDescrição
ruleTipo: required, min, max, pattern
valueValor de referência (string)
messageMensagem de erro exibida ao usuário

2. Preparar os dados

O data.json contém registros de funcionários organizados por departamento:

json
{
  "employees": [
    {
      "department": "Engenharia",
      "name": "Ana Silva",
      "role": "Tech Lead",
      "salary": 18500,
      "hire_date": "2019-03-15",
      "performance": "A"
    }
  ]
}

3. Exibir filtros aplicados com RichText

No header, use richText para mostrar quais filtros estão ativos:

json
{
  "type": "richText",
  "id": "filter_summary",
  "x": 40,
  "y": 62,
  "width": 500,
  "spans": [
    { "content": "Filtros: ", "fontSize": 9, "bold": true, "color": "0d47a1" },
    { "content": "Depto: {{department}}", "fontSize": 9, "color": "424242" },
    { "content": "  |  Sal. min: R$ {{min_salary}}", "fontSize": 9, "color": "424242" },
    { "content": "  |  Desde: {{hire_date_from}}", "fontSize": 9, "color": "424242" }
  ]
}

Os placeholders são substituídos pelos valores dos parâmetros em tempo de render.

4. GroupBands por departamento

Agrupe os funcionários por departamento:

json
{
  "type": "groupHeader",
  "id": "dept_header",
  "dataSourceId": "employees",
  "groupBy": "department",
  "height": 30,
  "backgroundColor": "1565c0",
  "elements": [
    {
      "type": "field",
      "id": "dept_name",
      "x": 40,
      "y": 7,
      "width": 300,
      "binding": "department",
      "fontSize": 12,
      "bold": true,
      "color": "ffffff"
    }
  ]
}

O groupFooter mostra o total de funcionários e média salarial do departamento:

json
{
  "type": "groupFooter",
  "id": "dept_footer",
  "dataSourceId": "employees",
  "groupBy": "department",
  "height": 25,
  "backgroundColor": "e3f2fd",
  "elements": [
    {
      "type": "aggregate",
      "id": "dept_count",
      "x": 40,
      "y": 5,
      "width": 200,
      "verb": "COUNT",
      "dataSourceId": "employees",
      "targetKey": "name",
      "prefix": "Funcionários: "
    },
    {
      "type": "aggregate",
      "id": "dept_avg_salary",
      "x": 350,
      "y": 5,
      "width": 150,
      "verb": "AVG",
      "dataSourceId": "employees",
      "targetKey": "salary",
      "format": "currency:BRL",
      "prefix": "Média: "
    }
  ]
}

5. Injetar parâmetros ao gerar

No código Dart, passe os parâmetros como Map<String, String>:

dart
import 'dart:convert';
import 'dart:io';
import 'package:sulfite_core/sulfite_core.dart';

void main() async {
  final engine = SulfiteEngineImpl();
  final report = await engine.parseReport(
    File('examples/08-hr-report/report.json').readAsStringSync(),
  );
  final data = jsonDecode(
    File('examples/08-hr-report/data.json').readAsStringSync(),
  );

  // Parâmetros do usuário
  final params = {
    'department': 'Engenharia',
    'min_salary': '10000',
    'hire_date_from': '2021-01-01',
  };

  final ctx = await engine.processData(report, data, params: params);
  final pdf = await engine.renderToPdf(ctx);
  File('rh_filtrado.pdf').writeAsBytesSync(pdf);
  print('Relatório de RH filtrado gerado!');
}

Tipo dos valores

Todos os valores no mapa de parâmetros devem ser String, mesmo números e datas. O motor faz a conversão internamente.

6. Como a filtragem funciona

Parâmetros do usuário


  ScriptEngine recebe params


  Transforms filtram dados
  (se configurados)


  Bands renderizam apenas
  os registros filtrados


  Placeholders {{param}}
  são substituídos no output

Os parâmetros ficam disponíveis via ctx.param(id) em scripts. Para filtragem explícita por parâmetro, use um script afterQuery:

dart
engine.register('filtrar_salario', (ctx) {
  final minSalary = (ctx.param('min_salary') as num?) ?? 0;
  final rows = ctx.datasource('employees')
    .where((r) => (r['salary'] as num) >= minSalary)
    .toList();
  ctx.setDatasource('employees', rows);
});
json
{
  "scripts": [
    { "id": "filtrar_salario", "hook": "afterQuery" }
  ]
}

7. Resultado

┌──────────────────────────────────────────────┐
│  RELATÓRIO DE RECURSOS HUMANOS               │
│  Filtros: Depto: Engenharia | Sal.min: 10000 │
├──────────────────────────────────────────────┤
│  ▌ ENGENHARIA                                │
│   Ana Silva     Tech Lead    R$ 18.500   A   │
│   Pedro Santos  Senior Dev   R$ 16.000   A   │
│   Funcionários: 2  |  Média: R$ 17.250      │
├──────────────────────────────────────────────┤
│           TOTAL GERAL                        │
│  Funcionários: 2  |  Folha: R$ 34.500       │
├──────────────────────────────────────────────┤
│  Confidencial - RH | Página 1 de 1          │
└──────────────────────────────────────────────┘

Dicas

  • Use defaultValue para pré-popular filtros com valores sensatos
  • O tipo select com options gera um dropdown no Studio
  • A validação min impede valores inválidos antes da geração
  • Parâmetros podem ser usados em URLs de RestDataSource via {paramId}
  • Use lookup para carregar opções dinamicamente de uma API

Próximos passos

Sulfite do 🇧🇷 para o mundo © 2026 Rafael S. Pinheiro