import React, { useMemo } from 'react'; import * as THREE from 'three'; import DeviceModel from './DeviceModel'; import LODManager, { LOD_LEVELS } from './LODManager'; const RackModel = ({ rack, devices = [], selectedDeviceId, onDeviceClick, onDeviceLeave, onDeviceHover, onEditDevice, onAddNic, onAddPort, tooltipFields, deviceSlideEnabled = true }) => { const width = 0.6; const depth = 1.0; const uHeight = 0.04445; const postWidth = 0.05; const rackHeight = rack?.height || 45; const height = rackHeight * uHeight + 0.2; // 颜色映射 const colors = { server: '#3b82f6', switch: '#22c55e', router: '#f59e0b', firewall: '#ef4444', storage: '#8b5cf6', default: '#3b82f6', status: { running: '#10b981', warning: '#f59e0b', error: '#ef4444', offline: '#6b7280' } }; const getDeviceColor = (type) => { const t = type?.toLowerCase() || ''; if (t.includes('server') || t.includes('服务器')) return colors.server; if (t.includes('switch') || t.includes('交换机')) return colors.switch; if (t.includes('router') || t.includes('路由器')) return colors.router; if (t.includes('firewall') || t.includes('防火墙')) return colors.firewall; if (t.includes('storage') || t.includes('存储')) return colors.storage; return colors.default; }; // 设备组的Y偏移量(与下方设备渲染的偏移一致) const deviceGroupOffset = 0.1; // 生成U位刻度标识 - 写在机柜左右两侧柱子上 const uLabels = useMemo(() => { const labels = []; // 每一个U位都显示数字,从底部开始(U1在底部) for (let u = 1; u <= rackHeight; u += 1) { // 计算U位标识的Y坐标,需要加上设备组的偏移量 const yPos = (u - 1) * uHeight + uHeight / 2 + deviceGroupOffset; // 创建数字纹理 - 白色数字在深色背景上更清晰 const createNumberTexture = (num) => { const canvas = document.createElement('canvas'); canvas.width = 128; canvas.height = 128; const ctx = canvas.getContext('2d'); // 清除画布 ctx.clearRect(0, 0, 128, 128); // 绘制白色数字 ctx.fillStyle = '#ffffff'; ctx.font = 'bold 80px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(num.toString(), 64, 64); return new THREE.CanvasTexture(canvas); }; const leftTexture = createNumberTexture(u); const rightTexture = createNumberTexture(u); // 创建平面几何体显示数字 - 每5U使用稍大的尺寸 const isMajorU = u % 5 === 0; const planeSize = isMajorU ? 0.035 : 0.025; const planeGeometry = new THREE.PlaneGeometry(planeSize, planeSize); // 前侧柱子的位置: [-width/2 + postWidth/2, y, depth/2 - postWidth/2] const leftPostX = -width/2 + postWidth/2; const rightPostX = width/2 - postWidth/2; const frontPostZ = depth/2 - postWidth/2; // 刻度线颜色:每5U使用醒目的黄色,其他使用灰色 const tickColor = isMajorU ? '#fbbf24' : '#6b7280'; const tickHeight = isMajorU ? 0.002 : 0.001; labels.push( {/* 左前侧柱子上的U位标识 - 贴在柱子正侧面(面向前方) */} {/* 右前侧柱子上的U位标识 - 贴在柱子正侧面(面向前方) */} {/* 左前侧柱子上的刻度线 */} {/* 右前侧柱子上的刻度线 */} ); } return labels; }, [rackHeight, uHeight, width, depth, deviceGroupOffset]); // 生成机柜框架 const frame = useMemo(() => { const materialProps = { color: "#333", roughness: 0.5, metalness: 0.8 }; const postArgs = [postWidth, height, postWidth]; const topBottomArgs = [width + 0.02, 0.02, depth + 0.02]; return ( {[-1, 1].map((side) => ( ))} {/* U位刻度标识 */} {uLabels} ); }, [width, height, depth, postWidth, uLabels]); return ( {frame} {devices.map((device) => { const uStart = device.position || device.u_position || 1; const uSize = device.height || device.u_height || 1; const yPos = (uStart - 1) * uHeight + (uSize * uHeight) / 2; const deviceColor = getDeviceColor(device.type); const statusColor = colors.status[device.status] || colors.status.running; return ( ); })} ); }; export default RackModel;