Rechnungsanalyse: Kalkulationsseite fuer Leads im Admin-Panel

Bei Leads (customerStatus=lead) steht in der Kundenliste jetzt der Button
"Rechnungsanalyse". Er oeffnet /kalkulation.html?customer=<id> - die Seite,
die im Gespraech vor Ort oder am Telefon ausgefuellt wird.

- Positionen nach Bereich (Website, Onlineshop, Softwareprojekt,
  Automatisierung/KI, laufende Kosten) mit Stundenwerten und Mengen
- Preis ueber die Stundenstaffel (150/130/115/100), Brutto mit 19 % MwSt.,
  Zahlungsmodalitaeten ab 1.000 / 3.000 EUR
- Hinweis, ob selbst zusagbar (<= 5 Std), Termin abzustimmen oder ob Kenso
  freigeben muss (Shop, Software, Automatisierung)
- Termin mit Justin/Kenso aus den hinterlegten Zeitfenstern, Notizen,
  Kundenportal-Zugang mit QR-Code
- Zusammenfassung als Text zum Kopieren -> gehoert ins Akquise-Ticket

Bewusst ohne eigenen Datensatz: dokumentiert wird im Ticket. Der Stand liegt
pro Kunde nur im localStorage, damit ein angefangenes Gespraech nicht
verloren geht.

Fonts (Caprasimo, Figtree) liegen lokal unter public/fonts, kein Abruf beim
Google-CDN. Neue Route GET /api/portal-admin/customers/:customerId liefert
die Stammdaten zum Vorbefuellen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-08-08 21:42:13 +00:00
parent a4b4974431
commit 9108c90a53
11 changed files with 1269 additions and 1 deletions

169
public/kalkulation.html Normal file
View File

