You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

748 lines
29 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import React, { useEffect, useRef, useState } from 'react';
import { Card, Result, Select, Button } from 'antd';
import { CheckCircleOutlined } from '@ant-design/icons';
import * as echarts from 'echarts';
import StandardTable from '@/components/StandardTable';
import styles from './RiskAssessment.less';
// import './RiskAssessment.less';
import img1 from '@/assets/safe_majorHazard/online_monitoring/img1.png';
import img2 from '@/assets/safe_majorHazard/online_monitoring/img2.png';
import img3 from '@/assets/safe_majorHazard/online_monitoring/img3.png';
import map1 from '@/assets/safe_majorHazard/online_monitoring/map.png';
import risk1 from '@/assets/safe_majorHazard/online_monitoring/risk1.png';
import risk2 from '@/assets/safe_majorHazard/online_monitoring/risk2.png';
import risk3 from '@/assets/safe_majorHazard/online_monitoring/risk3.png';
const RiskAssessment = () => {
const chartRef = useRef(null);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [selectedRows, setSelectedRows] = useState([]);
const [loading, setLoading] = useState(false);
const [dataSource, setDataSource] = useState([]);
const [pagination, setPagination] = useState({
current: 1,
pageSize: 5,
total: 0,
});
useEffect(() => {
if (chartRef.current) {
const chart = echarts.init(chartRef.current);
// 强制初始化时调整大小
setTimeout(() => {
if (chart && !chart.isDisposed()) {
chart.resize();
}
}, 100);
const option = {
color: ['#FF2526', '#FF8800', '#FFC403', '#65E5F9'],
legend: {
data: ['重大风险', '较高风险', '一般风险', '低风险'],
top: "-3px",
left: "center",
itemGap: 40,
itemWidth: 20,
itemHeight: 9,
textStyle: {
fontSize: 10
}
},
grid: {
left: '2%',
right: '4%',
bottom: '2%',
top: '12%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['9/22', '9/23', '9/24', '9/25', '9/26', '9/27', '9/28'],
axisLabel: {
fontSize: 10
}
},
yAxis: {
type: 'value',
min: 0,
max: 30,
axisLabel: {
formatter: '{value}',
fontSize: 10
}
},
series: [
{
name: '重大风险',
type: 'line',
smooth: true,
lineStyle: {
width: 1.5,
color: '#FF2526'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(38, 12, 12, 0.4)' },
{ offset: 1, color: 'rgba(255, 37, 38, 0)' }
]
}
},
symbol: 'none',
symbolSize: 6,
itemStyle: {
color: '#fff',
borderColor: '#FF2526',
borderWidth: 1
},
data: [8, 15, 12, 22, 18, 26, 20]
},
{
name: '较高风险',
type: 'line',
smooth: true,
lineStyle: {
width: 1.5,
color: '#FF8800'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(255, 136, 0, 0.4)' },
{ offset: 1, color: 'rgba(255, 136, 0, 0)' }
]
}
},
symbol: 'none',
symbolSize: 6,
itemStyle: {
color: '#fff',
borderColor: '#FF8800',
borderWidth: 1
},
data: [5, 8, 6, 12, 10, 15, 13]
},
{
name: '一般风险',
type: 'line',
smooth: true,
lineStyle: {
width: 1.5,
color: '#FFC403'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(255, 196, 3, 0.4)' },
{ offset: 1, color: 'rgba(255, 196, 3, 0)' }
]
}
},
symbol: 'none',
symbolSize: 6,
itemStyle: {
color: '#fff',
borderColor: '#FFC403',
borderWidth: 1
},
data: [12, 18, 15, 25, 22, 24, 26]
},
{
name: '低风险',
type: 'line',
smooth: true,
lineStyle: {
width: 1.5,
color: '#65E5F9'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(101, 229, 249, 0.4)' },
{ offset: 1, color: 'rgba(101, 229, 249, 0)' }
]
}
},
symbol: 'none',
symbolSize: 6,
itemStyle: {
color: '#fff',
borderColor: '#65E5F9',
borderWidth: 1
},
data: [3, 5, 7, 9, 6, 8, 4]
}
]
};
chart.setOption(option);
// 响应式调整 - 使用多种方式监听容器尺寸变化
let resizeTimer = null;
const handleResize = () => {
// 防抖处理避免频繁调用resize
if (resizeTimer) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(() => {
if (chart && !chart.isDisposed()) {
chart.resize();
}
}, 50); // 减少延迟时间
};
// 监听窗口大小变化
window.addEventListener('resize', handleResize);
// 监听容器尺寸变化(解决菜单栏伸缩时的自适应问题)
let resizeObserver = null;
if (window.ResizeObserver) {
resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
// 使用requestAnimationFrame确保在下一帧执行
requestAnimationFrame(() => {
handleResize();
});
}
});
resizeObserver.observe(chartRef.current);
}
// 额外监听父容器的尺寸变化
const parentContainer = chartRef.current?.parentElement;
let parentObserver = null;
if (parentContainer && window.ResizeObserver) {
parentObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
requestAnimationFrame(() => {
handleResize();
});
}
});
parentObserver.observe(parentContainer);
}
// 使用MutationObserver监听DOM结构变化菜单展开收起时
const mutationObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' &&
(mutation.attributeName === 'class' || mutation.attributeName === 'style')) {
// 延迟执行确保DOM更新完成
setTimeout(() => {
handleResize();
}, 200);
}
});
});
// 监听整个页面的class和style变化
mutationObserver.observe(document.body, {
attributes: true,
attributeFilter: ['class', 'style'],
subtree: true
});
return () => {
window.removeEventListener('resize', handleResize);
if (resizeObserver) {
resizeObserver.disconnect();
}
if (parentObserver) {
parentObserver.disconnect();
}
if (mutationObserver) {
mutationObserver.disconnect();
}
if (resizeTimer) {
clearTimeout(resizeTimer);
}
if (chart && !chart.isDisposed()) {
chart.dispose();
}
};
}
}, []);
// 表格列定义
const columns = [
{
title: '编号',
dataIndex: 'id',
key: 'id',
width: 80,
render: (text, record, index) => {
const page = pagination.current || 1;
const pageSize = pagination.pageSize || 5;
const number = (page - 1) * pageSize + index + 1;
return `0${number}`.slice(-2);
}
},
{
title: '设备编号',
dataIndex: 'deviceId',
key: 'deviceId',
width: 120,
},
{
title: '风险等级',
dataIndex: 'riskLevel',
key: 'riskLevel',
width: 100,
render: (text) => {
const colorMap = {
'高': '#FF4D4F',
'中': '#FAAD14',
'低': '#52C41A'
};
return <span style={{ color: colorMap[text] || '#333' }}>{text}</span>;
}
},
{
title: '预警时间',
dataIndex: 'warningTime',
key: 'warningTime',
width: 150,
},
{
title: '主要原因',
dataIndex: 'mainReason',
key: 'mainReason',
width: 200,
},
{
title: '处理状态',
dataIndex: 'status',
key: 'status',
width: 100,
render: (text) => {
const statusMap = {
'未处理': { color: '#FF4D4F', bg: '#FFF2F0' },
'处理中': { color: '#FAAD14', bg: '#FFFBE6' },
'已处理': { color: '#52C41A', bg: '#F6FFED' }
};
const status = statusMap[text] || { color: '#333', bg: '#F5F5F5' };
return (
<span style={{
color: status.color,
backgroundColor: status.bg,
padding: '2px 8px',
borderRadius: '4px',
fontSize: '12px'
}}>
{text}
</span>
);
}
},
{
title: '操作',
key: 'action',
width: 120,
render: (_, record) => (
<div>
<Button type="link" size="small" style={{ padding: 0, marginRight: 8 }}>
查看
</Button>
<Button type="link" size="small" style={{ padding: 0 }}>
详情
</Button>
</div>
),
},
];
// 模拟数据
const mockData = [
{
key: '1',
id: '001',
deviceId: 'DEV-001',
riskLevel: '高',
warningTime: '2024-01-15 08:30:25',
mainReason: '设备温度异常升高',
status: '未处理',
},
{
key: '2',
id: '002',
deviceId: 'DEV-002',
riskLevel: '中',
warningTime: '2024-01-15 09:15:10',
mainReason: '压力波动超出正常范围',
status: '处理中',
},
{
key: '3',
id: '003',
deviceId: 'DEV-003',
riskLevel: '高',
warningTime: '2024-01-15 10:45:30',
mainReason: '液位传感器故障',
status: '已处理',
},
{
key: '4',
id: '004',
deviceId: 'DEV-004',
riskLevel: '高',
warningTime: '2024-01-15 11:20:45',
mainReason: '检测到气体泄漏',
status: '未处理',
},
{
key: '5',
id: '005',
deviceId: 'DEV-005',
riskLevel: '低',
warningTime: '2024-01-15 12:10:20',
mainReason: '设备振动异常',
status: '已处理',
},
{
key: '6',
id: '006',
deviceId: 'DEV-006',
riskLevel: '中',
warningTime: '2024-01-15 13:25:15',
mainReason: '流量传感器读数异常',
status: '未处理',
},
{
key: '7',
id: '007',
deviceId: 'DEV-007',
riskLevel: '高',
warningTime: '2024-01-15 14:10:30',
mainReason: '储罐压力超限',
status: '处理中',
},
{
key: '8',
id: '008',
deviceId: 'DEV-008',
riskLevel: '中',
warningTime: '2024-01-15 15:45:20',
mainReason: '管道温度异常',
status: '已处理',
},
{
key: '9',
id: '009',
deviceId: 'DEV-009',
riskLevel: '高',
warningTime: '2024-01-15 16:30:45',
mainReason: '阀门控制系统故障',
status: '未处理',
},
{
key: '10',
id: '010',
deviceId: 'DEV-010',
riskLevel: '低',
warningTime: '2024-01-15 17:15:10',
mainReason: '轻微泄漏检测',
status: '已处理',
},
{
key: '11',
id: '011',
deviceId: 'DEV-011',
riskLevel: '高',
warningTime: '2024-01-15 18:20:35',
mainReason: '安全阀异常开启',
status: '处理中',
},
{
key: '12',
id: '012',
deviceId: 'DEV-012',
riskLevel: '中',
warningTime: '2024-01-15 19:05:50',
mainReason: '液位计读数不稳定',
status: '未处理',
},
];
// 初始化数据
useEffect(() => {
setPagination(prev => ({ ...prev, total: mockData.length }));
}, []);
// 根据分页获取当前页数据
const getCurrentPageData = () => {
const { current, pageSize } = pagination;
const startIndex = (current - 1) * pageSize;
const endIndex = startIndex + pageSize;
return mockData.slice(startIndex, endIndex);
};
// 表格选择变化
const onSelectChange = (newSelectedRowKeys, newSelectedRows) => {
setSelectedRowKeys(newSelectedRowKeys);
setSelectedRows(newSelectedRows);
};
// 分页变化处理
const handleTableChange = (pagination) => {
setPagination(prev => ({
...prev,
current: pagination.current,
pageSize: pagination.pageSize,
}));
};
return (
<div className={styles.Rcontainer}>
{/* 第一个div - 高度20% */}
<div className={styles.RcontainerTop}>
<div className={styles.sectionContent}>
<div className={styles.blocksContainer}>
{/* 块1 */}
<div className={styles.blockItem}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>总危险源数量</div>
<div className={styles.blockNumber}>65</div>
<div className={styles.blockChange}>
<span className={styles.arrow}></span>
较昨日 +2
</div>
</div>
<div className={styles.blockRight}>
<img src={img1} alt="总危险源数量" className={styles.blockImage} />
</div>
</div>
{/* 块2 */}
<div className={styles.blockItem}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>高风险设备</div>
<div className={styles.blockNumber}>65</div>
<div className={styles.blockChange}>
<span className={styles.arrow}></span>
较昨日 +2
</div>
</div>
<div className={styles.blockRight}>
<img src={img2} alt="高风险设备" className={styles.blockImage} />
</div>
</div>
{/* 块3 */}
<div className={styles.blockItem}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>今日预警次数</div>
<div className={styles.blockNumber}>65</div>
<div className={styles.blockChange}>
<span className={styles.arrow}></span>
较昨日 -2
</div>
</div>
<div className={styles.blockRight}>
<img src={img3} alt="今日预警次数" className={styles.blockImage} />
</div>
</div>
{/* 块4 */}
<div className={styles.blockItem}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>未处理预警</div>
<div className={styles.blockNumber}>65</div>
<div className={styles.blockChange}>
<span className={styles.arrow}></span>
与昨日持平
</div>
</div>
<div className={styles.blockRight}>
<img src={img1} alt="未处理预警" className={styles.blockImage} />
</div>
</div>
{/* 块5 */}
<div className={styles.blockItem}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>已处理预警</div>
<div className={styles.blockNumber}>65</div>
<div className={styles.blockChange}>
<CheckCircleOutlined className={styles.checkIcon} />
已完成
</div>
</div>
<div className={styles.blockRight}>
<img src={img2} alt="已处理预警" className={styles.blockImage} />
</div>
</div>
</div>
</div>
</div>
<div className={styles.RcontainerMiddle}>
<div className={styles.sectionContent}>
<div className={styles.middleBlock1}>
<div className={styles.block1Header}>
<div className={styles.block1Title}>
<div className={styles.titleIcon}></div>
危险源风险热力分布
</div>
<Select
className={styles.block1Select}
defaultValue="全部区域"
options={[
{ value: '全部区域', label: '全部区域' },
{ value: '区域A', label: '区域A' },
{ value: '区域B', label: '区域B' },
{ value: '区域C', label: '区域C' }
]}
/>
</div>
{/* 风险等级图例 */}
<div className={styles.riskLegend}>
<div className={styles.legendItem}>
<div className={styles.legendDot} style={{ backgroundColor: '#F53F3F' }}></div>
<span className={styles.legendText}>重大风险</span>
</div>
<div className={styles.legendItem}>
<div className={styles.legendDot} style={{ backgroundColor: '#FF7D00' }}></div>
<span className={styles.legendText}>较大风险</span>
</div>
<div className={styles.legendItem}>
<div className={styles.legendDot} style={{ backgroundColor: '#FFAA01' }}></div>
<span className={styles.legendText}>一般风险</span>
</div>
<div className={styles.legendItem}>
<div className={styles.legendDot} style={{ backgroundColor: '#65E5F9' }}></div>
<span className={styles.legendText}>低风险</span>
</div>
</div>
<div className={styles.block1Chart}>
<img src={map1} alt="地图" className={styles.mapImage} />
</div>
</div>
<div className={styles.middleBlock2}>
<div className={styles.middleBlock2Title}>
<div className={styles.titleLeft}>
<div className={styles.titleIcon}></div>
<div>风险等级趋势</div>
</div>
<div className={styles.titleRight}>
<Select
style={{ width: 100 }}
defaultValue="近七天"
options={[
{ value: '近三天', label: '近3天' },
{ value: '近30天', label: '近30天' },
]}
/>
</div>
</div>
<div className={styles.middleBlock2Chart} ref={chartRef}>
</div>
</div>
</div>
</div>
{/* 第三个div - 占满剩余位置 */}
<div className={styles.RcontainerBottom}>
<div className={styles.sectionContent}>
<div className={styles.leftBlock}>
{/* 第一行块 - 蓝色方块加标题 */}
<div className={styles.leftBlockTitle}>
<div className={styles.titleIcon}></div>
<div>风险评估参数</div>
</div>
{/* 第二行块 - 图片 */}
<div className={styles.leftBlockImage}>
{/* <img src={risk2} alt="风险评估图" style={{ width: '40%', height: '40%', objectFit: 'cover' }} /> */}
</div>
{/* 第三行块 */}
<div className={styles.leftBlockItem}>
<div className={styles.itemTitle}>风险等级</div>
<div className={styles.itemValue}>高风险</div>
</div>
{/* 第四行块 */}
<div className={styles.leftBlockItem}>
<div className={styles.itemTitle}>评估时间</div>
<div className={styles.itemValue}>2024-01-15</div>
</div>
{/* 第五行块 */}
<div className={styles.leftBlockItem}>
<div className={styles.itemTitle}>评估人员</div>
<div className={styles.itemValue}>张三</div>
</div>
</div>
<div className={styles.rightBlock}>
{/* 表格 */}
<div className={styles.tableHeader}>
<div className={styles.tableTitle}>
<div className={styles.titleIcon}></div>
<div>最新预警信息</div>
</div>
</div>
{/* 表格 */}
<div className={styles.tableContainer}>
<StandardTable
columns={columns}
data={{
list: getCurrentPageData(),
pagination: pagination
}}
loading={loading}
selectionType="checkbox"
onSelectRow={onSelectChange}
onChange={handleTableChange}
pagination={{
...pagination,
showSizeChanger: false,
showQuickJumper: true,
showTotal: (total, range) =>
`${total}`,
}}
scroll={{ x: 1200 }}
/>
</div>
</div>
</div>
</div>
</div>
);
};
export default RiskAssessment;