Docs›Componentes (Admin)›mad-sheet
Componentes (Admin)

mad-sheet

Planilha estilo Excel para lançamento em lote: teclado, paste TSV, colunas calculadas e save transacional.

Planilha de lancamento em lote estilo Excel: grade de celulas editaveis com navegacao por teclado, paste TSV, coluna calculada, linha de totais e save tudo-ou-nada numa transacao unica. Toda a config visual mora no Blade (<mad-sheet> + filhos <mad-sheet-col>); o PHP so entra quando ha escopo multi-tenant ou enriquecimento por linha.

Compilador: Mad\Sheet\MadSheetCompiler (passo 1.08 do MadBlade). Componente: Mad\Sheet\MadSheet. Sem host proprio, o compiler instancia um Mad\Sheet\MadSheetStandalone.

Tag

<mad-sheet model="StockCount" database="business" rows-min="10" max-rows="2000">
    <mad-sheet-col field="produto_id" type="combo" model="Produto" display="nome"
                   label="Produto" required width="220px" />
    <mad-sheet-col field="quantidade" type="number" label="Qtd" total="sum"
                   decimals="0" required />
    <mad-sheet-col field="valor" type="money" label="Valor unit." total="sum" width="140px" />
    <mad-sheet-col field="total" label="Total" compute="{quantidade} * {valor}" />
    <mad-sheet-col field="data" type="date" label="Data" :default="date('Y-m-d')" width="150px" />
    <mad-sheet-col field="obs" label="Observacao" placeholder="opcional" />
</mad-sheet>

Props de <mad-sheet>

Prop Tipo Default Descricao
model string — Model Eloquent alvo dos INSERTs (short name ou FQCN). Obrigatorio
database string MAIN_DATABASE Conexao
rows-min int 8 Linhas em branco iniciais
max-rows int 2000 Guard de payload do batch
totals bool true Linha de totais. Desliga com totals="false" ou no-totals

Props de <mad-sheet-col>

Uma coluna por filho self-closing; a ordem dos filhos e a ordem visual.

Prop Tipo Default Descricao
field string — Coluna do model. Obrigatorio
label string valor de field Header
type string text text | number | money | date | combo (dbcombo = alias de combo)
required bool false Celula obrigatoria nas linhas preenchidas
readonly bool false Celula nao editavel (descartada no save)
width string auto Largura fixa, ex. 140px
total string — Totalizador da coluna: sum | count
default string — Valor inicial das celulas novas
placeholder string — Placeholder do input
compute string — Coluna calculada, ex. {qtd} * {valor} — readonly e nunca persiste

Extras por tipo

Tipo Props
number / money decimals min max step prefix suffix decimal-sep thousand-sep fill-direction allow-negative
date min max display-mask (default dd/mm/yyyy) database-mask (default yyyy-mm-dd)
text mask (cpf, cnpj, ...) strip-mask maxlength force-case
combo options="1:Ativo,2:Inativo" (vence model), model (alias legado: source), database ('' herda a do sheet), key (default id), display (coluna ou mask {nome} - {uf}; alias legado source-label), order-by order, where (DSL, ou :where="$closure"), search min-length, depends-on / depends-column (cascade por linha, forca search), no-results-message e a familia no-results-create-* / no-results-quick-register-*

O combo aceita ainda o filho <mad-quick-form action="..."><mad-input-field .../></mad-quick-form> para cadastro rapido dentro da celula.

Comportamento no client

  • Teclado de planilha: Enter desce (cria linha nova no fim se a atual esta preenchida), setas navegam (esquerda/direita so com o caret na borda), Ctrl+D copia a celula de cima (fill-down), Ctrl+Z desfaz (stack de 50).
  • Paste TSV do Excel espalha multi-celula a partir da celula focada, pulando colunas readonly e normalizando money (1.234,56 -> 1234.56) e data (dd/mm/yyyy -> Y-m-d).
  • Virtual scroll com linha de altura fixa (37px).
  • Linha de totais soma/conta ao vivo no client.
  • Toolbar padrao: "+10 linhas", "Desfazer", "Validar", "Salvar", com contadores de linhas preenchidas e de erros.
  • Strings i18n em mad.sheet.* (en/pt/es).

Persistencia

O Salvar envia so as linhas preenchidas como JSON {indiceAbsoluto: {campo: valor}} para onSaveBatch, que valida tudo (required, faixa numerica, data no formato da database-mask, maxlength, mask com digito verificador de cpf/cnpj, membership do combo em lote e o pareamento pai->filho do cascade) e persiste numa transacao unica tudo-ou-nada. Qualquer erro devolve {row, field, msg}, o client destaca as celulas e foca a primeira; nada e gravado parcialmente. O botao "Validar" (onValidateBatch) roda a mesma validacao sem persistir.

Subclasse (hooks)

use Mad\Sheet\MadSheet;

class LancamentoSheet extends MadSheet
{
    protected static string $wrapper = self::INTERNAL;

    protected string $model    = 'Lancamento';
    protected string $database = 'business';

    /** Roda por linha DENTRO da transacao. Excecao aqui reverte o batch inteiro. */
    protected function beforeSaveRow(array $row, int $index): array
    {
        $row['unit_id'] = MadSession::unitId();
        return $row;
    }

    /** Models ja persistidos: notificar, recalcular agregados. */
    protected function afterSaveBatch(array $models): void
    {
    }
}

Gotchas

  • Atributo de tag mad-* nao aceita {{ }} — o compiler roda antes do Blade. Expressao PHP entra com dois-pontos: :default="date('Y-m-d')".
  • Persistencia via fill(): os campos das colunas precisam estar no $fillable do model, senao o insert sai vazio.
  • So campos declarados em colunas entram no insert; payload extra e descartado e readonly some no save.
  • Model e combo resolvem pelo registry — nunca uma classe crua vinda do request.
  • Zeros em money/number nao contam como linha preenchida (o cell-component escreve 0 no blur sem digitacao).
  • <mad-sheet-col> orfao fora de <mad-sheet> e removido no compile (defense in depth), nao vira componente Blade.