Elemente-Uebersicht: SIA-416 Bilanz pro Geschoss

Aggregiert alle raum_outline-Flaechen nach raum_sia-Klassifikation
(hnf/nnf/vf/ff) und zeigt sie als kompakte Mini-Tabelle direkt unter
dem Geschoss-Header in der Project-Browser-Uebersicht.

Backend (_build_overview):
- Neuer Returnschluessel siaBilanz: {geschossId: {hnf, nnf, vf, ff,
  ohne, nf, total, count}} in m^2
- NF = HNF + NNF (Nutzflaeche nach SIA 416)
- Raeume ohne SIA-Tag landen in "ohne"

Frontend (ElementeUebersichtApp):
- Direkt unter dem Geschoss-Header eine Inline-Tabelle mit nur den
  Klassen die > 0 sind (kein Spam wenn nichts klassifiziert ist)
- NF separat hervorgehoben (Accent-Farbe) als wichtigste Kennzahl
- Read-only, aktualisiert sich mit jedem state-emit (Raum-Aenderung,
  SIA-Tag setzen, neue Raeume) automatisch
This commit is contained in:
2026-05-26 23:20:00 +02:00
parent f1860ae85d
commit 3c28d2e29c
2 changed files with 77 additions and 1 deletions
+47
View File
@@ -40,6 +40,7 @@ export default function ElementeUebersichtApp() {
const items = state.items || []
const geschosse = state.geschosse || []
const siaBilanz = state.siaBilanz || {}
const filtered = useMemo(() => {
let r = items
@@ -163,6 +164,7 @@ export default function ElementeUebersichtApp() {
const total = Object.values(groupForG).reduce((s, arr) => s + arr.length, 0)
if (total === 0) return null
const gOpen = expanded[g.id] !== false // default: open
const bilanz = siaBilanz[g.id]
return (
<div key={g.id}>
<div onClick={() => toggle(g.id)}
@@ -192,6 +194,51 @@ export default function ElementeUebersichtApp() {
fontFamily: 'DM Mono, monospace',
}}>{total}</span>
</div>
{/* SIA-416 Bilanz pro Geschoss — read-only Mini-Tabelle,
nur angezeigt wenn mindestens ein klassifizierter Raum */}
{gOpen && bilanz && (bilanz.hnf + bilanz.nnf + bilanz.vf + bilanz.ff) > 0 && (
<div style={{
display: 'flex', flexWrap: 'wrap', gap: 10,
padding: '4px 14px 6px',
background: 'var(--bg-section)',
borderBottom: '1px solid var(--border-light)',
fontSize: 9, fontFamily: 'DM Mono, monospace',
color: 'var(--text-muted)',
}}>
{bilanz.hnf > 0 && (
<span title="Hauptnutzflaeche (SIA 416)">
HNF <strong style={{color:'var(--text-primary)'}}>{bilanz.hnf.toFixed(1)}</strong>
</span>
)}
{bilanz.nnf > 0 && (
<span title="Nebennutzflaeche">
NNF <strong style={{color:'var(--text-primary)'}}>{bilanz.nnf.toFixed(1)}</strong>
</span>
)}
{bilanz.vf > 0 && (
<span title="Verkehrsflaeche">
VF <strong style={{color:'var(--text-primary)'}}>{bilanz.vf.toFixed(1)}</strong>
</span>
)}
{bilanz.ff > 0 && (
<span title="Funktionsflaeche">
FF <strong style={{color:'var(--text-primary)'}}>{bilanz.ff.toFixed(1)}</strong>
</span>
)}
{bilanz.nf > 0 && (
<span title="Nutzflaeche = HNF + NNF"
style={{ paddingLeft: 4, borderLeft: '1px solid var(--border)' }}>
NF <strong style={{color:'var(--accent)'}}>{bilanz.nf.toFixed(1)}</strong>
</span>
)}
{bilanz.ohne > 0 && (
<span title="Raeume ohne SIA-Klassifikation"
style={{ opacity: 0.6 }}>
{bilanz.ohne.toFixed(1)}
</span>
)}
</div>
)}
{gOpen && KIND_ORDER.map(k => {
const arr = groupForG[k]
if (!arr || arr.length === 0) return null