Módulos visuais
mad-calendar-resource
mad-resource-timeline
Agenda de salas (resource timeline)
mad-calendar com mad-calendar-resource — cada linha é um recurso (sala) e os eventos ficam alinhados na coluna do horário. É o mesmo componente do calendário comum; o resource-timeline entra sozinho quando um recurso é configurado.
Cada linha é uma sala — passe o mouse num evento pra ver o popover.
resources/views/tutor/examples/modulos-calendario-recursos/timeline.blade.php
@php($that = \Mad\Component\MadRenderContext::getComponent())
<mad-calendar
calendar-id="tutor-modulos-calendario-recursos"
model="TutorEventoRecursoEvento" database="business"
title-field="titulo" start-field="inicio" end-field="fim" color-field="cor"
resource-field="recurso_id">
<mad-calendar-toolbar>
<span style="font-size:12px; color:var(--mad-text-muted);">
Cada linha é uma sala — passe o mouse num evento pra ver o popover.
</span>
</mad-calendar-toolbar>
<mad-calendar-resource model="TutorEventoRecurso" database="business"
id-field="id" title-field="nome" color-field="cor" label="Sala" order-by="nome" />
</mad-calendar>
Código-fonte completo da página
app/control/Tutor/TutorModulosCalendarioRecursos.php
<?php
namespace App\Control\Tutor;
use App\Models\TutorDemo\TutorEventoRecurso;
use App\Support\Tutor\TutorCatalog;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Mad\Calendar\MadCalendarComponent;
use Mad\Http\MadResponse;
/**
* TutorModulosCalendarioRecursos — página "Calendário de recursos" do MAD
* Tutor (LOTE L9 / Onda 1).
*
* Estende Mad\Calendar\MadCalendarComponent — a view "Resource Timeline" é o
* MESMO `<mad-calendar>`, só que com `<mad-calendar-resource>` configurado
* (aí o MadFullCalendar interno troca sozinho pra
* components.resource-timeline — ver MadCalendarComponent::renderCalendarHtml,
* `$wantResource = $this->resourceModel !== '' || ...`). Não existe uma tag
* `<mad-resource-timeline>` separada no compiler; "mad-resource-timeline" no
* catálogo é o nome conceitual dessa VIEW, não uma tag literal — ver
* relatório do lote.
*
* Mesma regra de instância única do TutorModulosCalendario (config em sessão
* chaveada só pela classe) — 1 `<mad-calendar>` só nesta página.
*/
class TutorModulosCalendarioRecursos extends MadCalendarComponent
{
protected static string $wrapper = self::INTERNAL;
protected string $catalogKey = 'modulos_calendario_recursos';
public function mount(array $params = []): void
{
$this->ensureFixture();
parent::mount($params);
}
protected function view(): string|array
{
return TutorCatalog::page($this->catalogKey)['view'];
}
public function onEventClick(string $id, string $title, string $view): MadResponse
{
return (new MadResponse())->toast("Reserva: {$title}", 'info');
}
// ── Fixture (molde: KanbanDevView::ensureFixture) ───────────────────────
private function ensureFixture(): void
{
$schema = Schema::connection('business');
if (!$schema->hasTable('tutor_evento_recursos')) {
$schema->create('tutor_evento_recursos', function ($t) {
$t->increments('id');
$t->string('nome');
$t->string('cor', 16)->nullable();
});
}
if (!$schema->hasTable('tutor_evento_recurso_eventos')) {
$schema->create('tutor_evento_recurso_eventos', function ($t) {
$t->increments('id');
$t->string('titulo');
$t->unsignedInteger('recurso_id');
$t->dateTime('inicio');
$t->dateTime('fim');
$t->string('cor', 16)->nullable();
});
}
if (TutorEventoRecurso::query()->count() > 0) {
return;
}
$salas = [
['id' => 1, 'nome' => 'Sala A — Térreo', 'cor' => '#3b82f6'],
['id' => 2, 'nome' => 'Sala B — 2º andar', 'cor' => '#f59e0b'],
['id' => 3, 'nome' => 'Sala C — Auditório', 'cor' => '#8b5cf6'],
];
DB::connection('business')->table('tutor_evento_recursos')->insert($salas);
$titulos = ['Reunião de time', 'Apresentação ao cliente', 'Entrevista', 'Workshop', 'Alinhamento'];
$hoje = new \DateTimeImmutable('today');
$rows = [];
foreach ($salas as $i => $sala) {
for ($d = 0; $d <= 4; $d++) {
if ($d % (2 + $i) === 0) {
continue; // agenda esburacada de propósito (nem toda sala ocupada todo dia)
}
$dia = $hoje->modify("{$d} days");
$horaIni = 9 + $i * 2;
$inicio = $dia->setTime($horaIni, 0);
$fim = $inicio->modify('+60 minutes');
$rows[] = [
'titulo' => $titulos[($i + $d) % count($titulos)],
'recurso_id' => $sala['id'],
'inicio' => $inicio->format('Y-m-d H:i:s'),
'fim' => $fim->format('Y-m-d H:i:s'),
'cor' => $sala['cor'],
];
}
}
DB::connection('business')->table('tutor_evento_recurso_eventos')->insert($rows);
}
}
resources/views/tutor/modulos/calendario-recursos.blade.php
<x-tutor-page page="modulos_calendario_recursos">
<x-tutor-demo demo="tutor.examples.modulos-calendario-recursos.timeline"
title="Agenda de salas (resource timeline)" desc="mad-calendar com mad-calendar-resource — cada linha é um recurso (sala) e os eventos ficam alinhados na coluna do horário. É o mesmo componente do calendário comum; o resource-timeline entra sozinho quando um recurso é configurado." />
</x-tutor-page>