- aether-medical: Stationen/Belegung, Intensivstation, Blutbank, Fuhrpark, Nachrichten/Aushänge, Berichte und Textbausteine (server + NUI) - aether-admin: vollständiges Server-Admin-Panel als echtes FiveM-Resource, an aether-core gekoppelt (Rechte über aether_users.admin_group), mit WebRTC-Live-Kameras (Bildschirmfreigabe) und separatem Media-Server (SFU) - Prototypen admin/ vervollständigt - SQL-Schema aether_admin.sql - Docker-Compose mit MariaDB und idempotenter Auto-Migration (schema_migrations) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
425 lines
22 KiB
HTML
425 lines
22 KiB
HTML
<!doctype html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="color-scheme" content="dark">
|
||
<title>Aether — Tankstelle</title>
|
||
<style>
|
||
:root{
|
||
--bg:#0a0806;--fg:#f3efe4;--muted:#9c9585; /* Grundfarben */
|
||
--surface:rgba(26,22,16,0.72);--surface2:rgba(38,32,22,0.9); /* Panel-Flächen */
|
||
--slot:#120f0a;--border:rgba(255,255,255,0.09); /* Eingaben/Rahmen */
|
||
--accent:#f5a742;--accent2:#f0d24a;--ink:#241603;/* Tank-Orange als Leitfarbe */
|
||
--accent-soft:rgba(245,167,66,0.15);
|
||
--violet:#7c5cf6; /* Aether-Akzent (sekundär) */
|
||
--green:#34d39a;--red:#f0506e; /* Erfolg / Fehler */
|
||
}
|
||
*{box-sizing:border-box;} html,body{margin:0;height:100%;}
|
||
body{min-height:100%;background:radial-gradient(1000px 620px at 50% -8%,rgba(245,167,66,0.1),transparent 55%),var(--bg);
|
||
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;color:var(--fg);
|
||
display:flex;align-items:center;justify-content:center;padding:22px 14px;}
|
||
|
||
.app{position:relative;width:min(940px,98vw);border-radius:22px;overflow:hidden;
|
||
background:linear-gradient(160deg,rgba(24,20,14,0.96),rgba(8,7,5,0.98));border:1px solid rgba(245,167,66,0.22);
|
||
box-shadow:0 50px 100px -30px rgba(0,0,0,0.85);}
|
||
/* Kopfzeile */
|
||
.head{display:flex;align-items:center;gap:12px;padding:16px 22px;border-bottom:1px solid var(--border);}
|
||
.head .bl{width:40px;height:40px;border-radius:11px;display:grid;place-items:center;font-size:21px;
|
||
background:linear-gradient(150deg,var(--accent),#c47f1e);color:var(--ink);}
|
||
.head .bn{font-size:17px;font-weight:800;letter-spacing:-0.02em;}
|
||
.head .bn span{color:var(--accent);} .head .bn small{display:block;font-size:10.5px;color:var(--muted);font-weight:500;letter-spacing:0.04em;}
|
||
.head .money{margin-left:auto;display:flex;gap:8px;}
|
||
.head .chip{background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:7px 13px;text-align:right;}
|
||
.head .chip .l{font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;font-weight:800;}
|
||
.head .chip .v{font-size:15px;font-weight:800;font-variant-numeric:tabular-nums;}
|
||
|
||
/* Zweispaltiger Körper: Zapfsäulen-Display + Steuerung */
|
||
.body{display:grid;grid-template-columns:1fr 1fr;gap:0;}
|
||
.display{padding:24px;border-right:1px solid var(--border);}
|
||
.controls{padding:24px;display:flex;flex-direction:column;gap:16px;}
|
||
|
||
/* Digitale Zähler (Liter + Preis) */
|
||
.counters{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:18px;}
|
||
.counter{background:#0c0a06;border:1px solid rgba(245,167,66,0.3);border-radius:14px;padding:14px 16px;
|
||
box-shadow:inset 0 0 24px rgba(0,0,0,0.6);}
|
||
.counter .cl{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.08em;font-weight:800;}
|
||
.counter .cv{font-size:34px;font-weight:800;font-variant-numeric:tabular-nums;letter-spacing:0.02em;
|
||
color:var(--accent2);text-shadow:0 0 14px rgba(240,210,74,0.35);line-height:1.15;}
|
||
.counter .cu{font-size:13px;color:var(--muted);font-weight:700;}
|
||
.counter.preis .cv{color:var(--accent);text-shadow:0 0 14px rgba(245,167,66,0.4);}
|
||
.ppl{text-align:center;font-size:11.5px;color:var(--muted);margin:-6px 0 16px;font-weight:600;}
|
||
|
||
/* Tankanzeige (Balken E → F) + Pumpe */
|
||
.tankwrap{display:flex;align-items:center;gap:16px;}
|
||
.nozzle{font-size:40px;transition:.15s;filter:drop-shadow(0 4px 8px rgba(0,0,0,0.5));}
|
||
.nozzle.on{animation:wackel .5s ease-in-out infinite;color:var(--accent);}
|
||
@keyframes wackel{50%{transform:translateY(-3px) rotate(-4deg);}}
|
||
.tank{flex:1;}
|
||
.tank .tl{display:flex;justify-content:space-between;font-size:11px;color:var(--muted);font-weight:800;margin-bottom:5px;}
|
||
.tank .bar{height:26px;border-radius:9px;background:var(--slot);border:1px solid var(--border);overflow:hidden;position:relative;}
|
||
.tank .bar .fill{height:100%;width:0;border-radius:8px 0 0 8px;transition:width .12s linear;
|
||
background:linear-gradient(90deg,var(--accent),var(--accent2));}
|
||
.tank .bar .pct{position:absolute;inset:0;display:grid;place-items:center;font-size:12.5px;font-weight:800;
|
||
color:#fff;text-shadow:0 1px 3px rgba(0,0,0,0.7);font-variant-numeric:tabular-nums;}
|
||
.tank .bar .fill.warn{background:linear-gradient(90deg,var(--red),#f0806e);}
|
||
|
||
/* Steuerungs-Bausteine */
|
||
.card{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:14px;}
|
||
.lh{font-size:10px;text-transform:uppercase;letter-spacing:0.07em;color:var(--muted);font-weight:800;margin:0 0 10px;}
|
||
.veh{display:flex;align-items:center;gap:12px;}
|
||
.veh .vi{font-size:26px;}
|
||
.veh .vn{font-weight:800;font-size:15px;} .veh .vs{font-size:12px;color:var(--muted);}
|
||
.veh .plate{margin-left:auto;background:#f3efe4;color:#1a1a1a;font-weight:800;border-radius:6px;padding:5px 10px;
|
||
font-size:13px;letter-spacing:0.06em;border:2px solid #c9c4b4;}
|
||
|
||
.seg{display:flex;gap:6px;} .seg button{flex:1;border:1px solid var(--border);background:var(--slot);color:var(--fg);
|
||
border-radius:10px;padding:10px 8px;font-family:inherit;font-weight:700;font-size:12.5px;cursor:pointer;transition:.12s;}
|
||
.seg button:hover{border-color:var(--accent);} .seg button.active{background:var(--accent-soft);border-color:var(--accent);color:var(--accent);}
|
||
.seg.sorte button{flex-direction:column;gap:3px;display:flex;align-items:center;}
|
||
.seg.sorte button .p{font-size:10.5px;color:var(--muted);font-weight:600;} .seg.sorte button.active .p{color:var(--accent);}
|
||
|
||
.inrow{display:flex;align-items:center;gap:10px;margin-top:10px;}
|
||
.input{flex:1;background:var(--slot);border:1px solid var(--border);border-radius:10px;padding:11px 13px;color:var(--fg);
|
||
font-size:16px;font-family:inherit;font-weight:700;outline:none;font-variant-numeric:tabular-nums;}
|
||
.input:focus{border-color:var(--accent);} .inrow .unit{font-size:14px;color:var(--muted);font-weight:800;}
|
||
|
||
.zahlung{display:flex;gap:8px;} .zahlung button{flex:1;display:flex;align-items:center;justify-content:space-between;
|
||
border:1px solid var(--border);background:var(--slot);color:var(--fg);border-radius:10px;padding:10px 12px;
|
||
font-family:inherit;font-weight:700;font-size:13px;cursor:pointer;transition:.12s;}
|
||
.zahlung button:hover{border-color:var(--accent);} .zahlung button.active{background:var(--accent-soft);border-color:var(--accent);}
|
||
.zahlung button .zb{font-size:11px;color:var(--muted);font-weight:700;}
|
||
|
||
.btn{border:none;border-radius:12px;padding:15px;font-size:15px;font-weight:800;cursor:pointer;font-family:inherit;transition:.12s;width:100%;}
|
||
.btn.go{background:linear-gradient(150deg,var(--accent),#d88a1e);color:var(--ink);} .btn.go:hover{filter:brightness(1.06);}
|
||
.btn.stop{background:var(--red);color:#2a0910;} .btn:active{transform:scale(0.99);}
|
||
.btn:disabled{opacity:.45;cursor:not-allowed;}
|
||
.hint{font-size:12px;color:var(--muted);text-align:center;min-height:16px;}
|
||
.hint.err{color:var(--red);} .hint.ok{color:var(--green);}
|
||
|
||
/* Beleg-Overlay */
|
||
.overlay{position:absolute;inset:0;background:rgba(6,5,3,0.72);backdrop-filter:blur(4px);display:none;
|
||
align-items:center;justify-content:center;padding:20px;z-index:10;}
|
||
.overlay.on{display:flex;}
|
||
.beleg{width:320px;background:#f6f2e8;color:#2a2418;border-radius:12px;padding:22px;font-family:"SF Mono",ui-monospace,Menlo,monospace;
|
||
box-shadow:0 30px 60px -20px rgba(0,0,0,0.8);animation:auf .3s ease;}
|
||
@keyframes auf{from{opacity:0;transform:translateY(12px);}to{opacity:1;transform:none;}}
|
||
.beleg h3{margin:0 0 3px;text-align:center;font-size:15px;letter-spacing:0.1em;}
|
||
.beleg .sub{text-align:center;font-size:11px;color:#8a8270;margin-bottom:14px;}
|
||
.beleg .bz{display:flex;justify-content:space-between;font-size:12.5px;padding:4px 0;border-bottom:1px dashed #cfc7b2;}
|
||
.beleg .bz.sum{border-bottom:none;border-top:2px solid #2a2418;margin-top:6px;padding-top:8px;font-size:15px;font-weight:800;}
|
||
.beleg .dank{text-align:center;font-size:11px;color:#8a8270;margin-top:14px;}
|
||
.beleg .b-btn{margin-top:16px;width:100%;border:none;background:#2a2418;color:#f6f2e8;border-radius:9px;padding:12px;
|
||
font-family:inherit;font-weight:700;cursor:pointer;font-size:13px;}
|
||
|
||
/* Demo-Leiste */
|
||
.demo{display:flex;align-items:center;gap:8px;padding:11px 22px;border-top:1px solid var(--border);}
|
||
.demo span{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;font-weight:800;}
|
||
.demo button{border:1px solid var(--border);background:rgba(255,255,255,0.04);color:var(--fg);border-radius:8px;
|
||
padding:6px 11px;font-family:inherit;font-size:11.5px;font-weight:700;cursor:pointer;}
|
||
.demo button:hover{border-color:var(--violet);color:#fff;}
|
||
|
||
@media (max-width:820px){.body{grid-template-columns:1fr;} .display{border-right:none;border-bottom:1px solid var(--border);}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="app">
|
||
<!-- Kopfzeile mit Geld-Anzeige -->
|
||
<div class="head">
|
||
<span class="bl">⛽</span>
|
||
<div class="bn">Aether <span>Fuel</span><small>Tankstelle · Los Santos</small></div>
|
||
<div class="money">
|
||
<div class="chip"><div class="l">Bargeld</div><div class="v" id="mBar">–</div></div>
|
||
<div class="chip"><div class="l">Konto</div><div class="v" id="mKonto">–</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="body">
|
||
<!-- Zapfsäulen-Display -->
|
||
<div class="display">
|
||
<div class="counters">
|
||
<div class="counter"><div class="cl">Menge</div><div class="cv" id="cLiter">0,00</div><div class="cu">Liter</div></div>
|
||
<div class="counter preis"><div class="cl">Zu zahlen</div><div class="cv" id="cPreis">0,00</div><div class="cu">Euro</div></div>
|
||
</div>
|
||
<div class="ppl" id="ppl">Grundpreis –</div>
|
||
<div class="tankwrap">
|
||
<div class="nozzle" id="nozzle">⛽</div>
|
||
<div class="tank">
|
||
<div class="tl"><span>E — leer</span><span>voll — F</span></div>
|
||
<div class="bar"><div class="fill" id="tankFill"></div><div class="pct" id="tankPct">0 %</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Steuerung -->
|
||
<div class="controls">
|
||
<div class="card">
|
||
<div class="lh">Fahrzeug</div>
|
||
<div class="veh">
|
||
<span class="vi">🚗</span>
|
||
<div><div class="vn" id="vName">–</div><div class="vs" id="vTank">–</div></div>
|
||
<span class="plate" id="vPlate">–</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="lh">Spritsorte</div>
|
||
<div class="seg sorte" id="sorte"></div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="lh">Menge wählen</div>
|
||
<div class="seg" id="modus">
|
||
<button data-m="voll" class="active">Volltanken</button>
|
||
<button data-m="liter">Liter</button>
|
||
<button data-m="betrag">Betrag €</button>
|
||
</div>
|
||
<div class="inrow" id="inrow" style="display:none">
|
||
<input class="input" id="wert" type="number" min="1" placeholder="0">
|
||
<span class="unit" id="unit">L</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="lh">Zahlung</div>
|
||
<div class="zahlung" id="zahlung">
|
||
<button data-z="bargeld" class="active">💵 Bargeld <span class="zb" id="zBar"></span></button>
|
||
<button data-z="konto">💳 Karte <span class="zb" id="zKonto"></span></button>
|
||
</div>
|
||
</div>
|
||
|
||
<button class="btn go" id="actionBtn">⛽ Tanken</button>
|
||
<div class="hint" id="hint">Wähle Sorte und Menge, dann tanken.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Demo-Leiste -->
|
||
<div class="demo">
|
||
<span>Demo</span>
|
||
<button id="dLeer">🚗 Tank leeren (Probefahrt)</button>
|
||
<button id="dReich">💰 Geld auffüllen</button>
|
||
</div>
|
||
|
||
<!-- Beleg-Overlay -->
|
||
<div class="overlay" id="overlay"><div class="beleg" id="beleg"></div></div>
|
||
</div>
|
||
|
||
<script>
|
||
"use strict";
|
||
/* Kurzer Zugriffshelfer auf Elemente per ID */
|
||
const $=id=>document.getElementById(id);
|
||
/* Betrag als Euro (2 Nachkommastellen) formatieren */
|
||
const euro=n=>n.toLocaleString("de-DE",{minimumFractionDigits:2,maximumFractionDigits:2})+" €";
|
||
/* Litermenge formatieren */
|
||
const liter=n=>n.toLocaleString("de-DE",{minimumFractionDigits:2,maximumFractionDigits:2});
|
||
/* Ganze Euro (für Geld-Chips) */
|
||
const euroKurz=n=>Math.round(n).toLocaleString("de-DE")+" €";
|
||
|
||
/* =====================================================================
|
||
DATEN (im echten Betrieb per NUI vom Client gesetzt) — vom UI getrennt.
|
||
===================================================================== */
|
||
const spieler={bargeld:1200, konto:8600}; // Geld des Spielers
|
||
const fahrzeug={modell:"Übermacht Sentinel", kennzeichen:"LS-4821",
|
||
tankGroesse:65, fuellstand:24}; // Tank in Litern (aktuell / max)
|
||
const spritSorten=[ // Verfügbare Sorten mit Literpreis
|
||
{id:"e10", name:"Benzin E10", preis:1.72},
|
||
{id:"super", name:"Super Plus", preis:1.94},
|
||
{id:"diesel", name:"Diesel", preis:1.66},
|
||
];
|
||
const FLUSS_L_PRO_S=9; // Durchfluss der Zapfsäule (Liter pro Sekunde)
|
||
const TICK_MS=45; // Aktualisierungsintervall der Zapf-Animation
|
||
|
||
/* =====================================================================
|
||
ZUSTAND
|
||
===================================================================== */
|
||
let sorteIndex=0; // gewählte Spritsorte
|
||
let modus="voll"; // Tankmodus: voll | liter | betrag
|
||
let zahlung="bargeld"; // Zahlungsart: bargeld | konto
|
||
let phase="idle"; // idle | tanken | fertig
|
||
let pumpTimer=null; // Timer der laufenden Zapf-Animation
|
||
let aktLiter=0; // bereits gezapfte Liter dieser Sitzung
|
||
let zielLiter=0; // Zielmenge der aktuellen Zapfung
|
||
let geklemmtDurchGeld=false; // wurde die Zielmenge durchs Guthaben begrenzt?
|
||
|
||
/* Aktuell gewählte Sorte / verfügbares Guthaben je Zahlungsart */
|
||
const sorte=()=>spritSorten[sorteIndex];
|
||
const guthaben=()=>zahlung==="bargeld"?spieler.bargeld:spieler.konto;
|
||
|
||
/* =====================================================================
|
||
RENDERING
|
||
===================================================================== */
|
||
/* Geld-Chips oben und in der Zahlungsauswahl aktualisieren */
|
||
function renderGeld(){
|
||
$("mBar").textContent=euroKurz(spieler.bargeld);
|
||
$("mKonto").textContent=euroKurz(spieler.konto);
|
||
$("zBar").textContent=euroKurz(spieler.bargeld);
|
||
$("zKonto").textContent=euroKurz(spieler.konto);
|
||
}
|
||
/* Fahrzeug-Karte füllen */
|
||
function renderFahrzeug(){
|
||
$("vName").textContent=fahrzeug.modell;
|
||
$("vTank").textContent="Tank "+fahrzeug.tankGroesse+" L";
|
||
$("vPlate").textContent=fahrzeug.kennzeichen;
|
||
}
|
||
/* Spritsorten-Buttons aufbauen */
|
||
function renderSorten(){
|
||
$("sorte").innerHTML=spritSorten.map((s,i)=>
|
||
`<button data-s="${i}" class="${i===sorteIndex?'active':''}">${s.name}<span class="p">${euro(s.preis)}/L</span></button>`).join('');
|
||
$("sorte").querySelectorAll("[data-s]").forEach(b=>b.addEventListener("click",()=>{if(phase==="tanken")return;sorteIndex=+b.dataset.s;renderSorten();renderPreisInfo();aktualisiereHint();}));
|
||
}
|
||
/* Grundpreis-Zeile unter den Zählern */
|
||
function renderPreisInfo(){$("ppl").textContent="Grundpreis "+euro(sorte().preis)+" / Liter";}
|
||
/* Digitale Zähler + Tankbalken aktualisieren */
|
||
function renderDisplay(){
|
||
$("cLiter").textContent=liter(aktLiter);
|
||
$("cPreis").textContent=liter(aktLiter*sorte().preis);
|
||
const gesamt=Math.min(fahrzeug.tankGroesse,fahrzeug.fuellstand+aktLiter);
|
||
const pct=gesamt/fahrzeug.tankGroesse*100;
|
||
$("tankFill").style.width=pct+"%";
|
||
$("tankFill").classList.toggle("warn",pct<15);
|
||
$("tankPct").textContent=Math.round(pct)+" %";
|
||
}
|
||
|
||
/* =====================================================================
|
||
ZIELMENGE BERECHNEN
|
||
===================================================================== */
|
||
/* Ermittelt die Zielmenge in Litern (begrenzt durch Tank und Guthaben) */
|
||
function berechneZiel(){
|
||
const platz=fahrzeug.tankGroesse-fahrzeug.fuellstand; // freier Platz im Tank
|
||
const proLiter=sorte().preis;
|
||
let ziel;
|
||
if(modus==="voll") ziel=platz;
|
||
else if(modus==="liter") ziel=Math.min(platz,parseFloat($("wert").value)||0);
|
||
else /* betrag */ ziel=Math.min(platz,(parseFloat($("wert").value)||0)/proLiter);
|
||
// Durch verfügbares Guthaben begrenzen
|
||
const maxDurchGeld=guthaben()/proLiter;
|
||
geklemmtDurchGeld=ziel>maxDurchGeld+1e-6;
|
||
ziel=Math.min(ziel,maxDurchGeld);
|
||
return Math.max(0,ziel);
|
||
}
|
||
/* Hinweistext passend zur aktuellen Auswahl setzen */
|
||
function aktualisiereHint(){
|
||
if(phase==="tanken")return;
|
||
const platz=fahrzeug.tankGroesse-fahrzeug.fuellstand;
|
||
if(platz<0.1){setHint("Tank ist bereits voll.","err");$("actionBtn").disabled=true;return;}
|
||
const ziel=berechneZiel();
|
||
$("actionBtn").disabled=ziel<0.1;
|
||
if(ziel<0.1){setHint(modus==="voll"?"Tank ist voll.":"Bitte gültige Menge / genug Guthaben.","err");return;}
|
||
const kosten=ziel*sorte().preis;
|
||
setHint((geklemmtDurchGeld?"Durch Guthaben begrenzt: ":"")+
|
||
liter(ziel)+" L ≈ "+euro(kosten)+" ("+(zahlung==="bargeld"?"Bargeld":"Karte")+")",geklemmtDurchGeld?"":"");
|
||
}
|
||
/* Hinweiszeile setzen */
|
||
function setHint(text,typ){$("hint").textContent=text;$("hint").className="hint"+(typ?" "+typ:"");}
|
||
|
||
/* =====================================================================
|
||
ZAPFVORGANG
|
||
===================================================================== */
|
||
/* Startet die Zapfung bis zur berechneten Zielmenge */
|
||
function starteTanken(){
|
||
zielLiter=berechneZiel();
|
||
if(zielLiter<0.1){aktualisiereHint();return;}
|
||
phase="tanken"; aktLiter=0;
|
||
$("nozzle").classList.add("on");
|
||
$("actionBtn").className="btn stop"; $("actionBtn").textContent="■ Stopp";
|
||
sperreEingaben(true);
|
||
const schritt=FLUSS_L_PRO_S*TICK_MS/1000; // Liter pro Tick
|
||
pumpTimer=setInterval(()=>{
|
||
aktLiter=Math.min(zielLiter,aktLiter+schritt);
|
||
renderDisplay();
|
||
setHint("Zapfe … "+liter(aktLiter)+" L · "+euro(aktLiter*sorte().preis),"");
|
||
if(aktLiter>=zielLiter-1e-6)stoppeTanken();
|
||
},TICK_MS);
|
||
}
|
||
/* Beendet die Zapfung (regulär oder per Stopp), bucht ab und zeigt den Beleg */
|
||
function stoppeTanken(){
|
||
clearInterval(pumpTimer); pumpTimer=null;
|
||
$("nozzle").classList.remove("on");
|
||
const kosten=aktLiter*sorte().preis;
|
||
// Betrag von der gewählten Zahlungsart abbuchen
|
||
if(zahlung==="bargeld")spieler.bargeld-=kosten; else spieler.konto-=kosten;
|
||
fahrzeug.fuellstand=Math.min(fahrzeug.tankGroesse,fahrzeug.fuellstand+aktLiter);
|
||
phase="fertig";
|
||
renderGeld(); renderDisplay();
|
||
zeigeBeleg(aktLiter,kosten);
|
||
}
|
||
/* Ein-/Ausgaben während der Zapfung sperren */
|
||
function sperreEingaben(sperr){
|
||
$("sorte").querySelectorAll("button").forEach(b=>b.disabled=sperr);
|
||
$("modus").querySelectorAll("button").forEach(b=>b.disabled=sperr);
|
||
$("zahlung").querySelectorAll("button").forEach(b=>b.disabled=sperr);
|
||
$("wert").disabled=sperr;
|
||
}
|
||
|
||
/* =====================================================================
|
||
BELEG
|
||
===================================================================== */
|
||
/* Zeigt den Kassenbeleg nach der Zapfung */
|
||
function zeigeBeleg(l,kosten){
|
||
const kontoRest=zahlung==="bargeld"?spieler.bargeld:spieler.konto;
|
||
$("beleg").innerHTML=`
|
||
<h3>AETHER FUEL</h3><div class="sub">Tankstelle Los Santos · ${new Date().toLocaleTimeString("de-DE",{hour:"2-digit",minute:"2-digit"})}</div>
|
||
<div class="bz"><span>Fahrzeug</span><span>${fahrzeug.kennzeichen}</span></div>
|
||
<div class="bz"><span>Sorte</span><span>${sorte().name}</span></div>
|
||
<div class="bz"><span>Menge</span><span>${liter(l)} L</span></div>
|
||
<div class="bz"><span>Literpreis</span><span>${euro(sorte().preis)}</span></div>
|
||
<div class="bz"><span>Zahlung</span><span>${zahlung==="bargeld"?"Bargeld":"Karte"}</span></div>
|
||
<div class="bz"><span>Neuer Füllstand</span><span>${Math.round(fahrzeug.fuellstand/fahrzeug.tankGroesse*100)} %</span></div>
|
||
<div class="bz sum"><span>Gesamt</span><span>${euro(kosten)}</span></div>
|
||
<div class="bz" style="border:none;padding-top:6px"><span>Restguthaben</span><span>${euroKurz(kontoRest)}</span></div>
|
||
<div class="dank">Gute Fahrt — danke fürs Tanken!</div>
|
||
<button class="b-btn" id="belegOk">Fertig</button>`;
|
||
$("overlay").classList.add("on");
|
||
$("belegOk").addEventListener("click",belegSchliessen);
|
||
}
|
||
/* Schließt den Beleg und stellt den Ausgangszustand wieder her */
|
||
function belegSchliessen(){
|
||
$("overlay").classList.remove("on");
|
||
phase="idle"; aktLiter=0;
|
||
$("actionBtn").className="btn go"; $("actionBtn").textContent="⛽ Tanken";
|
||
sperreEingaben(false);
|
||
renderDisplay(); aktualisiereHint();
|
||
}
|
||
|
||
/* =====================================================================
|
||
STEUERUNG (Buttons / Eingaben)
|
||
===================================================================== */
|
||
/* Tankmodus umschalten (blendet das Eingabefeld passend ein) */
|
||
$("modus").querySelectorAll("[data-m]").forEach(b=>b.addEventListener("click",()=>{
|
||
if(phase==="tanken")return;
|
||
modus=b.dataset.m;
|
||
$("modus").querySelectorAll("button").forEach(x=>x.classList.toggle("active",x===b));
|
||
$("inrow").style.display=modus==="voll"?"none":"flex";
|
||
$("unit").textContent=modus==="liter"?"L":"€";
|
||
$("wert").value="";
|
||
aktualisiereHint();
|
||
}));
|
||
$("wert").addEventListener("input",aktualisiereHint);
|
||
|
||
/* Zahlungsart umschalten */
|
||
$("zahlung").querySelectorAll("[data-z]").forEach(b=>b.addEventListener("click",()=>{
|
||
if(phase==="tanken")return;
|
||
zahlung=b.dataset.z;
|
||
$("zahlung").querySelectorAll("button").forEach(x=>x.classList.toggle("active",x===b));
|
||
aktualisiereHint();
|
||
}));
|
||
|
||
/* Haupt-Button: startet die Zapfung oder stoppt sie */
|
||
$("actionBtn").addEventListener("click",()=>{ if(phase==="tanken")stoppeTanken(); else starteTanken(); });
|
||
|
||
/* Demo-Buttons */
|
||
$("dLeer").addEventListener("click",()=>{ if(phase==="tanken")return;
|
||
fahrzeug.fuellstand=Math.round(Math.random()*18+4); renderFahrzeug(); renderDisplay(); aktualisiereHint(); });
|
||
$("dReich").addEventListener("click",()=>{ spieler.bargeld+=2000; spieler.konto+=5000; renderGeld(); aktualisiereHint(); });
|
||
|
||
/* =====================================================================
|
||
START
|
||
===================================================================== */
|
||
renderGeld(); renderFahrzeug(); renderSorten(); renderPreisInfo();
|
||
renderDisplay(); aktualisiereHint();
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|