#98 GWÖ-Matrix interaktiv: volle Begriffe + Tooltips + Staatsprinzipien

Matrix-Tabelle:
- Zeilen-Header: volle Berührungsgruppen-Namen (statt "A: Lieferant:innen"
  jetzt "A: Ausgelagerte Betriebe, Lieferant:innen")
- Spalten-Header: Mouseover zeigt Staatsprinzip + Kernfragen
  (z.B. "Sozialstaatsprinzip — Gerechte Verteilung? Daseinsvorsorge?")
- Bewertete Felder: Tooltip mit Feldcode + voller Name + Aspekt aus der
  Bewertung + Rating-Erklärung ("++ stark fördernd")
- Nicht-bewertete Felder: ○ mit Tooltip "Nicht bewertet (Antrag berührt
  dieses Feld nicht)" statt leere Zelle

Detail-Liste:
- Feld-Labels jetzt mit vollem Namen aus MATRIX_LABELS
- Aspekt kursiv hinter dem Label
- Rating-Zahl neben dem Symbol (z.B. "++ (+5)")

Daten aus models.py::MATRIX_LABELS via Template-Variable matrix_labels.

Tests: 206 passed.

Refs: #98
This commit is contained in:
Dotty Dotter 2026-04-10 23:06:37 +02:00
parent 5d2a0338ee
commit cfe36cbd65
2 changed files with 43 additions and 24 deletions

View File

@ -151,11 +151,13 @@ async def index(request: Request):
parlament_names = { parlament_names = {
bl.code: bl.parlament_name for bl in alle_bundeslaender() bl.code: bl.parlament_name for bl in alle_bundeslaender()
} }
from .models import MATRIX_LABELS
return templates.TemplateResponse("index.html", { return templates.TemplateResponse("index.html", {
"request": request, "request": request,
"app_name": settings.app_name, "app_name": settings.app_name,
"bundeslaender": bl_list, "bundeslaender": bl_list,
"parlament_names": parlament_names, "parlament_names": parlament_names,
"matrix_labels": MATRIX_LABELS,
}) })

View File

