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,numberedate - 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:
{
"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
| Tipo | Widget gerado | Uso |
|---|---|---|
text | Campo de texto livre | Buscas, nomes |
number | Campo numérico | Faixas de valor |
date | Date picker | Períodos |
select | Dropdown / radio | Listas fixas |
Validação
Cada parâmetro aceita um objeto validation com:
| Campo | Descrição |
|---|---|
rule | Tipo: required, min, max, pattern |
value | Valor de referência (string) |
message | Mensagem de erro exibida ao usuário |
2. Preparar os dados
O data.json contém registros de funcionários organizados por departamento:
{
"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:
{
"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:
{
"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:
{
"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>:
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 outputOs parâmetros ficam disponíveis via ctx.param(id) em scripts. Para filtragem explícita por parâmetro, use um script afterQuery:
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);
});{
"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
defaultValuepara pré-popular filtros com valores sensatos - O tipo
selectcomoptionsgera um dropdown no Studio - A validação
minimpede valores inválidos antes da geração - Parâmetros podem ser usados em URLs de
RestDataSourcevia{paramId} - Use
lookuppara carregar opções dinamicamente de uma API