@@ -0,0 +1,169 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Rechnungsanalyse Webklar</title>
<link rel="stylesheet" href="/kalkulation.css">
</head>
<body>
<header class="kal-header">
<div class="kal-header-inner">
<span class="kal-brand">webklar</span>
<a class="kal-back" href="/admin.html">← Admin</a>
<span class="kal-spacer" id="kal-lead"></span>
<span class="kal-stat">
<span class="kal-stat-lbl">Netto</span>
<span class="kal-stat-val big" id="hdr-net">0 €</span>
</span>
<span class="kal-stat">
<span class="kal-stat-lbl">Stunden</span>
<span class="kal-stat-val" id="hdr-hrs">0,00</span>
</span>
<span class="kal-stat">
<span class="kal-stat-lbl">Monatlich</span>
<span class="kal-stat-val" id="hdr-monthly"></span>
</span>
</div>
</header>
<main>
<!-- Preis-Übersicht -->
<section class="hero">
<div class="kicker" id="hero-kicker">Ihr Projekt</div>
<div class="hero-price-row">
<div class="hero-price" id="hero-net">0 €</div>
<div class="hero-price-sub" id="hero-sub">netto · 0 € brutto inkl. 19 % MwSt.</div>
</div>
<div class="hero-tiles">
<div class="tile">
<div class="tile-lbl">Aufwand</div>
<div class="tile-val" id="hero-hrs">0,00 Std</div>
<div class="tile-sub" id="hero-rate">Stundensatz 150 €/Std</div>
</div>
<div class="tile">
<div class="tile-lbl">Monatlich</div>
<div class="tile-val" id="hero-monthly"></div>
<div class="tile-sub" id="hero-monthly-sub">nichts Laufendes gewählt</div>
</div>
<div class="tile tile-pay">
<div class="tile-lbl">Zahlung</div>
<div class="tile-pay-title" id="pay-title">Noch nichts gewählt</div>
<div class="tile-pay-text" id="pay-text">Kreuze an, was der Kunde braucht.</div>
</div>
</div>
<div class="flag" id="flag"><b>Noch offen.</b> Sobald etwas gewählt ist, steht hier, ob du selbst abschließen kannst.</div>
<div class="hero-actions">
<button type="button" class="btn-solid" data-act="open-summary">Zusammenfassung</button>
<button type="button" class="btn-outline" data-act="reset">Zurücksetzen</button>
</div>
</section>
<!-- Bereiche -->
<section class="block">
<h2>Worum geht es?</h2>
<p class="block-lead">Bereiche antippen — nur die ausgewählten werden unten angezeigt.</p>
<div class="chips" id="type-chips"></div>
</section>
<!-- Positionen (gerendert) -->
<div id="sections"></div>
<div class="empty-hint" id="empty-hint" hidden>
<h3>Noch kein Bereich gewählt</h3>
<p>Tippe oben an, worum es geht — dann erscheinen hier die Positionen.</p>
</div>
<!-- Auswahl -->
<section class="panel" id="chosen-panel" hidden>
<div class="group-label" style="margin:0 0 14px" id="chosen-label">Ausgewählt (0)</div>
<div class="chips" id="chosen-list"></div>
</section>
<!-- Termin -->
<section class="panel">
<div class="kicker" style="color:var(--color-neutral-600)">Termin</div>
<h2>Gespräch festlegen</h2>
<p class="panel-lead">Nur wenn gewünscht: Mit wem, wann — und worum es geht. Der Termin hängt an der Zusammenfassung.</p>
<div class="seg" id="want-seg">
<button type="button" data-act="want" data-want="0" class="on">Kein Termin nötig</button>
<button type="button" data-act="want" data-want="1">Termin gewünscht</button>
</div>
<div id="termin-body" hidden>
<div class="chips" id="person-list"></div>
<div class="group-label" id="days-label">Freie Tage</div>
<div class="day-grid" id="day-list"></div>
<div id="slot-wrap" hidden>
<div class="group-label" id="slots-label">Uhrzeit</div>
<div class="chips" id="slot-list"></div>
</div>
<div style="margin-top:20px">
<label class="field-label" for="term-note">Worum geht es im Gespräch?</label>
<textarea class="kal-input" id="term-note"
placeholder="z. B. Shop-Anbindung an die Warenwirtschaft klären"></textarea>
</div>
<div class="term-status" id="term-status">
<b>Noch kein Termin.</b> Wähle einen Tag und eine Uhrzeit — beides landet in der Zusammenfassung.
</div>
</div>
<div style="margin-top:18px">
<label class="field-label" for="notes">Weitere Notizen zum Projekt</label>
<textarea class="kal-input" id="notes" style="min-height:110px"
placeholder="Alles, was sonst noch wichtig ist: Wünsche, Fristen, Ansprechpartner, Besonderheiten…"></textarea>
</div>
</section>
<!-- Kundenportal -->
<section class="portal-box">
<div class="portal-qr">
<img src="/img/portal-qr.png" alt="QR-Code zum Kundenportal project.webklar.com" width="180" height="180">
</div>
<div class="portal-info">
<div class="kicker" style="color:var(--color-neutral-600)">Kundenportal</div>
<h2>Code scannen und einloggen</h2>
<p class="panel-lead">Im Portal sieht der Kunde den Stand des Projekts, alle Dateien und die Rechnungen —
<a href="https://project.webklar.com/" target="_blank" rel="noreferrer">project.webklar.com</a></p>
<div class="cred-row">
<label class="cred">
<span>E-Mail</span>
<input id="portal-email" type="email" autocomplete="off" placeholder="kunde@firma.de">
</label>
<label class="cred">
<span>Passwort</span>
<input id="portal-pass" class="mono" type="text" autocomplete="off" placeholder="wird vergeben">
</label>
</div>
</div>
</section>
<footer>
webklar GbR · Am Schwimmbad 10 · 67722 Winnweiler · 0170 4969375<br>
Alle Preise netto zzgl. gesetzlicher Umsatzsteuer. Stundenwerte sind Richtwerte.
</footer>
</main>
<!-- Zusammenfassung -->
<div class="backdrop" id="summary-dialog" hidden>
<div class="dialog" role="dialog" aria-modal="true" aria-labelledby="summary-title">
<h2 id="summary-title">Zusammenfassung</h2>
<textarea id="summary-text" readonly></textarea>
<div class="dialog-actions">
<button type="button" class="btn-accent" data-act="copy">Kopieren</button>
<button type="button" class="btn-quiet" data-act="close-summary">Schließen</button>
</div>
</div>
</div>
<script src="/kalkulation.js"></script>
<script>
initKalkulation();
</script>
</body>
</html>