import { useEffect, useState } from 'react' import { Database, HardDrive, PieChart } from 'lucide-react' import { storageAPI, type StorageBreakdown } from '../api/storage' function fmtBytes(n: number): string { if (!n) return '0 B' const u = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'] let v = n let i = 0 while (v >= 1024 && i < u.length - 1) { v /= 1024 i++ } return `${v.toFixed(2)} ${u[i]}` } function fmtHours(seconds: number): string { if (!seconds) return '—' const h = Math.floor(seconds / 3600) return `${h.toLocaleString()} h` } // StoragePage shows disk usage broken down by library and by container. export function StoragePage() { const [data, setData] = useState(null) const [loading, setLoading] = useState(true) useEffect(() => { storageAPI .breakdown() .then(setData) .finally(() => setLoading(false)) }, []) if (loading) return

加载中…

if (!data) return

无法获取存储数据

const totalBytes = data.total_bytes || 1 return (

存储

按媒体库和容器格式统计的磁盘占用,数据来自数据库快照(无须实时扫描磁盘)。

} label="总占用" value={fmtBytes(data.total_bytes)} /> } label="媒体库" value={`${data.by_library.length}`} /> } label="累计时长" value={fmtHours(data.total_seconds)} />

按媒体库

{data.by_library.map((l) => { const pct = (l.total_bytes / totalBytes) * 100 return ( ) })}
名称 类型 媒体数 占用 占比
{l.name} {l.type} {l.media_count} {fmtBytes(l.total_bytes)}
{pct.toFixed(1)}%

按容器格式

{data.by_container.map((c) => (

{c.container}

{c.count} 项

{fmtBytes(c.bytes)}

))}
) } function Tile({ icon, label, value, }: { icon: React.ReactNode label: string value: string }) { return (
{icon}

{label}

{value}

) }