feat(ui): show SKM component-tier summary on the Normen list
Each Evaluation grows a componentSummary field — a small list of
plain strings, one per SKM ingredient (P / F / T / h), tagged
with its tier in the form 'P · T1 — DESTATIS Gewerbeanzeigen'.
The fixtures fill it in for all five pilot norms; the field
defaults to an empty list so flow-produced Evaluations remain
backwards-compatible until a future flow step writes one.
NormsListPage re-arranges the row to make use of the wide-screen
real-estate on the right that used to sit empty:
┌─────────────────────────────────────────────────────────────┐
│ GewO § 14 — Anzeigepflicht │ Schaden │ Komponenten │
│ eli/bund/gewo/14 │ 2.8 Mio € │ P · T1 … │
│ [T1 · amtlich] │ Nutzen │ F · T1 … │
│ │ 2.5 / 5 │ T · T1 … │
│ │ Betroffene │ h · T3 … │
│ │ 180 k │ │
└─────────────────────────────────────────────────────────────┘
The TierBadge moved into the title column (right under the eli)
so the eye lands on the tier of the figure right where the
figure's identity is named. The three metric columns stack
vertically (no more horizontal-only row) which leaves the right
third of the row free for the componentSummary lines — the
information a reviewer was always asking for ('which Komponente
is the bottleneck here?') is now visible without opening the
detail page.
Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
parent
c6400302dd
commit
ae9fc45177
3 changed files with 104 additions and 15 deletions
|
|
@ -90,6 +90,12 @@ class Fixtures {
|
||||||
'T (Tarif) T1 — DESTATIS Verdiensterhebung kaufm. Tätigkeit ~30 €/h; '
|
'T (Tarif) T1 — DESTATIS Verdiensterhebung kaufm. Tätigkeit ~30 €/h; '
|
||||||
'h (Zeitaufwand) T3 — eigene Schätzung ~30 min, NKR-Validierung ausstehend. '
|
'h (Zeitaufwand) T3 — eigene Schätzung ~30 min, NKR-Validierung ausstehend. '
|
||||||
'Regel der niedrigsten Stufe: Gesamt → T3 (in der Demo konservativ als T4 markiert).',
|
'Regel der niedrigsten Stufe: Gesamt → T3 (in der Demo konservativ als T4 markiert).',
|
||||||
|
componentSummary: const [
|
||||||
|
'P · T1 — DESTATIS Gewerbeanzeigen',
|
||||||
|
'F · T1 — anlassbezogen, je Vorgang',
|
||||||
|
'T · T1 — DESTATIS Verdiensterhebung',
|
||||||
|
'h · T3 — eigene Schätzung ~30 min',
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
static final _kassenSichV = Evaluation(
|
static final _kassenSichV = Evaluation(
|
||||||
|
|
@ -177,6 +183,12 @@ class Fixtures {
|
||||||
'Laufende Folgekosten (TSE-Ausfallmeldungen, Hardware-Erneuerung): T2 '
|
'Laufende Folgekosten (TSE-Ausfallmeldungen, Hardware-Erneuerung): T2 '
|
||||||
'aus DIHK-Bürokratie-Index + DEHOGA-Gastronomie-Stichprobe. '
|
'aus DIHK-Bürokratie-Index + DEHOGA-Gastronomie-Stichprobe. '
|
||||||
'Hoher Frust-Score wegen Pluralität TSE-Hersteller × Finanzamt-Vollzug.',
|
'Hoher Frust-Score wegen Pluralität TSE-Hersteller × Finanzamt-Vollzug.',
|
||||||
|
componentSummary: const [
|
||||||
|
'P · T1 — Kassen-pflichtige Betriebe',
|
||||||
|
'F · T1 — kontinuierlich + Ausfälle',
|
||||||
|
'T · T2 — DIHK Bürokratie-Index',
|
||||||
|
'h · T2 — DEHOGA-Stichprobe',
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
static final _dsgvoArt30 = Evaluation(
|
static final _dsgvoArt30 = Evaluation(
|
||||||
|
|
@ -272,6 +284,13 @@ class Fixtures {
|
||||||
'pro Unternehmen liegt im Streit zwischen BfDI-Position (gering, weil '
|
'pro Unternehmen liegt im Streit zwischen BfDI-Position (gering, weil '
|
||||||
'<250-MA-Ausnahme) und DIHK-Position (hoch, weil 5-Abs.-Ausnahme '
|
'<250-MA-Ausnahme) und DIHK-Position (hoch, weil 5-Abs.-Ausnahme '
|
||||||
'praktisch nicht greift). Tier T2 für Magnitude.',
|
'praktisch nicht greift). Tier T2 für Magnitude.',
|
||||||
|
componentSummary: const [
|
||||||
|
'P · T1 — DESTATIS Unternehmensregister',
|
||||||
|
'F · T1 — jährlich überprüfen',
|
||||||
|
'T · T2 — DIHK-Position',
|
||||||
|
'h · T2 — Streit BfDI ↔ DIHK',
|
||||||
|
'EU-determiniert · Reform-Hebel Brüssel',
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
static final _berlinBauO60 = Evaluation(
|
static final _berlinBauO60 = Evaluation(
|
||||||
|
|
@ -351,6 +370,13 @@ class Fixtures {
|
||||||
'→ Genehmigung sind im Land getrennt geregelt). Höchster Frust-Score '
|
'→ Genehmigung sind im Land getrennt geregelt). Höchster Frust-Score '
|
||||||
'aus Verweistiefe + Behörden-Pluralität (Bezirksamt × SenStadt × '
|
'aus Verweistiefe + Behörden-Pluralität (Bezirksamt × SenStadt × '
|
||||||
'Beteiligungsverfahren).',
|
'Beteiligungsverfahren).',
|
||||||
|
componentSummary: const [
|
||||||
|
'P · T2 — Handwerkskammer Berlin',
|
||||||
|
'F · T1 — pro Bauvorhaben',
|
||||||
|
'T · T2 — Bauwirtschaft Berlin',
|
||||||
|
'h · T3 — Verfahren mehrstufig',
|
||||||
|
'Frust · T2 — Bezirk × Senat × Beteiligung',
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
static final _miLoG17 = Evaluation(
|
static final _miLoG17 = Evaluation(
|
||||||
|
|
@ -428,5 +454,12 @@ class Fixtures {
|
||||||
'dokumentierte den initial-Erfüllungsaufwand; aktuelle Zahlen '
|
'dokumentierte den initial-Erfüllungsaufwand; aktuelle Zahlen '
|
||||||
'aus ZDH Bürokratiekosten-Handwerk. Bürokratieentlastungs-'
|
'aus ZDH Bürokratiekosten-Handwerk. Bürokratieentlastungs-'
|
||||||
'gesetz IV adressierte den § 17 — Reform-Bewegung ist im Lauf.',
|
'gesetz IV adressierte den § 17 — Reform-Bewegung ist im Lauf.',
|
||||||
|
componentSummary: const [
|
||||||
|
'P · T1 — DESTATIS MiLoG-pflichtig',
|
||||||
|
'F · T1 — arbeitstäglich',
|
||||||
|
'T · T1 — DESTATIS Tariflohn',
|
||||||
|
'h · T1 — NKR-Stellungnahme 2014',
|
||||||
|
'Reform · BEG IV in Lauf',
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ class Evaluation {
|
||||||
required this.sources,
|
required this.sources,
|
||||||
required this.auditEventId,
|
required this.auditEventId,
|
||||||
this.notes,
|
this.notes,
|
||||||
|
this.componentSummary = const [],
|
||||||
});
|
});
|
||||||
|
|
||||||
final Norm norm;
|
final Norm norm;
|
||||||
|
|
@ -172,4 +173,10 @@ class Evaluation {
|
||||||
final String auditEventId;
|
final String auditEventId;
|
||||||
|
|
||||||
final String? notes;
|
final String? notes;
|
||||||
|
|
||||||
|
/// Compact lines for at-a-glance reading on list views.
|
||||||
|
/// One line per SKM-Komponente (P / F / T / h) plus optional
|
||||||
|
/// extras — each carries its tier-tag inline. Empty list ⇒
|
||||||
|
/// fall back to the notes field for the list view.
|
||||||
|
final List<String> componentSummary;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,31 +107,42 @@ class _NormRow extends StatelessWidget {
|
||||||
color: ReclaimColors.mute,
|
color: ReclaimColors.mute,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: ReclaimSpace.sm),
|
||||||
|
TierBadge(tier: evaluation.tierLowest),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: ReclaimSpace.lg),
|
const SizedBox(width: ReclaimSpace.lg),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _MetricColumn(
|
flex: 2,
|
||||||
label: 'Schaden / Jahr',
|
child: Column(
|
||||||
value: _eur(evaluation.skmEurPerYear),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_MetricColumn(
|
||||||
|
label: 'Schaden / Jahr',
|
||||||
|
value: _eur(evaluation.skmEurPerYear),
|
||||||
|
),
|
||||||
|
const SizedBox(height: ReclaimSpace.sm),
|
||||||
|
_MetricColumn(
|
||||||
|
label: 'Nutzen',
|
||||||
|
value:
|
||||||
|
'${evaluation.benefitScore.toStringAsFixed(1)} / 5',
|
||||||
|
),
|
||||||
|
const SizedBox(height: ReclaimSpace.sm),
|
||||||
|
_MetricColumn(
|
||||||
|
label: 'Betroffene',
|
||||||
|
value: _kmu(evaluation.affectedCount),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(width: ReclaimSpace.lg),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _MetricColumn(
|
flex: 3,
|
||||||
label: 'Nutzen',
|
child: _ComponentSummary(
|
||||||
value:
|
summary: evaluation.componentSummary,
|
||||||
'${evaluation.benefitScore.toStringAsFixed(1)} / 5',
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
|
||||||
child: _MetricColumn(
|
|
||||||
label: 'Betroffene',
|
|
||||||
value: _kmu(evaluation.affectedCount),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: ReclaimSpace.md),
|
|
||||||
TierBadge(tier: evaluation.tierLowest),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -152,6 +163,44 @@ class _NormRow extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _ComponentSummary extends StatelessWidget {
|
||||||
|
const _ComponentSummary({required this.summary});
|
||||||
|
|
||||||
|
final List<String> summary;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final t = Theme.of(context).textTheme;
|
||||||
|
if (summary.isEmpty) {
|
||||||
|
return Text(
|
||||||
|
'—',
|
||||||
|
style: t.labelSmall?.copyWith(color: ReclaimColors.mute),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Komponenten',
|
||||||
|
style: t.labelSmall?.copyWith(color: ReclaimColors.mute),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
for (final line in summary)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 2),
|
||||||
|
child: Text(
|
||||||
|
line,
|
||||||
|
style: t.bodyLarge?.copyWith(
|
||||||
|
height: 1.35,
|
||||||
|
fontSize: 12.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _MetricColumn extends StatelessWidget {
|
class _MetricColumn extends StatelessWidget {
|
||||||
const _MetricColumn({required this.label, required this.value});
|
const _MetricColumn({required this.label, required this.value});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue