feat(costs): $-Tagesbudget pro Nutzer (Stufe 3)
cost_daily_limit_usd (Pref > global; 0 = unbegrenzt) in quota.py (cost_within_budget, cost_limit). ws.py-Gate: Web-Such- ODER Kostenbudget aufgebraucht -> Web-Suche fuer den Turn aus + freundlicher Hinweis. Admin: Schema-Feld + list_users + UI-Eingabe ($/Tag) + globales Live-Setting. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
d87f0ce424
commit
66d6708f59
7 changed files with 57 additions and 5 deletions
|
|
@ -1235,6 +1235,11 @@ function buildUserCard(u) {
|
|||
<input type="number" min="0" class="ws-limit w-20 rounded-lg border border-slate-300 dark:border-slate-600 bg-transparent px-2 py-1 text-xs focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="∞" />
|
||||
<span class="ws-limit-status text-xs text-slate-400"></span>
|
||||
</div>
|
||||
<div class="mt-1.5 flex items-center gap-2">
|
||||
<span class="text-xs text-slate-500 dark:text-slate-400">max. Kosten pro Tag ($):</span>
|
||||
<input type="number" min="0" step="0.01" class="cost-limit w-20 rounded-lg border border-slate-300 dark:border-slate-600 bg-transparent px-2 py-1 text-xs focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="∞" />
|
||||
<span class="cost-limit-status text-xs text-slate-400"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notfall-Profil -->
|
||||
|
|
@ -1358,6 +1363,24 @@ function buildUserCard(u) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Kosten-Tagesbudget in $ (leer/0 = unbegrenzt) — sofort speichern
|
||||
const costLimit = card.querySelector(".cost-limit");
|
||||
const costLimitStatus = card.querySelector(".cost-limit-status");
|
||||
if (costLimit) {
|
||||
const lim = Number(u.cost_daily_limit_usd);
|
||||
costLimit.value = Number.isFinite(lim) && lim > 0 ? lim : "";
|
||||
costLimit.addEventListener("change", async () => {
|
||||
const n = parseFloat(costLimit.value);
|
||||
const val = Number.isFinite(n) && n > 0 ? n : 0; // leer/0 = unbegrenzt
|
||||
if (costLimitStatus) costLimitStatus.textContent = "speichere …";
|
||||
const res = await adminFetch(`/api/admin/users/${uid}/prefs`, "PUT", { cost_daily_limit_usd: val });
|
||||
if (costLimitStatus) {
|
||||
costLimitStatus.textContent = res ? "✓" : "Fehler";
|
||||
setTimeout(() => { costLimitStatus.textContent = ""; }, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
const profBtn = card.querySelector(".btn-prof");
|
||||
const profSection = card.querySelector(".prof-section");
|
||||
const profArrow = card.querySelector(".prof-arrow");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue