diff --git a/app/auswertungen.py b/app/auswertungen.py index 49c2f45..98e469e 100644 --- a/app/auswertungen.py +++ b/app/auswertungen.py @@ -992,6 +992,65 @@ def aggregate_empfehlungs_konsistenz( } +def get_empfehlungs_konsistenz_cases( + partei: str, + filter_bl: Optional[str] = None, + filter_wp: Optional[str] = None, + limit: int = 50, + db_path: Optional[Path] = None, +) -> dict: + """Drilldown: konkrete Antraege wo ``partei`` mit NEIN gestimmt hat, + obwohl die GWÖ-Empfehlung "Unterstuetzen" lautete. + + Quelle fuer Klick auf Empfehlungs-Konsistenz-Bar im Stimmverhalten-Tab. + """ + rows = _load_assessments_with_votes(filter_bl, filter_wp, db_path) + + path = db_path or settings.db_path + if not Path(path).exists(): + return {"partei": partei, "count": 0, "items": [], "filter": { + "bundesland": filter_bl, "wahlperiode": filter_wp, + }} + + POSITIV = {"Uneingeschränkt unterstützen", "Unterstützen mit Änderungen"} + conn = sqlite3.connect(str(path)) + try: + empfehlung_map = { + (r[0], r[1]): r[2] for r in conn.execute( + "SELECT bundesland, drucksache, empfehlung FROM assessments" + ).fetchall() + } + finally: + conn.close() + + cases = [] + for row in rows: + if partei not in row["nein"]: + continue + empfehlung = empfehlung_map.get((row["bundesland"], row["drucksache"])) + if empfehlung not in POSITIV: + continue + cases.append({ + "drucksache": row["drucksache"], + "bundesland": row["bundesland"], + "datum": row.get("datum"), + "gwoe_score": row.get("gwoe_score"), + "empfehlung": empfehlung, + "ergebnis": row.get("ergebnis"), + }) + + cases.sort(key=lambda c: (c.get("gwoe_score") or 0), reverse=True) + return { + "partei": partei, + "count": len(cases), + "items": cases[:limit], + "filter": { + "bundesland": filter_bl, + "wahlperiode": filter_wp, + }, + } + + def aggregate_stimm_index_cross_bl( filter_wp: Optional[str] = None, exclude_antragsteller: bool = True, diff --git a/app/main.py b/app/main.py index c073cb6..ca4fb7a 100644 --- a/app/main.py +++ b/app/main.py @@ -2730,6 +2730,24 @@ async def auswertungen_heuchelei_cases( ) +@app.get("/api/auswertungen/empfehlungs-konsistenz-cases") +async def auswertungen_empfehlungs_konsistenz_cases( + partei: str, + bundesland: Optional[str] = None, + wahlperiode: Optional[str] = None, + limit: int = 50, +): + """Drilldown: Anträge wo `partei` mit NEIN stimmte trotz GWÖ-Empfehlung + 'Unterstützen'. Quelle für Klick auf Empfehlungs-Konsistenz-Bar (#167).""" + from .auswertungen import get_empfehlungs_konsistenz_cases + return get_empfehlungs_konsistenz_cases( + partei=partei, + filter_bl=bundesland, + filter_wp=wahlperiode, + limit=limit, + ) + + @app.get("/api/auswertungen/stimm-index-pro-wert") async def auswertungen_stimm_index_pro_wert( bundesland: Optional[str] = None, diff --git a/app/templates/v2/screens/auswertungen.html b/app/templates/v2/screens/auswertungen.html index cb2044f..95c0cbf 100644 --- a/app/templates/v2/screens/auswertungen.html +++ b/app/templates/v2/screens/auswertungen.html @@ -1053,6 +1053,80 @@ function closeHeucheleiDrilldown() { if (modal) modal.style.display = 'none'; } +async function openKonsistenzDrilldown(partei, bl) { + let modal = document.getElementById('sv-heuchelei-modal'); + if (!modal) { + // Modal-Markup analog zu openHeucheleiDrilldown — bei Bedarf injizieren + modal = document.createElement('div'); + modal.id = 'sv-heuchelei-modal'; + modal.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.6);z-index:9999;display:flex;align-items:center;justify-content:center;padding:8px;'; + modal.innerHTML = ` +
Keine Anträge gefunden.
'; + return; + } + body.innerHTML = ` ++ ${data.count} Treffer${data.items.length < data.count ? ` — Top ${data.items.length} angezeigt` : ''}. +
+| Drucksache | +BL | +Datum | +GWÖ | +Empfehlung | +Beschluss | +
|---|---|---|---|---|---|
| + ${it.drucksache} + | +${it.bundesland} | +${it.datum || ''} | +${it.gwoe_score != null ? it.gwoe_score.toFixed(1) : '—'} | +${it.empfehlung || '—'} | +${it.ergebnis || '—'} | +