fix: anpassungen lt. Besprechung Frontend/ Powerpoint 10-11-2025

This commit is contained in:
2025-11-10 21:35:52 +01:00
parent 08faf9fb86
commit 64b8ff48da
2 changed files with 133 additions and 121 deletions
+127 -115
View File
@@ -26,103 +26,115 @@
$formatCurrency=static fn (float $value): string=> number_format($value, 2, ',', '.') . ' €';
$formatCurrencyCompact = static function (float $value): string {
if ($value >= 1000000) {
return number_format($value / 1000000, 0, ',', '.') . ' Mio. €';
}
return number_format($value, 2, ',', '.') . ' €';
if ($value >= 1000000) {
return number_format($value / 1000000, 0, ',', '.') . ' Mio. €';
}
return number_format($value, 2, ',', '.') . ' €';
};
$formatNumber = static fn ($value): string => number_format($value, 0, ',', '.');
$riskSegments = collect([
'Kritisch (≥80)' => $transactions->filter(fn ($trx) => $trx->risk_score >= 80),
'Hoch (65-79)' => $transactions->filter(fn ($trx) => $trx->risk_score >= 65 && $trx->risk_score < 80),
'Beobachtung (40-64)' => $transactions->filter(fn ($trx) => $trx->risk_score >= 40 && $trx->risk_score < 65),
])->map(fn ($group, $label) => [
'label' => $label,
'count' => $group->count(),
'volume' => $group->sum('amount'),
]);
'Kritisch (≥80)' => [
'transactions' => $transactions->filter(fn ($trx) => $trx->risk_score >= 80),
'status' => \App\Models\Transaction::STATUS_TRUE_POSITIVE,
],
'Hoch (65-79)' => [
'transactions' => $transactions->filter(fn ($trx) => $trx->risk_score >= 65 && $trx->risk_score < 80),
'status' => \App\Models\Transaction::STATUS_FALSE_POSITIVE,
],
'Gering (40-64)' => [
'transactions' => $transactions->filter(fn ($trx) => $trx->risk_score >= 40 && $trx->risk_score < 65),
'status' => \App\Models\Transaction::STATUS_CLEARED,
],
])->map(fn ($data, $label) => [
'label' => $label,
'count' => $data['transactions']->count(),
'volume' => $data['transactions']->sum('amount'),
'status' => $data['status'],
]);
$topCompanies = $activeAlerts
->groupBy('company_id')
->map(fn ($group) => [
'company' => optional($group->first()->company)->legal_name ?? optional($group->first()->company)->name ?? 'Unbekanntes Unternehmen',
'alerts' => $group->count(),
'volume' => $group->sum('amount'),
'avg_risk' => (int) round($group->avg('risk_score')),
])
->sortByDesc('alerts')
->take(5);
@endphp
$topCompanies = $activeAlerts
->groupBy('company_id')
->map(fn ($group) => [
'company' => optional($group->first()->company)->legal_name ?? optional($group->first()->company)->name ?? 'Unbekanntes Unternehmen',
'alerts' => $group->count(),
'volume' => $group->sum('amount'),
'avg_risk' => (int) round($group->avg('risk_score')),
])
->sortByDesc('alerts')
->take(5);
@endphp
<div class="flex flex-col gap-8">
<section class="relative overflow-hidden rounded-3xl border border-slate-200/70 bg-gradient-to-br from-slate-950 via-indigo-950/90 to-slate-900 p-8 text-white shadow-[0_40px_120px_-60px_rgba(15,23,42,0.75)] dark:border-slate-800/60">
<span class="pointer-events-none absolute -left-24 top-1/2 h-64 w-64 -translate-y-1/2 rounded-full bg-emerald-500/20 blur-3xl"></span>
<span class="pointer-events-none absolute -right-16 top-0 h-48 w-48 rounded-full bg-sky-500/20 blur-3xl"></span>
<div class="relative flex flex-col gap-6 lg:flex-row lg:items-end lg:justify-between">
<div class="max-w-2xl space-y-3">
<p class="inline-flex items-center gap-2 rounded-full border border-white/20 bg-white/10 px-3 py-1 text-xs font-semibold uppercase tracking-[0.2em] text-slate-200">
Anti Financial Crime - Dashboard
</p>
<h1 class="text-3xl font-semibold tracking-tight sm:text-4xl">Qualifizierung der Verdachtsfälle juristischer Personen</h1>
<p class="text-sm leading-relaxed text-slate-300 sm:text-base">
Übersicht für AML-Verantwortliche für die Kapazitätssteuerung
</p>
<div class="flex flex-col gap-8">
<section class="relative overflow-hidden rounded-3xl border border-slate-200/70 bg-gradient-to-br from-slate-950 via-indigo-950/90 to-slate-900 p-8 text-white shadow-[0_40px_120px_-60px_rgba(15,23,42,0.75)] dark:border-slate-800/60">
<span class="pointer-events-none absolute -left-24 top-1/2 h-64 w-64 -translate-y-1/2 rounded-full bg-emerald-500/20 blur-3xl"></span>
<span class="pointer-events-none absolute -right-16 top-0 h-48 w-48 rounded-full bg-sky-500/20 blur-3xl"></span>
<div class="relative flex flex-col gap-6 lg:flex-row lg:items-end lg:justify-between">
<div class="max-w-2xl space-y-3">
<p class="inline-flex items-center gap-2 rounded-full border border-white/20 bg-white/10 px-3 py-1 text-xs font-semibold uppercase tracking-[0.2em] text-slate-200">
Anti Financial Crime - Dashboard
</p>
<h1 class="text-3xl font-semibold tracking-tight sm:text-4xl">Qualifizierung der Verdachtsfälle juristischer Personen</h1>
<p class="text-sm leading-relaxed text-slate-300 sm:text-base">
Übersicht für AML-Verantwortliche für die Kapazitätssteuerung
</p>
</div>
<div class="grid w-full grid-cols-2 gap-4 text-center sm:grid-cols-4 lg:w-auto">
<div class="rounded-2xl border border-white/10 bg-white/10 p-4 backdrop-blur-sm shadow-lg shadow-slate-950/30">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-200">Aktive Analyst:innen</p>
<p class="mt-2 text-2xl font-semibold text-white">{{ $formatNumber($activeAnalysts) }}</p>
</div>
<div class="grid w-full grid-cols-2 gap-4 text-center sm:grid-cols-4 lg:w-auto">
<div class="rounded-2xl border border-white/10 bg-white/10 p-4 backdrop-blur-sm shadow-lg shadow-slate-950/30">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-200">Aktive Analyst:innen</p>
<p class="mt-2 text-2xl font-semibold text-white">{{ $formatNumber($activeAnalysts) }}</p>
</div>
<div class="rounded-2xl border border-emerald-400/30 bg-emerald-500/20 p-4 backdrop-blur-sm shadow-lg shadow-emerald-900/30">
<p class="text-xs font-semibold uppercase tracking-wide text-emerald-50">Gesamtvolumen</p>
<p class="mt-2 text-2xl font-semibold text-emerald-100">{{ $formatCurrencyCompact($totalVolume) }}</p>
</div>
<div class="rounded-2xl border border-indigo-400/30 bg-indigo-500/20 p-4 backdrop-blur-sm shadow-lg shadow-indigo-900/30">
<p class="text-xs font-semibold uppercase tracking-wide text-indigo-50">Alerts pro Analyst:in</p>
<p class="mt-2 text-2xl font-semibold text-indigo-100">{{ $formatNumber($averagePerAnalyst) }}</p>
</div>
<div class="rounded-2xl border border-rose-400/30 bg-rose-500/20 p-4 backdrop-blur-sm shadow-lg shadow-rose-900/30">
<p class="text-xs font-semibold uppercase tracking-wide text-rose-50">Prior 1 Fälle</p>
<p class="mt-2 text-2xl font-semibold text-rose-100">{{ $formatNumber($highRiskAlerts->count()) }}</p>
</div>
<div class="rounded-2xl border border-emerald-400/30 bg-emerald-500/20 p-4 backdrop-blur-sm shadow-lg shadow-emerald-900/30">
<p class="text-xs font-semibold uppercase tracking-wide text-emerald-50">Gesamtvolumen</p>
<p class="mt-2 text-2xl font-semibold text-emerald-100">{{ $formatCurrencyCompact($totalVolume) }}</p>
</div>
<div class="rounded-2xl border border-indigo-400/30 bg-indigo-500/20 p-4 backdrop-blur-sm shadow-lg shadow-indigo-900/30">
<p class="text-xs font-semibold uppercase tracking-wide text-indigo-50">Alerts pro Analyst:in</p>
<p class="mt-2 text-2xl font-semibold text-indigo-100">{{ $formatNumber($averagePerAnalyst) }}</p>
</div>
<div class="rounded-2xl border border-rose-400/30 bg-rose-500/20 p-4 backdrop-blur-sm shadow-lg shadow-rose-900/30">
<p class="text-xs font-semibold uppercase tracking-wide text-rose-50">Prior 1 Fälle</p>
<p class="mt-2 text-2xl font-semibold text-rose-100">{{ $formatNumber($highRiskAlerts->count()) }}</p>
</div>
</div>
</section>
</div>
</section>
<section class="grid gap-6">
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<div class="flex flex-wrap items-end justify-between gap-4">
<div>
<h2 class="text-xl font-semibold text-zinc-900 dark:text-zinc-100">Risikolassen und Automatisierungsscore</h2>
</div>
<div class="inline-flex items-center gap-2 rounded-full border border-indigo-200/70 bg-indigo-500/10 px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-indigo-700 dark:border-indigo-500/30 dark:text-indigo-200">
Automationspräzision {{ $precisionRate }}%
</div>
<section class="grid gap-6">
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<div class="flex flex-wrap items-end justify-between gap-4">
<div>
<h2 class="text-xl font-semibold text-zinc-900 dark:text-zinc-100">Risikoklassen und Automatisierungsscore</h2>
</div>
<div class="mt-6 grid gap-3">
@foreach ($riskSegments as $segment)
<div class="flex items-center justify-between gap-4 rounded-2xl border border-zinc-200/70 bg-zinc-50/80 p-4 transition hover:-translate-y-0.5 hover:shadow-md dark:border-zinc-700/60 dark:bg-zinc-800/70">
<div class="flex items-center gap-3">
<span class="inline-flex h-10 w-10 items-center justify-center rounded-full bg-gradient-to-br from-indigo-500 to-emerald-500 text-sm font-semibold text-white">
{{ $loop->iteration }}
</span>
<div>
<p class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">{{ $segment['label'] }}</p>
<p class="text-xs text-zinc-500 dark:text-zinc-400">{{ $formatNumber($segment['count']) }} Beobachtungen</p>
</div>
</div>
<div class="text-right">
<p class="text-xs uppercase tracking-wide text-zinc-400">Volumen</p>
<p class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">{{ $formatCurrencyCompact($segment['volume']) }}</p>
</div>
</div>
@endforeach
<div class="inline-flex items-center gap-2 rounded-full border border-indigo-200/70 bg-indigo-500/10 px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-indigo-700 dark:border-indigo-500/30 dark:text-indigo-200">
Automatisierungsscore {{ $precisionRate }}%
</div>
</div>
<!-- <div class="flex flex-col gap-6">
<div class="mt-6 grid gap-3">
@foreach ($riskSegments as $segment)
<a
href="{{ route('transaction-review', ['status' => $segment['status']]) }}"
class="flex items-center justify-between gap-4 rounded-2xl border border-zinc-200/70 bg-zinc-50/80 p-4 transition hover:-translate-y-0.5 hover:shadow-md hover:border-indigo-300/70 hover:bg-indigo-50/50 dark:border-zinc-700/60 dark:bg-zinc-800/70 dark:hover:border-indigo-500/50 dark:hover:bg-indigo-900/20 cursor-pointer group">
<div class="flex items-center gap-3">
<span class="inline-flex h-10 w-10 items-center justify-center rounded-full bg-gradient-to-br from-indigo-500 to-emerald-500 text-sm font-semibold text-white group-hover:scale-110 transition-transform">
{{ $loop->iteration }}
</span>
<div>
<p class="text-sm font-semibold text-zinc-900 dark:text-zinc-100 group-hover:text-indigo-700 dark:group-hover:text-indigo-300">{{ $segment['label'] }}</p>
<p class="text-xs text-zinc-500 dark:text-zinc-400">{{ $formatNumber($segment['count']) }} Beobachtungen</p>
</div>
</div>
<div class="text-right">
<p class="text-xs uppercase tracking-wide text-zinc-400">Volumen</p>
<p class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">{{ $formatCurrencyCompact($segment['volume']) }}</p>
</div>
</a>
@endforeach
</div>
</div>
<!-- <div class="flex flex-col gap-6">
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h2 class="text-base font-semibold text-zinc-900 dark:text-zinc-100">AI-Agent Telemetrie</h2>
<ul class="mt-4 space-y-4 text-sm text-zinc-600 dark:text-zinc-300">
@@ -150,7 +162,7 @@
</ul>
</div> -->
<!-- <div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<!-- <div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h2 class="text-base font-semibold text-zinc-900 dark:text-zinc-100">Top-Alarme nach Unternehmen</h2>
<ul class="mt-4 space-y-3 text-sm text-zinc-600 dark:text-zinc-300">
@forelse ($topCompanies as $company)
@@ -172,39 +184,39 @@
</ul>
</div>
</div> -->
</section>
</section>
<section class="grid gap-6 lg:grid-cols-3">
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h3 class="text-base font-semibold text-zinc-900 dark:text-zinc-100">Knowledge Graph Coverage</h3>
<p class="mt-2 text-sm text-zinc-500 dark:text-zinc-400">
Netzwerkanalyse verbindet Sanktionsdaten, Unternehmensregister und Zahlungsverhalten in Echtzeit.
</p>
<div class="mt-4 flex items-center justify-between rounded-2xl bg-zinc-50/80 p-4 text-sm dark:bg-zinc-800/70">
<span class="text-zinc-500 dark:text-zinc-400">Investigierte Entitäten</span>
<span class="font-semibold text-zinc-900 dark:text-zinc-100">{{ $formatNumber($transactions->pluck('company_id')->unique()->count()) }}</span>
</div>
<section class="grid gap-6 lg:grid-cols-3">
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h3 class="text-base font-semibold text-zinc-900 dark:text-zinc-100">Knowledge Graph Coverage</h3>
<p class="mt-2 text-sm text-zinc-500 dark:text-zinc-400">
Netzwerkanalyse verbindet Sanktionsdaten, Unternehmensregister und Zahlungsverhalten in Echtzeit.
</p>
<div class="mt-4 flex items-center justify-between rounded-2xl bg-zinc-50/80 p-4 text-sm dark:bg-zinc-800/70">
<span class="text-zinc-500 dark:text-zinc-400">Investigierte Entitäten</span>
<span class="font-semibold text-zinc-900 dark:text-zinc-100">{{ $formatNumber($transactions->pluck('company_id')->unique()->count()) }}</span>
</div>
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h3 class="text-base font-semibold text-zinc-900 dark:text-zinc-100">Sanctions Uplift</h3>
<p class="mt-2 text-sm text-zinc-500 dark:text-zinc-400">
Dynamische Listenaktualisierung und NLP-Medien-Screening liefern kontextstarke Treffer.
</p>
<div class="mt-4 flex items-center justify-between rounded-2xl bg-zinc-50/80 p-4 text-sm dark:bg-zinc-800/70">
<span class="text-zinc-500 dark:text-zinc-400">Neue Treffer letzte 24h</span>
<span class="font-semibold text-zinc-900 dark:text-zinc-100">{{ $formatNumber(random_int(6, 14)) }}</span>
</div>
</div>
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h3 class="text-base font-semibold text-zinc-900 dark:text-zinc-100">Sanctions Uplift</h3>
<p class="mt-2 text-sm text-zinc-500 dark:text-zinc-400">
Dynamische Listenaktualisierung und NLP-Medien-Screening liefern kontextstarke Treffer.
</p>
<div class="mt-4 flex items-center justify-between rounded-2xl bg-zinc-50/80 p-4 text-sm dark:bg-zinc-800/70">
<span class="text-zinc-500 dark:text-zinc-400">Neue Treffer letzte 24h</span>
<span class="font-semibold text-zinc-900 dark:text-zinc-100">{{ $formatNumber(random_int(6, 14)) }}</span>
</div>
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h3 class="text-base font-semibold text-zinc-900 dark:text-zinc-100">Runbook Automation</h3>
<p class="mt-2 text-sm text-zinc-500 dark:text-zinc-400">
Intelligente Workflows orchestrieren Mensch und Maschine inklusive Quality Gates.
</p>
<div class="mt-4 flex items-center justify-between rounded-2xl bg-zinc-50/80 p-4 text-sm dark:bg-zinc-800/70">
<span class="text-zinc-500 dark:text-zinc-400">Durchgeführte Runbooks heute</span>
<span class="font-semibold text-zinc-900 dark:text-zinc-100">{{ $formatNumber(random_int(32, 48)) }}</span>
</div>
</div>
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h3 class="text-base font-semibold text-zinc-900 dark:text-zinc-100">Runbook Automation</h3>
<p class="mt-2 text-sm text-zinc-500 dark:text-zinc-400">
Intelligente Workflows orchestrieren Mensch und Maschine inklusive Quality Gates.
</p>
<div class="mt-4 flex items-center justify-between rounded-2xl bg-zinc-50/80 p-4 text-sm dark:bg-zinc-800/70">
<span class="text-zinc-500 dark:text-zinc-400">Durchgeführte Runbooks heute</span>
<span class="font-semibold text-zinc-900 dark:text-zinc-100">{{ $formatNumber(random_int(32, 48)) }}</span>
</div>
</section>
</div>
</div>
</section>
</div>
</x-layouts.app>
@@ -80,9 +80,9 @@ new #[Layout('components.layouts.app'), Title('Transaktionsprüfung')] class ext
{
return [
'all' => 'Alle Prüfaufträge',
Transaction::STATUS_TRUE_POSITIVE => 'Bestätigte Treffer',
Transaction::STATUS_FALSE_POSITIVE => 'Fehlalarme',
Transaction::STATUS_CLEARED => 'Freigegebene Vorgänge',
Transaction::STATUS_TRUE_POSITIVE => 'Kritisches Risiko',
Transaction::STATUS_FALSE_POSITIVE => 'Hohes Risiko',
Transaction::STATUS_CLEARED => 'Geringes Risiko',
];
}
@@ -261,17 +261,17 @@ Transaction::STATUS_CLEARED => [
<p class="mt-1 text-xs text-slate-300">Volumen: {{ $formatAmount($total['amount']) }}</p>
</div>
<div class="rounded-2xl border border-rose-400/40 bg-rose-500/15 p-4 text-center backdrop-blur-sm shadow-lg shadow-rose-900/40">
<p class="text-xs font-medium uppercase tracking-wide text-rose-50">Bestätigte Treffer</p>
<p class="text-xs font-medium uppercase tracking-wide text-rose-50">Kritisches Risiko</p>
<p class="text-2xl font-semibold text-rose-100">{{ $confirmed['count'] }}</p>
<p class="mt-1 text-xs text-rose-100/80">Volumen: {{ $formatAmount($confirmed['amount']) }}</p>
</div>
<div class="rounded-2xl border border-amber-400/40 bg-amber-400/15 p-4 text-center backdrop-blur-sm shadow-lg shadow-amber-900/30">
<p class="text-xs font-medium uppercase tracking-wide text-amber-50">Fehlalarme</p>
<p class="text-xs font-medium uppercase tracking-wide text-amber-50">Hohes Risiko</p>
<p class="text-2xl font-semibold text-amber-100">{{ $falseAlarm['count'] }}</p>
<p class="mt-1 text-xs text-amber-100/80">Volumen: {{ $formatAmount($falseAlarm['amount']) }}</p>
</div>
<div class="rounded-2xl border border-emerald-400/40 bg-emerald-400/15 p-4 text-center backdrop-blur-sm shadow-lg shadow-emerald-900/30">
<p class="text-xs font-medium uppercase tracking-wide text-emerald-50">Freigegeben</p>
<p class="text-xs font-medium uppercase tracking-wide text-emerald-50">Geringes Risiko</p>
<p class="text-2xl font-semibold text-emerald-100">{{ $cleared['count'] }}</p>
<p class="mt-1 text-xs text-emerald-100/80">Volumen: {{ $formatAmount($cleared['amount']) }}</p>
</div>