leistung_pct-Fundament (Teacher+Backend bevorzugen) + Tempo-Button-Zustaende

- teacher.html _leistungPct: von der Sim geliefertes s.leistung_pct hat
  Vorrang, sonst zentrale Ableitung (Fallback).
- live.php extractScore: leistung_pct (0-100) hat Vorrang vor score/Sterne.
- admin-styleguide.html: Tempo-Button zeigt IMMER den Stand (1x/2x/8x Auto/
  Pause); Toggle-Verhalten (Panel bleibt offen bis erneutem Klick) beschrieben.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 12:31:23 +02:00
parent 7e1a7c5228
commit 539f6b012e
3 changed files with 22 additions and 1 deletions
+16
View File
@@ -267,6 +267,13 @@
.khz-select{height:30px;border:1px solid rgba(0,0,0,.12);border-radius:8px;padding:0 .55rem;font-size:.78rem;color:#1f4e5a;font-weight:700;background:#f7f6f3;display:inline-flex;align-items:center;gap:.35rem;white-space:nowrap}
.khz-range{width:96px;height:6px;border-radius:99px;background:linear-gradient(90deg,#4a7c8a 0 62%,#dfe6e9 62% 100%);position:relative}
.khz-range::after{content:'';position:absolute;left:62%;top:50%;transform:translate(-50%,-50%);width:14px;height:14px;border-radius:50%;background:#4a7c8a;box-shadow:0 1px 3px rgba(0,0,0,.3)}
/* Tempo-Button zeigt IMMER den aktuellen Stand */
.khz-spd{width:38px;height:38px;border-radius:12px;border:none;background:#fff;box-shadow:0 2px 9px rgba(0,0,0,.2);display:inline-flex;flex-direction:column;align-items:center;justify-content:center;color:#1f4e5a;font-weight:800;line-height:1;cursor:pointer;vertical-align:middle}
.khz-spd b{font-size:.82rem}
.khz-spd small{font-size:.5rem;font-weight:700;margin-top:1px;color:#4a7c8a;letter-spacing:.02em}
.khz-spd.act{background:#4a7c8a;color:#fff}
.khz-spd.act small{color:#dbe9ee}
.khz-spd .ic{width:18px;height:18px;color:inherit}
</style>
<svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs>
<symbol id="ic-home" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11.4 12 4l8 7.4"/><path d="M6 10.3V19a1 1 0 0 0 1 1h3v-5h4v5h3a1 1 0 0 0 1-1v-8.7"/></symbol>
@@ -323,6 +330,15 @@
<button class="khz-seg">4×</button>
</div>
<div class="khz-frame-lab">Tempo-Button im Header — zeigt IMMER den aktuellen Stand</div>
<div style="display:flex;gap:.5rem;align-items:center;flex-wrap:wrap">
<button class="khz-spd" title="Normal"><b>1×</b></button>
<button class="khz-spd" title="Doppelt"><b>2×</b></button>
<button class="khz-spd act" title="Logistik: Auto-Tempo"><b>8×</b><small>Auto</small></button>
<button class="khz-spd" title="Pausiert"><svg class="ic"><use href="#ic-pause"/></svg></button>
</div>
<p style="font-size:.76rem;color:#6a6a6a;margin:.5rem 0 0">Klick öffnet das Tempo-Panel und lässt es offen bis zum erneuten Klick (Toggle) — genauso beim Musik-Player. Der Button selbst zeigt jederzeit den Speed: <b>1×</b>, <b>2×</b>, <b>8× Auto</b> (z. B. Logistik) oder <b>⏸ Pause</b>. So bleibt der Zustand sichtbar, ohne dass das Panel offen bleiben muss.</p>
<div class="khz-frame-lab">Aufgeklappt · Musikplayer (Klick auf das Musik-Icon)</div>
<div class="khz-pop khz-music">
<button class="khz-seg on" title="Pause"><svg class="ic"><use href="#ic-pause"/></svg></button>
+3 -1
View File
@@ -148,7 +148,9 @@ if ($method === 'GET') {
// sonst der Sim-Score (Farmer/Weltküche liefern `score`).
$extractScore = function($row) {
$r = $row['results'] ? json_decode($row['results'], true) : [];
foreach ([$r['score'] ?? null, $r['results']['score'] ?? null] as $c) if (is_numeric($c)) return max(0, min(100, (int)round($c)));
// Von der Sim geliefertes Leistungs-% (0100) hat Vorrang, dann score, dann Sterne→%.
foreach ([$r['leistung_pct'] ?? null, $r['results']['leistung_pct'] ?? null, $r['data']['leistung_pct'] ?? null,
$r['score'] ?? null, $r['results']['score'] ?? null] as $c) if (is_numeric($c)) return max(0, min(100, (int)round($c)));
if (isset($r['stars']) && is_numeric($r['stars'])) return (int)round($r['stars'] / 5 * 100);
return null;
};
+3
View File
@@ -682,6 +682,9 @@ function _pctBadge(pct) {
function _leistungPct(simId, s) {
if (!s || typeof s !== 'object') return null;
var cl = function(v,a,b){ return Math.max(a, Math.min(b, v)); };
// Von der Sim selbst geliefertes Leistungs-% hat Vorrang (Fundament-Umbau) —
// sonst zentrale Ableitung als Fallback.
if (typeof s.leistung_pct === 'number' && !isNaN(s.leistung_pct)) return cl(Math.round(s.leistung_pct), 0, 100);
// Sims mit echtem 0100-Live-Score (klima, fluss, kofferdetektiv, heli) direkt:
if (typeof s.score === 'number' && simId !== 'weltkueche' && simId !== 'busfahrt' && simId !== 'fluggesellschaft')
return cl(Math.round(s.score), 0, 100);