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

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, { useState, useEffect, useRef } from 'react';
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';
import styles from './EventWarningManagement.less';
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';
const EventWarningManagement = () => {
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%',
top: '15%',
bottom: '3%',
containLabel: true
},
legend: {
data: ['气象灾害', '安全事故', '公共卫生'],
top: '0%',
left: 'center',
itemGap: 30,
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',
borderWidth: 1
},
lineStyle: {
color: '#8979FF',
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: {
color: '#fff',
borderColor: '#8979FF',
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',
borderWidth: 1
},
lineStyle: {
color: '#FF928A',
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: {
color: '#fff',
borderColor: '#FF928A',
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',
borderWidth: 1
},
lineStyle: {
color: '#3CC3DF',
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: {
color: '#fff',
borderColor: '#3CC3DF',
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',
right: 30,
top: 'center',
itemGap: 15,
itemWidth: 14,
itemHeight: 3,
textStyle: {
color: '#666666',
fontSize: 12
},
formatter: function (name) {
return name;
}
},
series: [
{
type: 'pie',
radius: ['45%', '75%'],
center: ['35%', '50%'],
avoidLabelOverlap: false,
label: {
show: false
},
labelLine: {
show: false
},
data: [
{ value: 65, name: '气象灾害', itemStyle: { color: '#4B69F1' } },
{ value: 10, name: '社会安全', itemStyle: { color: '#44BB5F' } },
{ value: 20, name: '公共卫生', itemStyle: { color: '#A493FB' } },
{ 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',
width: 180,
align: 'center'
},
{
title: '预警类型',
dataIndex: 'alertType',
key: 'alertType',
width: 110,
align: 'center'
},
{
title: '来源渠道',
dataIndex: 'sourceChannel',
key: 'sourceChannel',
width: 130,
align: 'center'
},
{
title: '影响区域',
dataIndex: 'affectedArea',
key: 'affectedArea',
width: 160,
align: 'center'
},
{
title: '预警级别',
dataIndex: 'alertLevelColor',
key: 'alertLevelColor',
width: 120,
align: 'center',
render: (text) => {
let color = '#FF3E48';
let backgroundColor = '#FFE0E2';
if (text === '橙色预警') {
color = '#FF8800';
backgroundColor = '#FFF3E9';
} else if (text === '蓝色预警') {
color = '#00AAFA';
backgroundColor = '#DAF3FF';
}
return (
<Tag style={{ color, backgroundColor, border: 'none' }}>
{text}
</Tag>
);
}
},
{
title: '预警时间',
dataIndex: 'alertTime',
key: 'alertTime',
width: 180,
align: 'center'
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 100,
align: 'center',
render: (text) => {
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>
);
}
},
{
title: '操作',
key: 'action',
width: 140,
align: 'center',
render: () => (
<div className={styles.actionButtons}>
<Button type="link" size="small" style={{ color: "#2E4CD4" }}>编辑</Button>
<Button type="link" size="small" style={{ color: "#2E4CD4" }}>查看</Button>
</div>
)
}
];
// 显示添加预警抽屉
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);
}
};
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}>
<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}>
<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}>
<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>
<Button
type="primary"
icon={<PlusOutlined />}
className={styles.addButton}
onClick={showAddDrawer}
>
添加预警
</Button>
</div>
<div className={styles.tableContent}>
<StandardTable
data={tableData}
columns={columns}
rowKey="key"
/>
</div>
</div>
{/* 添加事件预警抽屉 */}
<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>
</div>
);
};
export default EventWarningManagement;