checkflo/app/src/routes/admin/dashboard/+page.svelte

155 lines
4.5 KiB
Svelte

<script lang="ts">
import { pb } from '$lib/pb';
import { onMount } from 'svelte';
const STATUS_LABEL: Record<string, string> = {
ok: 'OK', abweichung: 'Abweichung', kritisch: 'Kritisch'
};
const STATUS_COLOR: Record<string, string> = {
ok: '#16a34a', abweichung: '#ea580c', kritisch: '#dc2626'
};
let logs = $state<any[]>([]);
let stats = $state({ total: 0, ok: 0, abweichung: 0, kritisch: 0 });
let loading = $state(true);
onMount(async () => {
try {
const today = new Date();
today.setHours(0, 0, 0, 0);
// User-Record explizit laden damit tenant-Relation sicher gesetzt ist
const user = await pb.collection('users').getOne(pb.authStore.record!.id);
const tenantId = user.tenant;
const dateStr = today.toISOString().slice(0, 19).replace('T', ' ');
const result = await pb.collection('check_logs').getList(1, 50, {
sort: '-created'
});
logs = result.items;
stats.total = result.totalItems;
stats.ok = logs.filter(l => l.status === 'ok').length;
stats.abweichung = logs.filter(l => l.status === 'abweichung').length;
stats.kritisch = logs.filter(l => l.status === 'kritisch').length;
} catch {
// Keine Einträge oder Zugriffsrechte noch nicht gesetzt
} finally {
loading = false;
}
});
function formatTime(iso: string) {
return new Date(iso).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' });
}
</script>
<svelte:head><title>Dashboard — checkflo</title></svelte:head>
<div class="page">
<h1>Dashboard</h1>
<p class="date">{new Date().toLocaleDateString('de-DE', { weekday: 'long', day: 'numeric', month: 'long' })}</p>
<div class="stats">
<div class="stat">
<span class="stat-num">{stats.total}</span>
<span class="stat-label">Checks heute</span>
</div>
<div class="stat stat-ok">
<span class="stat-num">{stats.ok}</span>
<span class="stat-label">In Ordnung</span>
</div>
<div class="stat stat-warn">
<span class="stat-num">{stats.abweichung}</span>
<span class="stat-label">Abweichungen</span>
</div>
<div class="stat stat-crit">
<span class="stat-num">{stats.kritisch}</span>
<span class="stat-label">Kritisch</span>
</div>
</div>
<h2>Heutige Einträge</h2>
{#if loading}
<p class="hint">Lädt…</p>
{:else if logs.length === 0}
<p class="hint">Noch keine Einträge heute.</p>
{:else}
<div class="log-list">
{#each logs as log}
<div class="log-item">
<div class="log-status" style="background: {STATUS_COLOR[log.status]}20; color: {STATUS_COLOR[log.status]}">
{STATUS_LABEL[log.status]}
</div>
<div class="log-info">
<span class="log-station">{log.expand?.station?.name ?? '—'}</span>
{#if log.temperature}
<span class="log-temp">{log.temperature} °C</span>
{/if}
</div>
<div class="log-meta">
<span>{log.checked_by}</span>
<span class="log-time">{formatTime(log.created)}</span>
</div>
</div>
{/each}
</div>
{/if}
</div>
<style>
.page { max-width: 800px; }
h1 { font-size: 1.6rem; font-weight: 800; color: #0B1023; }
h2 { font-size: 1.1rem; font-weight: 700; color: #0B1023; margin: 2rem 0 1rem; }
.date { color: #888; margin-top: 0.25rem; margin-bottom: 2rem; }
.stats {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
margin-bottom: 2rem;
}
.stat {
background: #fff;
border-radius: 12px;
padding: 1.25rem;
box-shadow: 0 1px 4px rgba(0,0,0,0.06);
border-left: 3px solid #e2e8f0;
}
.stat-ok { border-color: #16a34a; }
.stat-warn { border-color: #ea580c; }
.stat-crit { border-color: #dc2626; }
.stat-num { display: block; font-size: 2rem; font-weight: 800; color: #0B1023; line-height: 1; }
.stat-label { font-size: 0.8rem; color: #888; margin-top: 0.25rem; display: block; }
.hint { color: #aaa; font-size: 0.95rem; }
.log-list { display: flex; flex-direction: column; gap: 0.6rem; }
.log-item {
background: #fff;
border-radius: 10px;
padding: 0.9rem 1.1rem;
display: flex;
align-items: center;
gap: 1rem;
box-shadow: 0 1px 4px rgba(0,0,0,0.05);
}
.log-status {
padding: 0.25rem 0.7rem;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 700;
white-space: nowrap;
}
.log-info { flex: 1; display: flex; flex-direction: column; gap: 0.1rem; }
.log-station { font-weight: 600; font-size: 0.95rem; }
.log-temp { font-size: 0.85rem; color: #555; }
.log-meta { display: flex; flex-direction: column; align-items: flex-end; gap: 0.1rem; font-size: 0.85rem; color: #888; }
.log-time { font-size: 0.8rem; }
@media (max-width: 600px) {
.stats { grid-template-columns: repeat(2, 1fr); }
}
</style>