SIA-Bilanz CSV-Export aus Elemente-Uebersicht
Download-Button (file_download Icon) neben den Expand/Collapse-Buttons in der Toolbar. Klick → SaveFileDialog (Default 'sia_bilanz.csv') → schreibt Excel-kompatible CSV. Backend (elemente_uebersicht._export_bilanz): - Wide-Format: Spalten = Kategorie + ein Geschoss + Total - Zeilen: HNF, NNF, NF, VF, FF, NGF, GF, AGF, Räume (count), Personen - Werte via _elm.compute_sia_bilanz fuer jeden Scope (gleiche Logik wie Bilanz-Stempel + Uebersicht — single source of truth) - Format: Semikolon-Separator + UTF-8 BOM + Komma als Dezimaltrenner (Excel CH/DE-kompatibel, oeffnet ohne Umweg) - Flaechen mit 2 Nachkommastellen, Raume/Personen als int
This commit is contained in:
@@ -208,6 +208,88 @@ class ElementeUebersichtBridge(panel_base.BaseBridge):
|
|||||||
print("[UEBERSICHT] zoom:", ex)
|
print("[UEBERSICHT] zoom:", ex)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[UEBERSICHT] zoom find:", ex)
|
print("[UEBERSICHT] zoom find:", ex)
|
||||||
|
elif t == "EXPORT_BILANZ":
|
||||||
|
self._export_bilanz()
|
||||||
|
|
||||||
|
def _export_bilanz(self):
|
||||||
|
"""Exportiert SIA-416 Bilanz als CSV (Excel-kompatibel: Semikolon-
|
||||||
|
Separator + UTF-8 BOM + Komma als Dezimaltrenner). Wide-Format:
|
||||||
|
eine Spalte pro Geschoss + Total-Spalte, Zeilen pro Kategorie.
|
||||||
|
"""
|
||||||
|
doc = Rhino.RhinoDoc.ActiveDoc
|
||||||
|
if doc is None: return
|
||||||
|
# Geschoss-Liste (geordnet) + Total am Ende
|
||||||
|
geschosse = _elm._load_geschosse(doc) or []
|
||||||
|
gs_list = [g for g in geschosse
|
||||||
|
if isinstance(g, dict) and g.get("isGeschoss")]
|
||||||
|
# Bilanz pro Geschoss + Total via compute_sia_bilanz
|
||||||
|
per_gid = {} # gid → bilanz dict
|
||||||
|
for g in gs_list:
|
||||||
|
per_gid[g["id"]] = _elm.compute_sia_bilanz(
|
||||||
|
doc, "geschoss:" + g["id"])
|
||||||
|
total = _elm.compute_sia_bilanz(doc, "total")
|
||||||
|
# SaveFileDialog
|
||||||
|
try:
|
||||||
|
from Rhino.UI import SaveFileDialog
|
||||||
|
sfd = SaveFileDialog()
|
||||||
|
sfd.DefaultExt = "csv"
|
||||||
|
sfd.Filter = "CSV (*.csv)|*.csv"
|
||||||
|
sfd.FileName = "sia_bilanz.csv"
|
||||||
|
ok = False
|
||||||
|
try: ok = sfd.ShowSaveDialog()
|
||||||
|
except Exception:
|
||||||
|
try: ok = sfd.ShowDialog()
|
||||||
|
except Exception: ok = False
|
||||||
|
if not ok:
|
||||||
|
print("[UEBERSICHT] Bilanz-Export abgebrochen"); return
|
||||||
|
path = sfd.FileName
|
||||||
|
except Exception as ex:
|
||||||
|
print("[UEBERSICHT] SaveFileDialog:", ex); return
|
||||||
|
|
||||||
|
# Zeilen-Definition: (Label, Bilanz-Key, ist_personen?)
|
||||||
|
rows = [
|
||||||
|
("HNF (m²)", "hnf", False),
|
||||||
|
("NNF (m²)", "nnf", False),
|
||||||
|
("NF (m²)", "nf", False),
|
||||||
|
("VF (m²)", "vf", False),
|
||||||
|
("FF (m²)", "ff", False),
|
||||||
|
("NGF (m²)", "ngf", False),
|
||||||
|
("GF (m²)", "gf", False),
|
||||||
|
("AGF (m²)", "agf", False),
|
||||||
|
("Räume", "count", True),
|
||||||
|
("Personen", "personen", True),
|
||||||
|
]
|
||||||
|
|
||||||
|
def _fmt(val, is_count):
|
||||||
|
if val is None: return ""
|
||||||
|
if is_count: return str(int(val))
|
||||||
|
return "{:.2f}".format(float(val)).replace(".", ",")
|
||||||
|
|
||||||
|
def _esc(s):
|
||||||
|
s = str(s)
|
||||||
|
if ";" in s or '"' in s or "\n" in s:
|
||||||
|
return '"' + s.replace('"', '""') + '"'
|
||||||
|
return s
|
||||||
|
|
||||||
|
try:
|
||||||
|
import io
|
||||||
|
with io.open(path, "w", encoding="utf-8-sig", newline="") as f:
|
||||||
|
# Header — Kategorie + Geschoss-Namen + Total
|
||||||
|
header = ["Kategorie"]
|
||||||
|
for g in gs_list: header.append(_esc(g.get("name") or "?"))
|
||||||
|
header.append("Total")
|
||||||
|
f.write(";".join(header) + "\n")
|
||||||
|
for label, key, is_count in rows:
|
||||||
|
line = [_esc(label)]
|
||||||
|
for g in gs_list:
|
||||||
|
b = per_gid.get(g["id"], {})
|
||||||
|
line.append(_fmt(b.get(key, 0), is_count))
|
||||||
|
line.append(_fmt(total.get(key, 0), is_count))
|
||||||
|
f.write(";".join(line) + "\n")
|
||||||
|
print("[UEBERSICHT] SIA-Bilanz exportiert: {} ({} Geschosse + Total)".format(
|
||||||
|
path, len(gs_list)))
|
||||||
|
except Exception as ex:
|
||||||
|
print("[UEBERSICHT] CSV schreiben:", ex)
|
||||||
|
|
||||||
|
|
||||||
def open_as_window():
|
def open_as_window():
|
||||||
|
|||||||
@@ -128,6 +128,9 @@ export default function ElementeUebersichtApp() {
|
|||||||
}} />
|
}} />
|
||||||
<BarButton icon="unfold_more" onClick={expandAll} title="Alle aufklappen" />
|
<BarButton icon="unfold_more" onClick={expandAll} title="Alle aufklappen" />
|
||||||
<BarButton icon="unfold_less" onClick={collapseAll} title="Alle einklappen" />
|
<BarButton icon="unfold_less" onClick={collapseAll} title="Alle einklappen" />
|
||||||
|
<BarButton icon="file_download"
|
||||||
|
onClick={() => send('EXPORT_BILANZ', {})}
|
||||||
|
title="SIA-416 Bilanz als CSV exportieren (eine Spalte pro Geschoss + Total)" />
|
||||||
</div>
|
</div>
|
||||||
{/* Kind-Filter Chips */}
|
{/* Kind-Filter Chips */}
|
||||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 3 }}>
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 3 }}>
|
||||||
|
|||||||
Reference in New Issue
Block a user