MAD Lab
/
Tutor > Módulos visuais > Gantt

Gantt

Módulos visuais

mad-gantt-chart mad-gantt-column mad-gantt-toolbar
Cronograma (dados do banco)

mad-gantt declarativo lendo a fixture TutorGanttTarefa — colunas via mad-gantt-column, texto livre via mad-gantt-toolbar e hierarquia (parent-field) com caminho crítico.

resources/views/tutor/examples/modulos-gantt/declarativo.blade.php
{{--
    Reabre o host — mesmo motivo do board do Kanban (escopo isolado do
    x-tutor-demo). O compiler do gantt também emite "$that ?? null". Ver a
    nota completa sobre as duas armadilhas de compilador regex (tag literal
    em QUALQUER comentário, Blade ou PHP + nome da diretiva de bloco PHP
    inline citado por extenso em qualquer comentário) em
    examples/modulos-kanban/board.blade.php.
--}}
@php
    $that = \Mad\Component\MadRenderContext::getComponent();
@endphp

<mad-gantt model="TutorGanttTarefa" database="business"
    name-field="nome" start-field="dt_inicio" end-field="dt_fim"
    parent-field="parent_id" progress-field="percentual" color-field="cor"
    owner-field="responsavel" order-by="ordem"
    title="Cronograma de exemplo" start-date="2026-08-24" interval="30 days"
    zoom="day" critical-path striped-rows>

    <mad-gantt-toolbar>
        <span style="font-size:12px; color:var(--mad-text-muted);">
            Arraste as barras para reagendar — a duração é salva em `dt_inicio`/`dt_fim`.
        </span>
    </mad-gantt-toolbar>

    <mad-gantt-column field="name"     label="Tarefa" width="220" tree />
    <mad-gantt-column field="start"    label="Início" width="100" format="date" />
    <mad-gantt-column field="end"      label="Fim"    width="100" format="date" />
    <mad-gantt-column field="duration" label="Dias"   width="70"  format="days" align="center" />
    <mad-gantt-column field="owner"    label="Resp."  width="90" />
    <mad-gantt-column field="progress" label="Prog."  width="80"  format="percent" align="right" />
</mad-gantt>
API programática (builder)

MadGantt::make(...) montado em PHP e renderizado via mad-gantt :chart — mesmo padrão do harness GanttDevView, útil quando os dados não vêm direto de uma tabela.

resources/views/tutor/examples/modulos-gantt/programatico.blade.php
@php
    // Modo "chart" (:chart=) do compiler ignora config do host e só chama
    // ->render() no builder devolvido — funciona mesmo sem reabrir $that,
    // mas reabrimos por padronização e porque $that->chartSimples() abaixo
    // precisa mesmo do host correto (TutorModulosGantt::chartSimples()).
    $that = \Mad\Component\MadRenderContext::getComponent();
@endphp

<mad-gantt :chart="$that->chartSimples()" />
Código-fonte completo da página
app/control/Tutor/TutorModulosGantt.php
<?php

namespace App\Control\Tutor;

use App\Models\TutorDemo\TutorGanttTarefa;
use App\Support\Tutor\TutorCatalog;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Mad\Calendar\MadGantt;
use Mad\Calendar\MadGanttComponent;

/**
 * TutorModulosGantt — página "Gantt" do MAD Lab (LOTE L9 / Onda 1).
 *
 * Estende Mad\Calendar\MadGanttComponent (base declarativa/auto-query do
 * módulo — analoga a MadKanban/MadCalendarComponent) para o demo GRANDE:
 * `<mad-gantt model=… database=…>` com `<mad-gantt-column>` e
 * `<mad-gantt-toolbar>` — as 3 tags do catálogo (mad-gantt-chart,
 * mad-gantt-column, mad-gantt-toolbar; "mad-gantt-chart" no catálogo é o
 * nome genérico da tag real `<mad-gantt>`).
 *
 * O demo PEQUENO usa o modo "legado"/programático (molde: app/control/Sys/
 * GanttDevView.php) — `<mad-gantt :chart="$that->chartSimples()" />` — que
 * ignora toda config do host e só chama `->render()` no builder MadGantt
 * devolvido pelo método. Os dois modos convivem na mesma página sem
 * conflito: o modo chart não lê nem grava props do host (diferente do modo
 * declarativo do Kanban), então não há o problema de "última config vence"
 * documentado em TutorModulosKanban.
 */
class TutorModulosGantt extends MadGanttComponent
{
    protected static string $wrapper = self::INTERNAL;

    protected string $catalogKey = 'modulos_gantt';

    protected string $model         = 'TutorGanttTarefa';
    protected string $database      = 'business';
    protected string $nameField     = 'nome';
    protected string $startField    = 'dt_inicio';
    protected string $endField      = 'dt_fim';
    protected string $parentField   = 'parent_id';
    protected string $progressField = 'percentual';
    protected string $colorField    = 'cor';
    protected string $ownerField    = 'responsavel';
    protected string $orderBy       = 'ordem';

    protected string $ganttTitle = 'Cronograma de exemplo';
    protected string $startDate  = '2026-08-24';
    protected string $interval   = '30 days';
    protected string $zoom       = 'day';
    protected bool   $criticalPath = true;

    public function mount(array $params = []): void
    {
        $this->ensureFixture();
        parent::mount($params);
    }

    protected function view(): string|array
    {
        return TutorCatalog::page($this->catalogKey)['view'];
    }

