import React, { useState, useEffect, useRef } from 'react'; function Records() { const [filter, setFilter] = useState('all'); const [sessions, setSessions] = useState([]); const [loading, setLoading] = useState(false); const chartRef = useRef(null); // 格式化时间 const formatDuration = (seconds) => { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return `${mins}m ${secs}s`; }; // 格式化日期 const formatDate = (dateString) => { const date = new Date(dateString); return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); }; // 加载会话数据 const loadSessions = async (filterType) => { setLoading(true); try { const response = await fetch(`/api/sessions?filter=${filterType}&limit=50`); const data = await response.json(); setSessions(data); drawChart(data); } catch (error) { console.error('Failed to load sessions:', error); } finally { setLoading(false); } }; // 绘制图表 const drawChart = (data) => { const canvas = chartRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); const width = canvas.width = canvas.offsetWidth; const height = canvas.height = 300; // 清空画布 ctx.clearRect(0, 0, width, height); if (data.length === 0) { ctx.fillStyle = '#999'; ctx.font = '16px Nunito'; ctx.textAlign = 'center'; ctx.fillText('No data available', width / 2, height / 2); return; } // 准备数据 (最多显示最近20个会话) const displayData = data.slice(0, 20).reverse(); const padding = 50; const chartWidth = width - padding * 2; const chartHeight = height - padding * 2; const barWidth = chartWidth / displayData.length; // 找到最大值用于缩放 const maxScore = 1.0; // 绘制坐标轴 ctx.strokeStyle = '#E0E0E0'; ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(padding, padding); ctx.lineTo(padding, height - padding); ctx.lineTo(width - padding, height - padding); ctx.stroke(); // 绘制Y轴刻度 ctx.fillStyle = '#666'; ctx.font = '12px Nunito'; ctx.textAlign = 'right'; for (let i = 0; i <= 4; i++) { const y = height - padding - (chartHeight * i / 4); const value = (maxScore * i / 4 * 100).toFixed(0); ctx.fillText(value + '%', padding - 10, y + 4); // 绘制网格线 ctx.strokeStyle = '#F0F0F0'; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(padding, y); ctx.lineTo(width - padding, y); ctx.stroke(); } // 绘制柱状图 displayData.forEach((session, index) => { const barHeight = (session.focus_score / maxScore) * chartHeight; const x = padding + index * barWidth + barWidth * 0.1; const y = height - padding - barHeight; const barActualWidth = barWidth * 0.8; // 根据分数设置颜色 - 使用蓝色主题 const score = session.focus_score; let color; if (score >= 0.8) color = '#4A90E2'; else if (score >= 0.6) color = '#5DADE2'; else if (score >= 0.4) color = '#85C1E9'; else color = '#AED6F1'; ctx.fillStyle = color; ctx.fillRect(x, y, barActualWidth, barHeight); // 绘制边框 ctx.strokeStyle = color; ctx.lineWidth = 1; ctx.strokeRect(x, y, barActualWidth, barHeight); }); // 绘制图例 ctx.textAlign = 'left'; ctx.font = 'bold 14px Nunito'; ctx.fillStyle = '#4A90E2'; ctx.fillText('Focus Score by Session', padding, 30); }; // 初始加载 useEffect(() => { loadSessions(filter); }, [filter]); // 处理筛选按钮点击 const handleFilterClick = (filterType) => { setFilter(filterType); }; // 查看详情 const handleViewDetails = (sessionId) => { // 这里可以实现查看详情的功能,比如弹窗显示该会话的详细信息 alert(`View details for session ${sessionId}\n(Feature can be extended later)`); }; return (

My Records

Recent Sessions

{loading ? (
Loading sessions...
) : sessions.length === 0 ? (
No sessions found for this period.
) : ( {sessions.map((session, index) => ( ))}
Date Duration Focus Score Action
{formatDate(session.start_time)} {formatDuration(session.duration_seconds)} = 0.8 ? '#28a745' : session.focus_score >= 0.6 ? '#ffc107' : session.focus_score >= 0.4 ? '#fd7e14' : '#dc3545', fontWeight: '600', fontSize: '13px' }} > {(session.focus_score * 100).toFixed(1)}%
)}
); } export default Records;