# Requerimento de Diárias — Views e UX

## 1. Inventário de views

### 1.1 CMS (`v6/resources/views/prefecture/contents/requerimento-diarias/`)

| Arquivo | Linhas | Função |
|---|---|---|
| `index.blade.php` | 64 | Listagem (AdminLTE box + tabela Yajra) |
| `create.blade.php` | 44 | Wrapper do formulário (create **ou** edit) |
| `form.blade.php` | 165 | Campos do requerimento + upload + checkbox de lei padrão |
| `configuracoes/create.blade.php` | 33 | Wrapper do formulário de configurações |
| `configuracoes/form.blade.php` | 49 | Lei padrão (texto) + arquivo da lei |
| `pdf/index.blade.php` | 210 | Template HTML do PDF do requerimento |
| `pdf/style.blade.php` | 117 | CSS do PDF |

### 1.2 Portal (`v6/resources/views/portal/layouts/busca-diarias/`)

| Arquivo | Função |
|---|---|
| `show.blade.php` | Página única: formulário de filtros + tabela de resultados + paginação |

## 2. Estrutura das telas do CMS

### 2.1 `index.blade.php` — Listagem

Estende `admin.layouts.app` (AdminLTE 1.22 / Bootstrap 3).

```
box box-success
├── box-header
│   ├── h3 "Lista de Requerimento Diárias"
│   ├── [Configurações]      → route('requerimento-diarias-config.index')
│   ├── [Cadastrar ...]      → route('requerimento-diarias.create')
│   └── [exclusão em lote]   → @component('prefecture.components.deleteByLoteSubmitButton', ['route' => 'requerimento-diarias.destroyAll'])
└── box-body
    └── table#tabela_requerimento_diarias
        thead: [master checkbox] | Número | Requerente | Objetivo da viagem | Fundamentos Legais | Ações
```

Os dois botões do cabeçalho só aparecem com `has_access(['requerimento-diarias.create'])`;
o botão de exclusão em lote e o checkbox master exigem
`has_access(['requerimento-diarias.delete'])`.

Scripts carregados no `@section('other-scripts')`:

| Asset | Função |
|---|---|
| `v6/public/assets/js/custom/utilities/deleteAll.js` | Exclusão em lote (SweetAlert + AJAX POST) |
| `v6/public/assets/js/custom/contents/requerimentos_diarias/datatable.js` | Definição das colunas do DataTable |

### 2.2 `create.blade.php` + `form.blade.php` — Cadastro/Edição

`create.blade.php` escolhe a rota conforme o contexto:

```php
@php $route = !isset($data) ? ['requerimento-diarias.store'] : ['requerimento-diarias.update', $data->id] @endphp
```

- `Form::open(['route' => $route, 'files' => true])` — `files => true` é
  obrigatório para o upload.
- `@isset($data)` → `method_field('PUT')`.
- O mesmo template serve para create e edit; `$data` (registro) distingue os
  casos.

Campos do `form.blade.php` (todos com `mandatory => true`):

| Campo | Componente | Observação |
|---|---|---|
| `codigo_diarias` | `components.inputs.input` (`tipo => number`) | Pré-preenchido com `$codigo_sugestao` no create |
| `id_servidor` | `components.inputs.select` | Lista `$servidores` |
| `dados_objetivo` | `components.inputs.textarea` | |
| `cidade_destino` | `components.inputs.input` | |
| `estado_destino` | `components.inputs.select` | Lista `$estados` (UF) |
| `placa_transporte` | `components.inputs.input` | Rótulo "Transporte Utilizado" |
| `data_saida` | `components.inputs.date` (`mask => br-data`) | Valor via `tobrdata()` |
| `data_entrada` | `components.inputs.date` | Valor via `tobrdata()` |
| `duracao_viagem` | `components.inputs.input` | |
| `fundamentos_legais` | `components.inputs.input` | Default = `$lei_padrao` da configuração |
| `numero_diarias` | `components.inputs.input` (`tipo => number`) | |
| `valor_diarias` | `components.inputs.input` (`mask => money`) | |
| `padrao_arquivo_config` | `components.inputs.checkbox` | **Exibido apenas no create** (`@if (!isset($data))`) |
| `archive` | `<input type="file">` | `accept=".pdf, .doc, .docx"` — exibido **só se** não houver arquivo anterior |

Comportamento do bloco de arquivo:

```blade
@isset($arquivo[0])<label class="ml-4" for="">Arquivo da Lei</label>@endisset
<p class="ml-4">{{ isset($arquivo[0]) ? $arquivo[0]['title'] : '' }}</p>
@if (isset($arquivo[0]['title']))
    <button id="btn_delete" value="@isset($id){{ $id }}@endisset" class="btn-danger ml-4 mb-3">Excluir Arquivo </button>
@else
<input type="file" class="custom-file-input ml-4 mb-3" name="archive" id="archive" value="" accept=".pdf, .doc, .docx">
@endif
```