    /**
     * Demo pequeno — API programática (molde: GanttDevView::chartA()).
     * Instância independente do host: não mexe em $this->model/columns/etc.
     */
    public function chartSimples(): MadGantt
    {
        $g = MadGantt::make('2026-08-24')
            ->title('Sprint curto (API programática)')
            ->zoom('day')
            ->interval('14 days')
            ->columns([
                ['field' => 'name',     'label' => 'Tarefa', 'width' => 200, 'tree' => true],
                ['field' => 'start',    'label' => 'Início', 'width' => 90,  'format' => 'date'],
                ['field' => 'end',      'label' => 'Fim',    'width' => 90,  'format' => 'date'],
                ['field' => 'progress', 'label' => 'Prog.',  'width' => 70,  'format' => 'percent', 'align' => 'right'],
            ]);

        $g->addTask('s1', ['name' => 'Planejamento', 'start' => '2026-08-24', 'end' => '2026-08-26', 'progress' => 1]);
        $g->addTask('s2', ['name' => 'Desenvolvimento', 'start' => '2026-08-26', 'end' => '2026-09-02', 'progress' => 0.4]);
        $g->addTask('s3', ['name' => 'Homologação', 'start' => '2026-09-02', 'end' => '2026-09-05', 'progress' => 0]);
        $g->addTask('s4', ['name' => 'Entrega', 'type' => 'milestone', 'date' => '2026-09-05']);

        $g->addDependency('s1', 's2', 'FS');
        $g->addDependency('s2', 's3', 'FS');
        $g->addDependency('s3', 's4', 'FS');

        return $g;
    }

    // ── Fixture (molde: KanbanDevView::ensureFixture) ───────────────────────

    private function ensureFixture(): void
    {
        $schema = Schema::connection('business');

        if (!$schema->hasTable('tutor_gantt_tarefas')) {
            $schema->create('tutor_gantt_tarefas', function ($t) {
                $t->increments('id');
                $t->string('nome');
                $t->string('dt_inicio', 10);
                $t->string('dt_fim', 10);
                $t->unsignedInteger('parent_id')->nullable();
                $t->decimal('percentual', 5, 2)->default(0);
                $t->string('cor', 16)->nullable();
                $t->string('responsavel')->nullable();
                $t->integer('ordem');
            });
        }

        if (TutorGanttTarefa::query()->count() > 0) {
            return;
        }

        DB::connection('business')->table('tutor_gantt_tarefas')->insert([
            ['id' => 1, 'nome' => 'Fase 1 — Descoberta', 'dt_inicio' => '2026-08-24', 'dt_fim' => '2026-08-31', 'parent_id' => null, 'percentual' => 100, 'cor' => '#3b82f6', 'responsavel' => 'Ana',   'ordem' => 1],
            ['id' => 2, 'nome' => 'Entrevistas',         'dt_inicio' => '2026-08-24', 'dt_fim' => '2026-08-27', 'parent_id' => 1,    'percentual' => 100, 'cor' => '#3b82f6', 'responsavel' => 'Ana',   'ordem' => 2],
            ['id' => 3, 'nome' => 'Relatório',           'dt_inicio' => '2026-08-27', 'dt_fim' => '2026-08-31', 'parent_id' => 1,    'percentual' => 80,  'cor' => '#3b82f6', 'responsavel' => 'Bruno', 'ordem' => 3],
            ['id' => 4, 'nome' => 'Fase 2 — Construção', 'dt_inicio' => '2026-08-31', 'dt_fim' => '2026-09-14', 'parent_id' => null, 'percentual' => 35,  'cor' => '#f59e0b', 'responsavel' => 'Carla', 'ordem' => 4],
            ['id' => 5, 'nome' => 'Back-end',            'dt_inicio' => '2026-08-31', 'dt_fim' => '2026-09-09', 'parent_id' => 4,    'percentual' => 50,  'cor' => '#f59e0b', 'responsavel' => 'Diego', 'ordem' => 5],
            ['id' => 6, 'nome' => 'Front-end',           'dt_inicio' => '2026-09-03', 'dt_fim' => '2026-09-14', 'parent_id' => 4,    'percentual' => 20,  'cor' => '#f59e0b', 'responsavel' => 'Carla', 'ordem' => 6],
            ['id' => 7, 'nome' => 'Fase 3 — Entrega',    'dt_inicio' => '2026-09-14', 'dt_fim' => '2026-09-21', 'parent_id' => null, 'percentual' => 0,   'cor' => '#16a34a', 'responsavel' => 'Elaine', 'ordem' => 7],
            ['id' => 8, 'nome' => 'Homologação',         'dt_inicio' => '2026-09-14', 'dt_fim' => '2026-09-18', 'parent_id' => 7,    'percentual' => 0,   'cor' => '#16a34a', 'responsavel' => 'Elaine', 'ordem' => 8],
            ['id' => 9, 'nome' => 'Go-live',             'dt_inicio' => '2026-09-21', 'dt_fim' => '2026-09-21', 'parent_id' => 7,    'percentual' => 0,   'cor' => '#16a34a', 'responsavel' => 'Elaine', 'ordem' => 9],
        ]);
    }
}
resources/views/tutor/modulos/gantt.blade.php
<x-tutor-page page="modulos_gantt">
    <x-tutor-demo demo="tutor.examples.modulos-gantt.declarativo"
        title="Cronograma (dados do banco)" desc="mad-gantt declarativo lendo a fixture TutorGanttTarefa — colunas via mad-gantt-column, texto livre via mad-gantt-toolbar e hierarquia (parent-field) com caminho crítico." />

    <x-tutor-demo demo="tutor.examples.modulos-gantt.programatico"
        title="API programática (builder)" desc="MadGantt::make(...) montado em PHP e renderizado via mad-gantt :chart — mesmo padrão do harness GanttDevView, útil quando os dados não vêm direto de uma tabela." />
</x-tutor-page>