---
name: fluig-formularios
description: Gera formulários HTML completos para TOTVS Fluig com Style Guide, campos zoom, tabelas pai-filho, máscaras e integração BPM. Use quando precisar criar ou modificar formulários Fluig.
license: MIT
metadata:
  author: Nevoa
  version: "1.1.0"
  category: development
  platform: totvs-fluig
---

# Skill: Formulários Fluig

## Quando Usar
- Criar novo formulário Fluig (HTML + JS)
- Modificar formulário existente
- Adicionar campos, tabelas pai-filho ou zooms
- Aplicar Style Guide em formulário legado
- Refatorar formulário com layout quebrado ou fora do padrão

---

## Regra Fundamental — Apenas Fluig Style Guide

> **Formulários Fluig são construídos EXCLUSIVAMENTE com o Fluig Style Guide.**

**Não existe CSS customizado** no desenvolvimento de formulários Fluig. Toda a estilização, layout e componentes visuais vêm do Fluig Style Guide — suas classes, componentes e utilitários cobrem 100% das necessidades.

O agente **NUNCA deve**:
- Criar arquivos `style.css` ou blocos `<style>`
- Usar CSS inline em qualquer situação
- Sobrescrever classes do Style Guide
- Incluir frameworks CSS externos (Tailwind, Materialize, etc.)
- Usar cores hexadecimais hardcoded
- Usar `!important`

> Para indicar campos obrigatórios, usar a classe do Style Guide: `<span class="text-danger">*</span>`

---

## Style Guide Obrigatório

Sempre respeite as seguintes diretrizes ao criar formulários:

- Painel fixo de **Dados da Solicitação** (sempre visível)
- Um painel separado por etapa/atividade do processo BPM
- Controle de visibilidade via `displayFields`
- Controle de habilitação via `enableFields`
- Validações via `validateForm`
- Padrão **snake_case** para nomes de campos
- Layout exclusivamente via **Fluig Bootstrap** (grid `row` / `col-md-*`)
- Código sempre comentado
- Todo HTML dentro de `<div class="fluig-style-guide">`
- Os fields names do HTML nunca devem conter mais de 30 caracteres (limitação do Fluig)

### Grid
- Utilizar `<div class="row">`
- Utilizar `col-md-*` (e variantes responsivas `col-xs-*`, `col-sm-*`, `col-lg-*`)
- Máximo de **12 colunas por linha** (a soma dos `col-*` em uma `row` deve ser 12)
- Sempre definir `col-xs-12` como **fallback mobile**
- Exemplo responsivo: `<div class="col-xs-12 col-sm-6 col-md-4">` → 100% mobile, 50% tablet, 33% desktop

---

## Estrutura de Saída

```
forms/{NomeFormulario}/
├── {NomeFormulario}.html        ← Formulário principal
├── custom.js                    ← JS client-side (máscaras, autopreenchimento)
└── events/
    ├── displayFields.js         ← Visibilidade por atividade
    ├── enableFields.js          ← Habilitar/desabilitar por atividade
    └── validateForm.js          ← Validação server-side
```

---

## Template HTML Base

Todo formulário DEVE seguir esta estrutura:

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>${TITULO_FORMULARIO}</title>
    <!-- Style Guide (usar versão flat — padrão atual) -->
    <link rel="stylesheet" type="text/css" href="/style-guide/css/fluig-style-guide-flat.min.css" />
    <!-- JS obrigatórios (ordem importa) -->
    <script src="/portal/resources/js/jquery/jquery.js"></script>
    <script src="/portal/resources/js/jquery/jquery-ui.min.js"></script>
    <script src="/portal/resources/js/mustache/mustache-min.js"></script>
    <script src="/style-guide/js/fluig-style-guide.min.js" charset="utf-8"></script>
    <!-- JS customizado -->
    <script src="custom.js"></script>
</head>
<body>
    <div class="fluig-style-guide">
        <form name="form" role="form">
            <!-- Campos hidden de controle -->
            <input type="hidden" name="nrSolicitacao" id="nrSolicitacao" />

            <div class="panel-group" id="geral">

                <!-- ============================================= -->
                <!-- PAINEL FIXO: Dados da Solicitação (OBRIGATÓRIO) -->
                <!-- ============================================= -->
                <div class="panel panel-primary" id="painel_dados_solicitacao">
                    <div class="panel-heading">
                        <div class="row">
                            <div class="col-xs-12 col-md-12">
                                <h4 class="panel-title"><strong>Dados da Solicitação</strong></h4>
                            </div>
                        </div>
                    </div>
                    <div class="panel-body">
                        <div class="row">
                            <div class="form-group col-xs-12 col-md-4">
                                <label for="nrSolic">Nº Solicitação</label>
                                <input type="text" class="form-control" name="nrSolic" id="nrSolic" readonly />
                            </div>
                            <div class="form-group col-xs-12 col-md-4">
                                <label for="solicitante">Solicitante</label>
                                <input type="text" class="form-control" name="solicitante" id="solicitante" readonly />
                            </div>
                            <div class="form-group col-xs-12 col-md-4">
                                <label for="dataSolicitacao">Data da Solicitação</label>
                                <input type="text" class="form-control" name="dataSolicitacao" id="dataSolicitacao" readonly />
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Cabeçalho do formulário -->
                <div class="panel-heading">
                    <div class="row">
                        <div class="col-xs-10 col-md-10">
                            <h2><strong>${TITULO_FORMULARIO}</strong></h2>
                        </div>
                    </div>
                </div>

                <!-- ============================================= -->
                <!-- PAINEL POR ATIVIDADE BPM (repetir para cada etapa) -->
                <!-- ============================================= -->
                <div class="panel panel-default" id="painel_ativ_${NUM}">
                    <div class="panel-heading">
                        <div class="row">
                            <div class="col-xs-12 col-md-12">
                                <a class="collapse-icon" data-toggle="collapse"
                                   data-parent="#painel_ativ_${NUM}"
                                   href="#painelA_ativ_${NUM}">
                                    <h4 class="panel-title">
                                        <strong>${TITULO_PAINEL}</strong>
                                    </h4>
                                </a>
                                <!-- Span de status (preenchido por JS) -->
                                <em><span class="label label-success" id="span_${NUM}"></span></em>
                                <input type="hidden" name="vUserSpan_${NUM}" id="vUserSpan_${NUM}" value="" />
                                <input type="hidden" name="vDateSpan_${NUM}" id="vDateSpan_${NUM}" value="" />
                            </div>
                        </div>
                    </div>
                    <div id="painelA_ativ_${NUM}" class="panel-collapse collapse">
                        <div class="panel-body">
                            <!-- Campos do painel aqui -->
                        </div>
                    </div>
                </div>
            </div>
        </form>
    </div>
</body>
</html>
```

### Estrutura de Painel (Referência rápida)

```html
<div class="panel panel-default" id="panel_nome_etapa">
  <div class="panel-heading">
    <h3 class="panel-title">Nome da Etapa</h3>
  </div>
  <div class="panel-body">
    ...
  </div>