Scripts do formulário: Summernote (`assets/plugins/summernote/summernote.min.js`,
`summernote-pt-BR.js`, `summernote-image-atr.js`) e
`assets/js/custom/utilities/richtext/summernote.js` (carregados mas **não
aplicados** a nenhum campo do formulário — o `dados_objetivo` é `textarea`
simples), mais `assets/js/custom/utilities/helpers/deleta_arquivo.js`.

### 2.3 `configuracoes/create.blade.php` + `configuracoes/form.blade.php`

- Rota do form: `route('requerimento-diarias-config.update')` com
  `method_field('PUT')` e `files => true`.
- Campo `lei_padrao` (input de texto) e upload `archive` (`.pdf, .doc, .docx`).
- Quando já existe `archive`, exibe o nome do arquivo e o botão
  "Excluir Arquivo" (`#btn_delete`), acionado por
  `v6/public/assets/js/custom/utilities/helpers/delete_archive.js`:

```js
btn_delete = document.querySelector('#btn_delete');
if (btn_delete) {
    btn_delete.addEventListener('click', function () {
        event.preventDefault();
        window.location.href = "/deletar-arquivo-padrao"
    })
}
```

### 2.4 `pdf/index.blade.php` — Template do PDF

Estrutura do documento (sem `<html>` do CMS, CSS próprio em `pdf/style.blade.php`):

| Bloco | Conteúdo |
|---|---|
| `<header>` | Data corrente, brasão do estado (`assets/images/states/{uf}.png`), `ESTADO DA {name}`, nome da prefeitura, "SECRETARIA DE FINANÇAS", favicon |
| Título | "REQUERIMENTO DE DIÁRIAS" e `Diaria nº {codigo_diarias}/{ano de created_at}` |
| "Dados da Diária" → "Dados do Requerente" | Nome, matrícula, CPF, identidade |
| (continuação) | Secretaria, cargo, banco, agência, conta |
| "Dados do Objetivo" | `dados_objetivo` |
| "Demais Informações" | Cidade de destino, UF (`$diaria->estado->uf`), transporte, data de saída, data de retorno, duração da viagem |

**Mascaramento** (controlado por `$reqPortal`):

```blade
{{ $reqPortal == true ? 'xxx'.substr($diaria->servidor->cpf, 3, -3).'.xx' : $diaria->servidor->cpf }}
{{ $reqPortal == true ? 'xxx-'.substr($diaria->servidor->identidade, -5) : $diaria->servidor->identidade }}
```

- CMS (`generatePDF($id)`): `$reqPortal = false` → CPF e identidade **completos**.
- Portal (`generatePDF($id, true)`): `$reqPortal = true` → CPF e identidade
  **parcialmente mascarados**.

> O PDF **não** mascara banco, agência, conta, matrícula nem cargo no Portal.

## 3. Portal — `show.blade.php`

Estende `"portal.layouts.$model.layout.layout"` (variável `$model` = template
ativo, ex. `modelo1`) e usa o breadcrumb
`"portal.layouts.$model.layout.breadcrumb"`.

### 3.1 Formulário de filtros

`method="POST"`, `action="{{ route('requerimento-de-diarias-portal.index') }}"`,
com `csrf_token()` hidden.

| Campo | Tipo | Máscara | Observação |
|---|---|---|---|
| `cpf` | text | jQuery Mask `000.000.000-00` | Erro exibido com `is-invalid` |
| `data_saida` | date | — | |
| `data_retorno` | date | — | |
| `num_diaria` | number | — | |
| `req_name` | text | — | |

Botões: "Limpar campos" (`type="reset"` + `clearInputs('#cpf','#num_diaria','#req_name')`)
e "Consultar" (submit).

### 3.2 Tabela de resultados

| Coluna | Origem |
|---|---|
| N° da diária | `$diaria->codigo_diarias` |
| Nome do requerente | `$diaria->servidor->name` |
| RG | `xxx-{{ substr($diaria->servidor->identidade, -5) }}` |
| CPF | `xxx{{ substr($diaria->servidor->cpf, 3, -2) }}xx` |

Ícones de ação por linha:

| Ícone | Destino | Condição |
|---|---|---|
| `fa-file` (Visualizar Regulamentação) | `url('storage/leis_de_requerimentos', $diaria->archives->title)` | `@if (isset($diaria->archives))` |
| `fa-file` (cinza) | `url('storage/leis_de_requerimentos', $lei_padrao)` | `@elseif(isset($lei_padrao))` |
| `fa-file` (cinza) | — | Sem arquivo: apenas ícone |
| `fa-eye` (Visualizar Requerimento) | `route('requerimento-de-diarias-portal.show', $diaria->id)` | Sempre |

