blob: f87ef7a6191876079658f5db30ef7c162be52ff6 [file] [log] [blame]
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;