</div>
```

### Painel Fixo Obrigatório — Dados da Solicitação

Criar painel "Dados da Solicitação" contendo:
- `nrSolic` (read-only) — número da solicitação
- `solicitante` (read-only) — nome do solicitante
- `dataSolicitacao` (read-only) — data da solicitação

Esses campos devem estar **sempre visíveis**, independentemente da atividade BPM.

### Estrutura BPM
- Criar um painel separado para **cada etapa** do processo
- Cada painel deve ter **ID único** (ex.: `painel_ativ_1`, `painel_ativ_2`)
- Cada painel deve ser preparado para controle via `displayFields` e `enableFields`

---

## Componentes Fluig — Resumo

| Componente | Classe/Atributo Principal | Uso |
|---|---|---|
| Campo texto | `<input class="form-control">` | Campos simples |
| Select dataset | `dataset="ID" datasetkey="" datasetvalue=""` | Dropdown com dados |
| Zoom field | `<input type="zoom" data-zoom="{}">` | Busca com pesquisa |
| Radio Sim/Nao | `custom-radio custom-radio-inline` | Aprovacao BPM |
| Checkbox | `custom-checkbox custom-checkbox-primary` | Selecao multipla |
| Switch | `switch switch-primary` | Toggle on/off |
| Data | `input-group date` + `FLUIGC.calendar()` | Campo com calendario |
| Monetario | `mask="#00.000.000.000.000,00"` | Valores financeiros |
| Textarea | `<textarea class="form-control" rows="4">` | Texto longo |
| Helper text | `<p class="help-block">` | Texto de ajuda |
| Alert | `alert alert-info\|success\|warning\|danger` | Mensagens informativas |
| Tabela pai-filho | `<table tablename="X">` + `wdkAddChild()` | Itens filhos |

> Catalogo completo com snippets HTML: [references/fluig-componentes-html.md](./references/fluig-componentes-html.md)

---

## Regras de Geração

### MUST (obrigatório)
- Todo HTML dentro de `<div class="fluig-style-guide">`
- Todo campo com `name` **E** `id` (mesmo valor)
- Obrigatórios marcados com `<span class="text-danger">*</span>`
- Um `<form name="form" role="form">` raiz
- Painéis colapsáveis com `id="painel_ativ_${NUM}"` para cada atividade BPM
- Painel fixo "Dados da Solicitação" com campos readonly (solicitante, data, nrSolicitacao)
- Usar grid Bootstrap: `col-xs-12 col-md-{N}` (sempre soma 12)
- Imports do Style Guide no `<head>` (ordem correta — ver Template HTML Base)
- Nomes de campos em **snake_case**
- IDs únicos para cada elemento
- Validação obrigatória para campos críticos
- Máscaras para CPF, CNPJ, datas e valores monetários
- Um painel separado para cada etapa do processo BPM
- Usar **exclusivamente** classes e componentes do Fluig Style Guide para layout e visual

### SHOULD (recomendado)
- `custom.js` separado do HTML (não inline `<script>`)
- Zoom fields com `filterValues` para limitar dados
- Campos hidden para armazenar IDs de zooms
- Comentários `<!-- Seção: Nome -->` separando blocos
- `form-group` envolvendo label + input
- Breakpoints responsivos: `col-xs-12 col-sm-6 col-md-4`
- Labels claros e concisos acima dos campos (nunca ao lado)
- Agrupamento lógico de campos relacionados

### MUST NOT (proibido)
- Usar `<table>` para layout (usar grid Bootstrap)
- Esquecer `addBlankLine="true"` em selects com dataset
- Usar `alert()` para mensagens (usar `FLUIGC.toast` ou `swal`)
- Colocar JS de eventos no HTML (vai em `events/`)
- Usar classes que não existem no Fluig Style Guide
- Usar `placeholder` como substituto de `label`
- Acessar o DOM diretamente no backend (usar `form.getValue` e `form.setValue`)

---

## Diretrizes de JavaScript

### Arquivos de eventos (pasta `events/`)

| Arquivo | Finalidade |
|---|---|
| `displayFields.js` | Controla a **visibilidade** de painéis e campos por atividade BPM |
| `enableFields.js` | Controla a **habilitação/desabilitação** de campos por atividade BPM |
| `validateForm.js` | **Validação server-side** dos dados antes de avançar no processo |

### Regras de JavaScript

1. Criar `custom.js` completo para lógica client-side
2. Implementar `validateForm` com validações de campos obrigatórios
3. Implementar `displayFields` para controle de visibilidade por atividade
4. Implementar `enableFields` para controle de habilitação por atividade
5. Usar `form.getValue("campo")` e `form.setValue("campo", valor)` nos eventos server-side
6. **Nunca** usar acesso direto ao DOM (`document.getElementById`) no backend/server-side
7. Isolar código front-end (DOM/Browser) do código server-side (Rhino)
8. Evitar lógica pesada de processamento síncrono em scripts backend
9. Documentar funções exportadas e pontos de integração entre JS e Java

### Compatibilidade Rhino
- Arquivos `.js` podem ser compilados em classes Java (bytecode) pelo engine Rhino
- Evitar dependências implícitas de runtime do navegador em scripts backend
- Usar a interoperabilidade Java↔JS conscientemente: definir contratos/assinaturas quando necessário
- Fazer logging e tratamento de exceções robusto

---

## Máscaras de Campos

O Fluig permite habilitar máscaras por campo via atributo `mask` em inputs do tipo `text`.

```html
<input name="cep" type="text" mask="00000-000">
```

### Caracteres de máscara

| Caractere | Significado |
|---|---|
| `0` | Somente números |
| `9` | Somente números (opcional) |
| `#` | Somente números (recursivo) |
| `A` | Números ou letras |
| `S` | Somente letras (A-Z, a-z) |

