HTML-Berichte
Zuletzt aktualisiert 25 May 2026

Wenn Sie HTML als Ausgabeformat wählen, ist der Körper des Berichts keine SQL-Abfrage. Es ist eine Vorlage, die Sie selbst schreiben: in HTML, mit CSS für die Gestaltung, JavaScript für Interaktivität und Flexie Scripting-Token, um Live-Daten zu ziehen und zu formen. Was immer Sie schreiben, ist das, was der Bericht anzeigt.
Beginnen Sie unter Berichte (/reports), klicken Sie auf Neu und setzen Sie das Ausgabeformat auf HTML.
Wann Sie es einsetzen
HTML-Berichte sind das richtige Werkzeug für alles, was das Datengitter nicht darstellen kann:
- Ein Dashboard auf einer Seite mit KPI-Karten, Abschnitten in Reitern und bedingter Formatierung.
- Ein Board im Kanban-Stil, gerendert aus einer Liste von Datensätzen.
- Ein druckfähiges Dokument (Kontoauszug, Zusammenfassung, Profil), genau so gestaltet, wie Sie es möchten.
- Eine Mini-App, die die gespeicherten Daten-Lookups aufruft, die Ergebnisse formatiert und ihre eigenen Visualisierungen zeichnet.
In Kombination mit Dashboard-Widgets machen HTML-Berichte fast jedes vorstellbare Widget möglich: Sie binden den HTML-Bericht als Widget ein, und das Dashboard rendert Ihr eigenes Layout.
Die Berichtseinstellungen
Dieselben wie bei Datengitter-Berichten, mit folgenden Ausnahmen:
- Ausgabeformat ist auf HTML gesetzt.
- Abfrage wird durch Vorlage ersetzt, den HTML-Körper des Berichts. Für das Vorlagenfeld selbst gibt es keine Zeilenobergrenze; die Rendergeschwindigkeit hängt von den darin enthaltenen Daten-Lookups ab (die sehr wohl begrenzt sind, siehe unten).
- Filter können weiterhin definiert werden, aber wie sie angewendet werden, liegt bei Ihnen (Sie lesen die übermittelten Filterwerte innerhalb Ihrer Vorlage aus).
- Standard-Sortierspalte und -richtung gelten für HTML-Berichte nicht.
Was Sie schreiben können
Alles, was in einem Browser gerendert wird:
- HTML für die Struktur.
- CSS für die Gestaltung, inline, in einem
<style>-Tag oder referenziert. - JavaScript für Interaktivität, in eingebetteten
<script>-Blöcken oder über eine<script src>-Referenz auf eine externe Datei. - Flexie Scripting für Daten. Jede Funktion und jeder Filter, die in der Flexie-Scripting-Referenz aufgeführt sind, stehen innerhalb der Vorlage zur Verfügung.
Ein minimales Beispiel:
<style>
.card { padding: 1rem; border: 1px solid #eee; border-radius: 8px;
background: #fff; margin-bottom: .75rem; }
.num { font-size: 2rem; font-weight: 600; color: #1a73e8; }
.lbl { font-size: .85rem; color: #555; text-transform: uppercase; }
</style>
<h2>This week at a glance</h2>
<div class="card">
<div class="num">{{ findCount("deal", "is_won", 1) }}</div>
<div class="lbl">Deals won (all-time)</div>
</div>
<div class="card">
<div class="num">{{ findCount("case", "status", "open") }}</div>
<div class="lbl">Open cases</div>
</div>
Öffnen Sie den Bericht, und Sie erhalten zwei KPI-Karten, gespeist aus Live-Daten. Dieselbe Idee skaliert bis hin zu einer vollständig eigenen Seite.
Daten ziehen, dann zusammenführen
Da Flexie Scripting innerhalb der Vorlage verfügbar ist, können Sie mehrere Lookups ausführen und sie nach Belieben kombinieren:
{% set winners = query("
SELECT u.full_name, SUM(d.amount) AS total
FROM deals d
JOIN users u ON u.id = d.owner_id
WHERE d.is_won = 1
GROUP BY u.id
ORDER BY total DESC
LIMIT 10
") %}
<h2>Top closers</h2>
<ol>
{% for row in winners %}
<li>
<strong>{{ row.full_name }}</strong> —
{{ row.total | number_format(0) }}
</li>
{% endfor %}
</ol>
Oder rufen Sie eine Liste von Datensätzen ab und rendern Sie sie als Karten, als Tabelle, als Kanban: ganz wie Sie möchten.
Schleifen, Bedingungen, Formatierung
Alles, was Sie von den Flexie-Scripting-Grundlagen erwarten, funktioniert:
{% set deals = query("
SELECT id, name, amount, is_won, is_lost
FROM deals
WHERE owner_id = {user_id}
ORDER BY date_modified DESC
LIMIT 50
") %}
<table>
<thead><tr><th>Deal</th><th>Amount</th><th>Status</th></tr></thead>
<tbody>
{% for d in deals %}
{% set status = d.is_won ? "Won" : (d.is_lost ? "Lost" : "Open") %}
{% set colour = d.is_won ? "#0a8a3f" : (d.is_lost ? "#c32c2c" : "#888") %}
<tr>
<td>{{ d.name }}</td>
<td>{{ d.amount | number_format(2) }}</td>
<td style="color: {{ colour }}">{{ status }}</td>
</tr>
{% endfor %}
</tbody>
</table>
Dieselben Platzhaltervariablen, die in Datengitter-Abfragen funktionieren ({user_id}, {group_id}, {role_id}, {timezone}), funktionieren auch innerhalb von query(...)-Aufrufen in HTML-Berichten.
Was die Vorlage nutzen kann
Das vollständige Flexie-Scripting-Toolkit steht in HTML-Berichten zur Verfügung:
- Daten-Lookups:
findOne,findMany,findCount,findSum,findMin,findMax,findDeals,findCases,findDealsValue,getSmartListRecords,getAccountContacts,getUserById,getOrganization,query(nur lesend, SQL). - Statistik-Pakete:
getDealStats,getInvoiceStats,getCaseStats. - Rechnen und Formatieren:
add,subtract,multiply,divide,numberFormat,formatCurrency,round. - Datumsfunktionen:
date,now,dateAdd,dateSubtract,dateDiff,daysBetween. - Text:
truncate,htmlToText,startsWith,endsWith,urlEncode,md5,base64encode. - Sammlungen:
sumField,avgField,minField,maxField,countDistinct,collectionColumnsowie die Filtergroup_by/sort_by/unique_by/sum_by. - JSON:
jsonDecode,jsonPath. - Visuell:
qrCode.
Kurz gesagt: Alles, was ein normaler Flexie-Scripting-Kontext kann, ist verfügbar, einschließlich der Sicherheits-Helfer (signUrl, jwtEncode, hashHmac) für eingebettete Aktionen und Links.
Einschränkungen gelten weiterhin
HTML-Berichte sind mächtig, aber die zugrunde liegenden Daten-Lookups halten sich weiterhin an die Regeln:
query(...)ist nur lesend. Es akzeptiertSELECTundWITH; es weistINSERT,UPDATE,DELETE,DROP,TRUNCATE,CREATEundSELECT *zurück.- Obergrenze von 1.000 Zeilen bei jedem
findMany(...),query(...)und jeder ähnlichen Daten zurückgebenden Funktion. Aggregieren Sie innerhalb des Aufrufs (SUM,COUNT,GROUP BY), wenn Sie eine Zahl über eine größere Grundgesamtheit benötigen. - Eingeschränkte Tabellen (Systemeinstellungen, Metadaten von Anhängen, Postfach- oder SMTP-Zugangsdaten) sind für
query(...)tabu, dieselbe Liste wie bei Datengitter-Berichten. - Nur die dokumentierten Flexie-Scripting-Funktionen, -Filter und -Tags funktionieren. Siehe die Sicherheits-Sandbox.
JavaScript und CSS, was wo läuft
JavaScript und CSS in Ihrer Vorlage laufen im Browser des Betrachters wie jede andere HTML-Seite. Für die gerenderte Ausgabe gibt es kein Sandboxing. Das bedeutet:
- Skripte können Ihr eigenes Back-End, Drittanbieter-APIs und Browser-APIs aufrufen, begrenzt durch die normalen Browser- bzw. CORS-Regeln.
- Stile können auf den Bericht beschränkt werden (verwenden Sie eine umschließende Klasse) oder global für die Seite gelten (verwenden Sie sorgfältige Selektoren).
- Das Skript läuft nachdem Flexie Scripting aufgelöst wurde.
{{ }}-Token werden serverseitig aufgelöst, und das JavaScript sieht die endgültigen Werte als wörtliche Zeichenketten oder Zahlen.
Ein gängiges Muster, JSON ausgeben, mit JS rendern
<div id="chart"></div>
<script>
const data = {{ query("
SELECT month, sales
FROM monthly_sales
WHERE year = 2026
ORDER BY month
") | json_encode | raw }};
data.forEach(row => {
const bar = document.createElement("div");
bar.style.width = row.sales / 1000 + "px";
bar.textContent = row.month + ": " + row.sales;
document.getElementById("chart").appendChild(bar);
});
</script>
Die Kette | json_encode | raw verwandelt das Abfrageergebnis in ein JSON-Literal, das direkt in das Skript eingebettet wird.
Verwenden Sie
| json_encodeimmer dann, wenn Sie einen Wert innerhalb eines<script>-Tags einbetten. Es setzt die Daten in Anführungszeichen und maskiert sie, sodass ein einzelnes Anführungszeichen oder ein Zeilenumbruch in den Daten Ihr JavaScript nicht zerstören oder eine Injektion ermöglichen kann.
Filter in HTML-Berichten
Filter können auf einem HTML-Bericht weiterhin definiert werden, wobei dieselbe JSON-Form verwendet wird, die unter Berichtsfilter (im Detail) behandelt wird. Ihre übermittelten Werte landen in der Sitzung des Nutzers, und Ihre Vorlage liest sie aus, wie Sie möchten.
In der Praxis verwenden HTML-Berichte oft Flexie-Scripting-Token direkt innerhalb ihrer query(...)-Aufrufe (über dieselben Platzhalter, {user_id}, {group_id}) statt der {filters}-Substitution, die Datengitter-Berichte nutzen. Das reichhaltigere Rendering bedeutet, dass Sie Filterwerte auch mit getQueryString("name") aus dem Query-String der URL lesen können.
Sicherheit, worauf Sie achten sollten
Jeder, der einen HTML-Bericht bearbeiten darf, kann beliebiges HTML, CSS und JavaScript in die gerenderte Seite einsetzen. Jeder, der den Bericht ansehen darf, führt diesen Code in seinem Browser aus. Also:
- Geben Sie das Recht „Berichte bearbeiten" nur vertrauenswürdigen Nutzern. Eine bösartige oder nachlässige Vorlage kann Zugangsdaten aus dem Browser des Betrachters abgreifen, ihn umleiten oder Daten abziehen. Das Rechtemodell steuert dies; halten Sie das Bearbeiten-Recht eng.
- Behandeln Sie Daten, die in
<script>-Blöcke interpoliert werden, mit Vorsicht. Lassen Sie sie immer durch| json_encodelaufen (und danach| raw, damit das resultierende JSON nicht erneut maskiert wird). Für Daten, die als sichtbares HTML eingefügt werden, lassen Sie die Standardmaskierung am besten eingeschaltet ({{ value }}ist bereits maskiert); verwenden Sie| rawnur dann, wenn Sie wirklich „das ist HTML" meinen. - Behandeln Sie Daten, die in
href/srcinterpoliert werden, mit Vorsicht. Verwenden Sie| url_encodefür Query-String-Werte.
Nächste Schritte
- Ansehen, Exportieren & Zugriff: die Ansichtsseite und die Rechte.
- Berichte als Dashboard-Widgets: wie aus einem HTML-Bericht ein vollständig eigenes Widget wird.
- Flexie-Scripting-Referenz: der Werkzeugkasten, den Ihre HTML-Vorlage nutzen kann.