import React, { useState, useCallback, ReactNode } from 'react'; import { createRoot } from 'react-dom/client'; import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query'; import { Pie, Column, Line } from '@ant-design/plots'; import { FullscreenOutlined, FullscreenExitOutlined } from '@ant-design/icons'; import { Card } from 'antd'; import { AlarmDeviceData } from '../share/monitorTypes.ts'; import { queryFns } from './api.ts'; import { ThreeJSRoom } from './components_three.tsx'; import { GlobalConfig } from "../share/types.ts"; const queryClient = new QueryClient(); // 声明全局配置对象类型 declare global { interface Window { CONFIG?: GlobalConfig; } } interface ServerMonitorChartsProps { type?: 'pie' | 'column' | 'line' | 'pie2'; } const pushStateAndTrigger = (url: string, target: string) => { window.history.pushState({}, '', url); window.dispatchEvent(new Event('popstate')); } // 统一的链接处理函数 const handleNavigate = (url: string) => { // 判断是否在iframe中 const isInIframe = window.self !== window.top; if (isInIframe) { pushStateAndTrigger(url, 'top'); } else { window.open(url, '_blank'); } }; function AlarmDeviceTable() { const { data = [], isLoading } = useQuery({ queryKey: ['topAlarmDevices'], queryFn: queryFns.fetchTopAlarmDevices, refetchInterval: 30000 }); if (isLoading) { return (
加载中...
); } return (
{/* 表头 */}
排名
告警次数
点位名称
{/* 表格内容 */}
{data.map((item: AlarmDeviceData) => (
{item.rank}
{item.alarmCount}
{item.deviceName}
))} {data.length === 0 && (
暂无数据
)}
); } function CustomCard({ title, children, className = '', bodyStyle = {}, onClick }: { title?: string; children: ReactNode; className?: string; bodyStyle?: React.CSSProperties; onClick?: () => void; }) { return (
{title && (
{title}
)}
{children}
); } function MetricCards() { const { data: metrics = { totalDevices: 0, onlineDevices: 0, offlineDevices: 0, onlineRate: "0.00", riskLevel: { level: '健康', color: '#52c41a' } }, isLoading } = useQuery({ queryKey: ['deviceMetrics'], queryFn: queryFns.fetchDeviceMetrics, refetchInterval: 30000, refetchIntervalInBackground: true }); const metricConfigs = [ { title: "设备数", value: metrics.totalDevices, link: "/admin/alarm/manage" }, { title: "正常数", value: metrics.onlineDevices, link: "/admin/alarm/manage" }, { title: "在线率", value: `${metrics.onlineRate}%`, link: "/admin/device/rate" }, { title: "异常数", value: metrics.offlineDevices, link: "/admin/alert/manage" }, { title: "风险等级", value: metrics.riskLevel.level, color: metrics.riskLevel.color, link: undefined } ]; return ( <> {metricConfigs.map((metric, index) => (
metric.link && handleNavigate(metric.link)} className={metric.link ? "cursor-pointer" : undefined} > {metric.title} {isLoading ? "-" : metric.value}
))} ); } function ServerMonitorCharts({ type = 'pie' }: ServerMonitorChartsProps) { // 资产分类数据 const { data: categoryData } = useQuery({ queryKey: ['zichanCategory'], queryFn: queryFns.fetchCategoryData, enabled: type === 'pie' }); // 在线率变化数据 const { data: onlineRateData } = useQuery({ queryKey: ['zichanOnlineRate'], queryFn: queryFns.fetchOnlineRateData, enabled: type === 'column' }); // 资产流转状态数据 const { data: stateData } = useQuery({ queryKey: ['zichanState'], queryFn: queryFns.fetchStateData, enabled: type === 'pie2' }); // 告警数据变化 const { data: alarmData } = useQuery({ queryKey: ['pingAlarm'], queryFn: queryFns.fetchAlarmData, enabled: type === 'line' }); const renderChart = () => { switch (type) { case 'pie': return ( { // 只有占比超过5%的项才显示标签 if (percent < 0.05) return null; return `${设备分类}\n(${设备数})`; }, style: { fill: '#fff', fontSize: 12, fontWeight: 500, }, transform: [{ type: 'overlapDodgeY' }], }} theme={{ colors10: ['#36cfc9', '#ff4d4f', '#ffa940', '#73d13d', '#4096ff'], }} legend={false} autoFit={true} interaction={{ tooltip: { render: (_: any, { items, title }: { items: any[], title: string }) => { if (!items || items.length === 0) return ''; // 获取当前选中项的数据 const item = items[0]; // 根据value找到对应的完整数据项 const fullData = categoryData?.find(d => d['设备数'] === item.value); if (!fullData) return ''; return `
${fullData['设备分类']}

数量: ${item.value}

占比: ${fullData['百分比']}%

`; } } }} /> ); case 'column': return ( { let content = items['time_interval']; content += `\n(${(items['total_devices'])})`; return content; }, }} xAxis={{ label: { style: { fill: '#fff', }, }, }} yAxis={{ label: { style: { fill: '#fff', }, }, }} autoFit={true} interaction={{ tooltip:false }} /> ); case 'line': return ( { const value = items['total_devices']; // if (value === 0) return null; // const maxValue = Math.max(...(alarmData || []).map(item => item.total_devices)); // if (value < maxValue * 0.3 && alarmData && alarmData.length > 8) return null; return `${items['time_interval']}\n(${value})`; }, transform: [{ type: 'overlapDodgeY' }], }} xAxis={{ label: { style: { fill: '#fff', }, autoHide: true, autoRotate: true, }, }} yAxis={{ label: { style: { fill: '#fff', }, }, }} autoFit={true} interaction={{ tooltip: { render: (_: any, { items, title }: { items: any[], title: string }) => { if (!items || items.length === 0) return ''; // 获取当前选中项的数据 const item = items[0]; // 根据value找到对应的完整数据项 const fullData = alarmData?.find(d => d.total_devices === item.value); if (!fullData) return ''; return `
${fullData.time_interval}

数量: ${item.value}

`; } } }} /> ); case 'pie2': return ( { // 只有占比超过5%的项才显示标签 if (percent < 0.05) return null; return `${资产流转}\n(${设备数})`; }, style: { fill: '#fff', fontSize: 12, fontWeight: 500, }, transform: [{ type: 'overlapDodgeY' }], }} theme={{ colors10: ['#36cfc9', '#ff4d4f', '#ffa940', '#73d13d', '#4096ff'], }} legend={{ color: { itemLabelFill: '#fff', } }} autoFit={true} interaction={{ tooltip: { render: (_: any, { items, title }: { items: any[], title: string }) => { if (!items || items.length === 0) return ''; // 获取当前选中项的数据 const item = items[0]; // 根据value找到对应的完整数据项 const fullData = stateData?.find(d => d['设备数'] === item.value); if (!fullData) return ''; return `
${fullData['资产流转']}

数量: ${item.value}

占比: ${fullData['百分比']}%

`; } } }} /> ); } }; return (
{renderChart()}
); } function PageTitle() { return (
{/* 背景图片 */}
title background
); } function DataCenter() { const [isFullscreen, setIsFullscreen] = useState(false); const toggleFullscreen = useCallback(() => { if (!document.fullscreenElement) { document.documentElement.requestFullscreen(); setIsFullscreen(true); } else { document.exitFullscreen().then(() => { setIsFullscreen(false); window.location.reload(); }); } }, []); return (
{/* 顶部标题区域 */}
{/* 全屏切换按钮 */}
{/* 主要内容区域 */}
{/* 顶部指标卡片 */}
{/* 左侧图表区域 */}
{/* 饼图 */} handleNavigate('/admin/device/type')} >
{/* 柱状图 */} handleNavigate('/admin/device/rate')} >
{/* 饼图2 */} handleNavigate('/admin/asset/transfer/chart')} >
{/* 右侧区域 */}
{/* 中间3D机房区域 */}
{/* 底部区域分为两列 */}
{/* 左侧告警曲线图 */} handleNavigate('/admin/alarm/trend')} >
{/* 右侧告警设备表格 */} handleNavigate('/admin/alert/manage')} >
); } // 渲染应用 const root = createRoot(document.getElementById('root') as HTMLElement); root.render( );