### Máscaras comuns

| Campo | Máscara |
|---|---|
| Data | `00/00/0000` |
| Horário | `00:00:00` |
| Data e Hora | `00/00/0000 00:00:00` |
| CEP | `00000-000` |
| Telefone | `0000-0000` |
| Telefone (DDD) | `(00) 0000-0000` |
| Telefone (DDD + 9º dígito) | `(00) 90000-0000` |
| Placa de carro | `SSS 0000` |
| CPF | `000.000.000-00` |
| CNPJ | `00.000.000/0000-00` |
| IP | `099.099.099.099` |
| Porcentagem | `#00.000,00%` |
| Valor | `#00.000.000.000.000,00` |

---

## APIs Client-side Úteis

```javascript
// Usuário logado
var nomeUser = WCMAPI.user;
var loginUser = WCMAPI.userId;
var codUser = WCMAPI.userCode;

// Consultar dataset no client
var ds = DatasetFactory.getDataset("${DATASET_ID}", null, constraints, null);

// Recarregar zoom com filtro dinâmico
reloadZoomFilterValues("${ID_ZOOM}", "${NOVO_FILTRO}");

// Calendário Fluig
FLUIGC.calendar('#${CAMPO}');

// Toast de notificação
FLUIGC.toast({ title: '${TITULO}', message: '${MENSAGEM}', type: 'success' });
// Tipos: success, info, warning, danger
```

---

## Melhores Práticas

### Layout e Design
- Utilizar estrutura de painéis (`panel panel-default`) para organizar seções
- Títulos de seção com `panel-heading` + `panel-title`
- Corpo do painel com `panel-body`
- Para formulários complexos, agrupar campos relacionados lado a lado usando o grid
- Sempre usar breakpoints responsivos com fallback mobile (`col-xs-12`)

### Acessibilidade
- Toda `<label>` deve estar associada ao campo via atributo `for`
- Não usar `placeholder` como substituto de `label`
- Campos obrigatórios devem ser indicados com `<span class="text-danger">*</span>`

### Validação e Feedback
- Implementar validação em `validateForm.js` para todos os campos obrigatórios
- Usar `FLUIGC.toast` ou `swal` para mensagens ao usuário — **nunca** `alert()`
- Fornecer mensagens de erro claras e específicas
- Validar formatos (CPF, CNPJ, e-mail, datas) antes de permitir avanço no processo

### Performance
- Evitar consultas excessivas a datasets no `$(document).ready`
- Usar `filterValues` em zooms para limitar o volume de dados retornados
- Carregar dados sob demanda quando possível

---

## Entrega Obrigatória

Todo formulário gerado por esta skill **deve** incluir:

1. **HTML completo** — formulário funcional com todos os campos, painéis e componentes
2. **custom.js** — lógica client-side (máscaras, autopreenchimento, interações)
3. **events/displayFields.js** — controle de visibilidade por atividade
4. **events/enableFields.js** — controle de habilitação por atividade
5. **events/validateForm.js** — validação server-side
6. **Explicação técnica** — descrição das decisões de arquitetura e mapeamento de campos
7. **Sugestões de melhoria** — recomendações para evolução futura do formulário

---

## Checklist de Revisão

- [ ] HTML envolto em `<div class="fluig-style-guide">`
- [ ] Painel fixo "Dados da Solicitação" presente e sempre visível
- [ ] Todos os campos têm `name` e `id` (mesmo valor)
- [ ] Nomes de campos em snake_case
- [ ] Labels com `<span class="text-danger">*</span>` para obrigatórios
- [ ] Painéis por atividade com `data-toggle="collapse"`
- [ ] Grid Bootstrap fecha em 12 colunas por row
- [ ] Fallback mobile com `col-xs-12` em todos os campos
- [ ] Select com dataset tem `addBlankLine="true"`
- [ ] Zoom fields têm campo hidden associado
- [ ] `custom.js` referenciado no `<head>`
- [ ] Campos financeiros com máscara jQuery Mask
- [ ] Campos de data com ícone calendário
- [ ] Imports JS na ordem correta (jQuery → jQuery UI → Mustache → Style Guide)
- [ ] Nenhuma classe inexistente no Fluig Style Guide foi utilizada
- [ ] `displayFields.js` implementado para cada atividade
- [ ] `enableFields.js` implementado para cada atividade
- [ ] `validateForm.js` com validação de campos obrigatórios
- [ ] Sem acesso direto ao DOM em código server-side
- [ ] Sem uso de `alert()` — usar `FLUIGC.toast` ou `swal`

