污染源管理

main
wangyunfei 2 weeks ago
parent 4e9c67ed3e
commit 4d9bcffa8a

@ -1,10 +1,474 @@
import React from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { Select, Button, Table, Input, Space, Tooltip, message } from 'antd';
import { SearchOutlined, PlusOutlined, FileTextOutlined, DeleteOutlined, EditOutlined, MoreOutlined, RobotOutlined } from '@ant-design/icons';
import ReactECharts from 'echarts-for-react';
import StandardTable from '@/components/StandardTable';
import styles from './PollutionSourceManagement.less'; import styles from './PollutionSourceManagement.less';
const { Option } = Select;
const PollutionSourceManagement = () => { const PollutionSourceManagement = () => {
const [loading, setLoading] = useState(false);
const [tableData, setTableData] = useState({
list: [],
pagination: {
current: 1,
pageSize: 5,
total: 85
}
});
// 污染物排放统计图表配置
const pollutantEmissionOption = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
series: [{
name: '污染物排放',
type: 'pie',
radius: ['40%', '70%'],
center: ['50%', '50%'],
data: [
{ value: 62, name: '超标污染物数量', itemStyle: { color: '#ff6b6b' } },
{ value: 38, name: '正常污染物数量', itemStyle: { color: '#4ecdc4' } }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
};
const pollutantTypeOption = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
series: [{
name: '污染物种类',
type: 'pie',
radius: ['40%', '70%'],
center: ['50%', '50%'],
data: [
{ value: 25, name: '超标污染物种类', itemStyle: { color: '#a8e6cf' } },
{ value: 75, name: '正常污染物种类', itemStyle: { color: '#ffd3a5' } }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
};
// 超标排放统计图表配置
const exceedanceOption = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function(params) {
const data = params[0];
const exceedanceData = [
{ name: '污染物1', status: '轻微超标', exceedance: '15%' },
{ name: '污染物2', status: '严重超标', exceedance: '66%' },
{ name: '污染物3', status: '轻微超标', exceedance: '8%' },
{ name: '污染物4', status: '正常', exceedance: '0%' },
{ name: '污染物5', status: '轻微超标', exceedance: '12%' }
];
const item = exceedanceData[data.dataIndex];
return `
<div style="padding: 10px; background: rgba(0,0,0,0.8); color: white; border-radius: 8px;">
<div style="font-weight: 600; margin-bottom: 5px;">${data.name}</div>
<div style="color: #ff6b6b; margin-bottom: 3px;">${item.status}</div>
<div style="color: #ffd93d; margin-bottom: 3px;">超标 ${item.exceedance}</div>
<div style="color: #a8e6cf; font-size: 11px;">大气环境特征污染物</div>
</div>
`;
}
},
grid: {
left: '20%',
right: '10%',
top: '10%',
bottom: '10%'
},
xAxis: {
type: 'value',
max: 100,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
color: '#666'
},
splitLine: {
lineStyle: {
color: '#f0f0f0',
type: 'dashed'
}
}
},
yAxis: {
type: 'category',
data: ['污染物1', '污染物2', '污染物3', '污染物4', '污染物5'],
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
color: '#666',
fontSize: 12
}
},
series: [{
type: 'bar',
data: [45, 66, 32, 28, 38],
itemStyle: {
color: '#ff6b6b',
borderRadius: [0, 4, 4, 0]
},
barWidth: '60%'
}]
};
// 表格列定义
const columns = [
{
title: '生产工艺设备',
dataIndex: 'equipment',
key: 'equipment',
width: 120,
},
{
title: '原材料产品',
dataIndex: 'material',
key: 'material',
width: 150,
},
{
title: '污染物排放处理设施',
dataIndex: 'facility',
key: 'facility',
width: 180,
},
{
title: '污染物排放种类',
dataIndex: 'type',
key: 'type',
width: 150,
render: (text) => (
<Space>
{text}
<SearchOutlined style={{ color: '#1890ff', cursor: 'pointer' }} />
</Space>
),
},
{
title: '排放数量',
dataIndex: 'quantity',
key: 'quantity',
width: 100,
},
{
title: '数量单位',
dataIndex: 'unit',
key: 'unit',
width: 100,
},
{
title: '排放方式',
dataIndex: 'method',
key: 'method',
width: 100,
},
{
title: '趋向',
dataIndex: 'trend',
key: 'trend',
width: 200,
ellipsis: true,
},
{
title: '操作',
key: 'action',
width: 80,
render: (_, record) => (
<Space size="middle">
<Tooltip title="删除">
<DeleteOutlined
style={{ color: '#ff4d4f', cursor: 'pointer' }}
onClick={() => handleDelete(record)}
/>
</Tooltip>
</Space>
),
},
];
// 模拟表格数据
const mockTableData = [
{
key: '1',
equipment: '比亚迪',
material: '丁硼乳膏(雅皓)',
facility: '净水设备234',
type: '种类1',
quantity: 47,
unit: 'm³',
method: '方式1',
trend: '近3年下达中央预算内投'
},
{
key: '2',
equipment: '荣威',
material: '东方活血膏(明仁)',
facility: '净水设备234',
type: '种类1',
quantity: 34,
unit: 'm³',
method: '方式1',
trend: '近3年下达中央预算内投'
},
{
key: '3',
equipment: '现代',
material: '骨友灵搽剂(太极)',
facility: '净水设备234',
type: '种类1',
quantity: 45,
unit: 'm³',
method: '方式1',
trend: '刘某及同伴三人前往该射'
},
{
key: '4',
equipment: '日产',
material: '对乙酰氨基酚栓',
facility: '净水设备234',
type: '种类1',
quantity: 55,
unit: 'm³',
method: '方式1',
trend: '一到假期,大量"xx暑假'
},
{
key: '5',
equipment: '北汽',
material: '对乙酰氨基酚片(必理通)',
facility: '净水设备234',
type: '种类1',
quantity: 22,
unit: 'm³',
method: '方式1',
trend: '近日,陕西延安培文实验'
}
];
useEffect(() => {
setTableData({
list: mockTableData,
pagination: {
current: 6,
pageSize: 5,
total: 85
}
});
}, []);
// 处理删除操作
const handleDelete = (record) => {
message.success(`删除 ${record.equipment} 成功`);
};
// 处理新增操作
const handleAdd = () => {
message.info('新增功能开发中');
};
// 处理生成报表操作
const handleGenerateReport = () => {
message.info('生成报表功能开发中');
};
// 处理表格变化
const handleTableChange = (pagination) => {
setTableData(prev => ({
...prev,
pagination: {
...prev.pagination,
current: pagination.current,
pageSize: pagination.pageSize
}
}));
};
return ( return (
<div className={styles.container}> <div className={styles.pollutionDashboard}>
开发中 {/* 顶部统计区域 */}
<div className={styles.statsSection}>
{/* 污染物排放统计 */}
<div className={styles.statsCard}>
<div className={styles.cardTitle}>
<span>污染物排放统计</span>
<div className={styles.cardHeader}>
<Select defaultValue="今日" className={styles.timeFilter}>
<Option value="今日">今日</Option>
<Option value="本周">本周</Option>
<Option value="本月">本月</Option>
</Select>
<Select defaultValue="所有名录" className={styles.categoryFilter}>
<Option value="所有名录">所有名录</Option>
<Option value="大气环境">大气环境</Option>
<Option value="水环境">水环境</Option>
</Select>
</div>
</div>
<div className={styles.chartsContainer}>
<div className={styles.pieChartContainer}>
<div className={styles.chartTitle}>超标污染物数量</div>
<ReactECharts
option={pollutantEmissionOption}
style={{ height: '120px', width: '100%' }}
opts={{ renderer: 'canvas' }}
/>
<div className={styles.chartValue}>62%</div>
</div>
<div className={styles.pieChartContainer}>
<div className={styles.chartTitle}>超标污染物种类</div>
<ReactECharts
option={pollutantTypeOption}
style={{ height: '120px', width: '100%' }}
opts={{ renderer: 'canvas' }}
/>
<div className={styles.chartValue}>25%</div>
</div>
</div>
</div>
{/* 超标排放统计 */}
<div className={styles.statsCard}>
<div className={styles.cardTitle}>超标排放统计</div>
<div className={styles.cardHeader}>
<Select defaultValue="今日" className={styles.timeFilter}>
<Option value="今日">今日</Option>
<Option value="本周">本周</Option>
<Option value="本月">本月</Option>
</Select>
<Select defaultValue="所有名录" className={styles.categoryFilter}>
<Option value="所有名录">所有名录</Option>
<Option value="大气环境">大气环境</Option>
<Option value="水环境">水环境</Option>
</Select>
</div>
<div className={styles.barChartContainer}>
<ReactECharts
option={exceedanceOption}
style={{ height: '100px', width: '100%' }}
opts={{ renderer: 'canvas' }}
/>
</div>
</div>
{/* 环境分类卡片 */}
<div className={styles.environmentalCategories}>
<div className={styles.categoryCard}>
<div className={styles.categoryContent}>
<div className={styles.categoryInfo}>
<div className={styles.categoryTitle}>大气环境</div>
<div className={styles.categorySubtitle}>特征污染物名录库</div>
</div>
<div className={styles.categoryIcon}>
<div className={styles.factoryIcon}>🏭</div>
</div>
</div>
</div>
<div className={styles.categoryCard}>
<div className={styles.categoryContent}>
<div className={styles.categoryInfo}>
<div className={styles.categoryTitle}>水环境</div>
<div className={styles.categorySubtitle}>特征污染物名录库</div>
</div>
<div className={styles.categoryIcon}>
<div className={styles.waterIcon}>💧</div>
</div>
</div>
</div>
<div className={styles.categoryCard}>
<div className={styles.categoryContent}>
<div className={styles.categoryInfo}>
<div className={styles.categoryTitle}>土壤及地下水</div>
<div className={styles.categorySubtitle}>特征污染物名录库</div>
</div>
<div className={styles.categoryIcon}>
<div className={styles.soilIcon}>🌱</div>
</div>
</div>
</div>
</div>
</div>
{/* 污染源管理表格区域 */}
<div className={styles.tableCard}>
<div className={styles.cardTitle}>污染源管理</div>
<div className={styles.tableHeader}>
<div className={styles.searchSection}>
<Input
placeholder="搜索污染源..."
prefix={<SearchOutlined />}
className={styles.searchInput}
/>
<Button icon={<RobotOutlined />} className={styles.aiButton}>
AI
</Button>
<Button icon={<EditOutlined />} className={styles.editButton}>
编辑
</Button>
<Button icon={<MoreOutlined />} className={styles.moreButton}>
...
</Button>
</div>
<div className={styles.actionButtons}>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={handleAdd}
className={styles.addButton}
>
新增
</Button>
<Button
icon={<FileTextOutlined />}
onClick={handleGenerateReport}
className={styles.reportButton}
>
生成报表
</Button>
</div>
</div>
<StandardTable
columns={columns}
data={tableData}
onChange={handleTableChange}
rowKey="key"
size="small"
scroll={{ x: 1200 }}
/>
</div>
</div> </div>
); );
}; };

