feat: Token-Nutzung Tab sichtbar + Budget-Bearbeitung

- display:none entfernt, .active-Klasse greift jetzt korrekt
- Budget-Formular mit 4 Feldern (Credits, Kosten/Credit, Budget-Limit, Verbrauch)
- Formular wird mit aktuellen Werten vorbelegt
- Speichern aktualisiert Lizenz und lädt Daten neu
Dieser Commit ist enthalten in:
Claude Dev
2026-03-18 00:12:51 +01:00
Ursprung 7cd36959b0
Commit 44425c6ef8
2 geänderte Dateien mit 84 neuen und 1 gelöschten Zeilen

Datei anzeigen

@@ -163,7 +163,7 @@
</div> </div>
</div> </div>
<div class="section" id="sub-tokens" style="display:none;"> <div class="section" id="sub-tokens">
<div class="token-overview"> <div class="token-overview">
<div class="token-stats-row" id="tokenStatsRow"> <div class="token-stats-row" id="tokenStatsRow">
<div class="token-stat-card"> <div class="token-stat-card">
@@ -206,6 +206,34 @@
</thead> </thead>
<tbody id="tokenMonthlyTable"></tbody> <tbody id="tokenMonthlyTable"></tbody>
</table> </table>
<h3 style="margin-top:24px;">Budget bearbeiten</h3>
<div class="card" style="margin-top:12px;">
<div class="card-body">
<form id="tokenBudgetForm" style="display:grid; grid-template-columns:1fr 1fr; gap:12px;">
<div class="form-group">
<label for="editCreditsTotal">Credits-Kontingent</label>
<input type="number" id="editCreditsTotal" placeholder="z.B. 600000">
</div>
<div class="form-group">
<label for="editCostPerCredit">Kosten pro Credit (USD)</label>
<input type="number" id="editCostPerCredit" step="0.0001" placeholder="z.B. 0.0033">
</div>
<div class="form-group">
<label for="editBudgetUsd">Budget-Limit (USD)</label>
<input type="number" id="editBudgetUsd" step="0.01" placeholder="z.B. 2000">
</div>
<div class="form-group">
<label for="editCreditsUsed">Verbrauchte Credits</label>
<input type="number" id="editCreditsUsed" step="0.01" placeholder="Aktueller Verbrauch">
</div>
<div style="grid-column:1/-1; display:flex; gap:8px; align-items:center;">
<button type="submit" class="btn btn-primary">Speichern</button>
<span id="tokenBudgetMsg" style="font-size:13px; color:var(--text-secondary);"></span>
</div>
</form>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

Datei anzeigen

@@ -595,6 +595,8 @@ async function loadOrgTokenUsage(orgId) {
} }
if (percentEl) percentEl.textContent = percent.toFixed(1) + '%'; if (percentEl) percentEl.textContent = percent.toFixed(1) + '%';
fillBudgetForm(budget);
const tbody = document.getElementById('tokenMonthlyTable'); const tbody = document.getElementById('tokenMonthlyTable');
if (tbody) { if (tbody) {
tbody.innerHTML = monthly.map(function(m) { tbody.innerHTML = monthly.map(function(m) {
@@ -613,6 +615,15 @@ async function loadOrgTokenUsage(orgId) {
} }
} }
// Budget-Formular Felder befuellen
function fillBudgetForm(budget) {
const el = (id, val) => { const e = document.getElementById(id); if (e && val != null) e.value = val; };
el('editCreditsTotal', budget.credits_total);
el('editCostPerCredit', budget.cost_per_credit);
el('editBudgetUsd', budget.token_budget_usd);
el('editCreditsUsed', budget.credits_used ? Math.round(budget.credits_used) : 0);
}
async function loadDashboardTokenStats() { async function loadDashboardTokenStats() {
try { try {
const data = await API.get('/api/token-usage/overview'); const data = await API.get('/api/token-usage/overview');
@@ -636,3 +647,47 @@ async function loadDashboardTokenStats() {
console.error('Token-Overview laden fehlgeschlagen:', err); console.error('Token-Overview laden fehlgeschlagen:', err);
} }
} }
// Budget-Formular Submit
document.addEventListener('DOMContentLoaded', function() {
var form = document.getElementById('tokenBudgetForm');
if (form) {
form.addEventListener('submit', async function(e) {
e.preventDefault();
var msgEl = document.getElementById('tokenBudgetMsg');
if (msgEl) msgEl.textContent = 'Speichern...';
// Lizenz-ID fuer die aktuelle Org ermitteln
try {
var licenses = await API.get('/api/licenses?org_id=' + currentOrgId);
var activeLic = licenses.find(function(l) { return l.status === 'active'; });
if (!activeLic) {
if (msgEl) msgEl.textContent = 'Keine aktive Lizenz gefunden';
return;
}
var body = {};
var creditsTotal = document.getElementById('editCreditsTotal');
var costPerCredit = document.getElementById('editCostPerCredit');
var budgetUsd = document.getElementById('editBudgetUsd');
var creditsUsed = document.getElementById('editCreditsUsed');
if (creditsTotal && creditsTotal.value) body.credits_total = parseInt(creditsTotal.value);
if (costPerCredit && costPerCredit.value) body.cost_per_credit = parseFloat(costPerCredit.value);
if (budgetUsd && budgetUsd.value) body.token_budget_usd = parseFloat(budgetUsd.value);
if (creditsUsed && creditsUsed.value !== '') body.credits_used = parseFloat(creditsUsed.value);
await API.put('/api/token-usage/budget/' + activeLic.id, body);
if (msgEl) msgEl.textContent = 'Gespeichert!';
setTimeout(function() { if (msgEl) msgEl.textContent = ''; }, 3000);
// Daten neu laden
loadOrgTokenUsage(currentOrgId);
} catch (err) {
if (msgEl) msgEl.textContent = 'Fehler: ' + err.message;
console.error('Budget speichern fehlgeschlagen:', err);
}
});
}
});