Files
bili-sync-ai/web/src/routes/logs/+page.svelte
2025-07-11 00:14:20 +08:00

83 lines
2.0 KiB
Svelte

<script lang="ts">
import api from '$lib/api';
import { setBreadcrumb } from '$lib/stores/breadcrumb';
import { onMount } from 'svelte';
import { Badge } from '$lib/components/ui/badge';
let unsubscribeLog: (() => void) | null = null;
let logs: Array<{ timestamp: string; level: string; message: string }> = [];
let shouldAutoScroll = true;
let main: HTMLElement | null = null;
function checkScrollPosition() {
if (main) {
const { scrollTop, scrollHeight, clientHeight } = main;
shouldAutoScroll = scrollTop + clientHeight >= scrollHeight - 5;
}
}
function scrollToBottom() {
if (shouldAutoScroll && main) {
main.scrollTop = main.scrollHeight;
}
}
onMount(() => {
setBreadcrumb([{ label: '日志' }]);
main = document.getElementById('main');
main?.addEventListener('scroll', checkScrollPosition);
unsubscribeLog = api.subscribeToLogs((data: string) => {
logs = [...logs.slice(-200), JSON.parse(data)];
setTimeout(scrollToBottom, 0);
});
return () => {
main?.removeEventListener('scroll', checkScrollPosition);
if (unsubscribeLog) {
unsubscribeLog();
unsubscribeLog = null;
}
};
});
function getLevelColor(level: string) {
switch (level) {
case 'ERROR':
return 'text-rose-600';
case 'WARN':
return 'text-yellow-600';
case 'INFO':
default:
return 'text-emerald-600';
}
}
</script>
<svelte:head>
<title>日志 - Bili Sync</title>
</svelte:head>
<div class="space-y-1">
{#each logs as log, index (index)}
<div
class="flex items-center gap-3 rounded-md p-1 font-mono text-xs {index % 2 === 0
? 'bg-muted/50'
: 'bg-background'}"
>
<span class="text-muted-foreground w-32 shrink-0">
{log.timestamp}
</span>
<Badge
class="w-16 shrink-0 justify-center {getLevelColor(log.level)} bg-primary/90 font-semibold"
>
{log.level}
</Badge>
<span class="flex-1 break-all">
{log.message}
</span>
</div>
{/each}
{#if logs.length === 0}
<div class="text-muted-foreground py-8 text-center">暂无日志记录</div>
{/if}
</div>