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.

685 lines
24 KiB
JavaScript

import React, { useState, useEffect, useRef } from 'react';
1 month ago
import { Button, Segmented, Tag, Drawer, Form, Input, Select } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import * as echarts from 'echarts';
import StandardTable from '@/components/StandardTable';
1 month ago
import styles from './EventWarningManagement.less';
1 month ago
import bgMan2 from '@/assets/business_Emergency/bgMan2.svg';
import bgMan3 from '@/assets/business_Emergency/bgMan3.svg';
import bgMan4 from '@/assets/business_Emergency/bgMan4.svg';
import bgMan5 from '@/assets/business_Emergency/bgMan5.svg';
1 month ago
const EventWarningManagement = () => {
1 month ago
const [form] = Form.useForm();
const [drawerVisible, setDrawerVisible] = useState(false);
const [timeType, setTimeType] = useState('month');
const lineChartRef = useRef(null);
const lineChartInstanceRef = useRef(null);
const donutChartRef = useRef(null);
const donutChartInstanceRef = useRef(null);
const [tableData, setTableData] = useState({
list: [
{
key: '1',
alertId: '#ALRT-20230512-001',
alertType: '气象预警',
alertLevel: '高级',
sourceChannel: '气象监测数据',
affectedArea: '东城区、西城区',
alertLevelColor: '红色预警',
alertTime: '2025-10-20 01:32:25',
status: '处理中',
statusType: 'processing'
},
{
key: '2',
alertId: '#ALRT-20230512-002',
alertType: '火灾隐患',
alertLevel: '中级',
sourceChannel: '安全监测设备',
affectedArea: '南山区工业园区',
alertLevelColor: '橙色预警',
alertTime: '2025-10-18 21:15:07',
status: '处理中',
statusType: 'processing'
},
{
key: '3',
alertId: '#ALRT-20230512-003',
alertType: '疫情传播',
alertLevel: '中级',
sourceChannel: '社会舆情信息',
affectedArea: '全市范围',
alertLevelColor: '蓝色预警',
alertTime: '2025-10-15 12:24:25',
status: '待处理',
statusType: 'pending'
},
{
key: '4',
alertId: '#ALRT-20230512-004',
alertType: '化工泄漏',
alertLevel: '低级',
sourceChannel: '安全监测设备',
affectedArea: '化工园区A区',
alertLevelColor: '蓝色预警',
alertTime: '2025-10-17 06:49:59',
status: '已处理',
statusType: 'processed'
}
],
pagination: {
current: 3,
currentPage: 3,
pageSize: 10,
total: 48,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total) => `${total}`
}
});
// 折线图配置
useEffect(() => {
if (!lineChartRef.current) return;
if (!lineChartInstanceRef.current) {
lineChartInstanceRef.current = echarts.init(lineChartRef.current);
}
const option = {
grid: {
left: '3%',
right: '4%',
1 month ago
top: '15%',
bottom: '3%',
containLabel: true
},
legend: {
1 month ago
data: ['气象灾害', '安全事故', '公共卫生'],
top: '0%',
left: 'center',
itemGap: 30,
1 month ago
itemWidth: 18, // 图例图标宽度
itemHeight: 8, // 图例图标高度
textStyle: {
color: '#666666',
fontSize: 12
}
},
xAxis: {
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
axisLabel: {
color: '#666666',
fontSize: 12
},
axisLine: {
lineStyle: {
color: '#E5E5E5'
}
},
axisTick: {
show: false
},
splitLine: {
show: true,
lineStyle: {
color: '#E5E5E5',
type: 'dashed'
}
}
},
yAxis: {
type: 'value',
min: 0,
max: 12,
interval: 2,
axisLabel: {
color: '#666666',
fontSize: 12
},
axisLine: {
show: false
},
axisTick: {
show: false
},
splitLine: {
lineStyle: {
color: '#E5E5E5',
type: 'dashed'
}
}
},
series: [
{
name: '气象灾害',
type: 'line',
smooth: true,
data: [4, 5, 6, 7, 10, 8, 6, 7, 8, 9, 10, 12],
itemStyle: {
color: '#ffffff',
borderColor: '#8979FF',
1 month ago
borderWidth: 1
},
lineStyle: {
color: '#8979FF',
1 month ago
width: 1
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(137, 121, 255, 0.3)' },
{ offset: 1, color: 'rgba(137, 121, 255, 0.05)' }
]
}
},
symbol: 'circle',
symbolSize: 8,
symbolKeepAspect: true,
emphasis: {
itemStyle: {
1 month ago
color: '#fff',
borderColor: '#8979FF',
1 month ago
borderWidth: 1
}
}
},
{
name: '安全事故',
type: 'line',
smooth: true,
data: [2, 3, 5, 4, 3, 4, 5, 4, 3, 6, 5, 7],
itemStyle: {
color: '#ffffff',
borderColor: '#FF928A',
1 month ago
borderWidth: 1
},
lineStyle: {
color: '#FF928A',
1 month ago
width: 1
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(255, 146, 138, 0.3)' },
{ offset: 1, color: 'rgba(255, 146, 138, 0.05)' }
]
}
},
symbol: 'circle',
symbolSize: 8,
symbolKeepAspect: true,
emphasis: {
itemStyle: {
1 month ago
color: '#fff',
borderColor: '#FF928A',
1 month ago
borderWidth: 1
}
}
},
{
name: '公共卫生',
type: 'line',
smooth: true,
data: [3, 5, 2, 1, 2, 3, 4, 2, 1, 2, 3, 2],
itemStyle: {
color: '#ffffff',
borderColor: '#3CC3DF',
1 month ago
borderWidth: 1
},
lineStyle: {
color: '#3CC3DF',
1 month ago
width: 1
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(60, 195, 223, 0.3)' },
{ offset: 1, color: 'rgba(60, 195, 223, 0.05)' }
]
}
},
symbol: 'circle',
symbolSize: 8,
symbolKeepAspect: true,
emphasis: {
itemStyle: {
1 month ago
color: '#fff',
borderColor: '#3CC3DF',
1 month ago
borderWidth: 1
}
}
}
]
};
lineChartInstanceRef.current.setOption(option);
const resizeObserver = new ResizeObserver(() => {
lineChartInstanceRef.current?.resize();
});
if (lineChartRef.current) {
resizeObserver.observe(lineChartRef.current);
}
const handleResize = () => {
lineChartInstanceRef.current?.resize();
};
window.addEventListener('resize', handleResize);
return () => {
resizeObserver.disconnect();
window.removeEventListener('resize', handleResize);
};
}, [timeType]);
// 环形图配置
useEffect(() => {
if (!donutChartRef.current) return;
if (!donutChartInstanceRef.current) {
donutChartInstanceRef.current = echarts.init(donutChartRef.current);
}
const option = {
legend: {
orient: 'vertical',
1 month ago
right: 30,
top: 'center',
itemGap: 15,
1 month ago
itemWidth: 14,
itemHeight: 3,
textStyle: {
color: '#666666',
fontSize: 12
},
1 month ago
formatter: function (name) {
return name;
}
},
series: [
{
type: 'pie',
1 month ago
radius: ['45%', '75%'],
center: ['35%', '50%'],
avoidLabelOverlap: false,
label: {
show: false
},
labelLine: {
show: false
},
data: [
1 month ago
{ value: 65, name: '气象灾害', itemStyle: { color: '#4B69F1' } },
{ value: 10, name: '社会安全', itemStyle: { color: '#44BB5F' } },
{ value: 20, name: '公共卫生', itemStyle: { color: '#A493FB' } },
1 month ago
{ value: 5, name: '安全事故', itemStyle: { color: '#FFD85A' } }
]
}
]
};
donutChartInstanceRef.current.setOption(option);
const resizeObserver = new ResizeObserver(() => {
donutChartInstanceRef.current?.resize();
});
if (donutChartRef.current) {
resizeObserver.observe(donutChartRef.current);
}
const handleResize = () => {
donutChartInstanceRef.current?.resize();
};
window.addEventListener('resize', handleResize);
return () => {
resizeObserver.disconnect();
window.removeEventListener('resize', handleResize);
};
}, []);
// 组件卸载时销毁图表
useEffect(() => {
return () => {
lineChartInstanceRef.current?.dispose();
donutChartInstanceRef.current?.dispose();
};
}, []);
// 表格列定义
const columns = [
{
title: '预警编号',
dataIndex: 'alertId',
key: 'alertId',
1 month ago
width: 180,
align: 'center'
},
{
title: '预警类型',
dataIndex: 'alertType',
key: 'alertType',
width: 110,
1 month ago
align: 'center'
},
{
title: '来源渠道',
dataIndex: 'sourceChannel',
key: 'sourceChannel',
width: 130,
1 month ago
align: 'center'
},
{
title: '影响区域',
dataIndex: 'affectedArea',
key: 'affectedArea',
width: 160,
1 month ago
align: 'center'
},
{
title: '预警级别',
dataIndex: 'alertLevelColor',
key: 'alertLevelColor',
width: 120,
1 month ago
align: 'center',
render: (text) => {
1 month ago
let color = '#FF3E48';
let backgroundColor = '#FFE0E2';
1 month ago
if (text === '橙色预警') {
color = '#FF8800';
backgroundColor = '#FFF3E9';
} else if (text === '蓝色预警') {
color = '#00AAFA';
backgroundColor = '#DAF3FF';
}
1 month ago
return (
<Tag style={{ color, backgroundColor, border: 'none' }}>
1 month ago
{text}
</Tag>
);
}
},
{
title: '预警时间',
dataIndex: 'alertTime',
key: 'alertTime',
1 month ago
width: 180,
align: 'center'
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 100,
1 month ago
align: 'center',
render: (text) => {
1 month ago
let color = "#00AAFA";
let backgroundColor = "#DAF3FF";
if (text === '处理中') {
color = '#FF8800';
backgroundColor = '#FFF3E9';
} else if (text === '已处理') {
color = '#44BB5F';
backgroundColor = '#D8F7DE';
}
return (
<Tag style={{ color, backgroundColor, border: 'none' }}>{text}</Tag>
1 month ago
);
}
},
{
title: '操作',
key: 'action',
width: 140,
1 month ago
align: 'center',
1 month ago
render: () => (
<div className={styles.actionButtons}>
<Button type="link" size="small" style={{ color: "#2E4CD4" }}>编辑</Button>
<Button type="link" size="small" style={{ color: "#2E4CD4" }}>查看</Button>
</div>
)
}
];
1 month ago
// 显示添加预警抽屉
const showAddDrawer = () => {
setDrawerVisible(true);
};
// 关闭抽屉
const onCloseDrawer = () => {
setDrawerVisible(false);
form.resetFields();
};
// 提交表单
const handleSubmit = async () => {
try {
const values = await form.validateFields();
console.log('提交的表单数据:', values);
// TODO: 调用API提交数据
// 提交成功后关闭抽屉并刷新表格
onCloseDrawer();
// 刷新表格数据
} catch (error) {
console.error('表单验证失败:', error);
}
};
1 month ago
return (
<div className={styles.container}>
{/* A块顶部统计区域 */}
<div className={styles.blockA}>
{/* a块左侧70% */}
<div className={styles.blockA_a}>
<div className={styles.sectionHeader}>
<div className={styles.titleBar}></div>
<div className={styles.titleText}>今日预警统计</div>
</div>
<div className={styles.threeCards}>
1 month ago
<img src={bgMan3} alt="" style={{ width: '140px', height: '75px' }} />
<img src={bgMan2} alt="" style={{ width: '140px', height: '75px' }} />
<img src={bgMan3} alt="" style={{ width: '140px', height: '75px' }} />
</div>
</div>
{/* b块右侧30% */}
<div className={styles.blockA_b}>
<div className={styles.imageTextCard}>
<div className={styles.cardIcon}>
1 month ago
<img src={bgMan4} alt="待处理指令" />
</div>
<div className={styles.cardContent}>
<div className={styles.cardNumber}>12</div>
<div className={styles.cardText}>待处理指令</div>
</div>
</div>
<div className={styles.imageTextCard}>
<div className={styles.cardIcon}>
1 month ago
<img src={bgMan5} alt="待审核上报" />
</div>
<div className={styles.cardContent}>
<div className={styles.cardNumber}>10</div>
<div className={styles.cardText}>待审核上报</div>
</div>
</div>
</div>
</div>
{/* B块中间图表区域 */}
<div className={styles.blockB}>
{/* c块左侧70% */}
<div className={styles.blockB_c}>
<div className={styles.chartHeader}>
<div className={styles.sectionHeader}>
<div className={styles.titleBar}></div>
<div className={styles.titleText}>演练数据统计</div>
</div>
<Segmented
options={['年', '月', '周']}
value={timeType}
onChange={setTimeType}
className={styles.timeFilter}
/>
</div>
<div className={styles.chartContent}>
<div ref={lineChartRef} className={styles.lineChart}></div>
</div>
</div>
{/* d块右侧30% */}
<div className={styles.blockB_d}>
<div className={styles.sectionHeader}>
<div className={styles.titleBar}></div>
<div className={styles.titleText}>预警类型分布</div>
</div>
<div className={styles.chartContent}>
<div ref={donutChartRef} className={styles.donutChart}></div>
</div>
</div>
</div>
{/* C块底部表格区域 */}
<div className={styles.blockC}>
<div className={styles.tableHeader}>
<div className={styles.sectionHeader}>
<div className={styles.titleBar}></div>
<div className={styles.titleText}>事件预警信息</div>
</div>
1 month ago
<Button
type="primary"
icon={<PlusOutlined />}
className={styles.addButton}
onClick={showAddDrawer}
>
添加预警
</Button>
</div>
<div className={styles.tableContent}>
<StandardTable
data={tableData}
columns={columns}
rowKey="key"
/>
</div>
1 month ago
</div>
1 month ago
{/* 添加事件预警抽屉 */}
<Drawer
title="添加事件预警"
placement="right"
onClose={onCloseDrawer}
open={drawerVisible}
width={400}
maskClosable={true}
className={styles.eventWarningDrawer}
headerStyle={{
backgroundColor: '#F6F7FF',
padding: '16px 24px'
}}
bodyStyle={{
color: '#333333',
padding: '24px'
}}
footer={
<div className={styles.drawerFooter}>
<Button
onClick={onCloseDrawer}
className={styles.drawerCancelBtn}
>
取消
</Button>
<Button
onClick={handleSubmit}
className={styles.drawerSubmitBtn}
>
提交
</Button>
</div>
}
>
<Form
form={form}
layout="vertical"
style={{ padding: 0 }}
>
<Form.Item
label="预警类型"
name="alertType"
rules={[{ required: true, message: '请选择预警类型' }]}
>
<Select placeholder="请选择预警类型">
<Select.Option value="气象预警">气象预警</Select.Option>
<Select.Option value="火灾隐患">火灾隐患</Select.Option>
<Select.Option value="疫情传播">疫情传播</Select.Option>
<Select.Option value="化工泄漏">化工泄漏</Select.Option>
<Select.Option value="安全事故">安全事故</Select.Option>
<Select.Option value="公共卫生">公共卫生</Select.Option>
</Select>
</Form.Item>
<Form.Item
label="预警级别"
name="alertLevel"
rules={[{ required: true, message: '请选择预警级别' }]}
>
<Select placeholder="请选择预警级别">
<Select.Option value="高级">高级</Select.Option>
<Select.Option value="中级">中级</Select.Option>
<Select.Option value="低级">低级</Select.Option>
</Select>
</Form.Item>
<Form.Item
label="来源渠道"
name="sourceChannel"
rules={[{ required: true, message: '请输入来源渠道' }]}
>
<Input placeholder="请输入来源渠道" />
</Form.Item>
<Form.Item
label="影响区域"
name="affectedArea"
rules={[{ required: true, message: '请输入影响区域' }]}
>
<Input placeholder="请输入影响区域" />
</Form.Item>
<Form.Item
label="预警内容"
name="alertContent"
rules={[{ required: true, message: '请输入预警内容' }]}
>
<Input.TextArea
placeholder="请输入预警内容..."
rows={6}
/>
</Form.Item>
</Form>
</Drawer>
1 month ago
</div>
);
};
export default EventWarningManagement;