From 1f8c45a797b6b6a2fad04f8c254675822bc59c07 Mon Sep 17 00:00:00 2001 From: qinjian Date: Thu, 21 Aug 2025 08:46:49 +0800 Subject: [PATCH] =?UTF-8?q?refactor=EF=BC=9A=E5=B0=86=E5=9B=BE=E8=A1=A8?= =?UTF-8?q?=E5=BA=93=E4=BB=8E=20ECharts=20=E8=BF=81=E7=A7=BB=E5=88=B0=20Ch?= =?UTF-8?q?art.js=EF=BC=8C=E4=BB=A5=E6=8F=90=E5=8D=87=E5=9B=BE=E8=A1=A8?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=92=8C=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/RealtimeCharts.jsx | 509 +++++++++++------- .../components/RealtimeDataTable.jsx | 12 +- .../sections/wuyuanbiaoba/container/index.jsx | 112 ++-- package-lock.json | 99 ++-- package.json | 4 +- server/tcpProxy/index.js | 6 +- 6 files changed, 416 insertions(+), 326 deletions(-) diff --git a/client/src/sections/wuyuanbiaoba/components/RealtimeCharts.jsx b/client/src/sections/wuyuanbiaoba/components/RealtimeCharts.jsx index 6cc3386..74f1e63 100644 --- a/client/src/sections/wuyuanbiaoba/components/RealtimeCharts.jsx +++ b/client/src/sections/wuyuanbiaoba/components/RealtimeCharts.jsx @@ -1,233 +1,344 @@ -import React from 'react'; -import { Typography, Badge } from 'antd'; -import ReactECharts from 'echarts-for-react'; +import React, { useMemo, useEffect, useRef } from "react"; +import { Typography, Badge } from "antd"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title as ChartTitle, + Tooltip, + Legend, +} from "chart.js"; +import { Line } from "react-chartjs-2"; + +// 注册Chart.js组件 +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + ChartTitle, + Tooltip, + Legend +); const { Title } = Typography; const RealtimeCharts = ({ tableData, lastUpdateTime }) => { + const xChartRef = useRef(null); + const yChartRef = useRef(null); + + // 添加数据验证 + if (!Array.isArray(tableData)) { + console.warn('tableData is not an array:', tableData); + return
数据格式错误
; + } + // 固定的设备颜色映射,确保颜色一致性 const getDeviceColor = (deviceId) => { const colorMap = { - 'DEV000': "#1890ff", // 蓝色 - 'DEV001': "#52c41a", // 绿色 - 'DEV002': "#faad14", // 橙色 - 'DEV003': "#f5222d", // 红色 - 'DEV004': "#722ed1", // 紫色 - 'DEV005': "#fa8c16", // 橙红色 - 'DEV006': "#13c2c2", // 青色 - 'DEV007': "#eb2f96", // 粉色 - 'DEV008': "#2f54eb", // 深蓝色 - 'DEV009': "#fa541c", // 火橙色 + target1: "#52c41a", // 绿色 + target2: "#faad14", // 橙色 + target3: "#f5222d", // 红色 + target4: "#722ed1", // 紫色 + target5: "#fa8c16", // 橙红色 + target6: "#13c2c2", // 青色 + target7: "#eb2f96", // 粉色 + target8: "#2f54eb", // 深蓝色 + target9: "#fa541c", // 火橙色 + target10: "#1890ff", // 蓝色 }; - // 如果设备ID在映射中,使用固定颜色 - if (colorMap[deviceId]) { - return colorMap[deviceId]; - } - - // 对于未预定义的设备,基于设备编号生成颜色 - const deviceNumber = deviceId.replace(/\D/g, ''); // 提取数字 - const colors = [ - "#1890ff", "#52c41a", "#faad14", "#f5222d", "#722ed1", - "#fa8c16", "#13c2c2", "#eb2f96", "#2f54eb", "#fa541c" - ]; - return colors[parseInt(deviceNumber) % colors.length]; + return colorMap[deviceId] || "#1890ff"; }; - // 准备图表数据 - const prepareChartData = () => { - // 获取所有唯一的设备ID并排序,确保顺序一致 - const deviceIds = [...new Set(tableData.map((item) => item.deviceId))].sort(); + // 数据采样函数 - 每秒采样一次,最多保留25个数据点 + const sampleData = (data) => { + if (!data || data.length === 0) { + return { + labels: [], + deviceIds: [], + timeGroups: {}, + sortedTimes: [] + }; + } - // 获取所有时间点并排序 - const allTimes = [ - ...new Set(tableData.map((item) => item.updateTime)), - ].sort((a, b) => new Date(a) - new Date(b)); - const timeLabels = allTimes.map((time) => { - const date = new Date(time); - return date.toLocaleTimeString("zh-CN", { - hour: "2-digit", - minute: "2-digit", - second: "2-digit", + try { + // 按时间分组数据 + const timeGroups = {}; + data.forEach((item) => { + if (!item || !item.updateTime) return; + + const timeKey = Math.floor(new Date(item.updateTime).getTime() / 1000); // 按秒分组 + if (!timeGroups[timeKey]) { + timeGroups[timeKey] = []; + } + timeGroups[timeKey].push(item); }); - }); - // 为每个设备准备数据 - const deviceData = deviceIds.map((deviceId) => { - const deviceItems = tableData.filter( - (item) => item.deviceId === deviceId - ); + // 取最新的25秒数据 + const sortedTimes = Object.keys(timeGroups) + .sort((a, b) => Number(b) - Number(a)) + .slice(0, 25) + .reverse(); - // 为每个时间点找到对应的X和Y值,如果没有则为null - const xData = allTimes.map((time) => { - const item = deviceItems.find((d) => d.updateTime === time); - return item ? parseFloat(item.xValue) : null; - }); + // 获取所有设备ID + const deviceIds = [...new Set(data.map((item) => item?.deviceId).filter(Boolean))].sort(); - const yData = allTimes.map((time) => { - const item = deviceItems.find((d) => d.updateTime === time); - return item ? parseFloat(item.yValue) : null; + // 生成时间标签 + const labels = sortedTimes.map((timeKey) => { + return new Date(Number(timeKey) * 1000).toLocaleTimeString("zh-CN", { + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + }); }); - // 使用固定的颜色映射 - const color = getDeviceColor(deviceId); - + return { labels, deviceIds, timeGroups, sortedTimes }; + } catch (error) { + console.error('数据采样出错:', error); return { - deviceId, - xData, - yData, - color, + labels: [], + deviceIds: [], + timeGroups: {}, + sortedTimes: [] }; - }); - - return { timeLabels, deviceData }; + } }; - const { timeLabels, deviceData } = prepareChartData(); + // 准备X轴图表数据 + const xChartData = useMemo(() => { + try { + const { labels, deviceIds, timeGroups, sortedTimes } = sampleData(tableData); - // X值折线图配置 - const getXChartOption = () => ({ - title: { - text: "X轴位移数据", - left: "center", - textStyle: { - fontSize: 16, - fontWeight: "normal", - }, - }, - tooltip: { - trigger: "axis", - formatter: function (params) { - let result = `时间: ${params[0].axisValue}
`; - params.forEach((param) => { - if (param.value !== null) { - result += `${param.seriesName}: ${param.value} mm
`; - } + if (!deviceIds || deviceIds.length === 0) { + return { labels: [], datasets: [] }; + } + + const datasets = deviceIds.map((deviceId) => { + const data = sortedTimes.map((timeKey) => { + const timeData = timeGroups[timeKey] || []; + const deviceData = timeData.find( + (item) => item.deviceId === deviceId + ); + return deviceData && deviceData.xValue !== undefined ? parseFloat(deviceData.xValue) : null; }); - return result; - }, + + return { + label: deviceId, + data: data, + borderColor: getDeviceColor(deviceId), + backgroundColor: getDeviceColor(deviceId) + "20", + borderWidth: 2, + pointRadius: 3, + pointHoverRadius: 5, + tension: 0, + connectNulls: false, + }; + }); + + return { labels, datasets }; + } catch (error) { + console.error('准备X轴图表数据出错:', error); + return { labels: [], datasets: [] }; + } + }, [tableData]); + + // 准备Y轴图表数据 + const yChartData = useMemo(() => { + try { + const { labels, deviceIds, timeGroups, sortedTimes } = sampleData(tableData); + + if (!deviceIds || deviceIds.length === 0) { + return { labels: [], datasets: [] }; + } + + const datasets = deviceIds.map((deviceId) => { + const data = sortedTimes.map((timeKey) => { + const timeData = timeGroups[timeKey] || []; + const deviceData = timeData.find( + (item) => item.deviceId === deviceId + ); + return deviceData && deviceData.yValue !== undefined ? parseFloat(deviceData.yValue) : null; + }); + + return { + label: deviceId, + data: data, + borderColor: getDeviceColor(deviceId), + backgroundColor: getDeviceColor(deviceId) + "20", + borderWidth: 2, + pointRadius: 3, + pointHoverRadius: 5, + tension: 0, + connectNulls: false, + }; + }); + + return { labels, datasets }; + } catch (error) { + console.error('准备Y轴图表数据出错:', error); + return { labels: [], datasets: [] }; + } + }, [tableData]); + + // Chart.js配置选项 + const chartOptions = { + responsive: true, + maintainAspectRatio: false, + interaction: { + mode: "index", + intersect: false, }, - legend: { - orient: "horizontal", - bottom: "5%", - textStyle: { - fontSize: 12, + plugins: { + legend: { + position: "bottom", + labels: { + usePointStyle: true, + padding: 20, + font: { + size: 12, + }, + }, }, - }, - grid: { - left: "3%", - right: "4%", - bottom: "15%", - top: "15%", - containLabel: true, - }, - xAxis: { - type: "category", - data: timeLabels, - axisLabel: { - rotate: 45, - fontSize: 11, + tooltip: { + filter: function (tooltipItem) { + return tooltipItem.parsed.y !== null; + }, }, }, - yAxis: { - type: "value", - name: "X值(mm)", - nameTextStyle: { - fontSize: 13, + scales: { + x: { + display: true, + title: { + display: true, + text: "时间", + }, + ticks: { + maxRotation: 45, + minRotation: 0, + font: { + size: 10, + }, + }, }, - axisLabel: { - fontSize: 11, + y: { + display: true, + title: { + display: true, + font: { + size: 12, + }, + }, + ticks: { + font: { + size: 10, + }, + }, }, }, - series: deviceData.map((device) => ({ - name: device.deviceId, - type: "line", - data: device.xData, - smooth: false, - connectNulls: false, - lineStyle: { - color: device.color, - width: 2, + elements: { + point: { + radius: 3, + hoverRadius: 5, }, - itemStyle: { - color: device.color, - }, - symbol: "circle", - symbolSize: 4, - })), - }); - - // Y值折线图配置 - const getYChartOption = () => ({ - title: { - text: "Y轴位移数据", - left: "center", - textStyle: { - fontSize: 16, - fontWeight: "normal", + line: { + tension: 0, }, }, - tooltip: { - trigger: "axis", - formatter: function (params) { - let result = `时间: ${params[0].axisValue}
`; - params.forEach((param) => { - if (param.value !== null) { - result += `${param.seriesName}: ${param.value} mm
`; - } - }); - return result; + }; + + // X轴图表配置 + const xChartOptions = { + ...chartOptions, + plugins: { + ...chartOptions.plugins, + title: { + display: true, + text: "X轴位移数据", + font: { + size: 16, + }, }, }, - legend: { - orient: "horizontal", - bottom: "5%", - textStyle: { - fontSize: 12, + scales: { + ...chartOptions.scales, + y: { + ...chartOptions.scales.y, + title: { + ...chartOptions.scales.y.title, + text: "X值(mm)", + }, }, }, - grid: { - left: "3%", - right: "4%", - bottom: "15%", - top: "15%", - containLabel: true, - }, - xAxis: { - type: "category", - data: timeLabels, - axisLabel: { - rotate: 45, - fontSize: 11, + }; + + // Y轴图表配置 + const yChartOptions = { + ...chartOptions, + plugins: { + ...chartOptions.plugins, + title: { + display: true, + text: "Y轴位移数据", + font: { + size: 16, + }, }, }, - yAxis: { - type: "value", - name: "Y值(mm)", - nameTextStyle: { - fontSize: 13, - }, - axisLabel: { - fontSize: 11, + scales: { + ...chartOptions.scales, + y: { + ...chartOptions.scales.y, + title: { + ...chartOptions.scales.y.title, + text: "Y值(mm)", + }, }, }, - series: deviceData.map((device) => ({ - name: device.deviceId, - type: "line", - data: device.yData, - smooth: false, - connectNulls: false, - lineStyle: { - color: device.color, - width: 2, - }, - itemStyle: { - color: device.color, - }, - symbol: "circle", - symbolSize: 4, - })), - }); + }; + + // 添加调试信息 + useEffect(() => { + console.log('RealtimeCharts - tableData:', tableData); + console.log('RealtimeCharts - xChartData:', xChartData); + console.log('RealtimeCharts - yChartData:', yChartData); + }, [tableData, xChartData, yChartData]); + + // 如果没有数据,显示空状态 + if (!tableData || tableData.length === 0) { + return ( +
+ + 实时数据图 + <Badge + status="default" + text="等待数据..." + style={{ marginLeft: "16px", fontSize: "12px" }} + /> + +
+
+

等待实时数据...

+
+
+
+ ); + } return (
{ backgroundColor: "white", borderRadius: "8px", border: "1px solid #e8e8e8", - minHeight: "250px", + minHeight: "280px", + padding: "16px", }} > -
@@ -279,13 +391,14 @@ const RealtimeCharts = ({ tableData, lastUpdateTime }) => { backgroundColor: "white", borderRadius: "8px", border: "1px solid #e8e8e8", - minHeight: "250px", + minHeight: "280px", + padding: "16px", }} > - diff --git a/client/src/sections/wuyuanbiaoba/components/RealtimeDataTable.jsx b/client/src/sections/wuyuanbiaoba/components/RealtimeDataTable.jsx index 020f740..2881194 100644 --- a/client/src/sections/wuyuanbiaoba/components/RealtimeDataTable.jsx +++ b/client/src/sections/wuyuanbiaoba/components/RealtimeDataTable.jsx @@ -10,15 +10,21 @@ const RealtimeDataTable = ({ realtimeData }) => { title: "X值(mm)", dataIndex: "xValue", key: "xValue", + render: (text) => Number(text), }, { title: "Y值(mm)", dataIndex: "yValue", key: "yValue", + render: (text) => Number(text), }, - { title: "更新时间", dataIndex: "updateTime", key: "updateTime", width: 180 }, + { + title: "更新时间", + dataIndex: "updateTime", + key: "updateTime", + }, ]; return ( @@ -48,10 +54,6 @@ const RealtimeDataTable = ({ realtimeData }) => { columns={tableColumns} pagination={false} size="small" - scroll={{ - y: 508, - }} - virtual /> diff --git a/client/src/sections/wuyuanbiaoba/container/index.jsx b/client/src/sections/wuyuanbiaoba/container/index.jsx index f46cea9..b91b2fa 100644 --- a/client/src/sections/wuyuanbiaoba/container/index.jsx +++ b/client/src/sections/wuyuanbiaoba/container/index.jsx @@ -10,7 +10,11 @@ import { TemplateModal, TargetDetailModal, } from "../components"; -import { WebSocketProvider, useWebSocket, useWebSocketSubscription } from "../actions/websocket.jsx"; +import { + WebSocketProvider, + useWebSocket, + useWebSocketSubscription, +} from "../actions/websocket.jsx"; import { useTemplateStorage } from "../hooks/useTemplateStorage.js"; import { useTargetStorage } from "../hooks/useTargetStorage.js"; @@ -21,7 +25,7 @@ const WuyuanbiaobaContent = () => { const { isConnected, sendMessage } = useWebSocket(); // 订阅实时数据 - const realtimeDataSubscription = useWebSocketSubscription('dev', 'data'); + const realtimeDataSubscription = useWebSocketSubscription("dev", "data"); const { templates: tempListData, @@ -45,6 +49,9 @@ const WuyuanbiaobaContent = () => { const [realtimeData, setRealtimeData] = useState([]); const [lastUpdateTime, setLastUpdateTime] = useState(new Date()); + // 数据采样相关状态 + const [lastSampleTime, setLastSampleTime] = useState(0); + // 模板相关状态 const [templateModalVisible, setTemplateModalVisible] = useState(false); const [templateModalMode, setTemplateModalMode] = useState("add"); // 'add' | 'edit' @@ -65,9 +72,9 @@ const WuyuanbiaobaContent = () => { return []; } - return data.data.map(item => ({ + return data.data.map((item) => ({ key: item.pos, - deviceId: `target${Number(item.pos)+1}`, + deviceId: `target${Number(item.pos) + 1}`, xValue: item.x, yValue: item.y, updateTime: data.time || new Date().toLocaleString(), @@ -79,22 +86,23 @@ const WuyuanbiaobaContent = () => { // 初始化空的实时数据表格 setRealtimeData([]); setTableData([]); - console.log('数据已初始化,等待实时数据...',import.meta.env.MODE); - + console.log("数据已初始化,等待实时数据...", import.meta.env.MODE); }, []); // 模板数据加载完成后,默认选中内置模板 useEffect(() => { if (!templatesLoading && tempListData.length > 0 && !selectedTemplate) { // 查找内置模板 - const builtinTemplate = tempListData.find(template => template.key === 'builtin_1'); + const builtinTemplate = tempListData.find( + (template) => template.key === "builtin_1" + ); if (builtinTemplate) { - setSelectedTemplate('builtin_1'); - console.log('默认选中内置模板:', builtinTemplate.name); + setSelectedTemplate("builtin_1"); + console.log("默认选中内置模板:", builtinTemplate.name); } else { // 如果没有内置模板,选择第一个模板 setSelectedTemplate(tempListData[0].key); - console.log('默认选中第一个模板:', tempListData[0].name); + console.log("默认选中第一个模板:", tempListData[0].name); } } }, [templatesLoading, tempListData, selectedTemplate]); @@ -110,59 +118,59 @@ const WuyuanbiaobaContent = () => { // 调试实时数据订阅状态 useEffect(() => { - console.log('实时数据订阅状态:', { - hasData: !!realtimeDataSubscription.latest, - dataCount: realtimeDataSubscription.data?.length || 0, - latestTimestamp: realtimeDataSubscription.latest?.timestamp, - }); + // console.log('实时数据订阅状态:', { + // hasData: !!realtimeDataSubscription.latest, + // dataCount: realtimeDataSubscription.data?.length || 0, + // latestTimestamp: realtimeDataSubscription.latest?.timestamp, + // }); }, [realtimeDataSubscription]); // 处理实时数据更新 useEffect(() => { - if (realtimeDataSubscription.latest && realtimeDataSubscription.latest.values) { - const newRealtimeData = processRealtimeData(realtimeDataSubscription.latest.values); + if ( + realtimeDataSubscription.latest && + realtimeDataSubscription.latest.values + ) { + const newRealtimeData = processRealtimeData( + realtimeDataSubscription.latest.values + ); if (newRealtimeData.length > 0) { - console.log('收到实时数据:', newRealtimeData); - - // 更新最新数据表格 - 保留之前设备的数据,只更新有新数据的设备 - setRealtimeData(prevRealtimeData => { - // 创建设备ID到数据的映射 - const deviceDataMap = new Map(); - - // 先保留所有之前的设备数据 - prevRealtimeData.forEach(data => { - deviceDataMap.set(data.deviceId, data); - }); - - // 用新数据更新或添加设备 - newRealtimeData.forEach(data => { - deviceDataMap.set(data.deviceId, data); + const currentTime = Date.now(); + const currentSecond = Math.floor(currentTime / 1000); + + // 每秒采样一次数据用于图表和表格显示 + if (currentSecond > lastSampleTime) { + setLastSampleTime(currentSecond); + + // 更新采样后的历史数据(用于图表显示) + setTableData((prevData) => { + const updatedData = [ + ...prevData, + ...newRealtimeData.map((point) => ({ + ...point, + key: `${currentTime}_${point.key}`, + timestamp: currentTime, + updateTime: new Date(currentTime).toLocaleString(), + })), + ]; + + // 只保留最近25个数据点(25秒) + return updatedData.slice(-75); // 3个设备 * 25个时间点 }); - // 转换回数组格式,按设备ID排序保持一致性 - return Array.from(deviceDataMap.values()).sort((a, b) => - a.deviceId.localeCompare(b.deviceId) - ); - }); - - // 更新历史数据(用于图表显示) - setTableData(prevData => { - const updatedData = [ - ...prevData, - ...newRealtimeData.map((point, index) => ({ - ...point, - key: `${Date.now()}_${point.key}`, // 为历史数据生成唯一key - })), - ]; - // 保持最多100个数据点 - return updatedData.slice(-100); - }); + // 更新实时数据表格(使用最新的采样数据) + setRealtimeData(newRealtimeData.map((point) => ({ + ...point, + key: `realtime_${point.key}`, + updateTime: new Date(currentTime).toLocaleString(), + }))); + } setLastUpdateTime(new Date()); } } - }, [realtimeDataSubscription.latest]); + }, [realtimeDataSubscription.latest, lastSampleTime]); // 编辑标靶的处理函数 const handleEditTarget = (target) => { @@ -436,7 +444,7 @@ const WuyuanbiaobaContent = () => { lastUpdateTime={lastUpdateTime} /> - {/* Table 区域 */} + {/* Table 区域 - 使用采样数据显示 */} diff --git a/package-lock.json b/package-lock.json index aabb1f7..dc2e88f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,9 +17,9 @@ "devDependencies": { "@ant-design/icons": "^5.4.0", "antd": "^5.19.0", - "echarts": "^5.6.0", - "echarts-for-react": "^3.0.2", + "chart.js": "^4.5.0", "react": "18.x", + "react-chartjs-2": "^5.3.0", "react-dom": "18.x", "react-redux": "^9.1.2", "react-router-dom": "^6.26.0" @@ -862,6 +862,13 @@ "node": ">= 18" } }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmmirror.com/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "dev": true, + "license": "MIT" + }, "node_modules/@noble/hashes": { "version": "1.8.0", "resolved": "https://nexus.ngaiot.com/repository/fs-npm/@noble/hashes/-/hashes-1.8.0.tgz", @@ -1771,6 +1778,19 @@ "tslib": "^2.0.3" } }, + "node_modules/chart.js": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/chart.js/-/chart.js-4.5.0.tgz", + "integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/classnames": { "version": "2.5.1", "resolved": "https://nexus.ngaiot.com/repository/fs-npm/classnames/-/classnames-2.5.1.tgz", @@ -2112,39 +2132,6 @@ "node": ">= 0.4" } }, - "node_modules/echarts": { - "version": "5.6.0", - "resolved": "https://nexus.ngaiot.com/repository/fs-npm/echarts/-/echarts-5.6.0.tgz", - "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "2.3.0", - "zrender": "5.6.1" - } - }, - "node_modules/echarts-for-react": { - "version": "3.0.3", - "resolved": "https://nexus.ngaiot.com/repository/fs-npm/echarts-for-react/-/echarts-for-react-3.0.3.tgz", - "integrity": "sha512-KdvZGkCwmx5DTHl7vjo0CBodSaPY31hPWRC4NZ5B+utQfoW+M54OTBvkoCmktR0kJ+1Bj6rP7pIJJnxPdySyug==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "size-sensor": "^1.0.1" - }, - "peerDependencies": { - "echarts": "^3.0.0 || ^4.0.0 || ^5.0.0", - "react": "^15.0.0 || >=16.0.0" - } - }, - "node_modules/echarts/node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://nexus.ngaiot.com/repository/fs-npm/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "dev": true, - "license": "0BSD" - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://nexus.ngaiot.com/repository/fs-npm/ee-first/-/ee-first-1.1.1.tgz", @@ -2289,13 +2276,6 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://nexus.ngaiot.com/repository/fs-npm/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", - "dev": true, - "license": "MIT" - }, "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://nexus.ngaiot.com/repository/fs-npm/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", @@ -4123,6 +4103,17 @@ "node": ">=0.10.0" } }, + "node_modules/react-chartjs-2": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz", + "integrity": "sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://nexus.ngaiot.com/repository/fs-npm/react-dom/-/react-dom-18.3.1.tgz", @@ -4503,13 +4494,6 @@ "node": ">=18" } }, - "node_modules/size-sensor": { - "version": "1.0.2", - "resolved": "https://nexus.ngaiot.com/repository/fs-npm/size-sensor/-/size-sensor-1.0.2.tgz", - "integrity": "sha512-2NCmWxY7A9pYKGXNBfteo4hy14gWu47rg5692peVMst6lQLPKrVjhY+UTEsPI5ceFRJSl3gVgMYaUi/hKuaiKw==", - "dev": true, - "license": "ISC" - }, "node_modules/snake-case": { "version": "3.0.4", "resolved": "https://nexus.ngaiot.com/repository/fs-npm/snake-case/-/snake-case-3.0.4.tgz", @@ -5004,23 +4988,6 @@ "engines": { "node": ">= 4.0.0" } - }, - "node_modules/zrender": { - "version": "5.6.1", - "resolved": "https://nexus.ngaiot.com/repository/fs-npm/zrender/-/zrender-5.6.1.tgz", - "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tslib": "2.3.0" - } - }, - "node_modules/zrender/node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://nexus.ngaiot.com/repository/fs-npm/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "dev": true, - "license": "0BSD" } } } diff --git a/package.json b/package.json index 48391ac..b19adc5 100644 --- a/package.json +++ b/package.json @@ -16,11 +16,11 @@ "devDependencies": { "@ant-design/icons": "^5.4.0", "antd": "^5.19.0", + "chart.js": "^4.5.0", "react": "18.x", + "react-chartjs-2": "^5.3.0", "react-dom": "18.x", "react-redux": "^9.1.2", - "echarts": "^5.6.0", - "echarts-for-react": "^3.0.2", "react-router-dom": "^6.26.0" }, "dependencies": { diff --git a/server/tcpProxy/index.js b/server/tcpProxy/index.js index afba718..cef885e 100644 --- a/server/tcpProxy/index.js +++ b/server/tcpProxy/index.js @@ -38,7 +38,7 @@ function setupTcpProxy(conf) { // 尝试解析为文本 try { textData = data.toString('utf8'); - console.log('收到TCP数据片段:', textData.length, '字节'); + // console.log('收到TCP数据片段:', textData.length, '字节'); } catch (e) { console.log('TCP数据无法解析为文本'); return; @@ -59,8 +59,8 @@ function setupTcpProxy(conf) { // 转发完整消息到WebSocket if (ws.readyState === WebSocket.OPEN) { - console.log('准备发送完整消息到WebSocket:', completeMessage.length, '字节'); - console.log('消息内容:', completeMessage); + // console.log('准备发送完整消息到WebSocket:', completeMessage.length, '字节'); + // console.log('消息内容:', completeMessage); ws.send(completeMessage, (err) => { if (err) { console.error('WebSocket发送数据错误:', err);