// 状态 let currentAgent = null; let currentSession = null; let currentMessage = null; let currentView = 'conversations'; // 'conversations' or 'sessions' let conversationsData = []; // 缓存对话汇总数据 // API 调用 async function fetchAPI(endpoint) { const response = await fetch(`/api${endpoint}`); if (!response.ok) { throw new Error(`API Error: ${response.status}`); } return response.json(); } // 格式化时间 function formatTime(isoString) { if (!isoString) return '-'; const date = new Date(isoString); return date.toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); } function formatFullTime(isoString) { if (!isoString) return '-'; const date = new Date(isoString); return date.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }); } // 格式化数字 function formatNumber(num) { if (!num) return '0'; if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M'; if (num >= 1000) return (num / 1000).toFixed(1) + 'K'; return num.toString(); } // 截断文本 function truncate(text, maxLen = 50) { if (!text) return ''; text = text.replace(/\n/g, ' ').trim(); if (text.length <= maxLen) return text; return text.substring(0, maxLen) + '...'; } // 加载智能体列表 async function loadAgents() { const container = document.getElementById('agents-list'); container.innerHTML = '
加载中...
'; try { const agents = await fetchAPI('/agents'); if (agents.length === 0) { container.innerHTML = '
没有找到智能体
'; return; } container.innerHTML = agents.map(agent => `
🤖 ${agent.name}
💬 ${agent.sessionCount} ${formatTime(agent.lastActive)}
`).join(''); } catch (error) { container.innerHTML = `
加载失败: ${error.message}
`; } } // 切换视图 function switchView(view) { currentView = view; document.querySelectorAll('.tab-btn').forEach(btn => { btn.classList.toggle('active', btn.dataset.view === view); }); document.querySelectorAll('.view-content').forEach(content => { content.classList.remove('active'); }); document.getElementById(`${view}-view`).classList.add('active'); } // 选择智能体 async function selectAgent(agentName) { currentAgent = agentName; currentSession = null; currentMessage = null; // 更新UI document.querySelectorAll('.agent-item').forEach(el => el.classList.remove('active')); event.target.closest('.agent-item')?.classList.add('active'); document.getElementById('agent-name-display').textContent = `🤖 ${agentName}`; document.getElementById('session-id-display').textContent = ''; document.getElementById('messages-list').innerHTML = '
请选择一个会话
'; document.getElementById('message-detail').innerHTML = '
请选择一条消息
'; // 同时加载对话汇总和会话列表 await Promise.all([ loadConversations(agentName), loadSessions(agentName) ]); } // 加载会话列表 async function loadSessions(agentName) { const container = document.getElementById('sessions-list'); container.innerHTML = '
加载中...
'; try { const sessions = await fetchAPI(`/agents/${agentName}/sessions`); if (sessions.length === 0) { container.innerHTML = '
没有找到会话
'; return; } container.innerHTML = sessions.map(session => `
${session.channel} ${session.status}
${session.model} ${formatTime(session.updatedAt)}
${truncate(session.target, 40)}
📊 ${formatNumber(session.totalTokens)} tokens (${formatNumber(session.inputTokens)} in / ${formatNumber(session.outputTokens)} out)
`).join(''); } catch (error) { container.innerHTML = `
加载失败: ${error.message}
`; } } // 选择会话 - 显示消息概览列表 async function selectSession(agentName, sessionId) { currentSession = sessionId; currentMessage = null; // 更新UI document.querySelectorAll('.session-item').forEach(el => el.classList.remove('active')); event.target.closest('.session-item')?.classList.add('active'); document.getElementById('session-id-display').textContent = `- ${sessionId.substring(0, 8)}...`; document.getElementById('message-detail').innerHTML = '
请选择一条消息查看详情
'; // 加载消息概览列表 await loadMessageSummaries(agentName, sessionId); } // 加载消息概览列表(不加载完整内容) async function loadMessageSummaries(agentName, sessionId) { const container = document.getElementById('messages-list'); container.innerHTML = '
加载中...
'; try { const messages = await fetchAPI(`/agents/${agentName}/sessions/${sessionId}/messages`); if (messages.length === 0) { container.innerHTML = '
没有找到消息
'; return; } container.innerHTML = messages.map((msg, index) => `
${msg.role === 'user' ? '👤' : '🤖'} ${msg.role} ${formatTime(msg.timestamp)}
${escapeHtml(msg.summary)}${msg.hasMoreContent ? '...' : ''}
${msg.hasMoreContent ? `📝 ${formatNumber(msg.contentLength)} 字符` : ''}
`).join(''); } catch (error) { container.innerHTML = `
加载失败: ${error.message}
`; } } // 选择消息 - 显示完整内容 async function selectMessage(agentName, sessionId, messageId) { currentMessage = messageId; // 更新UI document.querySelectorAll('.message-summary').forEach(el => el.classList.remove('active')); event.target.closest('.message-summary')?.classList.add('active'); // 加载完整消息内容 await loadMessageDetail(agentName, sessionId, messageId); } // 加载消息详情(完整内容) async function loadMessageDetail(agentName, sessionId, messageId) { const container = document.getElementById('message-detail'); container.innerHTML = '
加载中...
'; try { const msg = await fetchAPI(`/agents/${agentName}/sessions/${sessionId}/messages/${messageId}`); container.innerHTML = `
${msg.role === 'user' ? '👤' : '🤖'} ${msg.role} ${formatFullTime(msg.timestamp)}
${escapeHtml(msg.content)}
`; } catch (error) { container.innerHTML = `
加载失败: ${error.message}
`; } } // HTML 转义 function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // 键盘事件 document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { // 可以添加关闭操作 } }); // 加载对话汇总 async function loadConversations(agentName) { const container = document.getElementById('conversations-list'); container.innerHTML = '
加载中...
'; try { const conversations = await fetchAPI(`/agents/${agentName}/conversations`); conversationsData = conversations; if (conversations.length === 0) { container.innerHTML = '
没有找到对话
'; return; } container.innerHTML = conversations.map((conv, index) => `
💬 对话 ${index + 1} ${conv.sessionCount} 个会话
📨 消息: ${conv.totalMessages} 📊 Token: ${formatNumber(conv.totalTokens)} 🔄 压缩: ${conv.compactionCount} ⏱️ 时长: ${conv.durationHours || '?'}h
${conv.channel} · ${conv.chatType} · ${truncate(conv.target, 30)}
${formatTime(conv.firstStartedAt)} → ${formatTime(conv.lastUpdatedAt)}
`).join(''); } catch (error) { container.innerHTML = `
加载失败: ${error.message}
`; } } // 显示对话详情(包含该对话下的所有 session) function showConversationDetail(index) { const conv = conversationsData[index]; if (!conv) return; // 高亮选中的对话 document.querySelectorAll('.conversation-item').forEach((el, i) => { el.classList.toggle('active', i === index); }); // 切换到会话视图并显示该对话下的 session switchView('sessions'); const container = document.getElementById('sessions-list'); container.innerHTML = `
← 返回 💬 ${conv.channel} · ${conv.chatType}
${conv.sessions.map((session, sIndex) => `
${conv.channel} ${session.status} ${sIndex === 0 ? '原始' : `压缩 #${sIndex}`}
${session.model} ${formatTime(session.startedAt)}
📊 ${formatNumber(session.totalTokens)} tokens · 📨 ${session.messageCount} 条消息
${formatTime(session.startedAt)} → ${formatTime(session.updatedAt)}
`).join('')} `; } // 返回对话汇总 function backToConversations() { switchView('conversations'); document.querySelectorAll('.conversation-item').forEach(el => el.classList.remove('active')); } // 初始化 loadAgents();