import React, { useState, useEffect } from 'react'; import axios from 'axios'; import { toast } from 'react-hot-toast'; import { Activity, RefreshCw, Clock, User, FileText, TrendingUp, BarChart3, Zap, History, Square } from 'lucide-react'; import { adminAPI } from '../api'; const SessionMonitor = ({ adminToken }) => { const [activeSessions, setActiveSessions] = useState([]); const [historySessions, setHistorySessions] = useState([]); const [loading, setLoading] = useState(false); const [autoRefresh, setAutoRefresh] = useState(true); const [selectedUser, setSelectedUser] = useState(null); const [userSessions, setUserSessions] = useState([]); const [viewMode, setViewMode] = useState('active'); // 'active' or 'history' useEffect(() => { if (viewMode === 'active') { fetchActiveSessions(); if (autoRefresh) { const interval = setInterval(fetchActiveSessions, 5000); // 每5秒刷新 return () => clearInterval(interval); } } else if (viewMode === 'history') { fetchHistorySessions(); } }, [autoRefresh, viewMode]); const handleStopSession = async (sessionId) => { if (!window.confirm('确定要强制停止该会话吗?')) { return; } const password = prompt("请输入管理员密码以确认停止操作:"); if (!password) return; try { await adminAPI.stopSession(sessionId, password); toast.success('会话已停止'); fetchActiveSessions(); } catch (error) { toast.error('停止失败: ' + (error.response?.data?.detail || '未知错误')); } }; const fetchActiveSessions = async () => { try { const response = await axios.get('/api/admin/sessions/active', { headers: { Authorization: `Bearer ${adminToken}` } }); setActiveSessions(response.data); } catch (error) { if (error.response?.status !== 401) { console.error('获取活跃会话失败:', error); } } }; const fetchHistorySessions = async () => { // 如果已经有数据,不显示全屏loading,提升体验 if (historySessions.length === 0) { setLoading(true); } try { const response = await axios.get('/api/admin/sessions', { headers: { Authorization: `Bearer ${adminToken}` }, params: { limit: 100 } // 获取最近100条 }); setHistorySessions(response.data); } catch (error) { if (error.response?.status !== 401) { toast.error('获取历史会话失败'); } } finally { setLoading(false); } }; const fetchUserSessions = async (userId, cardKey) => { setLoading(true); try { const response = await axios.get(`/api/admin/users/${userId}/sessions`, { headers: { Authorization: `Bearer ${adminToken}` } }); setUserSessions(response.data); setSelectedUser({ id: userId, card_key: cardKey }); } catch (error) { toast.error('获取用户会话历史失败'); } finally { setLoading(false); } }; const getStatusColor = (status) => { switch (status) { case 'processing': return 'bg-blue-500'; case 'completed': return 'bg-green-500'; case 'failed': return 'bg-red-500'; case 'queued': return 'bg-yellow-500'; default: return 'bg-gray-500'; } }; const getStatusText = (status) => { switch (status) { case 'processing': return '处理中'; case 'completed': return '已完成'; case 'failed': return '失败'; case 'queued': return '排队中'; default: return status; } }; const formatDuration = (seconds) => { if (!seconds) return '-'; const mins = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${mins}分${secs}秒`; }; return (
{/* 头部 */}

会话监控

{/* 视图切换按钮 */}
{viewMode === 'active' && ( )}
{/* 统计卡片 */} {viewMode === 'active' && (

活跃会话

{activeSessions.length}

处理中

{activeSessions.filter(s => s.status === 'processing').length}

排队中

{activeSessions.filter(s => s.status === 'queued').length}

)} {viewMode === 'history' && (

已完成

{historySessions.filter(s => s.status === 'completed').length}

处理中

{historySessions.filter(s => s.status === 'processing').length}

失败

{historySessions.filter(s => s.status === 'failed').length}

总会话数

{historySessions.length}

)} {/* 会话列表 */}

{viewMode === 'active' ? '实时会话' : '历史会话'}

{loading ? (
) : (viewMode === 'active' ? activeSessions : historySessions).length === 0 ? (

{viewMode === 'active' ? '当前没有活跃会话' : '暂无历史会话'}

) : (
{(viewMode === 'active' ? activeSessions : historySessions).map((session) => (
{session.status === 'stopped' ? '已停止' : getStatusText(session.status)} {(session.status === 'processing' || session.status === 'queued') && ( )} {session.processing_mode && ( {session.processing_mode === 'paper_polish' ? '论文润色' : session.processing_mode === 'paper_polish_enhance' ? '论文润色+增强' : session.processing_mode === 'emotion_polish' ? '感情文章润色' : session.processing_mode} )} {session.original_char_count != null && ( {session.original_char_count.toLocaleString()} 字符 )} {viewMode === 'history' && session.polished_char_count != null && ( 润色后 {session.polished_char_count.toLocaleString()} 字符 )}
{/* 进度条 */} {session.total_segments > 0 && (
处理进度 {session.completed_segments || session.processed_segments || 0}/{session.total_segments} 段 {session.progress && ` (${session.progress}%)`}
)}
{new Date(session.created_at).toLocaleString('zh-CN')} {session.processing_time && ( 耗时: {formatDuration(session.processing_time)} )} {session.completed_at && ( 完成: {new Date(session.completed_at).toLocaleString('zh-CN')} )} {session.error_message && ( 错误: {session.error_message} )}
))}
)}
{/* 用户会话历史模态框 */} {selectedUser && (

用户会话历史: {selectedUser.card_key}

{loading ? (
) : userSessions.length === 0 ? (
该用户暂无会话记录
) : (
{userSessions.map((session) => (
{getStatusText(session.status)} {session.processing_mode && ( {session.processing_mode === 'paper_polish' ? '论文润色' : session.processing_mode === 'paper_polish_enhance' ? '论文润色+增强' : session.processing_mode === 'emotion_polish' ? '感情文章润色' : session.processing_mode} )} ID: {session.session_id || session.id}
{new Date(session.created_at).toLocaleString('zh-CN')}
{/* 字符统计信息 */}
{session.original_char_count != null && (

原文字符

{session.original_char_count.toLocaleString()}

)} {session.polished_char_count != null && (

润色字符

{session.polished_char_count.toLocaleString()}

)} {session.enhanced_char_count != null && (

增强字符

{session.enhanced_char_count.toLocaleString()}

)}

原文

{session.original_text?.substring(0, 100)} {session.original_text?.length > 100 ? '...' : ''}

{session.optimized_text && (

优化后

{session.optimized_text.substring(0, 100)} {session.optimized_text.length > 100 ? '...' : ''}

)}
{/* 进度统计 */} {session.total_segments > 0 && (
完成进度 {session.completed_segments || 0}/{session.total_segments} 段 ({session.progress || 0}%)
)}
分段: {session.completed_segments || 0}/{session.total_segments || 0} {session.processing_time && ( 耗时: {formatDuration(session.processing_time)} )} {session.completed_at && ( 完成: {new Date(session.completed_at).toLocaleString('zh-CN')} )}
))}
)}
)}
); }; export default SessionMonitor;