From 7336ba8ad0b0de6a849a4756b5eb83c0e6938cdc Mon Sep 17 00:00:00 2001 From: claude-dev Date: Sat, 25 Jul 2026 16:54:40 +0000 Subject: [PATCH] feat(dashboard): Kosten-Kachel zeigt den aktuellen Monat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die Kachel heißt jetzt API-Kosten aktueller Monat (Läufe des Monats und Lebenszeit-Summe klein in der Unterzeile) statt der nackten Gesamtsumme. Datenquelle ist der Statistik-Endpoint in einem Aufruf. Co-Authored-By: Claude Fable 5 --- src/static/dashboard.html | 2 +- src/static/js/app.js | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/static/dashboard.html b/src/static/dashboard.html index e25ac89..5b9ae96 100644 --- a/src/static/dashboard.html +++ b/src/static/dashboard.html @@ -1121,7 +1121,7 @@ - + diff --git a/src/static/js/app.js b/src/static/js/app.js index 3a94389..a6a317a 100644 --- a/src/static/js/app.js +++ b/src/static/js/app.js @@ -1249,15 +1249,24 @@ function onNewOrgLicPeriodChange() { async function loadDashboardTokenStats() { try { - const data = await API.get('/api/token-usage/overview'); + // Aktueller Monat im Vordergrund, Lebenszeit-Summe klein darunter. + // months=0 liefert beides in einem Aufruf (kpi = gesamt, Serien je Monat). + const data = await API.get('/api/statistik?months=0'); const grid = document.getElementById('statsGrid'); - if (grid && data.length > 0) { - const totals = data.reduce(function(acc, org) { - return { - cost: acc.cost + (org.total_cost_usd || 0), - refreshes: acc.refreshes + (org.total_refreshes || 0), - }; - }, { cost: 0, refreshes: 0 }); + if (grid && data && data.kpi) { + const jetzt = new Date(); + const monat = jetzt.getFullYear() + '-' + String(jetzt.getMonth() + 1).padStart(2, '0'); + let monatKosten = 0; + (data.monat_quelle || []).forEach(function(r) { + if (r.monat === monat) monatKosten += r.kosten || 0; + }); + let monatLaeufe = 0; + (data.monat_betrieb || []).forEach(function(r) { + if (r.monat === monat) monatLaeufe = r.completed || 0; + }); + const fmtUsd = function(n) { + return '$' + Number(n || 0).toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); + }; // Sprung-Kachel zum Statistik-Tab. Handler direkt anhaengen, denn die // Kachel entsteht NACH wireStatCardLinks() (ein erneuter Aufruf dort @@ -1267,9 +1276,9 @@ async function loadDashboardTokenStats() { card.setAttribute('role', 'link'); card.setAttribute('tabindex', '0'); card.title = 'Zur Statistik'; - card.innerHTML = '
API-Kosten gesamt
' + - '
$' + totals.cost.toFixed(2) + '
' + - '
' + totals.refreshes + ' Refreshes
'; + card.innerHTML = '
API-Kosten aktueller Monat
' + + '
' + fmtUsd(monatKosten) + '
' + + '
' + monatLaeufe.toLocaleString('de-DE') + ' Läufe · gesamt ' + fmtUsd(data.kpi.kosten_usd) + '
'; const springe = () => gotoSection('statistik'); card.addEventListener('click', springe); card.addEventListener('keydown', (e) => {