AI诊断中心

This commit is contained in:
mmc
2026-05-07 21:17:41 +08:00
parent dea212151a
commit 1554af83d3
7 changed files with 621 additions and 60 deletions

View File

@@ -250,7 +250,7 @@ export default function AlarmCenterPage() {
>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
<div>
<Typography.Text strong style={{ fontSize: 16 }}>告警列表(共8条)</Typography.Text><br />
<Typography.Text strong style={{ fontSize: 16, color: '#0837A8' }}>告警列表(共8条)</Typography.Text><br />
<Text type="secondary" style={{ fontSize: 12 }}>点击告警查看详情</Text>
</div>
</div>

View File

@@ -35,3 +35,15 @@
.custom-scrollbar::-webkit-scrollbar-track { background: transparent; }
.custom-scrollbar::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 10px; }
.custom-scrollbar::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.2); }
.ant-card-head-title{
color:#0837A8
}
.ant-statistic-content-suffix{
font-size: 14px;
}
.ant-statistic-title{
color:#000 !important;
opacity: 1;
font-weight: 800;
}

540
src/pages/AIAnalysis.tsx Normal file
View File

@@ -0,0 +1,540 @@
import React, { useState } from 'react';
import {
Row, Col, Card, Button, Tag, Table, Drawer, Typography, Space, Statistic, message
} from 'antd';
import { ReloadOutlined, PlusOutlined, ArrowDownOutlined, ArrowUpOutlined, CheckCircleOutlined, ExclamationCircleOutlined, LineHeightOutlined } from '@ant-design/icons';
import { Line, Bar, Pie } from '@ant-design/charts';
import he from '@/dist/assets/Organization-irk1gmLc';
const { Title, Text } = Typography;
// 模拟数据
const aiSummaryData = [
{ diagnosis: '热斑检测', status: '异常', confidence: '92%', impact: '高', conclusion: '检测到36处热斑疑似点' },
{ diagnosis: '组串失配', status: '异常', confidence: '90%', impact: '高', conclusion: '8串组串存在异常' },
{ diagnosis: '遮挡风险', status: '轻微', confidence: '78%', impact: '中', conclusion: '局部遮挡影响2%发电量' },
{ diagnosis: '组件衰减', status: '异常', confidence: '86%', impact: '中', conclusion: '平均衰减率-5.32%' },
{ diagnosis: '逆变器效率', status: '正常', confidence: '93%', impact: '低', conclusion: '运行效率稳定' },
{ diagnosis: '清洗收益', status: '建议', confidence: '88%', impact: '中', conclusion: '建议优先清洗B区' },
];
const aiRecommendations = [
{ measure: '处理劣质组件', priority: '高', expectedGain: '+2.15%', confidence: '92%' },
{ measure: '排查异常组串', priority: '高', expectedGain: '+1.85%', confidence: '90%' },
{ measure: '清洗受遮挡区域', priority: '中', expectedGain: '+0.45%', confidence: '78%' },
{ measure: '跟踪衰减组件', priority: '中', expectedGain: '+0.35%', confidence: '86%' },
{ measure: '持续监控逆变器效率', priority: '低', expectedGain: '+0.10%', confidence: '93%' },
{ measure: '复核电压波动点', priority: '中', expectedGain: '+0.28%', confidence: '82%' },
];
const thermalImagingData = [
{ title: '热斑异常', name: '方阵A-05', temp: '71.5℃', image: '' },
{ title: '高温风险', name: '方阵A-12', temp: '68.3℃', image: '' },
{ title: '疑似遮挡', name: '方阵B-03', temp: '64.8℃', image: '' },
{ title: '热斑异常', name: '方阵C-07', temp: '67.2℃', image: '' },
{ title: '轻微升温', name: '方阵D-11', temp: '58.9℃', image: '' },
{ title: '组件衰减', name: '方阵E-18', temp: '62.4℃', image: '' },
];
// 图表配置
const degradationConfig = {
data: [
{ date: 'D1', 平均衰减率: 0, 最佳组件: 0, 最差组件: -1 },
{ date: 'D4', 平均衰减率: -1, 最佳组件: -0.5, 最差组件: -2 },
{ date: 'D7', 平均衰减率: -1.5, 最佳组件: -0.8, 最差组件: -3 },
{ date: 'D10', 平均衰减率: -2, 最佳组件: -1, 最差组件: -4 },
{ date: 'D13', 平均衰减率: -2.5, 最佳组件: -1.2, 最差组件: -5 },
{ date: 'D16', 平均衰减率: -3, 最佳组件: -1.5, 最差组件: -6 },
{ date: 'D19', 平均衰减率: -3.5, 最佳组件: -1.8, 最差组件: -7 },
{ date: 'D22', 平均衰减率: -4, 最佳组件: -2, 最差组件: -8 },
{ date: 'D25', 平均衰减率: -4.5, 最佳组件: -2.2, 最差组件: -9 },
{ date: 'D28', 平均衰减率: -5.32, 最佳组件: -2.5, 最差组件: -10 },
],
xField: 'date',
yField: ['平均衰减率', '最佳组件', '最差组件'],
color: ['#1890ff', '#52c41a', '#faad14'],
smooth: true,
areaStyle: { fillOpacity: 0.15 },
legend: { position: 'top-left' },
};
const generationConfig = {
data: [
{ time: '00:00', 实际发电: 50, 预测发电: 60, 理论发电: 80 },
{ time: '03:00', 实际发电: 50, 预测发电: 60, 理论发电: 80 },
{ time: '06:00', 实际发电: 100, 预测发电: 120, 理论发电: 150 },
{ time: '09:00', 实际发电: 800, 预测发电: 900, 理论发电: 1000 },
{ time: '12:00', 实际发电: 1400, 预测发电: 1600, 理论发电: 1800 },
{ time: '15:00', 实际发电: 1200, 预测发电: 1400, 理论发电: 1600 },
{ time: '18:00', 实际发电: 600, 预测发电: 700, 理论发电: 800 },
{ time: '21:00', 实际发电: 100, 预测发电: 120, 理论发电: 150 },
{ time: '24:00', 实际发电: 50, 预测发电: 60, 理论发电: 80 },
{ time: '27:00', 实际发电: 50, 预测发电: 60, 理论发电: 80 },
],
xField: 'time',
yField: ['实际发电', '预测发电', '理论发电'],
color: ['#1890ff', '#52c41a', '#faad14'],
smooth: true,
areaStyle: { fillOpacity: 0.15 },
legend: { position: 'top' },
};
export default function AIDiagnosisPage() {
const [drawerVisible, setDrawerVisible] = useState(false);
const [selectedTask, setSelectedTask] = useState<any>(null);
// 状态标签渲染
const renderStatusTag = (status: string) => {
const statusMap: Record<string, React.ReactNode> = {
'异常': <Tag color="red">异常</Tag>,
'正常': <Tag color="green">正常</Tag>,
'轻微': <Tag color="orange">轻微</Tag>,
'建议': <Tag color="blue">建议</Tag>,
};
return statusMap[status] || <Tag>{status}</Tag>;
};
const renderPriorityTag = (priority: string) => {
const colorMap: Record<string, string> = { '高': 'red', '中': 'orange', '低': 'green' };
return <Tag color={colorMap[priority]}>{priority}</Tag>;
};
return (
<div style={{ background: '#f5f7fa', minHeight: '100vh', padding: 24 }}>
{/* 顶部标题和操作 */}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 24 }}>
<div>
<Title level={4} style={{ margin: 0 }}>AI诊断分析</Title>
<Text type="secondary">无人机热成像、组串异常定位、发电偏差与AI处置建议</Text>
</div>
<Space>
<Button icon={<ReloadOutlined />}>刷新</Button>
<Button type="primary" icon={<PlusOutlined />}>新建诊断任务</Button>
</Space>
</div>
{/* 顶部指标卡片 */}
<Row gutter={16} style={{ marginBottom: 24 }}>
<Col span={4}>
<Card bordered={false} style={{ borderRadius: 8 }}>
<Statistic
title="PR值"
value={82.6}
precision={1}
suffix="%"
valueStyle={{ color: '#52c41a', fontSize: 28, fontWeight: 700 }}
prefix={<div style={{ background: '#e6f7ff', borderRadius: '50%', width: 36, height: 36, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>AI</div>}
/>
<div style={{ fontSize: 12, color: '#999' }}>较昨日 -1.3% <ArrowDownOutlined style={{ color: '#ff4d4f' }} /></div>
</Card>
</Col>
<Col span={4}>
<Card bordered={false} style={{ borderRadius: 8 }}>
<Statistic
title="发电偏差"
value={-4.35}
precision={2}
suffix="%"
valueStyle={{ color: '#ff4d4f', fontSize: 28, fontWeight: 700 }}
prefix={<ArrowDownOutlined />}
/>
<div style={{ fontSize: 12, color: '#999' }}>较昨日 -1.02% <ArrowDownOutlined style={{ color: '#ff4d4f' }} /></div>
</Card>
</Col>
<Col span={4}>
<Card bordered={false} style={{ borderRadius: 8 }}>
<Statistic
title="异常组串数量"
value={8}
suffix="组"
valueStyle={{ color: '#faad14', fontSize: 28, fontWeight: 700 }}
prefix={<div style={{ background: '#fff7e6', borderRadius: '50%', width: 36, height: 36, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>▦</div>}
/>
<div style={{ fontSize: 12, color: '#999' }}>较昨日 +2 <ArrowUpOutlined style={{ color: '#52c41a' }} /></div>
</Card>
</Col>
<Col span={4}>
<Card bordered={false} style={{ borderRadius: 8 }}>
<Statistic
title="热斑疑似数量"
value={36}
suffix="处"
valueStyle={{ color: '#ff4d4f', fontSize: 28, fontWeight: 700 }}
prefix={<div style={{ background: '#fff2f0', borderRadius: '50%', width: 36, height: 36, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><span style={{ width: 8, height: 8, borderRadius: '50%', background: '#ff4d4f' }}></span></div>}
/>
<div style={{ fontSize: 12, color: '#999' }}>较昨日 +5 <ArrowUpOutlined style={{ color: '#52c41a' }} /></div>
</Card>
</Col>
<Col span={4}>
<Card bordered={false} style={{ borderRadius: 8 }}>
<Statistic
title="健康度评分"
value={86.3}
precision={1}
suffix="分"
valueStyle={{ color: '#52c41a', fontSize: 28, fontWeight: 700 }}
prefix={<CheckCircleOutlined style={{ color: '#52c41a' }} />}
/>
<div style={{ fontSize: 12, color: '#999' }}>较昨日 -1.7 <ArrowDownOutlined style={{ color: '#ff4d4f' }} /></div>
</Card>
</Col>
<Col span={4}>
<Card bordered={false} style={{ borderRadius: 8 }}>
<Statistic
title="预测发电量"
value={4821}
suffix="kWh"
valueStyle={{ color: '#722ed1', fontSize: 28, fontWeight: 700 }}
prefix={<div style={{ background: '#f9f0ff', borderRadius: '50%', width: 36, height: 36, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>⚡</div>}
/>
<div style={{ fontSize: 12, color: '#999' }}>较昨日 +2.6% <ArrowUpOutlined style={{ color: '#52c41a' }} /></div>
</Card>
</Col>
</Row>
{/* 热成像和组串定位 */}
<Row gutter={16} style={{ marginBottom: 24 }}>
<Col span={12}>
<Card
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>热成像分析(无人机巡检)</span>}
bordered={false}
style={{ borderRadius: 8 }}
extra={<Text type="secondary" style={{ fontSize: 12 }}>巡检时间:2026-05-06 09:30</Text>}
>
<Row gutter={[12, 12]}>
{thermalImagingData.map((item, idx) => (
<Col span={8} key={idx}>
<div style={{ position: 'relative', background: '#f0f2f5', borderRadius: 8, height: 120, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<div style={{ position: 'absolute', top: 8, left: 8, background: item.title === '热斑异常' ? '#ff4d4f' : item.title === '高温风险' ? '#faad14' : item.title === '疑似遮挡' ? '#1890ff' : '#52c41a', color: '#fff', padding: '2px 6px', borderRadius: 4, fontSize: 12 }}>
{item.title}
</div>
<div style={{ position: 'absolute', bottom: 8, left: 8 }}>
<div style={{ fontSize: 14, fontWeight: 600 }}>{item.name}</div>
<div style={{ fontSize: 12, color: '#666' }}>{item.temp}</div>
</div>
</div>
</Col>
))}
</Row>
<div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 16, fontSize: 12, color: '#999' }}>
<div style={{ display: 'flex', gap: 16 }}>
<span style={{ display: 'flex', alignItems: 'center' }}><span style={{ width: 10, height: 10, borderRadius: '50%', background: '#ff4d4f', marginRight: 4 }}></span>热斑疑似点</span>
<span style={{ display: 'flex', alignItems: 'center' }}><span style={{ width: 10, height: 10, borderRadius: '50%', background: '#faad14', marginRight: 4 }}></span>高温区域</span>
</div>
<span>温度范围:25℃ - 85℃</span>
</div>
</Card>
</Col>
<Col span={12}>
<Card
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>组串异常定位</span>}
bordered={false}
style={{ borderRadius: 8, height: "100%" }}
extra={<div style={{ display: 'flex', alignItems: 'center' }}><Text type="secondary" style={{ fontSize: 12 }}>20列 × 8排二维矩阵,点击点位查看详情</Text><Tag color="red" style={{ marginLeft: 8 }}>异常组串:8</Tag></div>}
>
<div style={{ display: 'flex', gap: 16 }}>
<div style={{ flex: 1 }}>
{/* 组串矩阵模拟 */}
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(20, 1fr)', gap: 4 }}>
{Array.from({ length: 8 }).map((_, row) =>
Array.from({ length: 20 }).map((_, col) => {
const isNormal = true;
const isLight = (row === 4 && col === 2);
const isAbnormal = (row === 1 && col === 1) || (row === 1 && col === 10) || (row === 3 && col === 15) || (row === 5 && col === 18);
const isSevere = (row === 0 && col === 8) || (row === 3 && col === 8);
let bgColor = '#91d5ff'; // 正常
if (isLight) bgColor = '#e6f7ff';
if (isAbnormal) bgColor = '#faad14';
if (isSevere) bgColor = '#ff4d4f';
return (
<div
key={`${row}-${col}`}
style={{
width: 16, height: 16, background: bgColor, borderRadius: 2, cursor: 'pointer'
}}
onClick={() => {
setSelectedTask({
id: `A-${col + 1}`,
temp: isSevere ? '75℃' : '68℃',
deviation: '-18.6%',
count: 3,
level: isSevere ? '严重异常' : '异常'
});
setDrawerVisible(true);
}}
/>
);
})
)}
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 16, fontSize: 12 }}>
<span style={{ display: 'flex', alignItems: 'center' }}><span style={{ width: 10, height: 10, background: '#91d5ff', marginRight: 4 }}></span>正常</span>
<span style={{ display: 'flex', alignItems: 'center' }}><span style={{ width: 10, height: 10, background: '#e6f7ff', marginRight: 4 }}></span>轻微异常</span>
<span style={{ display: 'flex', alignItems: 'center' }}><span style={{ width: 10, height: 10, background: '#faad14', marginRight: 4 }}></span>异常</span>
<span style={{ display: 'flex', alignItems: 'center' }}><span style={{ width: 10, height: 10, background: '#ff4d4f', marginRight: 4 }}></span>严重异常</span>
</div>
</div>
<div style={{ width: 180, borderLeft: '1px solid #f0f0f0', paddingLeft: 16 }}>
<div style={{ marginBottom: 12 }}>
<div style={{ fontWeight: 600, marginBottom: 4 }}>A-03</div>
<div style={{ fontSize: 12, color: '#999', marginBottom: 2 }}>温度 <span style={{ color: '#ff4d4f' }}>75℃</span></div>
<div style={{ fontSize: 12, color: '#999', marginBottom: 2 }}>发电偏差 <span style={{ color: '#ff4d4f' }}>-18.6%</span></div>
<div style={{ fontSize: 12, color: '#999', marginBottom: 2 }}>历史异常 3 次</div>
<div style={{ fontSize: 12, color: '#ff4d4f' }}>等级:严重异常</div>
</div>
<Button type="primary" block size="small" onClick={() => setDrawerVisible(true)}>查看详情</Button>
</div>
</div>
</Card>
</Col>
</Row>
{/* 图表和表格 */}
<Row gutter={16} style={{ marginBottom: 24, height: '285px' }}>
<Col span={8}>
<Card
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>组件衰减分析</span>}
bordered={false}
style={{ borderRadius: 8 }}
>
<Line {...degradationConfig} height={180} />
</Card>
</Col>
<Col span={8}>
<Card
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>发电表现分析</span>}
bordered={false}
style={{ borderRadius: 8 }}
>
<Line {...generationConfig} height={180} />
</Card>
</Col>
<Col span={8} style={{ height: '100%' }}>
<Card
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>AI诊断总结</span>}
bordered={false}
style={{ borderRadius: 8, height: '100%' }}
extra={<Text type="secondary" style={{ fontSize: 12 }}>模型置信度与影响程度</Text>}
>
{/* 关键:给 Table 设置固定高度 + 滚动 */}
<div style={{ height: "200px", overflow: "auto" }}>
<Table
columns={[
{ title: '诊断项', dataIndex: 'diagnosis', width: 100 },
{ title: '状态', dataIndex: 'status', render: renderStatusTag, width: 80 },
{ title: '置信度', dataIndex: 'confidence', width: 80 },
{ title: '影响', dataIndex: 'impact', width: 60 },
{ title: '结论', dataIndex: 'conclusion' },
]}
dataSource={aiSummaryData}
pagination={false}
size="small"
scroll={{ y: undefined }} // 关闭内部滚动,使用外层滚动
/>
</div>
</Card>
</Col>
</Row>
{/* 数据来源和AI建议 */}
<Row gutter={16} style={{ marginTop: 16 }}>
<Col span={12}>
<Card
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>数据来源状态</span>}
bordered={false}
style={{ borderRadius: 8, height: '100%' }}
extra={<Text type="secondary" style={{ fontSize: 12 }}>多源数据融合质量</Text>}
>
<Row gutter={16}>
<Col span={12}>
<div style={{ textAlign: 'center', padding: 12, background: '#f5f7fa', borderRadius: 8 }}>
<div style={{ fontSize: 16, fontWeight: 600, color: '#1890ff' }}>UAV</div>
<div style={{ fontSize: 12, marginTop: 4 }}>无人机</div>
<div style={{ fontSize: 10, color: '#52c41a' }}>数据状态:正常</div>
</div>
</Col>
<Col span={12}>
<div style={{ textAlign: 'center', padding: 12, background: '#f5f7fa', borderRadius: 8 }}>
<div style={{ fontSize: 16, fontWeight: 600, color: '#1890ff' }}>DB</div>
<div style={{ fontSize: 12, marginTop: 4 }}>SCA</div>
<div style={{ fontSize: 10, color: '#52c41a' }}>数据状态:正常</div>
</div>
</Col>
</Row>
<Row gutter={16} style={{ marginTop: 16 }}>
<Col span={12}>
<div style={{ textAlign: 'center', padding: 12, background: '#f5f7fa', borderRadius: 8 }}>
<div style={{ fontSize: 16, fontWeight: 600, color: '#1890ff' }}>UAV</div>
<div style={{ fontSize: 12, marginTop: 4 }}>无人机</div>
<div style={{ fontSize: 10, color: '#52c41a' }}>数据状态:正常</div>
</div>
</Col>
<Col span={12}>
<div style={{ textAlign: 'center', padding: 12, background: '#f5f7fa', borderRadius: 8 }}>
<div style={{ fontSize: 16, fontWeight: 600, color: '#1890ff' }}>UAV</div>
<div style={{ fontSize: 12, marginTop: 4 }}>无人机</div>
<div style={{ fontSize: 10, color: '#52c41a' }}>数据状态:正常</div>
</div>
</Col>
</Row>
</Card>
</Col>
<Col span={12}>
<Card
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>AI建议与处置</span>}
bordered={false}
style={{ borderRadius: 8 }}
extra={<Text type="secondary" style={{ fontSize: 12 }}>按收益、优先级与置信度排序</Text>}
>
{/* 👇 关键:外层包一层 div,设置高度 + 滚动 */}
<div style={{ height: 220, overflow: "auto" }}>
<Table
columns={[
{ title: '建议措施', dataIndex: 'measure' },
{ title: '优先级', dataIndex: 'priority', render: renderPriorityTag, width: 80 },
{ title: '预计收益', dataIndex: 'expectedGain', width: 80 },
{ title: '置信度', dataIndex: 'confidence', width: 80 },
{
title: '操作', width: 120, render: () => (
<Space>
<Button type="link" size="small">详情</Button>
<Button type="link" size="small">工单</Button>
</Space>
)
},
]}
dataSource={aiRecommendations}
pagination={false}
size="small"
scroll={{ y: undefined }}
/>
</div>
</Card>
</Col>
</Row>
{/* 二级入口按钮 */}
<Card bordered={false} style={{ borderRadius: 8, marginTop: 16 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
<div>
<Title level={5} style={{ margin: 0, color: '#0837A8' }}>二级入口</Title>
<Text type="secondary" style={{ fontSize: 12 }}>原诊断任务、热斑结果、AI建议、诊断报告保留为操作入口</Text>
</div>
<Space>
<Button onClick={() => message.info('跳转到诊断任务')}>诊断任务</Button>
<Button onClick={() => message.info('跳转到热斑结果')}>热斑结果</Button>
<Button onClick={() => message.info('跳转到AI建议')}>AI建议</Button>
<Button onClick={() => message.info('跳转到诊断报告')}>诊断报告</Button>
</Space>
</div>
</Card>
{/* 抽屉详情 */}
<Drawer
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>AI诊断详情</span>}
placement="right"
onClose={() => setDrawerVisible(false)}
open={drawerVisible}
width={600}
>
{selectedTask && (
<div>
<Row gutter={16} style={{ marginBottom: 24 }}>
<Col span={12}>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
<Text strong>任务</Text>
<Text>AIT-DEMO-HEALTH-01</Text>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
<Text strong>算法</Text>
<Text>设备健康演示算法</Text>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
<Text strong>结果</Text>
<Text>RES-DEMO-INV-A02</Text>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
<Text strong>最高温</Text>
<Text>{selectedTask.temp}</Text>
</div>
</Col>
<Col span={12}>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
<Text strong>状态</Text>
<Text>SUCCESS</Text>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
<Text strong>进度</Text>
<Text>100%</Text>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
<Text strong>等级</Text>
<Text>{selectedTask.level}</Text>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
<Text strong>置信度</Text>
<Text>90%</Text>
</div>
</Col>
</Row>
<div style={{ marginBottom: 24 }}>
<Text strong>摘要</Text>
<div style={{ background: '#f5f7fa', padding: 12, borderRadius: 8, marginTop: 8 }}>
结合遥感数据发现逆变器温度偏高且功率波动,建议检修散热。
</div>
</div>
<div style={{ marginBottom: 24 }}>
<Text strong>图片/热成像文件</Text>
<Row gutter={16} style={{ marginTop: 12 }}>
<Col span={8}>
<div style={{ background: '#f0f2f5', borderRadius: 8, height: 100, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Text type="secondary">方阵A-05<br />热点异常 · 71.5℃</Text>
</div>
</Col>
<Col span={8}>
<div style={{ background: '#f0f2f5', borderRadius: 8, height: 100, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Text type="secondary">方阵A-12<br />高温风险 · 68.3℃</Text>
</div>
</Col>
<Col span={8}>
<div style={{ background: '#f0f2f5', borderRadius: 8, height: 100, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Text type="secondary">方阵B-03<br />疑似遮挡 · 64.8℃</Text>
</div>
</Col>
</Row>
</div>
<div style={{ marginBottom: 24 }}>
<Text strong>热斑列表</Text>
<Table
columns={[
{ title: '热斑编码', dataIndex: 'id' },
{ title: '组件', dataIndex: 'component' },
{ title: '最高温', dataIndex: 'temp' },
{ title: '温差', dataIndex: 'diff' },
{ title: '等级', dataIndex: 'level' },
]}
dataSource={[]}
pagination={false}
size="small"
/>
</div>
<div>
<Text strong>AI JSON摘要</Text>
<pre style={{ background: '#111827', color: '#fff', padding: 12, borderRadius: 8, marginTop: 8, fontSize: 12 }}>
{`{
"demo": true,
"metric": [
"temperature",
"activePower"
]
}`}
</pre>
</div>
</div>
)}
</Drawer>
</div>
);
}

View File

@@ -6,7 +6,6 @@ import {
MinusOutlined, PlusOutlined, SyncOutlined
} from '@ant-design/icons';
import { Line, Bar, Pie } from '@ant-design/charts';
import { getOverflowOptions } from 'antd/es/_util/placements';
const { Text } = Typography;
@@ -177,7 +176,7 @@ export default function StationDashboard() {
{/* 左侧图表列 - 最终完美版:不溢出 + 一定可见 */}
<Col xs={24} lg={6} style={{ flex: '0 0 25%', padding: '0 8px', display: 'flex', flexDirection: 'column', height: '100%', gap: "8px", overflowX: 'hidden', overflowY: 'auto', scrollbarWidth: 'thin', scrollbarColor: '#ccc transparent' }}>
<Card
title="发电趋势"
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>发电趋势</span>}
bordered={false}
style={{
...cardStyle,
@@ -198,7 +197,7 @@ export default function StationDashboard() {
</Card>
<Card
title="辐照度与温度"
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>辐照度与温度</span>}
bordered={false}
style={{
...cardStyle,
@@ -219,7 +218,7 @@ export default function StationDashboard() {
</Card>
<Card
title="逆变器效率"
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>逆变器效率</span>}
bordered={false}
style={{
...cardStyle,
@@ -240,7 +239,7 @@ export default function StationDashboard() {
</Card>
<Card
title="运维任务进度"
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>运维任务进度</span>}
bordered={false}
style={{
...cardStyle,
@@ -267,7 +266,7 @@ export default function StationDashboard() {
title={
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<div style={{ fontWeight: 500 }}>电站概览</div>
<div style={{ fontWeight: 500, color: '#0837A8' }}>电站概览</div>
<div style={{ fontSize: 12, color: '#999' }}>GeoTIFF 正射底图 · 设备点位叠加</div>
</div>
@@ -319,7 +318,7 @@ export default function StationDashboard() {
<Card
title={
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ fontWeight: 600, fontSize: 14 }}>实时告警</span> {/* 缩小标题 */}
<span style={{ fontWeight: 600, fontSize: 14, color: '#0837A8' }}>实时告警</span>
<Button type="link" style={{ padding: 0, fontSize: 12 }}>更多</Button>
</div>
}
@@ -338,7 +337,7 @@ export default function StationDashboard() {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: idx === realtimeAlerts.length - 1 ? 0 : 8, // 缩小行间距
marginBottom: idx === realtimeAlerts.length - 1 ? 0 : 8,
fontSize: 12
}}
>
@@ -358,7 +357,7 @@ export default function StationDashboard() {
<span style={{ width: 6, height: 6, borderRadius: '50%', background: '#fff' }}></span>
{alert.level}
</Tag>
<span style={{ fontSize: 12 }}>{alert.type}</span> {/* 缩小 */}
<span style={{ fontSize: 12 }}>{alert.type}</span>
</div>
<span style={{ color: '#666', fontSize: 12 }}>{alert.time}</span>
</div>
@@ -367,7 +366,7 @@ export default function StationDashboard() {
{/* 设备在线状态 */}
<Card
title={<span style={{ fontWeight: 600, fontSize: 14 }}>设备在线状态</span>}
title={<span style={{ fontWeight: 600, fontSize: 14, color: '#0837A8' }}>设备在线状态</span>}
bordered={false}
style={{
borderRadius: 8,
@@ -400,7 +399,7 @@ export default function StationDashboard() {
{/* 天气信息 */}
<Card
title={<span style={{ fontWeight: 600, fontSize: 14 }}>天气信息</span>}
title={<span style={{ fontWeight: 600, fontSize: 14, color: '#0837A8' }}>天气信息</span>}
bordered={false}
style={{
borderRadius: 8,
@@ -421,13 +420,7 @@ export default function StationDashboard() {
<div style={{ fontSize: 11, color: '#999' }}>风速 4.1 m/s</div>
<div style={{ fontSize: 11, color: '#999' }}>中卫市</div>
</div>
</div>
</div>
</Card>
@@ -435,7 +428,7 @@ export default function StationDashboard() {
<Card
title={
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ fontWeight: 600, fontSize: 14 }}>清洗建议</span>
<span style={{ fontWeight: 600, fontSize: 14, color: '#0837A8' }}>清洗建议</span>
<Button type="link" style={{ padding: 0, fontSize: 12 }}>详情</Button>
</div>
}
@@ -475,7 +468,12 @@ export default function StationDashboard() {
</Row>
<Row gutter={16} style={{ height: '25%' }} >
<Col xs={12} style={{ height: '100%' }}>
<Card title="近期巡检记录" bordered={false} style={{ ...cardStyle, height: '100%' }} bodyStyle={{ padding: 12, height: '66%', overflow: 'auto', scrollbarWidth: 'thin', scrollbarColor: '#ccc transparent' }}>
<Card
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>近期巡检记录</span>}
bordered={false}
style={{ ...cardStyle, height: '100%' }}
bodyStyle={{ padding: 12, height: '66%', overflow: 'auto', scrollbarWidth: 'thin', scrollbarColor: '#ccc transparent' }}
>
{patrolRecords.map((item, idx) => (
<div key={idx} style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 10 }}>
<div>
@@ -490,7 +488,12 @@ export default function StationDashboard() {
</Card>
</Col>
<Col xs={12} style={{ height: '100%', }}>
<Card title="AI分析摘要" bordered={false} style={{ ...cardStyle, height: '100%' }} bodyStyle={{ padding: 12, height: '66%', overflow: 'auto', scrollbarWidth: 'thin', scrollbarColor: '#ccc transparent' }}>
<Card
title={<span style={{ color: '#0837A8', fontWeight: 600 }}>AI分析摘要</span>}
bordered={false}
style={{ ...cardStyle, height: '100%' }}
bodyStyle={{ padding: 12, height: '66%', overflow: 'auto', scrollbarWidth: 'thin', scrollbarColor: '#ccc transparent' }}
>
{aiAnalysis.map((item, idx) => (
<div key={idx} style={{ display: 'flex', marginBottom: 10 }}>
<Tag color={item.type === 'AI分析' ? 'blue' : 'red'} style={{ marginRight: 8 }}>{item.type}</Tag>
@@ -502,8 +505,6 @@ export default function StationDashboard() {
</Row>
</Col>
</Row >
</div >
);

View File

@@ -199,6 +199,11 @@ export default function SystemSettings() {
};
return (
<Layout style={{ minHeight: '100vh', background: '#fff', overflow: 'hidden' }}>
<div style={{ padding: '20px 24px 0' }}>
<Typography.Title level={4} style={{ margin: 0 }}>系统设置</Typography.Title>
<Text type="secondary"> 告警规则配置、用户角色、通知管理与系统参数设置
</Text>
</div>
<Header style={{ background: '#fff', padding: 0, borderBottom: '1px solid #f0f0f0', position: 'sticky', top: 0, zIndex: 10 }}>
<Menu
mode="horizontal"

View File

@@ -50,68 +50,68 @@ export default function VideoMonitorPage() {
return (
<div className="p-6 bg-[#f5f7fa] min-h-screen">
{/* ========== 顶部统计卡片:统一高度 ========== */}
<Row gutter={[16, 16]} className="mb-6">
<Col xs={24} sm={12} md={8} lg={4}>
<Card className="h-full">
<div className="flex justify-between items-center">
<Row gutter={[16, 16]} style={{ marginBottom: 16, display: 'flex', alignItems: 'stretch' }}>
<Col style={{ flex: 1 }}>
<Card bordered={false} style={{ borderRadius: 8, height: '100%' }} bodyStyle={{ padding: '16px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<div className="text-2xl font-bold">32 台</div>
<div className="text-gray-600 mt-1">在线摄像头</div>
<div className="text-xs text-gray-500 mt-1">在线率 <span className="text-green-500">↑ 4.1%</span></div>
<div style={{ fontSize: 24, fontWeight: 700 }}>32 台</div>
<div style={{ color: '#0837A8', fontSize: 14, marginTop: 4 }}>在线摄像头</div>
<div style={{ fontSize: 12, color: '#999', marginTop: 4 }}>在线率 <span style={{ color: '#52c41a' }}>↑ 4.1%</span></div>
</div>
<VideoCameraOutlined className="text-3xl text-blue-500" />
<VideoCameraOutlined style={{ fontSize: 28, color: '#1890ff' }} />
</div>
</Card>
</Col>
<Col xs={24} sm={12} md={8} lg={4}>
<Card className="h-full">
<div className="flex justify-between items-center">
<Col style={{ flex: 1 }}>
<Card bordered={false} style={{ borderRadius: 8, height: '100%' }} bodyStyle={{ padding: '16px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<div className="text-2xl font-bold">2 台</div>
<div className="text-gray-600 mt-1">离线摄像头</div>
<div className="text-xs text-gray-500 mt-1">离线率 <span className="text-red-500">↑ 5.9%</span></div>
<div style={{ fontSize: 24, fontWeight: 700 }}>2 台</div>
<div style={{ color: '#0837A8', fontSize: 14, marginTop: 4 }}>离线摄像头</div>
<div style={{ fontSize: 12, color: '#999', marginTop: 4 }}>离线率 <span style={{ color: '#ff4d4f' }}>↑ 5.9%</span></div>
</div>
<VideoCameraOutlined className="text-3xl text-gray-400" />
<VideoCameraOutlined style={{ fontSize: 28, color: '#999' }} />
</div>
</Card>
</Col>
<Col xs={24} sm={12} md={8} lg={4}>
<Card className="h-full">
<div className="flex justify-between items-center">
<Col style={{ flex: 1 }}>
<Card bordered={false} style={{ borderRadius: 8, height: '100%' }} bodyStyle={{ padding: '16px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<div className="text-2xl font-bold">6 起</div>
<div className="text-gray-600 mt-1">今日告警事件</div>
<div className="text-xs text-gray-500 mt-1">较昨日 <span className="text-red-500">↑ 50%</span></div>
<div style={{ fontSize: 24, fontWeight: 700 }}>6 起</div>
<div style={{ color: '#0837A8', fontSize: 14, marginTop: 4 }}>今日告警事件</div>
<div style={{ fontSize: 12, color: '#999', marginTop: 4 }}>较昨日 <span style={{ color: '#ff4d4f' }}>↑ 50%</span></div>
</div>
<BellOutlined className="text-3xl text-orange-500" />
<BellOutlined style={{ fontSize: 28, color: '#faad14' }} />
</div>
</Card>
</Col>
<Col xs={24} sm={12} md={8} lg={4}>
<Card className="h-full">
<div className="flex justify-between items-center">
<Col style={{ flex: 1 }}>
<Card bordered={false} style={{ borderRadius: 8, height: '100%' }} bodyStyle={{ padding: '16px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<div className="text-2xl font-bold">2 起</div>
<div className="text-gray-600 mt-1">周界告警</div>
<div className="text-xs text-gray-500 mt-1">较昨日 <span className="text-red-500">↑ 100%</span></div>
<div style={{ fontSize: 24, fontWeight: 700 }}>2 起</div>
<div style={{ color: '#0837A8', fontSize: 14, marginTop: 4 }}>周界告警</div>
<div style={{ fontSize: 12, color: '#999', marginTop: 4 }}>较昨日 <span style={{ color: '#ff4d4f' }}>↑ 100%</span></div>
</div>
<BorderOutlined className="text-3xl text-red-500" />
<BorderOutlined style={{ fontSize: 28, color: '#ff4d4f' }} />
</div>
</Card>
</Col>
<Col xs={24} sm={12} md={8} lg={4}>
<Card className="h-full">
<div className="flex justify-between items-center">
<Col style={{ flex: 1 }}>
<Card bordered={false} style={{ borderRadius: 8, height: '100%' }} bodyStyle={{ padding: '16px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<div className="text-2xl font-bold">78.6TB</div>
<div className="text-gray-600 mt-1">存储使用率</div>
<div className="text-xs text-gray-500 mt-1">使用率 <span className="text-green-500">65.5%</span></div>
<div style={{ fontSize: 24, fontWeight: 700 }}>78.6TB</div>
<div style={{ color: '#0837A8', fontSize: 14, marginTop: 4 }}>存储使用率</div>
<div style={{ fontSize: 12, color: '#999', marginTop: 4 }}>使用率 <span style={{ color: '#52c41a' }}>65.5%</span></div>
</div>
<DatabaseOutlined className="text-3xl text-blue-500" />
<DatabaseOutlined style={{ fontSize: 28, color: '#1890ff' }} />
</div>
</Card>
</Col>

View File

@@ -2,6 +2,7 @@ import React, { lazy, Suspense } from 'react';
import { createBrowserRouter } from 'react-router-dom';
import type { RouteObject } from 'react-router-dom';
import VideoMonitorPage from '../pages/VideoMonitorPage';
import AIDiagnosisPage from '../pages/AIAnalysis';
const Layout = lazy(() => import('../components/Layout'));
const ProtectedRoute = lazy(() => import('../components/ProtectedRoute'));
@@ -82,7 +83,9 @@ const routes: RouteObject[] = [
{ path: 'video', element: <Video /> },
{ path: 'monitor', element: <VideoMonitorPage /> },
{ path: 'alerts', element: <Alerts /> },
{ path: 'AIanalysis', element: <div>AI诊断分析</div> },
{
path: 'AIanalysis', element: <AIDiagnosisPage />
},
{ path: 'clean', element: <div>清洗优化</div> },
{ path: 'task', element: <div>工单任务</div> },
{ path: 'table', element: <div>报表中心</div> },