import { useState, useEffect } from 'react'; import { HardDrive, Lock, Unlock, Activity, Clock, FileText, RefreshCw } from 'lucide-react'; import { api } from '../lib/api'; import type { FileLock, Heartbeat, AgentResourceStatus } from '../types'; export function ResourcesPage() { const [locks, setLocks] = useState([]); const [heartbeats, setHeartbeats] = useState>({}); const [statuses, setStatuses] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [activeTab, setActiveTab] = useState<'locks' | 'heartbeats' | 'status'>('locks'); const loadData = async () => { try { setLoading(true); const [locksRes, heartbeatsRes, statusRes] = await Promise.all([ api.lock.list().catch(() => ({ locks: [] })), api.heartbeat.list().catch(() => ({ heartbeats: {} })), api.resource.getAllStatus().catch(() => ({ agents: [] })), ]); setLocks(locksRes.locks); setHeartbeats(heartbeatsRes.heartbeats); setStatuses(statusRes.agents); setError(null); } catch (err) { setError(err instanceof Error ? err.message : '加载失败'); } finally { setLoading(false); } }; useEffect(() => { loadData(); const interval = setInterval(loadData, 5000); // 5秒刷新一次 return () => clearInterval(interval); }, []); const handleReleaseLock = async (filePath: string, agentId: string) => { if (!confirm(`确定要释放 ${filePath} 的锁吗?`)) return; try { await api.lock.release(filePath, agentId); loadData(); } catch (err) { alert('释放失败: ' + (err instanceof Error ? err.message : '未知错误')); } }; const getStatusColor = (status: string) => { switch (status) { case 'working': return '#00ff9d'; case 'idle': return '#00f0ff'; case 'waiting': return '#ff9500'; case 'error': return '#ff006e'; default: return '#666'; } }; return (
{/* Header */}

资源监控

监控文件锁、Agent 心跳和系统状态

{loading && ( 加载中... )}
{error && (
连接后端失败: {error}
)} {/* Tabs */}
{[ { id: 'locks', label: '文件锁', icon: Lock, count: locks.length }, { id: 'heartbeats', label: '心跳状态', icon: Activity, count: Object.keys(heartbeats).length }, { id: 'status', label: 'Agent 状态', icon: HardDrive, count: statuses.length }, ].map((tab) => ( ))}
{/* Content */} {activeTab === 'locks' && (
{locks.map((lock, index) => ( ))}
文件路径 锁定者 锁定时间 操作
{lock.file_path}
{lock.agent_name} ({lock.agent_id})
{lock.elapsed_display}
{locks.length === 0 && (

暂无文件锁

)}
)} {activeTab === 'heartbeats' && (
{Object.entries(heartbeats).map(([agentId, hb]) => (
{agentId} {hb.is_timeout ? ( 超时 ) : ( 正常 )}
状态 {hb.status}
当前任务 {hb.current_task || '-'}
进度 {hb.progress}%
运行时间 {hb.elapsed_display}
))} {Object.keys(heartbeats).length === 0 && (

暂无心跳数据

)}
)} {activeTab === 'status' && (
{statuses.map((status) => (

{status.info.name}

{status.agent_id}

{status.heartbeat.status}

角色

{status.info.role}

模型

{status.info.model}

当前任务

{status.state.task || '-'}

{status.locks.length > 0 && (

文件锁 ({status.locks.length})

{status.locks.map((lock, i) => (
{lock.file} ({lock.elapsed})
))}
)}
))} {statuses.length === 0 && (

暂无 Agent 状态数据

)}
)}
); }