feat(dashboard): Kosten-Kachel zeigt den aktuellen Monat

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 <noreply@anthropic.com>
Dieser Commit ist enthalten in:
claude-dev
2026-07-25 16:54:40 +00:00
Ursprung 9d76fb994a
Commit 7336ba8ad0
2 geänderte Dateien mit 21 neuen und 12 gelöschten Zeilen

Datei anzeigen

@@ -1121,7 +1121,7 @@
</div> </div>
<script src="/static/js/a11y.js?v=20260725a"></script> <script src="/static/js/a11y.js?v=20260725a"></script>
<script src="/static/js/app.js?v=20260725n"></script> <script src="/static/js/app.js?v=20260725o"></script>
<script src="/static/js/sources.js?v=20260522x2"></script> <script src="/static/js/sources.js?v=20260522x2"></script>
<script src="/static/js/x-scraper.js?v=20260522a"></script> <script src="/static/js/x-scraper.js?v=20260522a"></script>
<script src="/static/js/source-health.js?v=20260509l"></script> <script src="/static/js/source-health.js?v=20260509l"></script>

Datei anzeigen

@@ -1249,15 +1249,24 @@ function onNewOrgLicPeriodChange() {
async function loadDashboardTokenStats() { async function loadDashboardTokenStats() {
try { 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'); const grid = document.getElementById('statsGrid');
if (grid && data.length > 0) { if (grid && data && data.kpi) {
const totals = data.reduce(function(acc, org) { const jetzt = new Date();
return { const monat = jetzt.getFullYear() + '-' + String(jetzt.getMonth() + 1).padStart(2, '0');
cost: acc.cost + (org.total_cost_usd || 0), let monatKosten = 0;
refreshes: acc.refreshes + (org.total_refreshes || 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 });
}; };
}, { cost: 0, refreshes: 0 });
// Sprung-Kachel zum Statistik-Tab. Handler direkt anhaengen, denn die // Sprung-Kachel zum Statistik-Tab. Handler direkt anhaengen, denn die
// Kachel entsteht NACH wireStatCardLinks() (ein erneuter Aufruf dort // Kachel entsteht NACH wireStatCardLinks() (ein erneuter Aufruf dort
@@ -1267,9 +1276,9 @@ async function loadDashboardTokenStats() {
card.setAttribute('role', 'link'); card.setAttribute('role', 'link');
card.setAttribute('tabindex', '0'); card.setAttribute('tabindex', '0');
card.title = 'Zur Statistik'; card.title = 'Zur Statistik';
card.innerHTML = '<div class="stat-label">API-Kosten gesamt</div>' + card.innerHTML = '<div class="stat-label">API-Kosten aktueller Monat</div>' +
'<div class="stat-value">$' + totals.cost.toFixed(2) + '</div>' + '<div class="stat-value">' + fmtUsd(monatKosten) + '</div>' +
'<div class="stat-sub">' + totals.refreshes + ' Refreshes</div>'; '<div class="stat-sub">' + monatLaeufe.toLocaleString('de-DE') + ' Läufe · gesamt ' + fmtUsd(data.kpi.kosten_usd) + '</div>';
const springe = () => gotoSection('statistik'); const springe = () => gotoSection('statistik');
card.addEventListener('click', springe); card.addEventListener('click', springe);
card.addEventListener('keydown', (e) => { card.addEventListener('keydown', (e) => {