Browse Source

feat:将认证后的重定向地址更新为上位机,优化标靶名称处理,并为实时图表实现交互式标靶显示/隐藏功能

master
qinjian 3 days ago
parent
commit
29ecefe176
  1. 2
      client/src/layout/container/index.jsx
  2. 3
      client/src/sections/wuyuanbiaoba/components/CameraView.jsx
  3. 137
      client/src/sections/wuyuanbiaoba/components/RealtimeCharts.jsx
  4. 10
      server/tcpProxy/index.js

2
client/src/layout/container/index.jsx

@ -11,7 +11,7 @@ export default (props) => {
useEffect(() => {
if (!sessionStorage.getItem("user")) {
window.location.replace("/signin");
window.location.replace("/wuyuanbiaoba");
}
}, []);

3
client/src/sections/wuyuanbiaoba/components/CameraView.jsx

@ -286,8 +286,7 @@ const CameraView = ({
const templateParams = selectedTemplate
? {
//
name:
selectedTemplate.name || `target${rectangles.length + 1}`,
name: `target${rectangles.length + 1}` || selectedTemplate.name,
radius: selectedTemplate.physicalRadius || 40.0,
isReferencePoint: selectedTemplate.isBaseline || false,
gradientThreshold:

137
client/src/sections/wuyuanbiaoba/components/RealtimeCharts.jsx

@ -1,5 +1,5 @@
import React, { useMemo, useEffect, useRef } from "react";
import { Typography, Badge } from "antd";
import React, { useMemo, useEffect, useRef, useState, useCallback } from "react";
import { Typography, Badge, Button, Space } from "antd";
import {
Chart as ChartJS,
CategoryScale,
@ -29,9 +29,11 @@ const RealtimeCharts = ({ tableData, lastUpdateTime }) => {
const xChartRef = useRef(null);
const yChartRef = useRef(null);
//
const [visibleTargets, setVisibleTargets] = useState({});
//
if (!Array.isArray(tableData)) {
// console.warn('tableData is not an array:', tableData);
return <div>数据格式错误</div>;
}
@ -104,7 +106,7 @@ const RealtimeCharts = ({ tableData, lastUpdateTime }) => {
return { labels, deviceIds, timeGroups, sortedTimes };
} catch (error) {
console.error("数据采样出错:", error);
console.error(`${new Date().toLocaleString()} - 数据采样出错:`, error);
return {
labels: [],
deviceIds: [],
@ -114,6 +116,72 @@ const RealtimeCharts = ({ tableData, lastUpdateTime }) => {
}
};
//
const { deviceIds } = sampleData(tableData);
useEffect(() => {
if (deviceIds.length > 0) {
const initialVisible = {};
deviceIds.forEach(deviceId => {
initialVisible[deviceId] = true; //
});
setVisibleTargets(prev => ({ ...initialVisible, ...prev }));
}
}, [deviceIds.join(',')]);
//
const toggleTargetVisibility = useCallback((deviceId) => {
setVisibleTargets(prev => ({
...prev,
[deviceId]: !prev[deviceId]
}));
//
const xChart = xChartRef.current;
const yChart = yChartRef.current;
if (xChart && yChart) {
const xDatasetIndex = xChart.data.datasets.findIndex(dataset => dataset.label === deviceId);
const yDatasetIndex = yChart.data.datasets.findIndex(dataset => dataset.label === deviceId);
if (xDatasetIndex !== -1 && yDatasetIndex !== -1) {
const isVisible = xChart.isDatasetVisible(xDatasetIndex);
//
xChart.setDatasetVisibility(xDatasetIndex, !isVisible);
yChart.setDatasetVisibility(yDatasetIndex, !isVisible);
//
xChart.update();
yChart.update();
}
}
}, []);
// /
const toggleAllTargets = useCallback((visible) => {
const newVisibleTargets = {};
deviceIds.forEach(deviceId => {
newVisibleTargets[deviceId] = visible;
});
setVisibleTargets(newVisibleTargets);
//
const xChart = xChartRef.current;
const yChart = yChartRef.current;
if (xChart && yChart) {
xChart.data.datasets.forEach((_, index) => {
xChart.setDatasetVisibility(index, visible);
});
yChart.data.datasets.forEach((_, index) => {
yChart.setDatasetVisibility(index, visible);
});
xChart.update();
yChart.update();
}
}, [deviceIds]);
// X
const xChartData = useMemo(() => {
try {
@ -145,15 +213,16 @@ const RealtimeCharts = ({ tableData, lastUpdateTime }) => {
pointHoverRadius: 5,
tension: 0,
connectNulls: false,
hidden: !visibleTargets[deviceId], //
};
});
return { labels, datasets };
} catch (error) {
console.error("准备X轴图表数据出错:", error);
console.error(`${new Date().toLocaleString()} - 准备X轴图表数据出错:`, error);
return { labels: [], datasets: [] };
}
}, [tableData]);
}, [tableData, visibleTargets]);
// Y
const yChartData = useMemo(() => {
@ -186,15 +255,16 @@ const RealtimeCharts = ({ tableData, lastUpdateTime }) => {
pointHoverRadius: 5,
tension: 0,
connectNulls: false,
hidden: !visibleTargets[deviceId], //
};
});
return { labels, datasets };
} catch (error) {
console.error("准备Y轴图表数据出错:", error);
console.error(`${new Date().toLocaleString()} - 准备Y轴图表数据出错:`, error);
return { labels: [], datasets: [] };
}
}, [tableData]);
}, [tableData, visibleTargets]);
// Chart.js
const chartOptions = {
@ -206,14 +276,7 @@ const RealtimeCharts = ({ tableData, lastUpdateTime }) => {
},
plugins: {
legend: {
position: "bottom",
labels: {
usePointStyle: true,
padding: 20,
font: {
size: 12,
},
},
display: false, // 使
},
tooltip: {
filter: function (tooltipItem) {
@ -312,13 +375,6 @@ const RealtimeCharts = ({ tableData, lastUpdateTime }) => {
},
};
//
// 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 (
@ -378,6 +434,41 @@ const RealtimeCharts = ({ tableData, lastUpdateTime }) => {
/>
</Title>
{/* 统一的图例控制器 */}
<div style={{ marginBottom: "16px", padding: "12px", backgroundColor: "#fafafa", borderRadius: "6px" }}>
<div style={{ marginBottom: "8px", fontSize: "14px", fontWeight: "500" }}>显示控制</div>
<Space wrap>
<Button
size="small"
onClick={() => toggleAllTargets(true)}
type="primary"
>
全部显示
</Button>
<Button
size="small"
onClick={() => toggleAllTargets(false)}
>
全部隐藏
</Button>
{deviceIds.map(deviceId => (
<Button
key={deviceId}
size="small"
type={visibleTargets[deviceId] ? "primary" : "default"}
style={{
borderColor: getDeviceColor(deviceId),
color: visibleTargets[deviceId] ? "#fff" : getDeviceColor(deviceId),
backgroundColor: visibleTargets[deviceId] ? getDeviceColor(deviceId) : "#fff"
}}
onClick={() => toggleTargetVisibility(deviceId)}
>
{deviceId}
</Button>
))}
</Space>
</div>
<div
style={{
flex: 1,

10
server/tcpProxy/index.js

@ -63,7 +63,7 @@ function setupTcpProxy(conf) {
// console.log('消息内容:', completeMessage);
ws.send(completeMessage, (err) => {
if (err) {
console.error('WebSocket发送数据错误:', err);
console.error(`[${new Date().toLocaleString()}] WebSocket发送数据错误:`, err);
} else {
// console.log('完整消息已转发到WebSocket客户端');
}
@ -101,7 +101,7 @@ function setupTcpProxy(conf) {
// 直接发送完整数据
tcpClient.write(messageStr + '\n\n', (err) => {
if (err) {
console.error('TCP发送数据错误:', err);
console.error(`[${new Date().toLocaleString()}] TCP发送数据错误:`, err);
} else {
// console.log('数据已发送到TCP服务器');
}
@ -113,7 +113,7 @@ function setupTcpProxy(conf) {
// TCP连接错误处理
tcpClient.on('error', (err) => {
console.error('TCP连接错误:', err);
console.error(`[${new Date().toLocaleString()}] TCP连接错误:`, err);
tcpDataBuffer = ''; // 清理缓冲区
if (ws.readyState === WebSocket.OPEN) {
ws.close(1011, 'TCP连接错误');
@ -140,7 +140,7 @@ function setupTcpProxy(conf) {
// WebSocket错误处理
ws.on('error', (err) => {
console.error('WebSocket错误:', err);
console.error(`[${new Date().toLocaleString()}] WebSocket错误:`, err);
if (tcpClient.writable) {
tcpClient.destroy();
}
@ -155,7 +155,7 @@ function setupTcpProxy(conf) {
});
wss.on('error', (err) => {
console.error('WebSocket服务器错误:', err);
console.error(`[${new Date().toLocaleString()}] WebSocket服务器错误:`, err);
});
return wss;

Loading…
Cancel
Save