Alle Beispiele
Etikettenbogen · N-up Detailband
Ein Detailband über die volle Breite, in vier Zellen pro Zeile aufgeteilt: 30 Etiketten über zwei Seiten, mit der Zeile als Paginationseinheit.
Strict
N-up
/reports/label_sheet/run
Was hier typisch ist
- Ein Detailband, vier Zellen pro Zeile via columns(4, gap: 3, rowGap: 2)
- gap verteilt die Zellen horizontal, rowGap die Zeilen vertikal
- Detail::height ist die Höhe der Zeile, nicht eines einzelnen Etiketts
- Die Engine fasst jede Zeile in ein eigenes Grid — nie ein Grid über mehrere Seiten
- Die letzte Zeile wird mit leeren Zellen aufgefüllt, damit die Spalten bündig bleiben
- Strict-Modus: 7 Zeilen × 4 Etiketten = 28 Etiketten pro Seite, mit Seitenzahlen im Fuss
Modul-Struktur
app/Reports/LabelSheet/
├── Report.php # strict, columns(4, gap: 3, rowGap: 2)
├── Source.php # 30 demo labels
└── views/
├── header.blade.php
├── label.blade.php # one cell (one record)
└── footer.blade.php
Dateien
<?php
declare(strict_types=1);
namespace App\Reports\LabelSheet;
use Guggach\Reports\Definition\PageSetup;
use Guggach\Reports\Definition\ReportBuilder;
use Guggach\Reports\Definition\ReportMode;
use Guggach\Reports\Report as BaseReport;
use Guggach\Reports\Sources\ReportSource;
/**
* N-up demo: one full-width detail band split into four label cells per row
* (docs/spec.md 6.7). Strict mode makes the row the pagination unit.
*/
final class Report extends BaseReport
{
public function key(): string
{
return 'label_sheet';
}
public function name(): string
{
return 'Versandetiketten';
}
public function layout(): string
{
return 'default';
}
public function source(): ReportSource
{
return new Source;
}
public function define(ReportBuilder $r): void
{
$r->mode(ReportMode::Strict);
$r->pageSetup(PageSetup::a4()->portrait()->marginsMm(16, 12, 16, 12));
$r->pageHeader(view: 'header')->height(14);
$r->pageFooter(view: 'footer')->height(8);
// One row holds four labels; height is the height of the whole row.
// A row occupies 32 mm + 2 mm row gap = 34 mm; 7 rows (238 mm) fit
// into the 243 mm body of an A4 page => 28 labels.
$r->detail(view: 'label', height: 32)
->columns(4, gap: 3, rowGap: 2);
}
}
<?php
declare(strict_types=1);
namespace App\Reports\LabelSheet;
use Guggach\Reports\Sources\ReportSource;
/**
* Demo labels. 30 records at 4 per row = 7 full rows + 1 row with 2 labels
* (and 2 padded cells); with 7 rows per page the report spans two pages
* (28 + 2 labels).
*/
final class Source extends ReportSource
{
public function records(): iterable
{
$people = [
['Müller', 'Anna', 'Bahnhofstrasse 12', '8001', 'Zürich', 'CH'],
['Meier', 'Beat', 'Dorfplatz 4', '3000', 'Bern', 'CH'],
['Weber', 'Clara', 'Hauptgasse 7', '4500', 'Solothurn', 'CH'],
['Fischer', 'David', 'Seestrasse 88', '6000', 'Luzern', 'CH'],
['Huber', 'Elena', 'Rosenweg 3', '9000', 'St. Gallen', 'CH'],
['Schmid', 'Fabian', 'Marktgasse 21', '8400', 'Winterthur', 'CH'],
['Brunner', 'Greta', 'Kirchplatz 2', '5000', 'Aarau', 'CH'],
['Wagner', 'Hans', 'Bergstrasse 15', '7000', 'Chur', 'CH'],
['Keller', 'Ida', 'Gartenweg 9', '3600', 'Thun', 'CH'],
['Baumann', 'Jonas', 'Poststrasse 5', '9500', 'Wil', 'CH'],
];
$rows = [];
// Copy-major order keeps the three cells of a row visually varied.
for ($copy = 1; $copy <= 3; $copy++) {
foreach ($people as $person) {
[$surname, $firstName, $street, $zip, $city, $country] = $person;
$rows[] = [
'name' => $firstName.' '.$surname,
'street' => $street,
'zip' => $zip,
'city' => $city,
'country' => $country,
];
}
}
return $rows;
}
}
<style>
.sheet-head {
display: flex;
justify-content: space-between;
align-items: baseline;
border-bottom: 1px solid #cbd5e1;
padding-bottom: 4px;
font-family: sans-serif;
color: #0f172a;
}
.sheet-head strong { font-size: 14px; }
.sheet-head span { font-size: 10px; color: #64748b; }
/* The engine owns the row/cell wrapper; this view styles the cell content. */
.label {
box-sizing: border-box;
height: 100%;
padding: 6px 8px;
border: 1px solid #94a3b8;
border-radius: 2px;
overflow: hidden;
font-family: sans-serif;
color: #0f172a;
background: #fff;
}
.label__sender {
font-size: 7px;
color: #64748b;
text-transform: uppercase;
letter-spacing: .06em;
white-space: nowrap;
}
.label__name {
margin-top: 4px;
font-size: 12px;
font-weight: 700;
line-height: 1.2;
}
.label__address {
margin-top: 2px;
font-size: 10px;
line-height: 1.35;
}
.label__country {
margin-top: 4px;
font-size: 8px;
color: #64748b;
text-transform: uppercase;
letter-spacing: .08em;
}
</style>
<div class="sheet-head">
<strong>Acme AG · Versandetiketten</strong>
<span>4 Etiketten pro Zeile · N-up Detailband</span>
</div>
<div class="label">
<div class="label__sender">Acme AG · Beispielstrasse 1 · 8000 Zürich</div>
<div class="label__name">{{ $ctx->name }}</div>
<div class="label__address">
{{ $ctx->street }}<br>
{{ $ctx->zip }} {{ $ctx->city }}
</div>
<div class="label__country">{{ $ctx->country }}</div>
</div>
<div style="display:flex;justify-content:space-between;border-top:1px solid #cbd5e1;padding-top:4px;font-family:sans-serif;font-size:9px;color:#64748b">
<span>Acme AG · Beispielstrasse 1 · 8000 Zürich</span>
<span>Seite {page}/{pages}</span>
</div>