feat(3d): 添加Scene3DContext优化3D场景状态管理

refactor(3d): 重构LODManager使用ref优化性能

feat(3d): 在RackModel中添加U位刻度标识

refactor(3d): 优化Scene组件相机控制和渲染设置

refactor(3d): 重构DeviceModel使用共享几何体和材质缓存

refactor(3d): 优化Rack3DVisualization使用Scene3DContext

style(dashboard): 改进响应式布局和样式

perf(3d): 优化InstancedMesh性能减少内存占用
This commit is contained in:
zhang1106
2026-01-29 13:09:43 +08:00
parent a0ad9ad604
commit 6d61d6e54c
8 changed files with 1000 additions and 375 deletions
+47 -21
View File
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { Layout, Select, Card, Spin, message, Typography, Descriptions, Tag, Button, Space, Empty, Modal, Form, Input, InputNumber, DatePicker, Checkbox, Switch } from 'antd';
import { CloudServerOutlined, ReloadOutlined, ArrowLeftOutlined, InfoCircleOutlined, UpOutlined, DownOutlined, EditOutlined, SettingOutlined, FullscreenOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
@@ -9,6 +9,7 @@ import NetworkCardCreateModal from '../components/NetworkCardCreateModal';
import PortCreateModal from '../components/PortCreateModal';
import CableCreateModal from '../components/CableCreateModal';
import DeviceDetailDrawer from '../components/DeviceDetailDrawer';
import { useScene3D } from '../context/Scene3DContext';
const { Header, Content, Sider } = Layout;
const { Title, Text } = Typography;
@@ -16,14 +17,29 @@ const { Option } = Select;
const Rack3DVisualization = () => {
const navigate = useNavigate();
const [racks, setRacks] = useState([]);
const [selectedRack, setSelectedRack] = useState(null);
// 使用 Scene3DContext 管理3D场景状态
const {
devices,
setDevices,
selectedDevice,
setSelectedDevice,
hoveredDevice,
setHoveredDevice,
deviceSlideEnabled,
setDeviceSlideEnabled,
selectedRack,
setSelectedRack,
racks,
setRacks,
deviceCables,
setDeviceCables,
loadingDevices,
setLoadingDevices,
} = useScene3D();
const [selectedRoom, setSelectedRoom] = useState(null);
const [devices, setDevices] = useState([]);
const [loading, setLoading] = useState(false);
const [loadingDevices, setLoadingDevices] = useState(false);
const [selectedDevice, setSelectedDevice] = useState(null); // Currently selected device in 3D view
const [hoveredDevice, setHoveredDevice] = useState(null); // Currently hovered device
const [isRackInfoCollapsed, setIsRackInfoCollapsed] = useState(false); // Rack Info Card collapsed state
// Edit Modal State
@@ -44,11 +60,13 @@ const Rack3DVisualization = () => {
const [operatingDevice, setOperatingDevice] = useState(null);
const [refreshTrigger, setRefreshTrigger] = useState(0);
// Device Cables State
const [deviceCables, setDeviceCables] = useState([]);
// Device Slide Animation Toggle
const [deviceSlideEnabled, setDeviceSlideEnabled] = useState(false);
// 使用 ref 存储模态框状态,避免 handleDeviceHover 频繁重新创建
const modalsOpenRef = useRef(false);
// 同步 ref 与 state
useEffect(() => {
modalsOpenRef.current = modalVisible || nicModalVisible || portModalVisible || cableModalVisible;
}, [modalVisible, nicModalVisible, portModalVisible, cableModalVisible]);
const fetchDeviceCables = useCallback(async (deviceId) => {
if (!deviceId) return;
@@ -79,9 +97,14 @@ const Rack3DVisualization = () => {
// Handle Edit Device Click
const handleEditDevice = (device) => {
setEditingDevice(device);
setModalVisible(true);
};
// 当 Modal 打开时,初始化表单数据
useEffect(() => {
if (modalVisible && editingDevice) {
// Prepare form data (similar to DeviceManagement)
const deviceData = { ...device };
const deviceData = { ...editingDevice };
if (deviceData.purchaseDate) deviceData.purchaseDate = dayjs(deviceData.purchaseDate);
if (deviceData.warrantyExpiry) deviceData.warrantyExpiry = dayjs(deviceData.warrantyExpiry);
@@ -107,8 +130,8 @@ const Rack3DVisualization = () => {
}
form.setFieldsValue(cleanDeviceData);
setModalVisible(true);
};
}
}, [modalVisible, editingDevice, form]);
const handleModalCancel = () => {
setModalVisible(false);
@@ -300,12 +323,13 @@ const Rack3DVisualization = () => {
});
}, [selectedRoom, racks]);
const handleDeviceClick = (device) => {
// 使用 useCallback 稳定回调函数引用,避免 DeviceModel 不必要的重渲染
const handleDeviceClick = useCallback((device) => {
setSelectedDevice(device);
if (device) {
fetchDeviceCables(device.deviceId || device.id);
}
};
}, [fetchDeviceCables]);
const handleDeviceLeave = (device) => {
// 移除鼠标离开事件,避免抽屉意外关闭
@@ -316,10 +340,12 @@ const Rack3DVisualization = () => {
// });
};
// 优化 handleDeviceHover - 使用 ref 获取最新状态,减少依赖项
const handleDeviceHover = useCallback((device) => {
if (modalVisible || nicModalVisible || portModalVisible) return;
// 使用 ref 检查模态框状态,避免频繁重新创建回调
if (modalsOpenRef.current) return;
setHoveredDevice(device);
}, [modalVisible, nicModalVisible, portModalVisible]);
}, []); // 空依赖项,回调引用永远稳定
const handleClosePortModal = useCallback(() => {
setPortModalVisible(false);
@@ -627,7 +653,7 @@ const Rack3DVisualization = () => {
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
{[
{ icon: '🖱️', text: '左键旋转 / 中键平移' },
{ icon: '🖱️', text: '左键旋转视图' },
{ icon: '🔍', text: '滚轮缩放视图' },
{ icon: '👆', text: '点击设备查看详情' }
].map((item, i) => (