@ -1700,20 +1700,26 @@
const matrixData = {}; const matrixData = {};
(item.gwoeMatrix || []).forEach(m => { matrixData[m.field] = m; }); (item.gwoeMatrix || []).forEach(m => { matrixData[m.field] = m; });
// GWÖ-Matrix Definitionen (aus models.py)
const rowLabels = { const rowLabels = {
'A': 'Lieferant:innen', 'A': 'Ausgelagerte Betriebe, Lieferant:innen',
'B': 'Finanzen', 'B': 'Finanzpartner:innen, Steuerzahler:innen',
'C': 'Führung/Verwaltung', 'C': 'Politische Führung, Verwaltung',
'D': 'Bürger:innen', 'D': 'Bürger:innen und Wirtschaft',
'E': 'Gesellschaft/Natur' 'E': 'Staat, Gesellschaft und Natur'
};
const rowTooltips = {
'A': 'Externe Beschaffung, Lieferketten, Dienstleister:innen',
'B': 'Umgang mit öffentlichen Mitteln, Haushalt, Geldgeber:innen',
'C': 'Mandatsträger:innen, Mitarbeitende, Ehrenamtliche',
'D': 'Wirkung innerhalb der Grenzen, Daseinsvorsorge',
'E': 'Wirkung über die Grenzen hinaus, Zukunft'
}; };
// Spaltenüberschriften der GWÖ-Matrix (5 Werte)
const colLabels = { const colLabels = {
1: 'Menschen-würde', 1: 'Menschenwürde',
2: 'Solidarität', 2: 'Solidarität',
3: 'Ökol. Nachh.', 3: 'Ökol. Nachhaltigkeit',
4: 'Soz. Gerecht.', 4: 'Soz. Gerechtigkeit',
5: 'Transparenz' 5: 'Transparenz'
}; };
const colFull = { const colFull = {
@ -1723,32 +1729,43 @@
4: 'Soziale Gerechtigkeit', 4: 'Soziale Gerechtigkeit',
5: 'Transparenz & Mitbestimmung' 5: 'Transparenz & Mitbestimmung'
}; };
const colPrinzip = {
1: 'Rechtsstaatsprinzip — Werden Grundrechte geschützt? Rechtliche Gleichstellung?',
2: 'Gemeinnutz — Wird das Gemeinwohl gefördert? Mehrwert für die Gemeinschaft?',
3: 'Umwelt-Verantwortung — Klimaschutz? Ressourcenschonung? Biodiversität?',
4: 'Sozialstaatsprinzip — Gerechte Verteilung? Daseinsvorsorge? Soziale Absicherung?',
5: 'Demokratie — Bürgerbeteiligung? Offenlegung? Demokratische Prozesse?'
};
const fieldLabels = {{ matrix_labels | tojson }};
const ratingExplain = (r) => r >= 4 ? '++ stark fördernd' : r >= 1 ? '+ fördernd' : r === 0 ? '○ neutral' : r >= -3 ? ' widersprechend' : ' stark widersprechend';
let matrixTableHtml = '<table class="matrix-table"><thead><tr><th></th>'; let matrixTableHtml = '<table class="matrix-table"><thead><tr><th style="min-width:120px;"></th>';
for (let col = 1; col <= 5; col++) matrixTableHtml += `<th title="${colFull[col]}">${colLabels[col]}</th>`; for (let col = 1; col <= 5; col++) matrixTableHtml += `<th title="${colPrinzip[col]}" style="cursor:help;">${colLabels[col]}</th>`;
matrixTableHtml += '</tr></thead><tbody>'; matrixTableHtml += '</tr></thead><tbody>';
['A', 'B', 'C', 'D', 'E'].forEach(row => { ['A', 'B', 'C', 'D', 'E'].forEach(row => {
matrixTableHtml += `<tr><th>${row}: ${rowLabels[row]}</th>`; matrixTableHtml += `<tr><th title="${rowTooltips[row]}" style="cursor:help;text-align:left;font-size:0.8rem;">${row}: ${rowLabels[row]}</th>`;
for (let col = 1; col <= 5; col++) { for (let col = 1; col <= 5; col++) {
const field = `${row}${col}`; const field = `${row}${col}`;
const entry = matrixData[field]; const entry = matrixData[field];
const fullLabel = fieldLabels[field] || field;
if (entry) { if (entry) {
const cssClass = entry.rating > 0 ? 'positive' : (entry.rating < 0 ? 'negative' : 'neutral'); const cssClass = entry.rating > 0 ? 'positive' : (entry.rating < 0 ? 'negative' : 'neutral');
matrixTableHtml += `<td class="${cssClass}" title="${entry.aspect || entry.label}">${entry.symbol}</td>`; const tooltip = `${field}: ${fullLabel}\n\n${entry.aspect || ''}\n\nBewertung: ${entry.rating} (${ratingExplain(entry.rating)})`;
matrixTableHtml += `<td class="${cssClass}" title="${tooltip.replace(/"/g,'&quot;')}" style="cursor:help;">${entry.symbol}</td>`;
} else { } else {
matrixTableHtml += '<td></td>'; matrixTableHtml += `<td title="${field}: ${fullLabel}\n\n○ Nicht bewertet (Antrag berührt dieses Feld nicht)" style="cursor:help;color:#ccc;"></td>`;
} }
} }
matrixTableHtml += '</tr>'; matrixTableHtml += '</tr>';
}); });
matrixTableHtml += '</tbody></table>'; matrixTableHtml += '</tbody></table>';
// Zusätzlich die Detail-Liste der bewerteten Felder // Detail-Liste der bewerteten Felder mit vollen Beschreibungen
const matrixDetailHtml = (item.gwoeMatrix || []).map(m => ` const matrixDetailHtml = (item.gwoeMatrix || []).map(m => `
<div class="matrix-item"> <div class="matrix-item" title="${ratingExplain(m.rating)}">
<span class="matrix-label">${m.field}: ${m.label}</span> <span class="matrix-label"><strong>${m.field}</strong> ${fieldLabels[m.field] || m.label}: <em>${m.aspect || ''}</em></span>
<span class="matrix-rating ${m.rating > 0 ? 'rating-pos' : m.rating < 0 ? 'rating-neg' : 'rating-neutral'}">${m.symbol}</span> <span class="matrix-rating ${m.rating > 0 ? 'rating-pos' : m.rating < 0 ? 'rating-neg' : 'rating-neutral'}">${m.symbol} (${m.rating})</span>
</div> </div>
`).join(''); `).join('');