@ -1,41 +1,354 @@
.container { .pollutionDashboard {
width: 100%; width: 100%;
height: 100%; min-height: 75vh;
display: flex; // background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
justify-content: center; padding: 15px;
align-items: center; box-sizing: border-box;
background-color: #fff;
border-radius: 4px; // 顶部统计区域
padding: 20px; .statsSection {
display: grid;
.developingBox { grid-template-columns: 1fr 1fr 1fr;
gap: 15px;
margin-bottom: 15px;
height: 20%;
// 统计卡片通用样式
.statsCard {
background: linear-gradient(180deg, #E2FFF5 0%, rgba(255, 255, 255, 0.6) 51.44%),
linear-gradient(0deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.2));
border-radius: 2px;
padding: 10px 20px;
.cardTitle {
background: transparent;
color: #000000;
font-weight: 500;
font-size: 16px;
padding: 0;
margin: 0 0 15px 0;
border: none;
display: flex;
align-items: center;
justify-content: space-between;
}
}
// 卡片头部筛选器
.cardHeader {
display: flex;
gap: 10px;
margin-bottom: 0;
.timeFilter,
.categoryFilter {
flex: 1;
min-width: 80px;
:global(.ant-select-selector) {
border-radius: 8px;
border: 1px solid #d9d9d9;
background: transparent;
transition: all 0.3s ease;
}
}
}
// 图表容器
.chartsContainer {
display: flex;
gap: 20px;
justify-content: space-between;
background: transparent;
.pieChartContainer {
flex: 1;
text-align: center;
position: relative;
background: transparent;
.chartTitle {
font-size: 14px;
color: #666;
margin-bottom: 10px;
font-weight: 500;
background: transparent;
}
.chartValue {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 18px;
font-weight: bold;
color: #333;
z-index: 10;
background: transparent;
}
}
}
// 条形图容器
.barChartContainer {
// height: 200px;
margin-top: 10px;
}
// 环境分类卡片区域
.environmentalCategories {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 15px;
.categoryCard {
background: rgba(255, 255, 255, 0.95);
border-radius: 12px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
transition: all 0.3s ease;
cursor: pointer;
padding: 15px;
.categoryContent {
display: flex;
justify-content: space-between;
align-items: center;
.categoryInfo {
flex: 1;
.categoryTitle {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 5px;
}
.categorySubtitle {
font-size: 12px;
color: #666;
}
}
.categoryIcon {
width: 40px;
height: 40px;
display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 60px 80px; border-radius: 50%;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
.factoryIcon,
.waterIcon,
.soilIcon {
font-size: 20px;
filter: grayscale(0);
}
}
}
}
}
}
// 表格卡片
.tableCard {
background: rgba(255, 255, 255, 0.95);
border-radius: 12px; border-radius: 12px;
box-shadow: 0 10px 30px rgba(240, 147, 251, 0.3); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
padding: 20px;
.developingText { .cardTitle {
font-size: 32px; background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
color: white;
font-weight: 600; font-weight: 600;
color: #ffffff; font-size: 16px;
letter-spacing: 4px; padding: 12px 16px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); margin: -20px -20px 20px -20px;
animation: pulse 2s ease-in-out infinite; border-radius: 12px 12px 0 0;
border-bottom: 2px solid #e8f4fd;
} }
} }
}
@keyframes pulse { // 表格头部
0%, 100% { .tableHeader {
opacity: 1; display: flex;
transform: scale(1); justify-content: space-between;
align-items: center;
margin-bottom: 20px;
flex-wrap: wrap;
gap: 15px;
.searchSection {
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
.searchInput {
width: 200px;
border-radius: 8px;
border: 1px solid #d9d9d9;
background: rgba(255, 255, 255, 0.9);
transition: all 0.3s ease;
}
.aiButton,
.editButton,
.moreButton {
border-radius: 8px;
border: 1px solid #d9d9d9;
background: rgba(255, 255, 255, 0.9);
transition: all 0.3s ease;
}
}
.actionButtons {
display: flex;
gap: 10px;
align-items: center;
.addButton {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 8px;
color: white;
font-weight: 500;
transition: all 0.3s ease;
}
.reportButton {
border-radius: 8px;
border: 1px solid #d9d9d9;
background: rgba(255, 255, 255, 0.9);
transition: all 0.3s ease;
}
}
} }
50% {
opacity: 0.8; // 自定义Tooltip样式
transform: scale(1.05); .customTooltip {
background: rgba(0, 0, 0, 0.8);
border-radius: 8px;
padding: 10px;
color: white;
font-size: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
.tooltipLabel {
font-weight: 600;
margin-bottom: 5px;
color: #fff;
}
.tooltipStatus {
color: #ff6b6b;
margin-bottom: 3px;
}
.tooltipExceedance {
color: #ffd93d;
margin-bottom: 3px;
}
.tooltipType {
color: #a8e6cf;
font-size: 11px;
}
}
// 响应式设计
@media (max-width: 1200px) {
.statsSection {
grid-template-columns: 1fr 1fr;
grid-template-rows: auto auto;
.environmentalCategories {
grid-column: 1 / -1;
flex-direction: row;
gap: 15px;
.categoryCard {
flex: 1;
}
}
}
}
@media (max-width: 768px) {
padding: 10px;
.statsSection {
grid-template-columns: 1fr;
gap: 15px;
.environmentalCategories {
flex-direction: column;
}
}
.tableHeader {
flex-direction: column;
align-items: stretch;
.searchSection {
justify-content: center;
}
.actionButtons {
justify-content: center;
}
}
}
// 表格样式优化
:global(.ant-table) {
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
:global(.ant-table-thead > tr > th) {
background: linear-gradient(90deg, #f8f9fa 0%, #e9ecef 100%);
border-bottom: 2px solid #dee2e6;
font-weight: 600;
color: #495057;
}
:global(.ant-table-tbody > tr) {
transition: all 0.3s ease;
}
:global(.ant-table-tbody > tr > td) {
border-bottom: 1px solid #f0f0f0;
}
}
// 分页器样式
:global(.ant-pagination) {
margin-top: 20px;
text-align: center;
:global(.ant-pagination-item) {
border-radius: 6px;
border: 1px solid #d9d9d9;
transition: all 0.3s ease;
&.ant-pagination-item-active {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-color: #667eea;
color: white;
}
}
:global(.ant-pagination-prev),
:global(.ant-pagination-next) {
border-radius: 6px;
border: 1px solid #d9d9d9;
transition: all 0.3s ease;
}
} }
} }

Loading…
Cancel
Save