"use client" import * as React from "react" import {useCallback, useEffect, useState} from "react" import {toast} from "sonner" import {HardDrive, RefreshCw, Trash2} from "lucide-react" import {Card, CardContent, CardDescription, CardHeader, CardTitle} from "@/components/ui/card" import {Button} from "@/components/ui/button" import {Skeleton} from "@/components/ui/skeleton" import {Label} from "@/components/ui/label" import {Input} from "@/components/ui/input" import {Switch} from "@/components/ui/switch" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog" import type {CacheStatus} from "@/lib/services/admin" import {AdminService} from "@/lib/services/admin" /** * 格式化字节大小 */ const formatBytes = (bytes: number) => { if (bytes === 0) return "0 Bytes" const k = 1024 const sizes = ["Bytes", "KB", "MB", "GB", "TB"] const i = Math.floor(Math.log(bytes) / Math.log(k)) return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i] } /** * 格式化数字,每3位加逗号 */ const formatNumber = (num: number | string) => { if (num === undefined || num === null) return "0" return num.toString().replace(/\B(?=(\d{3})+(?!\B))/g, ",") } interface CacheManagerProps { refreshTrigger: number } export function CacheManager({ refreshTrigger }: CacheManagerProps) { const [cacheStatus, setCacheStatus] = useState(null) const [loadingCache, setLoadingCache] = useState(true) const [savingConfig, setSavingConfig] = useState(false) const [clearingCache, setClearingCache] = useState(false) const [showClearConfirm, setShowClearConfirm] = useState(false) // 策略配置表单状态 const [maxSizeMB, setMaxSizeMB] = useState("100") const [ttlMinutes, setTtlMinutes] = useState("60") const [lruEnabled, setLruEnabled] = useState(true) // 获取磁盘缓存状态 const fetchCacheStatus = useCallback(async (isSilent = false) => { if (!isSilent) setLoadingCache(true) try { const data = await AdminService.getCacheStatus() setCacheStatus(data) setMaxSizeMB(data.max_size_mb.toString()) setTtlMinutes(data.ttl_minutes.toString()) setLruEnabled(data.lru_enabled) } catch (err) { toast.error("获取磁盘缓存状态失败", { description: err instanceof Error ? err.message : "未知错误", }) } finally { setLoadingCache(false) } }, []) // 保存配置 const handleSaveConfig = async (e: React.FormEvent) => { e.preventDefault() const size = parseInt(maxSizeMB, 10) const ttl = parseInt(ttlMinutes, 10) if (isNaN(size) || size < 1) { toast.error("保存失败", { description: "最大容量限制必须是大于等于 1 的整数" }) return } if (isNaN(ttl) || ttl < 0) { toast.error("保存失败", { description: "默认过期时间必须是大于等于 0 的整数" }) return } setSavingConfig(true) try { await AdminService.updateCacheConfig({ max_size_mb: size, ttl_minutes: ttl, lru_enabled: lruEnabled, }) toast.success("保存成功", { description: "磁盘缓存策略已热更新" }) await fetchCacheStatus(true) } catch (err) { toast.error("保存配置失败", { description: err instanceof Error ? err.message : "未知错误", }) } finally { setSavingConfig(false) } } // 清空磁盘缓存数据 const handleClearCache = async () => { setClearingCache(true) try { await AdminService.clearCache() toast.success("清空成功", { description: "缓存数据已全部清除" }) setShowClearConfirm(false) await fetchCacheStatus(true) } catch (err) { toast.error("清空缓存失败", { description: err instanceof Error ? err.message : "未知错误", }) } finally { setClearingCache(false) } } // 初始化拉取 useEffect(() => { fetchCacheStatus() }, [fetchCacheStatus]) // 当外部刷新触发器改变时自动刷新 useEffect(() => { fetchCacheStatus(true) }, [refreshTrigger, fetchCacheStatus]) return (
缓存管理
管理和监控系统级磁盘缓存的资源占用、生命周期及淘汰策略
{loadingCache && !cacheStatus ? (
) : cacheStatus ? (
{/* 左边:状态区 (2/5 cols) */}

运行状态

{/* 已占空间 */}

已用空间

{formatBytes(cacheStatus.total_size)}

{/* Key数量 */}

缓存键数量

{formatNumber(cacheStatus.keys_count)} 个文件

{/* 存储路径 */}

缓存基准目录

{cacheStatus.base_path}
{/* 右边:配置区 (3/5 cols) */}

策略配置

setMaxSizeMB(e.target.value)} className="h-8 text-xs bg-background/50 border-border/40" placeholder="例如 100" required />

当总大小超出该值时,自动触发淘汰算法

setTtlMinutes(e.target.value)} className="h-8 text-xs bg-background/50 border-border/40" placeholder="例如 60,0 表示永不过期" required />

缓存项的最长存活时间,超期后将失效被清理

在到达最大容量限制时,自动移除最久未被访问的缓存项。关闭该功能仅清理过期项。
) : (
未加载到缓存状态信息
)}
{/* 清除缓存确认对话框 */} 确认清空所有缓存? 该操作将彻底清空磁盘目录下的全部缓存文件(包含临时解压、处理后的图片及各种块文件),重置键数量统计为 0。此操作不可撤销,且可能导致用户拉取资源时出现一过性的响应变慢。
) }