feat(floorplan): 新增机房平面图功能模块
refactor(models): 为Room和Rack模型添加布局相关字段 feat(routes): 实现机房平面图相关API接口 feat(components): 添加平面图编辑器、画布渲染及交互组件 feat(hooks): 实现平面图数据管理和状态管理 feat(pages): 新增机房平面图页面入口 style(components): 优化平面图组件样式和交互体验
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
import React from 'react';
|
||||
import { Drawer, Descriptions, Tag, Progress, Button, Space } from 'antd';
|
||||
import {
|
||||
CloudServerOutlined,
|
||||
ThunderboltOutlined,
|
||||
RightOutlined,
|
||||
EyeOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { RACK_STATUS_COLORS } from '../canvas/CanvasConstants';
|
||||
|
||||
const statusMap = {
|
||||
active: { text: '在用', color: 'blue' },
|
||||
maintenance: { text: '维护中', color: 'orange' },
|
||||
inactive: { text: '停用', color: 'default' },
|
||||
};
|
||||
|
||||
const RackDetailPanel = ({ rack, visible, onClose }) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
if (!rack) return null;
|
||||
|
||||
const statusInfo = statusMap[rack.status] || { text: rack.status, color: 'default' };
|
||||
const utilization = rack.utilization != null ? Math.round(rack.utilization * 100) : 0;
|
||||
const powerPercent = rack.maxPower > 0
|
||||
? Math.round(((rack.currentPower || 0) / rack.maxPower) * 100)
|
||||
: 0;
|
||||
|
||||
const handleView3D = () => {
|
||||
navigate('/visualization-3d', { state: { rackId: rack.rackId } });
|
||||
};
|
||||
|
||||
const handleViewDevices = () => {
|
||||
navigate('/devices', { state: { rackId: rack.rackId } });
|
||||
};
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
title={
|
||||
<Space>
|
||||
<CloudServerOutlined style={{ color: RACK_STATUS_COLORS[rack.status] || '#1677ff' }} />
|
||||
{rack.name}
|
||||
</Space>
|
||||
}
|
||||
placement="right"
|
||||
width={360}
|
||||
open={visible}
|
||||
onClose={onClose}
|
||||
extra={
|
||||
<Space>
|
||||
<Button
|
||||
size="small"
|
||||
icon={<EyeOutlined />}
|
||||
onClick={handleView3D}
|
||||
>
|
||||
3D视图
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
icon={<RightOutlined />}
|
||||
onClick={handleViewDevices}
|
||||
>
|
||||
设备
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Descriptions column={1} size="small" bordered>
|
||||
<Descriptions.Item label="机柜ID">{rack.rackId}</Descriptions.Item>
|
||||
<Descriptions.Item label="状态">
|
||||
<Tag color={statusInfo.color}>{statusInfo.text}</Tag>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="位置">
|
||||
{rack.rowPos != null && rack.colPos != null
|
||||
? `第${rack.rowPos + 1}排 第${rack.colPos + 1}列`
|
||||
: '未分配'}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="朝向">{rack.facing || 'front'}</Descriptions.Item>
|
||||
<Descriptions.Item label="高度">{rack.height}U</Descriptions.Item>
|
||||
<Descriptions.Item label="设备数量">{rack.deviceCount || 0} 台</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
<div style={{ marginTop: 16 }}>
|
||||
<div style={{ marginBottom: 8, fontWeight: 500 }}>U位使用率</div>
|
||||
<Progress
|
||||
percent={utilization}
|
||||
strokeColor={
|
||||
utilization < 30 ? '#52c41a' :
|
||||
utilization < 70 ? '#faad14' : '#ff4d4f'
|
||||
}
|
||||
format={() => `${rack.usedU || 0}/${rack.totalU || rack.height || 0}U`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 16 }}>
|
||||
<div style={{ marginBottom: 8, fontWeight: 500 }}>
|
||||
<ThunderboltOutlined /> 功率
|
||||
</div>
|
||||
<Progress
|
||||
percent={powerPercent}
|
||||
strokeColor={
|
||||
powerPercent < 50 ? '#52c41a' :
|
||||
powerPercent < 80 ? '#faad14' : '#ff4d4f'
|
||||
}
|
||||
format={() => `${rack.currentPower || 0}/${rack.maxPower || 0}W`}
|
||||
/>
|
||||
</div>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default RackDetailPanel;
|
||||
Reference in New Issue
Block a user