diff --git a/package.json b/package.json index 254174c..fb24f5a 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,16 @@ "type": "module", "dependencies": { "axios": "^1.3.4", + "chart.js": "^4.4.6", "form-data": "^4.0.1", "js-yaml": "^4.1.0", "next": "^14.2.16", "node-id3": "^0.2.6", + "os-utils": "^0.0.14", "p-queue": "^8.0.1", "qrcode": "^1.5.3", "react": "^18.3.1", + "react-chartjs-2": "^5.2.0", "react-circular-progressbar": "^2.1.0", "react-dom": "^18.3.1", "systeminformation": "^5.23.5" diff --git a/server/app/r/api/network2/route.js b/server/app/r/api/network2/route.js new file mode 100644 index 0000000..31a7198 --- /dev/null +++ b/server/app/r/api/network2/route.js @@ -0,0 +1,56 @@ +import os from 'os'; + +let lastBytesReceived = 0; +let lastBytesSent = 0; +let lastTimestamp = Date.now(); + +function getNetworkStats() { + const networkInterfaces = os.networkInterfaces(); + let bytesReceived = 0; + let bytesSent = 0; + + // 累加所有网络接口的数据 + Object.values(networkInterfaces).forEach(interfaces => { + interfaces.forEach(netInterface => { + if (netInterface.internal === false) { + bytesReceived += netInterface.bytes_received || 0; + bytesSent += netInterface.bytes_sent || 0; + } + }); + }); + + const now = Date.now(); + const timeDiff = (now - lastTimestamp) / 1000; // 转换为秒 + + // 计算速率(字节/秒) + const downloadSpeed = (bytesReceived - lastBytesReceived) / timeDiff; + const uploadSpeed = (bytesSent - lastBytesSent) / timeDiff; + + // 更新上次的值 + lastBytesReceived = bytesReceived; + lastBytesSent = bytesSent; + lastTimestamp = now; + + return { + downloadSpeed: (downloadSpeed / 1024).toFixed(2), // KB/s + uploadSpeed: (uploadSpeed / 1024).toFixed(2), // KB/s + totalReceived: (bytesReceived / (1024 * 1024 * 1024)).toFixed(2), // GB + totalSent: (bytesSent / (1024 * 1024 * 1024)).toFixed(2), // GB + timestamp: now + }; +} + +export async function GET() { + try { + const stats = getNetworkStats(); + return new Response(JSON.stringify(stats), { + status: 200, + headers: { 'Content-Type': 'application/json' }, + }); + } catch (error) { + return new Response(JSON.stringify({ error: error.message }), { + status: 500, + headers: { 'Content-Type': 'application/json' }, + }) + } +} diff --git a/server/components/contents/home.jsx b/server/components/contents/home.jsx index eff1a96..6d68f90 100644 --- a/server/components/contents/home.jsx +++ b/server/components/contents/home.jsx @@ -1,5 +1,6 @@ import React from 'react'; import BotInfo from "../home/bot-info.jsx"; +import Network from "../home/network.jsx"; import System from "../home/system.jsx"; export default function Home({ }) { @@ -7,24 +8,7 @@ export default function Home({ }) {
-
- {/* 监控卡片 */ } -
-
-

监控

-
-
-

上传: 0.87 KB/s

-

下载: 3.21 KB/s

-
-
-

总发送: 21.17 GB

-

总接收: 90.46 GB

-
-
-
-
-
+
); } diff --git a/server/components/home/network.jsx b/server/components/home/network.jsx new file mode 100644 index 0000000..b3335a5 --- /dev/null +++ b/server/components/home/network.jsx @@ -0,0 +1,141 @@ +import React, { useEffect, useState } from "react"; +import { Line } from "react-chartjs-2"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend +} from 'chart.js'; + +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend +); + +const MAX_DATA_POINTS = 30; + +export default function Network() { + const [networkData, setNetworkData] = useState({ + uploadSpeed: 0, + downloadSpeed: 0, + totalSent: 0, + totalReceived: 0 + }); + const [chartData, setChartData] = useState({ + labels: [], + datasets: [ + { + label: '上传速度 (KB/s)', + data: [], + borderColor: 'rgb(75, 192, 192)', + tension: 0.1 + }, + { + label: '下载速度 (KB/s)', + data: [], + borderColor: 'rgb(255, 99, 132)', + tension: 0.1 + } + ] + }); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await fetch('/r/api/network2'); + const data = await response.json(); + + setNetworkData({ + uploadSpeed: data.uploadSpeed, + downloadSpeed: data.downloadSpeed, + totalSent: data.totalSent, + totalReceived: data.totalReceived + }); + + setChartData(prevData => { + const newLabels = [...prevData.labels, new Date().toLocaleTimeString()]; + const newUploadData = [...prevData.datasets[0].data, data.uploadSpeed]; + const newDownloadData = [...prevData.datasets[1].data, data.downloadSpeed]; + + // 保持最新的30个数据点 + if (newLabels.length > MAX_DATA_POINTS) { + newLabels.shift(); + newUploadData.shift(); + newDownloadData.shift(); + } + + return { + labels: newLabels, + datasets: [ + { + ...prevData.datasets[0], + data: newUploadData + }, + { + ...prevData.datasets[1], + data: newDownloadData + } + ] + }; + }); + } catch (error) { + console.error('获取网络数据失败:', error); + } + }; + + // 每秒更新一次数据 + const interval = setInterval(fetchData, 1000); + return () => clearInterval(interval); + }, []); + + const chartOptions = { + responsive: true, + animation: { + duration: 0 + }, + scales: { + y: { + beginAtZero: true + } + }, + plugins: { + legend: { + position: 'top' + } + } + }; + + return ( +
+
+
+
+

网络监控

+
+
+

上传: {networkData.uploadSpeed} KB/s

+

下载: {networkData.downloadSpeed} KB/s

+
+
+

总发送: {networkData.totalSent} GB

+

总接收: {networkData.totalReceived} GB

+
+
+
+ +
+
+
+
+
+ ); +}