---

## Padrões Internos

- Desenvolver formulários seguindo o padrão Fluig Style Guide
- Sempre usar dataset para integrações
- Nunca hardcode de credenciais
- Usar constraints corretamente
- Evitar loops desnecessários
- Garantir compatibilidade ECM/BPM
- Documentar funções exportadas e pontos de integração entre JS e Java

---

## Troubleshooting

| Problema | Causa provável | Solução |
|---|---|---|
| Zoom não abre ou não carrega dados | JSON inválido no `data-zoom` ou dataset inexistente | Validar JSON com aspas duplas; verificar se dataset existe e está ativo |
| Tabela pai-filho não adiciona/remove linhas | jQuery não carregado ou conflito de IDs | Verificar ordem dos imports JS; garantir IDs únicos por linha |
| Formulário em branco | Arquivos HTML/JS não encontrados no servidor | Verificar se todos os arquivos estão na pasta correta com nomes corretos |
| Grid quebrado / layout desalinhado | Soma de colunas ≠ 12 ou `row` ausente | Envolver `col-*` em `<div class="row">` e garantir soma = 12 |
| Campos não salvam dados | Campo sem atributo `name` ou `id` | Todo campo deve ter `name` e `id` com o mesmo valor |
| Imports JS falham | Ordem incorreta dos scripts no `<head>` | Seguir: jQuery → jQuery UI → Mustache → Style Guide JS |

---

## Prompts Estratégicos Disponíveis

- `criar-formulario-bpm-matriz-atividades.md` — Criação de formulário BPM completo com matriz de atividades.
- `refatorar-formulario-legado-padrao-fluig.md` — Refatoração de formulário legado para padrão escalável.
- `diagnosticar-visibilidade-habilitacao-atividade.md` — Troubleshooting de `displayFields`/`enableFields` por atividade.
- `otimizar-formulario-pai-filho-zoom-ux-performance.md` — Otimização de pai-filho/zoom, UX e performance.

Use estes prompts para cobrir criação, refatoração, diagnóstico e otimização sem sobrepor responsabilidades.

---

## Skills Relacionadas

- [fluig-eventos-formulario](../fluig-eventos-formulario/SKILL.md) — inputFields, beforeSendValidate, afterSaveNew, gravaHistorico
- [fluig-eventos-processo](../fluig-eventos-processo/SKILL.md) — Eventos de workflow (hAPI, afterTaskComplete)
- [fluig-process-reader](../fluig-process-reader/SKILL.md) — Ler .process para mapear atividades antes de criar displayFields

## Recursos Adicionais
- Para templates base, consulte os arquivos em [templates/](./templates/)
- Para exemplos de implementação real, consulte [examples/](./examples/)
- Para referência do Fluig Style Guide, consulte [references/fluig-style-guide.md](./references/fluig-style-guide.md)

---

## Complemento de Base Real: DisplayFields + ValidateForm

- Base complementar (Grupo Felice): [references/displayfields-validateform-base-felice.md](./references/displayfields-validateform-base-felice.md)
- Template complementar de `displayFields`: [templates/displayFields-base-felice.js](./templates/displayFields-base-felice.js)
- Template complementar de `validateForm`: [templates/validateForm-base-felice.js](./templates/validateForm-base-felice.js)
- Exemplo complementar: [examples/exemplo_03_base_displayfields_validateform_grupo_felice/](./examples/exemplo_03_base_displayfields_validateform_grupo_felice/)

## Curadoria de Contexto Local

Para buscar exemplos reais no acervo local `Contexto`, consulte [references/contexto-curadoria.md](./references/contexto-curadoria.md).
Abra essa referencia quando a tarefa exigir aderencia a legado/producao ou comparacao com implementacoes existentes.
