Verwaltung: neue Kennzahlen-Kachel "Diesen Monat"

Bisher gab es nur "Heute"/"Letzte 7 Tage" — der ganze aktuelle Kalendermonat
fehlte. Neue Kachel zeigt Bestellanzahl + Umsatz diesen Monat, anklickbar wie
die anderen Kennzahlen-Kacheln (filtert die Bestellliste direkt danach). Auch
als neue Option "Dieser Monat" im Zeitraum-Dropdown ergänzt — bewusst als
echter Kalendermonat (ab dem 1.) berechnet, nicht einfach "letzte 30 Tage".

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
qcigano
2026-08-03 23:26:44 +02:00
co-authored by Claude Sonnet 5
parent 398ff2f886
commit 056ff6e574
+26 -2
View File
@@ -121,6 +121,11 @@ const lang: Locale = "de";
<span class="verwaltung-stat-value" id="stat-7tage">0</span>
<span class="verwaltung-stat-label">Letzte 7 Tage</span>
</button>
<button type="button" class="card verwaltung-stat-tile verwaltung-stat-tile-mini" data-zeitraum="monat">
<span class="verwaltung-stat-icon" aria-hidden="true">📆</span>
<span class="verwaltung-stat-value" id="stat-monat">0</span>
<span class="verwaltung-stat-label" id="stat-monat-label">Diesen Monat</span>
</button>
<div class="card verwaltung-stat-tile verwaltung-stat-tile-mini">
<span class="verwaltung-stat-icon" aria-hidden="true">📈</span>
<span class="verwaltung-stat-value" id="stat-avg"></span>
@@ -224,6 +229,7 @@ const lang: Locale = "de";
<option value="alle">Alle Zeiträume</option>
<option value="heute">Heute</option>
<option value="7tage">Letzte 7 Tage</option>
<option value="monat">Dieser Monat</option>
<option value="30tage">Letzte 30 Tage</option>
</select>
<select id="verwaltung-sort" class="verwaltung-input verwaltung-select">
@@ -405,13 +411,24 @@ const lang: Locale = "de";
setText("stat-umsatz-label", `Gesamtumsatz (${aktive.length} Bestellung${aktive.length === 1 ? "" : "en"})`);
setText("stat-avg", aktive.length > 0 ? formatPrice(gesamtumsatz / aktive.length, lang) : "");
// ── Heute / letzte 7 Tage + "braucht Aufmerksamkeit" ──
// ── Heute / letzte 7 Tage / diesen Monat + "braucht Aufmerksamkeit" ──
const jetzt = Date.now();
const heuteStr = new Date().toLocaleDateString("de-DE");
const heuteCount = aktive.filter((b) => new Date(b.created_at).toLocaleDateString("de-DE") === heuteStr).length;
const siebenTageCount = aktive.filter((b) => jetzt - new Date(b.created_at).getTime() <= 7 * MS_PRO_TAG).length;
// "Diesen Monat" = echter Kalendermonat (1. bis heute), nicht "letzte 30 Tage" — deshalb ein
// eigenes Feld statt einfach den 30-Tage-Wert zu verwenden.
const heuteDatum = new Date();
const monatsStart = new Date(heuteDatum.getFullYear(), heuteDatum.getMonth(), 1).getTime();
const monatCount = aktive.filter((b) => new Date(b.created_at).getTime() >= monatsStart).length;
const monatUmsatz = aktive.filter((b) => new Date(b.created_at).getTime() >= monatsStart).reduce((s, b) => s + Number(b.summe), 0);
setText("stat-heute", String(heuteCount));
setText("stat-7tage", String(siebenTageCount));
setText("stat-monat", String(monatCount));
setText(
"stat-monat-label",
`Diesen Monat${monatCount > 0 ? ` (${formatPrice(monatUmsatz, lang)})` : ""}`
);
const attentionIds = new Set(
aktive.filter((b) => b.status === "bezahlt" && jetzt - new Date(b.created_at).getTime() > ALTER_SCHWELLE_TAGE * MS_PRO_TAG).map((b) => b.id)
@@ -774,12 +791,19 @@ const lang: Locale = "de";
const zeitraum = zeitraumSelect.value;
const jetzt = Date.now();
const zeitraumMs = zeitraum === "heute" ? MS_PRO_TAG : zeitraum === "7tage" ? 7 * MS_PRO_TAG : zeitraum === "30tage" ? 30 * MS_PRO_TAG : null;
// "Dieser Monat" ist kein festes Zeitfenster (wie die anderen), sondern der echte
// Kalendermonat ab dem 1. — deshalb separat berechnet statt über zeitraumMs.
const heuteDatum = new Date();
const monatsStart = zeitraum === "monat" ? new Date(heuteDatum.getFullYear(), heuteDatum.getMonth(), 1).getTime() : null;
let sichtbar = 0;
document.querySelectorAll("#verwaltung-order-list .order-card").forEach((card) => {
const matchStatus = aktuellerStatusFilter === "alle" || card.dataset.bucket === aktuellerStatusFilter;
const matchSuche = !suchtext || card.dataset.search.includes(suchtext);
const matchZeitraum = !zeitraumMs || jetzt - new Date(card.dataset.created).getTime() <= zeitraumMs;
const erstelltMs = new Date(card.dataset.created).getTime();
const matchZeitraum = monatsStart !== null
? erstelltMs >= monatsStart
: !zeitraumMs || jetzt - erstelltMs <= zeitraumMs;
const zeigen = matchStatus && matchSuche && matchZeitraum;
card.style.display = zeigen ? "" : "none";
if (zeigen) sichtbar++;