> O `@if/@elseif/@else` está com o `@else` **dentro** do `@elseif` (chaveamento
> Blade malformado) — o bloco "sem arquivo" nunca é renderizado como texto.
> Na prática o resultado é apenas a ausência do link.

Paginação: `{{ $diarias->links() }}` (10 por página).

### 3.3 Layout do Portal

`getTemplateActived()` (`v6/app/Http/Traits/GetInformationsPrefectureTrait.php:92`)
lê `configurations.key = 'layout'` (valor atual no banco: `modelo1`) e valida
que `portal.layouts.<layout>.home.index` existe; se não existir, **ativa a
página de manutenção** (`pagina_em_manutencao = 1`) e responde 404.

Variantes disponíveis em `v6/resources/views/portal/layouts/`:
`modelo1`, `modelo2`, `modelo3`, `modelo4`, `modelo5`, `modelo6`, `default`,
além das pastas específicas (`busca-diarias`, `diario-oficial`, `calendar-events`,
`contratos`, `dynamics-forms`, `newsbit`, `surveys`, `barra-privacidade`).

## 4. JavaScript do DataTable

Arquivo: `v6/public/assets/js/custom/contents/requerimentos_diarias/datatable.js`

```js
let collums = [
    { data: 'requerente', ... },
    { data: 'objetivo_viagem', ... },
    { data: 'fundamentos_legais', ... },
    { data: null, orderable: false, render: function (data) {
        return `<div class='flex justify-center'>`
            + createDownloadButton(data.download_link)
            + createBTN(data.id, `requerimento-diarias/${data.id}/edit`, data.edit, data.delete, `requerimento-diarias/${data.id}`)
            + `</div>`;
    }}
];

runDatatables('requerimento_diarias', collums, true, 'ASC', null, true);
```

Helpers em `v6/public/assets/js/custom/utilities/table.js`:

| Função | Linha | Comportamento |
|---|---|---|
| `runDatatables(url, columns, ordenavel, type_order, callback, deleteAll, ...)` | 3 | Injeta a coluna `value` e, se `deleteAll`, a coluna de seleção; monta `ajax.url = /cms/datatable/${url}` (linha 183) |
| `createDownloadButton(url)` | 449 | Link com ícone de download, `target=_blank` |
| `createBTN(id, url, editable, deletable, del_url)` | 227 | Botões Editar/Excluir condicionados por `data.edit` / `data.delete` |
| `createDeleteAllButton(id, deletable)` | (tabela) | Checkbox de seleção em lote |

Exportação: `runDatatables` registra os botões **Excel** (`extend: 'excel'`) e
**PDF** (`extend: 'pdf'`, com `orientation: 'landscape'`, `pageSize: 'A4'`),
customizando larguras de coluna por contagem (linhas 29-120). A exportação usa
`columns: ':visible:not(.column-actions)'` e `stripHtml: true`.

## 5. Exclusão em lote

`v6/public/assets/js/custom/utilities/deleteAll.js`:

1. `#checkAll` marca/desmarca `input[name="toDeleteAll[]"]` e atualiza o
   contador `#countDeleteLote`.
2. `submitDeleteAll(routeDelete)` coleta os ids marcados, pede confirmação via
   SweetAlert e faz `POST` para a rota com `{_token, toDelete: [...]}`.
3. Em sucesso, recarrega o DataTable (`datatable.ajax.reload()`).

O componente Blade `prefecture.components.deleteByLoteSubmitButton` recebe
`['route' => 'requerimento-diarias.destroyAll']`.

## 6. Exclusão de arquivo (dois scripts distintos)

| Script | Destino | Efeito |
|---|---|---|
| `v6/public/assets/js/custom/utilities/helpers/deleta_arquivo.js` | `/deletar-arquivo/{id}` | Remove o `archives` do requerimento e marca `padrao_arquivo_config = false` |
| `v6/public/assets/js/custom/utilities/helpers/delete_archive.js` | `/deletar-arquivo-padrao` | Zera `archive` e `path` da configuração |

Ambos usam `window.location.href` (navegação), não AJAX.

## 7. Dependências de assets

| Asset | Onde |
|---|---|
| `assets/js/custom/utilities/table.js` | Helper global de DataTable |
| `assets/js/custom/utilities/deleteAll.js` | Exclusão em lote |
| `assets/js/custom/utilities/helpers/deleta_arquivo.js` | Exclusão do arquivo do requerimento |
| `assets/js/custom/utilities/helpers/delete_archive.js` | Exclusão do arquivo padrão |
| `assets/js/custom/utilities/functions.js` | `clearInputs()` (Portal) |
| `assets/plugins/jquery-mask/jquery.mask.min.js` | Máscara de CPF no Portal |
| `assets/plugins/summernote/*` | Carregados no formulário CMS (sem efeito real) |
| `assets/images/states/{uf}.png` | Brasão do estado no PDF |
