| import React, { useState, useEffect } from 'react'; |
| import { |
| ResponsiveContainer, LineChart, Line, |
| XAxis, YAxis, Tooltip, CartesianGrid, Legend |
| } from 'recharts'; |
| import { fetchSysCost } from '../api/posts_trm'; |
| |
| function PerformanceLogs({ userId }) { |
| const [data, setData] = useState([]); |
| const [loading, setLoading] = useState(true); |
| const [unauthorized, setUnauthorized] = useState(false); |
| |
| useEffect(() => { |
| setLoading(true); |
| fetchSysCost(userId) |
| .then(result => { |
| // 检查是否是权限错误 |
| if (result && result.status === 'error' && result.message === 'Unauthorized') { |
| setUnauthorized(true); |
| setData([]); |
| return; |
| } |
| |
| // 确保数据是数组格式 |
| let list = []; |
| if (Array.isArray(result)) { |
| list = result; |
| } else if (Array.isArray(result.data)) { |
| list = result.data; |
| } else if (Array.isArray(result.syscost)) { |
| list = result.syscost; |
| } |
| |
| const msList = list.map(item => ({ |
| ...item, |
| elapsed_time: item.elapsed_time * 1000, |
| cpu_user: item.cpu_user * 1000, |
| cpu_system: item.cpu_system * 1000, |
| memory_rss: item.memory_rss / (1024 * 1024*8), // convert bytes to MB |
| record_time_ts: new Date(item.record_time).getTime() // add numeric timestamp |
| })); |
| console.log('Converted data:', msList[0]); // debug first item |
| setData(msList); |
| setUnauthorized(false); |
| }) |
| .catch(err => { |
| console.error('fetchSysCost error:', err); |
| if (err.message === 'Unauthorized') { |
| setUnauthorized(true); |
| setData([]); |
| } |
| }) |
| .finally(() => setLoading(false)); |
| }, [userId]); |
| |
| if (loading) { |
| return ( |
| <section className="dashboard-performance"> |
| <div style={{ |
| display: 'flex', |
| justifyContent: 'center', |
| alignItems: 'center', |
| height: '400px', |
| flexDirection: 'column' |
| }}> |
| <div style={{ |
| border: '4px solid #f3f3f3', |
| borderTop: '4px solid #3498db', |
| borderRadius: '50%', |
| width: '50px', |
| height: '50px', |
| animation: 'spin 1s linear infinite' |
| }}></div> |
| <p style={{ marginTop: '20px', color: '#666' }}>加载中...</p> |
| <style>{` |
| @keyframes spin { |
| 0% { transform: rotate(0deg); } |
| 100% { transform: rotate(360deg); } |
| } |
| `}</style> |
| </div> |
| </section> |
| ); |
| } |
| |
| if (unauthorized) { |
| return ( |
| <section className="dashboard-performance"> |
| <div style={{ |
| display: 'flex', |
| justifyContent: 'center', |
| alignItems: 'center', |
| height: '400px', |
| flexDirection: 'column', |
| textAlign: 'center' |
| }}> |
| <div style={{ |
| fontSize: '18px', |
| color: '#ff4d4f', |
| marginBottom: '10px' |
| }}> |
| 权限不足,无法访问性能监控数据 |
| </div> |
| <div style={{ |
| fontSize: '14px', |
| color: '#666' |
| }}> |
| 请联系管理员获取相应权限 |
| </div> |
| </div> |
| </section> |
| ); |
| } |
| |
| return ( |
| <section className="dashboard-performance"> |
| {/* 响应时间图表 */} |
| <div style={{ marginBottom: '30px' }}> |
| <h3>响应时间</h3> |
| <ResponsiveContainer width="100%" height={300}> |
| <LineChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}> |
| <CartesianGrid strokeDasharray="3 3" /> |
| <XAxis |
| dataKey="record_time_ts" |
| type="number" |
| domain={['dataMin', 'dataMax']} |
| tickFormatter={ts => new Date(ts).toLocaleTimeString()} |
| /> |
| <YAxis domain={[0, 'auto']} label={{ value: '时间 (ms)', angle: -90, position: 'insideLeft' }} /> |
| <Tooltip formatter={(val) => typeof val === 'number' ? `${val.toFixed(2)} ms` : val} /> |
| <Legend /> |
| <Line type="monotone" dataKey="elapsed_time" stroke="#8884d8" name="响应时间 (ms)" /> |
| </LineChart> |
| </ResponsiveContainer> |
| </div> |
| |
| {/* CPU时间图表 */} |
| <div style={{ marginBottom: '30px' }}> |
| <h3>CPU 使用时间</h3> |
| <ResponsiveContainer width="100%" height={300}> |
| <LineChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}> |
| <CartesianGrid strokeDasharray="3 3" /> |
| <XAxis |
| dataKey="record_time_ts" |
| type="number" |
| domain={['dataMin', 'dataMax']} |
| tickFormatter={ts => new Date(ts).toLocaleTimeString()} |
| /> |
| <YAxis domain={[0, 'auto']} label={{ value: '时间 (ms)', angle: -90, position: 'insideLeft' }} /> |
| <Tooltip formatter={(val) => typeof val === 'number' ? `${val.toFixed(2)} ms` : val} /> |
| <Legend /> |
| <Line type="monotone" dataKey="cpu_user" stroke="#82ca9d" name="CPU 用户时间 (ms)" /> |
| <Line type="monotone" dataKey="cpu_system" stroke="#ffc658" name="CPU 系统时间 (ms)" /> |
| </LineChart> |
| </ResponsiveContainer> |
| </div> |
| |
| {/* 内存图表 */} |
| <div style={{ marginBottom: '30px' }}> |
| <h3>内存使用</h3> |
| <ResponsiveContainer width="100%" height={300}> |
| <LineChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}> |
| <CartesianGrid strokeDasharray="3 3" /> |
| <XAxis |
| dataKey="record_time_ts" |
| type="number" |
| domain={['dataMin', 'dataMax']} |
| tickFormatter={ts => new Date(ts).toLocaleTimeString()} |
| /> |
| <YAxis domain={[0, 'auto']} label={{ value: '内存 (MB)', angle: -90, position: 'insideLeft' }} /> |
| <Tooltip formatter={(val) => typeof val === 'number' ? `${val.toFixed(2)} MB` : val} /> |
| <Legend /> |
| <Line type="monotone" dataKey="memory_rss" stroke="#ff7300" name="内存 RSS" /> |
| </LineChart> |
| </ResponsiveContainer> |
| </div> |
| </section> |
| ); |
| } |
| |
| export default PerformanceLogs; |