Grotti 3.2.0: Jetzt-Liste, Filament-Pause, Strom-Torte, UI-Polish.

Jetzt/Topbar und Material-Routing, Pause bei Filament-Ende, Druckbericht mit Stromanteilen, Design- und Kamera-Stream-Polish; Bedarf-Alert-Spam und Platte-belegt-Bugs behoben.
This commit is contained in:
Dominic Gundel committed 2026-10-18 14:58:32 +02:00
1 parent 6e59df22e5
commit 4ddffbbeb1
68 files changed
+4348 -1215

No files matched your search

+21 -19
View File
@@ -9,30 +9,30 @@
<a class="ghost" id="csv-link" href="/api/v1/statistik.csv">CSV</a>
</div>
</div>
<div class="page-tools">
<div class="segmented period-presets" id="period" role="group" aria-label="Zeitraum">
<button type="button" data-period="all" class="on">Alles</button>
<button type="button" data-period="day">Tag</button>
<button type="button" data-period="week">Woche</button>
<button type="button" data-period="month">Monat</button>
<button type="button" data-period="yesterday">Gestern</button>
<button type="button" data-period="last_week">Letzte Woche</button>
<button type="button" data-period="last_month">Letzter Monat</button>
<div class="toolbar page-tools">
<div class="segmented period-presets fchips" id="period" role="group" aria-label="Zeitraum">
<button type="button" data-period="all" class="fchip on">Alles</button>
<button type="button" data-period="day" class="fchip">Tag</button>
<button type="button" data-period="week" class="fchip">Woche</button>
<button type="button" data-period="month" class="fchip">Monat</button>
<button type="button" data-period="yesterday" class="fchip">Gestern</button>
<button type="button" data-period="last_week" class="fchip">Letzte Woche</button>
<button type="button" data-period="last_month" class="fchip">Letzter Monat</button>
</div>
<input type="date" id="since" title="Von" class="date-field">
<input type="date" id="until" title="Bis" class="date-field">
<select id="host"><option value="">Alle Drucker</option></select>
<input type="text" id="material" placeholder="Sorte" size="10">
<input type="text" id="brand" placeholder="Marke" size="10">
<button type="button" id="reload">Aktualisieren</button>
<div class="tools-end"><button type="button" id="reload" class="ghost"><svg class="ico"><use href="#i-refresh"/></svg>Aktualisieren</button></div>
</div>
<p id="stat-note"></p>
<div id="stat" class="statistik"></div>
{% endblock %}
{% block script %}
<script>
function kpi(label, value, hint) {
return `<div class="kpi"><div class="kpi-val">${value}</div><div class="kpi-label">${escapeHtml(label)}</div>${hint ? '<div class="tiny">' + escapeHtml(hint) + "</div>" : ""}</div>`;
function kpi(label, value, hint, ico) {
return `<div class="kpi"><div class="kpi-label">${ico ? icon(ico) : ""}${escapeHtml(label)}</div><div class="kpi-value">${value}</div>${hint ? '<div class="kpi-sub">' + escapeHtml(hint) + "</div>" : ""}</div>`;
}
function isoDate(date) {
@@ -181,13 +181,15 @@ function render(data) {
document.getElementById("stat").innerHTML = `
<div class="kpi-row">
${kpi("Läufe", String(jobs))}
${kpi("Druckzeit", hours(o.duration_s))}
${kpi("Verbrauch", grams(o.weight_g))}
${kpi("Kosten", euro(o.cost))}
${kpi("Erfolg", success + " %", (o.completed || 0) + " fertig · " + (o.failed || 0) + " abgebrochen")}
${kpi("Ausschuss", scrap + " %", (o.scrap || 0) + " mit Urteil Ausschuss")}
${kpi("Schätztreue", ratio, data.estimate_count ? data.estimate_count + " Läufe mit Soll-Zeit" : "keine Soll-Zeit")}
${kpi("Läufe", String(jobs), "", "layers")}
${kpi("Druckzeit", hours(o.duration_s), "", "clock")}
${kpi("Verbrauch", grams(o.weight_g), "", "weight")}
${kpi("Kosten", euro(o.cost), "", "euro")}
${kpi("Erfolg", success + " %", (o.completed || 0) + " fertig · " + (o.failed || 0) + " abgebrochen", "circle-check")}
${kpi("Ausschuss", scrap + " %", (o.scrap || 0) + " mit Urteil Ausschuss", "ban")}
${kpi("Stück-Yield", o.yield_percent != null ? Math.round(o.yield_percent) + " %" : "—", (o.pieces_ok || 0) + " gut · " + (o.pieces_bad || 0) + " schlecht", "percent")}
${kpi("€ / Teil", o.cost_per_part != null ? euro(o.cost_per_part) : "—", "Material + Strom ÷ gut", "tag")}
${kpi("Schätztreue", ratio, data.estimate_count ? data.estimate_count + " Läufe mit Soll-Zeit" : "keine Soll-Zeit", "gauge")}
</div>
<div class="split">
<div class="card">