feat: Antragsteller + Beratungsergebnis pro Kettenglied

- Backend: Batch-Queries für Antragsteller + Beratungen pro Glied
- Jedes Glied zeigt: Partei-Badges + Gremium: Beschlusstext
- Explorer Panel 2: Farbige Partei-Badges + Beratungsergebnis an jedem Schritt
This commit is contained in:
Dotty Dotter 2026-04-01 23:51:26 +02:00
parent e35dab8f7d
commit 601d07b787
3 changed files with 74 additions and 19 deletions

View File

@ -118,7 +118,7 @@ class KetteDetail(BaseModel):
letzte_aktivitaet: date | None = None
vertagungen_count: int = 0
begruendung: str | None = None
glieder: list[KettenGliedOut] = []
glieder: list[dict] = []
antragsteller: list[ParteiOut] = []
graph: dict | None = None
strang: str | None = None

View File

@ -161,8 +161,45 @@ def get_kette(kette_id: int, conn=Depends(_db)):
(kette_id,),
).fetchall()
# Collect IDs for batch queries
glied_ids = [g["id"] for g in glieder_rows]
placeholders = ",".join("?" * len(glied_ids)) if glied_ids else "0"
# Antragsteller per Glied
glied_ast: dict[int, list] = {}
if glied_ids:
ast_rows = conn.execute(
f"""SELECT a.vorlage_id, p.kuerzel, p.name, p.farbe
FROM antragsteller a JOIN parteien p ON a.partei_id = p.id
WHERE a.vorlage_id IN ({placeholders})""",
glied_ids,
).fetchall()
for a in ast_rows:
glied_ast.setdefault(a["vorlage_id"], []).append(
{"kuerzel": a["kuerzel"], "name": a["name"], "farbe": a["farbe"]}
)
# Beratungen per Glied (Gremium + Ergebnis)
glied_beratungen: dict[int, list] = {}
if glied_ids:
ber_rows = conn.execute(
f"""SELECT b.vorlage_id, g.name as gremium, b.ergebnis, b.beschlusstext, b.sitzung_datum
FROM beratungen b LEFT JOIN gremien g ON b.gremium_id = g.id
WHERE b.vorlage_id IN ({placeholders})
ORDER BY b.sitzung_datum""",
glied_ids,
).fetchall()
for b in ber_rows:
glied_beratungen.setdefault(b["vorlage_id"], []).append({
"gremium": b["gremium"],
"ergebnis": b["ergebnis"],
"beschlusstext": b["beschlusstext"][:200] if b["beschlusstext"] else None,
"sitzung_datum": b["sitzung_datum"],
})
glieder = [
KettenGliedOut(
{
**KettenGliedOut(
vorlage=VorlageKurz(
id=g["id"],
aktenzeichen=g["aktenzeichen"],
@ -173,7 +210,10 @@ def get_kette(kette_id: int, conn=Depends(_db)):
),
position=g["position"],
rolle=g["rolle"],
)
).model_dump(),
"antragsteller": glied_ast.get(g["id"], []),
"beratungen": glied_beratungen.get(g["id"], []),
}
for g in glieder_rows
]

View File

@ -414,13 +414,28 @@
{glied.vorlage.aktenzeichen || `#${glied.vorlage.id}`}
</span>
</div>
<div class="flex flex-wrap items-center gap-1 mb-0.5">
{#if glied.rolle}
<span class="inline-block text-[10px] px-1.5 py-0.5 rounded bg-gray-100 text-gray-600 mb-0.5">
<span class="text-[10px] px-1.5 py-0.5 rounded bg-gray-100 text-gray-600">
{glied.rolle}
</span>
{/if}
{#each glied.antragsteller || [] as a}
<span class="text-[10px] px-1 py-0.5 rounded font-medium"
style="background-color: {a.farbe || '#6b7280'}20; color: {a.farbe || '#6b7280'}; border: 1px solid {a.farbe || '#6b7280'}40;">
{a.kuerzel}
</span>
{/each}
</div>
{#each glied.beratungen || [] as b}
{#if b.beschlusstext || b.ergebnis}
<div class="text-[10px] text-gray-500 leading-tight">
<span class="font-medium">{b.gremium || '?'}</span>: {b.beschlusstext || b.ergebnis || ''}
</div>
{/if}
{/each}
{#if glied.vorlage.datum_eingang}
<div class="text-[10px] text-gray-400">
<div class="text-[10px] text-gray-400 mt-0.5">
{formatDate(glied.vorlage.datum_eingang)}
</div>
{/if}