Refine admin panel workflows
This commit is contained in:
@@ -12,11 +12,9 @@ const riskSaving = ref<number | null>(null)
|
||||
const adminMessage = ref('')
|
||||
const adminError = ref('')
|
||||
const riskFilter = ref('')
|
||||
const auditFilter = ref('')
|
||||
const severityFilter = ref<'all' | 'high' | 'medium' | 'low'>('all')
|
||||
|
||||
const riskFlags = computed(() => store.admin.riskFlags)
|
||||
const auditEntries = computed(() => store.admin.auditEntries)
|
||||
const filteredRiskFlags = computed(() => {
|
||||
const query = riskFilter.value.trim().toLowerCase()
|
||||
return riskFlags.value.filter((flag) =>
|
||||
@@ -27,16 +25,6 @@ const filteredRiskFlags = computed(() => {
|
||||
.includes(query)),
|
||||
)
|
||||
})
|
||||
const filteredAuditEntries = computed(() => {
|
||||
const query = auditFilter.value.trim().toLowerCase()
|
||||
if (!query) return auditEntries.value
|
||||
return auditEntries.value.filter((entry) =>
|
||||
[entry.summary, entry.adminTwitchUserId, entry.actionType, entry.entityType, entry.entityId]
|
||||
.join(' ')
|
||||
.toLowerCase()
|
||||
.includes(query),
|
||||
)
|
||||
})
|
||||
const riskStats = computed(() => [
|
||||
{ label: 'Offen', value: riskFlags.value.length },
|
||||
{ label: 'High', value: riskFlags.value.filter((flag) => flag.severity.toLowerCase() === 'high').length },
|
||||
@@ -68,13 +56,13 @@ async function resolveRiskFlag(riskFlagId: number, status = 'resolved') {
|
||||
<template>
|
||||
<div class="space-y-6">
|
||||
<AdminPageHeader
|
||||
eyebrow="Risiko & Audit"
|
||||
title="Auffällige Muster und Admin-Aktionen verfolgen"
|
||||
description="Dieser Bereich trennt operative Risiko-Sichtung von der Nachvollziehbarkeit. So findest du sowohl offene Flags als auch bereits ausgeführte Eingriffe deutlich schneller."
|
||||
eyebrow="Risiko"
|
||||
title="Auffällige Muster entscheiden"
|
||||
description="Dieser Bereich ist nur für operative Risiko-Sichtung zuständig: Voting-, Login- und Einreichungsmuster prüfen, verwerfen oder erledigt markieren. Audit-Logs liegen separat im Team-Audit."
|
||||
:icon="ShieldAlert"
|
||||
/>
|
||||
|
||||
<div class="grid gap-6 xl:grid-cols-[0.95fr_1.05fr]">
|
||||
<div class="grid gap-6 xl:grid-cols-[0.82fr_1.18fr]">
|
||||
<Card class="p-7">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div>
|
||||
@@ -167,48 +155,21 @@ async function resolveRiskFlag(riskFlagId: number, status = 'resolved') {
|
||||
</Card>
|
||||
|
||||
<Card class="p-7">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 class="font-[Cormorant_Garamond] text-4xl text-violet-800">Audit-Protokoll</h2>
|
||||
<p class="mt-2 text-sm text-slate-500">Nachvollziehbare Admin-Aktionen für Kategorie-, Kandidaten- und Review-Änderungen.</p>
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-violet-500">Review-Protokoll</p>
|
||||
<h2 class="mt-2 font-[Cormorant_Garamond] text-4xl text-violet-800">Risk Playbook</h2>
|
||||
<div class="mt-6 space-y-3">
|
||||
<div class="rounded-[22px] border border-violet-100 bg-white/90 p-4">
|
||||
<p class="font-semibold text-slate-900">1. Quelle prüfen</p>
|
||||
<p class="mt-1 text-sm leading-6 text-slate-500">Vote-Flags vor Ergebnisfreigabe priorisieren, Clip-Flags vor Public-Einbindung, Login-Flags bei wiederholten IP-Mustern.</p>
|
||||
</div>
|
||||
<span class="text-sm uppercase tracking-[0.2em] text-slate-500">
|
||||
{{ filteredAuditEntries.length }} / {{ auditEntries.length }} Einträge
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<input
|
||||
v-model="auditFilter"
|
||||
type="text"
|
||||
class="w-full rounded-2xl border border-violet-200 px-4 py-3"
|
||||
placeholder="Audit-Einträge nach Aktion, Admin oder Objekt filtern"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 space-y-4">
|
||||
<div
|
||||
v-for="entry in filteredAuditEntries"
|
||||
:key="entry.id"
|
||||
class="rounded-[26px] border border-violet-100 bg-violet-50/60 px-5 py-5"
|
||||
>
|
||||
<div class="flex flex-wrap items-start justify-between gap-4">
|
||||
<div>
|
||||
<p class="font-semibold text-slate-800">{{ entry.summary }}</p>
|
||||
<p class="mt-1 text-sm text-slate-500">
|
||||
{{ entry.adminTwitchUserId }} · {{ entry.actionType }} · {{ entry.entityType }} {{ entry.entityId }}
|
||||
</p>
|
||||
</div>
|
||||
<p class="text-sm text-slate-500">{{ new Date(entry.createdAt).toLocaleString('de-DE') }}</p>
|
||||
</div>
|
||||
<div class="rounded-[22px] border border-violet-100 bg-white/90 p-4">
|
||||
<p class="font-semibold text-slate-900">2. Entscheidung dokumentieren</p>
|
||||
<p class="mt-1 text-sm leading-6 text-slate-500">„Erledigt“ bedeutet geprüft und relevant; „Verwerfen“ bedeutet false positive oder kein Award-Risiko.</p>
|
||||
</div>
|
||||
<div class="rounded-[22px] border border-violet-100 bg-white/90 p-4">
|
||||
<p class="font-semibold text-slate-900">3. Audit separat lesen</p>
|
||||
<p class="mt-1 text-sm leading-6 text-slate-500">Admin-Aktionen findest du im Team-Audit, damit Risikoentscheidungen nicht mit normalen Bearbeitungen vermischt werden.</p>
|
||||
</div>
|
||||
|
||||
<p v-if="auditEntries.length === 0" class="rounded-[26px] border border-dashed border-violet-100 px-5 py-6 text-sm text-slate-500">
|
||||
Noch keine Audit-Einträge vorhanden.
|
||||
</p>
|
||||
<p v-else-if="filteredAuditEntries.length === 0" class="rounded-[26px] border border-dashed border-violet-100 px-5 py-6 text-sm text-slate-500">
|
||||
Keine Audit-Einträge passen zum aktuellen Filter.
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user