main
wangyunfei 3 weeks ago
parent d2c15883fd
commit 7c58c21108

@ -0,0 +1,16 @@
<svg width="203" height="109" viewBox="0 0 203 109" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.5">
<path d="M110.418 97.5333C139.462 55.1498 197.651 -30.3263 198.056 -33.163V-45.3211L122.069 -50.3867L6.06291 -27.0842L-5.58789 108.172L110.418 97.5333Z" fill="url(#paint0_linear_965_16251)" fill-opacity="0.2"/>
<path d="M153.788 62.8755C169.993 39.2271 202.46 -8.46525 202.686 -10.048V-16.8318L160.288 -19.6582L95.5612 -6.6563L89.0605 68.8112L153.788 62.8755Z" fill="url(#paint1_linear_965_16251)" fill-opacity="0.2"/>
</g>
<defs>
<linearGradient id="paint0_linear_965_16251" x1="169.992" y1="-1.32425" x2="81.965" y2="108.277" gradientUnits="userSpaceOnUse">
<stop stop-color="#3758FF"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_965_16251" x1="187.027" y1="7.71677" x2="137.912" y2="68.8703" gradientUnits="userSpaceOnUse">
<stop stop-color="#3758FF"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,16 @@
<svg width="203" height="109" viewBox="0 0 203 109" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.5">
<path d="M110.418 97.5333C139.462 55.1498 197.651 -30.3263 198.056 -33.163V-45.3211L122.069 -50.3867L6.06291 -27.0842L-5.58789 108.172L110.418 97.5333Z" fill="url(#paint0_linear_965_16260)" fill-opacity="0.2"/>
<path d="M153.788 62.8755C169.993 39.2271 202.46 -8.46525 202.686 -10.048V-16.8318L160.288 -19.6582L95.5612 -6.6563L89.0605 68.8112L153.788 62.8755Z" fill="url(#paint1_linear_965_16260)" fill-opacity="0.2"/>
</g>
<defs>
<linearGradient id="paint0_linear_965_16260" x1="169.992" y1="-1.32425" x2="81.965" y2="108.277" gradientUnits="userSpaceOnUse">
<stop stop-color="#D0BF00"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_965_16260" x1="187.027" y1="7.71677" x2="137.912" y2="68.8703" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFEA00"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,16 @@
<svg width="203" height="109" viewBox="0 0 203 109" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.5">
<path d="M110.418 97.5333C139.462 55.1498 197.651 -30.3263 198.056 -33.163V-45.3211L122.069 -50.3867L6.06291 -27.0842L-5.58789 108.172L110.418 97.5333Z" fill="url(#paint0_linear_965_16270)" fill-opacity="0.2"/>
<path d="M153.788 62.8755C169.993 39.2271 202.46 -8.46525 202.686 -10.048V-16.8318L160.288 -19.6582L95.5612 -6.6563L89.0605 68.8112L153.788 62.8755Z" fill="url(#paint1_linear_965_16270)" fill-opacity="0.2"/>
</g>
<defs>
<linearGradient id="paint0_linear_965_16270" x1="169.992" y1="-1.32425" x2="81.965" y2="108.277" gradientUnits="userSpaceOnUse">
<stop stop-color="#00F8EB"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_965_16270" x1="187.027" y1="7.71677" x2="137.912" y2="68.8703" gradientUnits="userSpaceOnUse">
<stop stop-color="#00EADE"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,16 @@
<svg width="203" height="109" viewBox="0 0 203 109" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.5">
<path d="M110.418 97.5333C139.462 55.1498 197.651 -30.3263 198.056 -33.163V-45.3211L122.069 -50.3867L6.06291 -27.0842L-5.58789 108.172L110.418 97.5333Z" fill="url(#paint0_linear_965_16280)" fill-opacity="0.2"/>
<path d="M153.788 62.8755C169.993 39.2271 202.46 -8.46525 202.686 -10.048V-16.8318L160.288 -19.6582L95.5612 -6.6563L89.0605 68.8112L153.788 62.8755Z" fill="url(#paint1_linear_965_16280)" fill-opacity="0.2"/>
</g>
<defs>
<linearGradient id="paint0_linear_965_16280" x1="169.992" y1="-1.32425" x2="81.965" y2="108.277" gradientUnits="userSpaceOnUse">
<stop stop-color="#04D9FF"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_965_16280" x1="187.027" y1="7.71677" x2="137.912" y2="68.8703" gradientUnits="userSpaceOnUse">
<stop stop-color="#04D9FF"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,16 @@
<svg width="203" height="109" viewBox="0 0 203 109" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.5">
<path d="M110.418 97.5333C139.462 55.1498 197.651 -30.3263 198.056 -33.163V-45.3211L122.069 -50.3867L6.06291 -27.0842L-5.58789 108.172L110.418 97.5333Z" fill="url(#paint0_linear_965_16290)" fill-opacity="0.2"/>
<path d="M153.788 62.8755C169.993 39.2271 202.46 -8.46525 202.686 -10.048V-16.8318L160.288 -19.6582L95.5612 -6.6563L89.0605 68.8112L153.788 62.8755Z" fill="url(#paint1_linear_965_16290)" fill-opacity="0.2"/>
</g>
<defs>
<linearGradient id="paint0_linear_965_16290" x1="169.992" y1="-1.32425" x2="81.965" y2="108.277" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF81A9"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_965_16290" x1="187.027" y1="7.71677" x2="137.912" y2="68.8703" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF6363"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,16 @@
<svg width="203" height="109" viewBox="0 0 203 109" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.5">
<path d="M110.418 97.5333C139.462 55.1498 197.651 -30.3263 198.056 -33.163V-45.3211L122.069 -50.3867L6.06291 -27.0842L-5.58789 108.172L110.418 97.5333Z" fill="url(#paint0_linear_965_16300)" fill-opacity="0.2"/>
<path d="M153.788 62.8755C169.993 39.2271 202.46 -8.46525 202.686 -10.048V-16.8318L160.288 -19.6582L95.5612 -6.6563L89.0605 68.8112L153.788 62.8755Z" fill="url(#paint1_linear_965_16300)" fill-opacity="0.2"/>
</g>
<defs>
<linearGradient id="paint0_linear_965_16300" x1="169.992" y1="-1.32425" x2="81.965" y2="108.277" gradientUnits="userSpaceOnUse">
<stop stop-color="#9C81FF"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_965_16300" x1="187.027" y1="7.71677" x2="137.912" y2="68.8703" gradientUnits="userSpaceOnUse">
<stop stop-color="#9E83FF"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -1,8 +1,7 @@
import React, { useEffect, useRef, useState } from 'react';
import { Card, Result, Select, Button, Segmented } from 'antd';
import React, { useState, useEffect } from 'react';
import { Card, Result, Select, Button } from 'antd';
import { CheckCircleOutlined, ExportOutlined } from '@ant-design/icons';
import * as echarts from 'echarts';
import StandardTable from '@/components/StandardTable';
import styles from './EnvironmentalPersonnelManagement.less';
// import './EnvironmentalPersonnelManagement.less';
@ -20,9 +19,6 @@ import eqicon3 from '@/assets/business_basic/eqicon3.png';
import eqicon4 from '@/assets/business_basic/eqicon4.png';
const EnvironmentalPersonnelManagement = () => {
const chartRef = useRef(null);
const pieChartRef = useRef(null);
const faultPieChartRef = useRef(null);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [selectedRows, setSelectedRows] = useState([]);
const [loading, setLoading] = useState(false);
@ -33,343 +29,8 @@ const EnvironmentalPersonnelManagement = () => {
total: 0,
});
// 饼图初始化
useEffect(() => {
if (pieChartRef.current) {
const pieChart = echarts.init(pieChartRef.current);
const pieOption = {
color: ['#44BB5F', '#F8C541', '#A493FB', '#4B69F1', '#949FD0'],
legend: {
orient: 'vertical',
right: '10%',
top: 'center',
itemWidth: 8,
itemHeight: 8,
textStyle: {
fontSize: 12,
color: '#333'
}
},
series: [{
name: '设备状态',
type: 'pie',
radius: ['40%', '70%'],
center: ['35%', '50%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '14',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{ value: 480, name: '正常' },
{ value: 289, name: '故障' },
{ value: 200, name: '维修中' },
{ value: 150, name: '待验收' },
{ value: 161, name: '停用' }
]
}]
};
pieChart.setOption(pieOption);
// 响应式调整
const handlePieResize = () => {
if (pieChart && !pieChart.isDisposed()) {
pieChart.resize();
}
};
window.addEventListener('resize', handlePieResize);
return () => {
window.removeEventListener('resize', handlePieResize);
if (pieChart && !pieChart.isDisposed()) {
pieChart.dispose();
}
};
}
}, []);
// 故障类型饼图初始化
useEffect(() => {
if (faultPieChartRef.current) {
const faultPieChart = echarts.init(faultPieChartRef.current);
const faultPieOption = {
color: ['#FF3E48', '#FF8800', '#FFC403'],
legend: {
orient: 'vertical',
right: '10%',
top: 'center',
itemWidth: 8,
itemHeight: 8,
textStyle: {
fontSize: 12,
color: '#333'
}
},
series: [{
name: '设备故障类型',
type: 'pie',
radius: '70%',
center: ['35%', '50%'],
avoidLabelOverlap: false,
label: {
show: true,
position: 'outside',
formatter: '{b}: {c}',
fontSize: 12
},
emphasis: {
label: {
show: true,
fontSize: '14',
fontWeight: 'bold'
}
},
labelLine: {
show: true
},
data: [
{ value: 120, name: '紧急' },
{ value: 80, name: '重要' },
{ value: 60, name: '一般' }
]
}]
};
faultPieChart.setOption(faultPieOption);
// 响应式调整
const handleFaultPieResize = () => {
if (faultPieChart && !faultPieChart.isDisposed()) {
faultPieChart.resize();
}
};
window.addEventListener('resize', handleFaultPieResize);
return () => {
window.removeEventListener('resize', handleFaultPieResize);
if (faultPieChart && !faultPieChart.isDisposed()) {
faultPieChart.dispose();
}
};
}
}, []);
useEffect(() => {
if (chartRef.current) {
const chart = echarts.init(chartRef.current);
// 强制初始化时调整大小
setTimeout(() => {
if (chart && !chart.isDisposed()) {
chart.resize();
}
}, 100);
const option = {
color: ['#8979FF', '#3CC3DF'],
legend: {
// data: ['消防水泵1', '消防水泵2'],
top: "-3px",
// left: "center",
// itemGap: 40,
itemWidth: 20,
itemHeight: 8,
// icon: 'path://M902 472.7H747.9c-19.1-113.3-117.7-200-236.4-200s-217.3 86.7-236.4 200H119.7c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h155.5c19.1 113.3 117.7 200 236.4 200S728.9 666 748 552.7h154c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8z m-390.5 200c-88.2 0-160-71.8-160-160s71.8-160 160-160 160 71.8 160 160-71.8 160-160 160z',
textStyle: {
fontSize: 10
}
},
grid: {
left: '2%',
right: '4%',
bottom: '2%',
top: '12%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['9:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00'],
axisLabel: {
fontSize: 10
}
},
yAxis: {
type: 'value',
min: 0,
max: 30,
axisLabel: {
formatter: '{value}',
fontSize: 10
}
},
series: [
{
name: '消防水泵1',
type: 'line',
smooth: false,
lineStyle: {
width: 2,
color: '#8979FF'
},
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: 4,
itemStyle: {
color: '#fff',
borderColor: '#8979FF',
borderWidth: 1
},
data: [12, 15, 18, 14, 16, 20, 22, 19, 17, 21, 23, 25]
},
{
name: '消防水泵2',
type: 'line',
smooth: false,
lineStyle: {
width: 2,
color: '#3CC3DF'
},
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: 4,
itemStyle: {
color: '#fff',
borderColor: '#3CC3DF',
borderWidth: 1
},
data: [8, 11, 14, 10, 13, 17, 19, 16, 14, 18, 20, 22]
}
]
};
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 = [
@ -641,128 +302,64 @@ const EnvironmentalPersonnelManagement = () => {
<div className={styles.sectionContent}>
<div className={styles.blocksContainer}>
{/* 块1 */}
<div className={styles.blockItem}>
<div className={`${styles.blockItem} ${styles.block1}`}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>设备总数</div>
<div className={styles.blockNumber}>1280</div>
</div>
<div className={styles.blockRight}>
<img src={eqicon1} alt="设备总数" className={styles.blockImage} />
<div className={styles.blockTitle}>环保总人数</div>
<div className={styles.blockNumber}>258</div>
<div className={styles.blockTime}>截止到 2025-09-11 07:35</div>
</div>
</div>
{/* 块2 */}
<div className={styles.blockItem}>
<div className={`${styles.blockItem} ${styles.block2}`}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>正常运行</div>
<div className={styles.blockNumber}>480</div>
</div>
<div className={styles.blockRight}>
<img src={eqicon2} alt="高风险设备" className={styles.blockImage} />
<div className={styles.blockTitle}>环保总人数</div>
<div className={styles.blockNumber}>258</div>
<div className={styles.blockTime}>截止到 2025-09-11 07:35</div>
</div>
</div>
{/* 块3 */}
<div className={styles.blockItem}>
<div className={`${styles.blockItem} ${styles.block3}`}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>需要维护</div>
<div className={styles.blockNumber}>347</div>
</div>
<div className={styles.blockRight}>
<img src={eqicon3} alt="今日预警次数" className={styles.blockImage} />
</div>
</div>
{/* 块4 */}
<div className={styles.blockItem}>
<div className={`${styles.blockItem} ${styles.block4}`}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>故障设备</div>
<div className={styles.blockNumber}>289</div>
</div>
<div className={styles.blockRight}>
<img src={eqicon4} alt="未处理预警" className={styles.blockImage} />
<div className={styles.blockTitle}>环保总人数</div>
<div className={styles.blockNumber}>258</div>
<div className={styles.blockTime}>截止到 2025-09-11 07:35</div>
</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>
设备状态分布
{/* 块5 */}
<div className={`${styles.blockItem} ${styles.block5}`}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>环保总人数</div>
<div className={styles.blockNumber}>258</div>
<div className={styles.blockTime}>截止到 2025-09-11 07:35</div>
</div>
<Segmented
className={styles.block1Segmented}
options={['月', '季', '年']}
onChange={(value) => {
console.log(value);
}}
/>
</div>
{/* 设备状态饼图 */}
<div className={styles.deviceStatusChart} ref={pieChartRef}>
</div>
</div>
<div className={styles.middleBlock12}>
<div className={styles.block1Header}>
<div className={styles.block1Title}>
<div className={styles.titleIcon}></div>
设备故障类型分布
{/* 块6 */}
<div className={`${styles.blockItem} ${styles.block6}`}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>环保总人数</div>
<div className={styles.blockNumber}>258</div>
<div className={styles.blockTime}>截止到 2025-09-11 07:35</div>
</div>
<Select
className={styles.customSelect}
style={{
width: 120,
display: 'flex',
alignItems: 'center'
}}
defaultValue="全部区域22"
options={[
{ value: '全部区域33', label: '全部区域33' },
{ value: '部分区域', label: '部分区域' },
]}
/>
</div>
{/* 设备故障类型饼图 */}
<div className={styles.deviceStatusChart} ref={faultPieChartRef}>
</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: 80 }}
defaultValue="今日"
options={[
{ value: '近3天', label: '近3天' },
{ value: '近7天', label: '近7天' },
]}
/>
</div>
</div>
<div className={styles.middleBlock2Chart} ref={chartRef}>
</div>
</div>
</div>
</div>
{/* 第三个div - 占满剩余位置 */}
<div className={styles.RcontainerBottom}>
<div className={styles.sectionContent}>

@ -7,7 +7,7 @@
// 第一个div - 高度20%
.RcontainerTop {
height: 16%;
height: 18%;
// background-color: #fff;
border-radius: 4px;
display: flex;
@ -29,12 +29,72 @@
flex: 1;
height: 100%;
display: flex;
background: linear-gradient(170.5deg, #F5F7FF 6.87%, #FFFFFF 47.65%);
// background: linear-gradient(170.5deg, #F5F7FF 6.87%, #FFFFFF 47.65%);
border-radius: 4px;
border: 2px solid #FFFFFF;
// border: 2px solid #FFFFFF;
// 块1 - 蓝色渐变 + SVG背景
&.block1 {
background:
url('@/assets/business_envinformation/background1.svg'),
linear-gradient(180deg, #DBEBFF 0%, #DBEBFF 12.5%, rgba(255, 255, 255, 0.700824) 56%, rgba(255, 255, 255, 0.01) 100%);
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
}
// 块2 - 黄色渐变
&.block2 {
background:
url('@/assets/business_envinformation/background2.svg'),
linear-gradient(180deg, #FFFEDB 0%, #F5FFDB 19.23%, #FFFFFF 55.77%, #FFFFFF 100%);
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
}
// 块3 - 绿色渐变
&.block3 {
background:
url('@/assets/business_envinformation/background3.svg'),
linear-gradient(180deg, #8CFFCD 0%, #C0FFE4 12.5%, #FFFFFF 56%, #FFFFFF 100%);
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
}
// 块4 - 青色渐变
&.block4 {
background:
url('@/assets/business_envinformation/background4.svg'),
linear-gradient(180deg, #C5FFFC 0%, #C0FFFC 12.5%, #FFFFFF 56%, #FFFFFF 100%);
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
}
// 块5 - 红色渐变
&.block5 {
background:
url('@/assets/business_envinformation/background4.svg'),
linear-gradient(180deg, #FFD2D2 0%, #FFD9D9 12.5%, #FFFFFF 56%, #FFFFFF 100%);
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
}
// 块6 - 紫色渐变
&.block6 {
background:
url('@/assets/business_envinformation/background6.svg'),
linear-gradient(180deg, #F2D7FF 0%, #F4DDFF 12.5%, #FFFFFF 56%, #FFFFFF 100%);
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
}
.blockLeft {
width: 60%;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
@ -59,6 +119,14 @@
line-height: 1.2;
}
.blockTime {
font-family: PingFang SC;
font-weight: 400;
font-size: 10px;
color: #999999;
line-height: 1.2;
}
.blockChange {
font-family: PingFang SC;
font-weight: 400;
@ -103,268 +171,10 @@
}
}
// 第二个div - 高度39%
.RcontainerMiddle {
height: 33%;
border-radius: 4px;
display: flex;
flex-direction: column;
.sectionContent {
height: 100%;
display: flex;
display: flex;
gap: 10px;
height: 100%;
.middleBlock1 {
// flex: 1;
width: 28%;
height: 100%;
background: #fff;
border: 2px solid #fff;
// border-radius: 4px;
position: relative;
padding: 0px 10px 10px 2px;
font-family: PingFang SC;
font-size: 14px;
color: #333333;
.block1Header {
position: absolute;
top: 5px;
left: 10px;
right: 10px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 10;
.block1Title {
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
color: #333333;
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
}
}
.block1Segmented {
padding: 0;
margin: 0;
border: 1px solid #E3E3E3;
border-radius: 4px;
height: 28px;
:global(.ant-segmented) {
padding: 0;
margin: 0;
height: 28px;
}
:global(.ant-segmented-item) {
font-size: 12px;
padding: 2px 8px;
height: 26px;
line-height: 26px;
display: flex;
align-items: center;
justify-content: center;
}
:global(.ant-segmented-item-selected) {
background-color: #1890ff;
color: #fff;
}
}
}
.deviceStatusChart {
position: absolute;
top: 35px;
left: 10px;
right: 10px;
bottom: 10px;
z-index: 10;
}
// .block1Chart {
// width: 100%;
// height: 100%;
// margin-top: 20px;
// .mapImage {
// margin-top: 7%;
// width: 90%;
// height: 77%;
// object-fit: cover;
// border-radius: 4px;
// display: block;
// margin-left: auto;
// margin-right: auto;
// }
// }
}
.middleBlock12 {
flex: 1;
height: 100%;
background-color: #fff;
display: flex;
flex-direction: column;
font-family: PingFang SC;
font-size: 14px;
color: #333333;
padding: 5px 10px 5px 10px;
position: relative;
.block1Header {
position: absolute;
top: 5px;
left: 10px;
right: 10px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 10;
.block1Title {
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
color: #333333;
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
}
}
.block1Segmented {
padding: 0;
margin: 0;
border: 1px solid #E3E3E3;
border-radius: 4px;
height: 28px;
:global(.ant-segmented) {
padding: 0;
margin: 0;
height: 28px;
}
:global(.ant-segmented-item) {
font-size: 12px;
padding: 2px 8px;
height: 26px;
line-height: 26px;
display: flex;
align-items: center;
justify-content: center;
}
:global(.ant-segmented-item-selected) {
background-color: #1890ff;
color: #fff;
}
}
.customSelect {
:global(.ant-select-single:not(.ant-select-customize-input) .ant-select-selector) {
height: 26px !important;
display: flex !important;
align-items: center !important;
}
:global(.ant-select-selection-item) {
line-height: 24px !important;
// height: 24px !important;
display: flex !important;
align-items: center !important;
}
}
}
.deviceStatusChart {
position: absolute;
top: 35px;
left: 10px;
right: 10px;
bottom: 10px;
z-index: 10;
}
}
.middleBlock2 {
flex: 1;
height: 100%;
// background: linear-gradient(170.5deg, #EBEFF4 6.87%, #FFFFFF 53.01%);
// border: 2px solid #fff;
background-color: #fff;
// border-radius: 4px;
display: flex;
flex-direction: column;
font-family: PingFang SC;
font-size: 14px;
color: #333333;
padding: 5px 10px 5px 10px;
.middleBlock2Title {
display: flex;
justify-content: space-between;
align-items: center;
// margin-bottom: 10px;
.titleLeft {
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
color: #333333;
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
}
}
.titleRight {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: #666;
}
}
.middleBlock2Chart {
width: 100%;
height: 100%;
// min-height: 200px;
}
}
}
}
// 第三个div - 高度不超过45%
// 第三个div - 占满剩余位置
.RcontainerBottom {
height: 45%; // 限制高度不超过45%
max-height: 45%; // 确保最大高度不超过45%
flex: 1; // 占满剩余空间
display: flex;
flex-direction: column;

@ -4,9 +4,9 @@ import styles from './EquipmentManagement.less';
const EquipmentManagement = () => {
return (
<div className={styles.container}>
<div className={styles.developingBox}>
<div className={styles.developingText}>开发中</div>
</div>
开发中
</div>
);
};

@ -1,920 +1,52 @@
import React, { useEffect, useRef, useState } from 'react';
import { Card, Result, Select, Button, Segmented, Progress, Input } from 'antd';
import { CheckCircleOutlined, ExportOutlined, HeartFilled, LineHeightOutlined, ExclamationCircleOutlined, SearchOutlined } from '@ant-design/icons';
import * as echarts from 'echarts';
import StandardTable from '@/components/StandardTable';
import React, { useState } from 'react';
import { Tabs } from 'antd';
import styles from './EvaluationReport.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';
import eqicon1 from '@/assets/business_basic/eqicon1.png';
import eqicon2 from '@/assets/business_basic/eqicon2.png';
import eqicon3 from '@/assets/business_basic/eqicon3.png';
import eqicon4 from '@/assets/business_basic/eqicon4.png';
// 导入子页面组件
import PermitStatistics from './secondary_menu/PermitStatistics';
import EnvironmentalTaskList from './secondary_menu/EnvironmentalTaskList';
import DischargePermitManagement from './secondary_menu/DischargePermitManagement';
const EvaluationReport = () => {
const chartRef = useRef(null);
const pieChartRef = useRef(null);
const faultPieChartRef = 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: 8,
total: 0,
});
const [searchText, setSearchText] = useState('');
const [activeTab, setActiveTab] = useState('permit-statistics');
// 柱状图初始化
useEffect(() => {
if (pieChartRef.current) {
const barChart = echarts.init(pieChartRef.current);
const barOption = {
grid: {
left: '5%',
right: '5%',
bottom: '10%',
top: '20%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['灭火器', '消火栓', '报警器', '疏散灯', '排烟设备'],
axisLabel: {
fontSize: 12,
color: '#333',
interval: 0,
rotate: 0
},
axisLine: {
show: false
},
axisTick: {
show: false
}
},
yAxis: {
type: 'value',
min: 0,
max: 50,
interval: 10,
axisLabel: {
fontSize: 12,
color: '#666',
formatter: '{value}'
},
axisLine: {
show: false
},
axisTick: {
show: false
},
splitLine: {
lineStyle: {
color: '#00001A26',
type: 'dashed'
}
}
},
series: [{
name: '使用次数',
type: 'bar',
barWidth: 27,
data: [35, 28, 42, 31, 38],
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: '#199BFB' },
{ offset: 1, color: '#1373FA' }
]
}
},
emphasis: {
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: '#0D7AE8' },
{ offset: 1, color: '#0F5BC7' }
]
}
}
}
}],
legend: {
show: true,
top: '5%',
left: 'center',
itemWidth: 15,
itemHeight: 3,
textStyle: {
fontSize: 12,
color: '#333'
},
data: [{
name: '使用次数',
icon: 'rect',
itemStyle: {
color: '#4B69F1'
}
}]
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function (params) {
return `${params[0].name}<br/>使用次数: ${params[0].value}`;
}
}
};
barChart.setOption(barOption);
// 响应式调整
const handleBarResize = () => {
if (barChart && !barChart.isDisposed()) {
barChart.resize();
}
};
window.addEventListener('resize', handleBarResize);
return () => {
window.removeEventListener('resize', handleBarResize);
if (barChart && !barChart.isDisposed()) {
barChart.dispose();
}
};
}
}, []);
// 维护费用趋势折线图初始化
useEffect(() => {
if (faultPieChartRef.current) {
const faultPieChart = echarts.init(faultPieChartRef.current);
const faultPieOption = {
legend: {
show: true,
top: '5%',
left: 'center',
itemWidth: 20,
itemHeight: 8,
textStyle: {
color: '#333',
fontSize: 12
}
},
grid: {
left: '5%',
right: '5%',
bottom: '10%',
top: '20%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
axisLine: {
lineStyle: {
color: '#E5E5E5'
}
},
axisTick: {
show: false
},
axisLabel: {
color: '#666',
fontSize: 12,
interval: 0
}
},
yAxis: {
type: 'value',
min: 20000,
max: 30000,
interval: 2000,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
color: '#666',
fontSize: 12,
formatter: '¥{value}'
},
splitLine: {
lineStyle: {
color: '#00001A26',
type: 'dashed'
}
}
},
series: [{
name: '费用',
type: 'line',
data: [29000, 21000, 27500, 21900, 26000, 25000, 27000, 24000, 22300, 28000, 29000, 27000],
smooth: false,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
color: '#1269FF',
width: 1
},
itemStyle: {
color: '#FFFFFF',
borderColor: '#1269FF',
borderWidth: 1
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: 'rgba(18, 105, 255, 0.3)'
}, {
offset: 1,
color: 'rgba(18, 105, 255, 0.05)'
}]
}
}
}]
};
faultPieChart.setOption(faultPieOption);
// 响应式调整
const handleFaultPieResize = () => {
if (faultPieChart && !faultPieChart.isDisposed()) {
faultPieChart.resize();
}
};
window.addEventListener('resize', handleFaultPieResize);
return () => {
window.removeEventListener('resize', handleFaultPieResize);
if (faultPieChart && !faultPieChart.isDisposed()) {
faultPieChart.dispose();
}
};
}
}, []);
useEffect(() => {
if (chartRef.current) {
const chart = echarts.init(chartRef.current);
// 强制初始化时调整大小
setTimeout(() => {
if (chart && !chart.isDisposed()) {
chart.resize();
}
}, 100);
const option = {
color: ['#3C7EFF', '#FF8800', '#FFC403', '#31BCFF'],
legend: {
orient: 'vertical',
right: '2%',
top: 'middle',
itemWidth: 14,
itemHeight: 5,
textStyle: {
fontSize: 10,
color: '#666'
}
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{d}%'
},
series: [
{
name: '设备类型占比',
type: 'pie',
radius: '70%',
center: ['40%', '55%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 0,
borderColor: '#fff',
borderWidth: 1
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: false
}
},
labelLine: {
show: false
},
data: [
{ value: 25, name: '灭火器' },
{ value: 30, name: '消防栓' },
{ value: 20, name: '报警器' },
{ value: 25, name: '烟雾探测器' }
]
}
]
};
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: 60,
render: (text, record, index) => {
const page = pagination.current || 1;
const pageSize = pagination.pageSize || 8;
const number = (page - 1) * pageSize + index + 1;
return `0${number}`.slice(-2);
}
},
// 标签页配置
const tabItems = [
{
title: '设备编号',
dataIndex: 'deviceId',
key: 'deviceId',
width: 140,
key: 'permit-statistics',
label: '许可证信息统计表',
children: <PermitStatistics />
},
{
title: '设备名称',
dataIndex: 'deviceName',
key: 'deviceName',
width: 110,
key: 'environmental-task-list',
label: '环保管理任务清单2',
children: <EnvironmentalTaskList />
},
{
title: '类型',
dataIndex: 'modelSpec',
key: 'modelSpec',
width: 120,
},
{
title: '安装位置',
dataIndex: 'installLocation',
key: 'installLocation',
width: 100,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 100,
render: (text) => {
const statusMap = {
'报废': { color: '#FF3E48', bg: '#FFE0E2' },
'待维修': { color: '#FF8800', bg: '#FFF3E9' },
'已使用': { color: '#00AAFA', bg: '#DAF3FF' },
'正常': { color: '#44BB5F', bg: '#D8F7DE' }
};
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: '最后维护时间',
dataIndex: 'lastMaintenance',
key: 'lastMaintenance',
width: 150,
},
{
title: '操作',
key: 'action',
width: 140,
render: (_, record) => (
<div>
<Button type="link" size="small" style={{
padding: '2px 8px',
fontSize: 12,
marginRight: 8,
border: '1px solid #E6E9FB',
backgroundColor: 'transparent',
borderRadius: '4px'
}}>
编辑
</Button>
<Button type="link" size="small" style={{
padding: '2px 8px',
fontSize: 12,
color: '#FF2526',
border: '1px solid #FFE0E2',
backgroundColor: 'transparent',
borderRadius: '4px'
}}>
删除
</Button>
</div>
),
},
];
// 模拟数据
const mockData = [
{
key: '1',
id: '001',
deviceId: 'HQ-XF-01-001',
deviceName: '干粉灭火器',
modelSpec: '灭火设备',
installLocation: '1层大厅',
status: '报废',
lastMaintenance: '2025-09-10',
},
{
key: '2',
id: '002',
deviceId: 'HQ-XF-02-015',
deviceName: '室内消火栓',
modelSpec: '灭火设备',
installLocation: '3层东区',
status: '已使用',
lastMaintenance: '2025-09-10',
},
{
key: '3',
id: '003',
deviceId: 'HQ-XF-03-007',
deviceName: '火警报警器',
modelSpec: '报警设备',
installLocation: '地下一层',
status: '正常',
lastMaintenance: '2025-09-10',
},
{
key: '4',
id: '004',
deviceId: 'HQ-XF-03-008',
deviceName: '火警报警器',
modelSpec: '报警设备',
installLocation: '地下一层',
status: '待维修',
lastMaintenance: '2025-09-10',
},
{
key: '5',
id: '005',
deviceId: 'HQ-XF-01-009',
deviceName: '干粉灭火器',
modelSpec: '灭火设备',
installLocation: '地下一层',
status: '报废',
lastMaintenance: '2025-09-10',
},
{
key: '6',
id: '006',
deviceId: 'HQ-XF-01-010',
deviceName: '室内消火栓',
modelSpec: '灭火设备',
installLocation: '地下一层',
status: '已使用',
lastMaintenance: '2025-09-10',
},
{
key: '7',
id: '007',
deviceId: 'HQ-XF-01-011',
deviceName: '火警报警器',
modelSpec: '报警设备',
installLocation: '地下一层',
status: '待维修',
lastMaintenance: '2025-09-10',
},
{
key: '8',
id: '008',
deviceId: 'HQ-XF-01-012',
deviceName: '火警报警器',
modelSpec: '报警设备',
installLocation: '地下一层',
status: '正常',
lastMaintenance: '2025-09-10',
},
{
key: '9',
id: '009',
deviceId: 'HQ-XF-01-013',
deviceName: '干粉灭火器',
modelSpec: '灭火设备',
installLocation: '地下一层',
status: '已使用',
lastMaintenance: '2025-09-10',
},
{
key: '10',
id: '010',
deviceId: 'HQ-XF-01-014',
deviceName: '室内消火栓',
modelSpec: '灭火设备',
installLocation: '地下一层',
status: '待维修',
lastMaintenance: '2025-09-10',
},
{
key: '11',
id: '011',
deviceId: 'HQ-XF-01-015',
deviceName: '火警报警器',
modelSpec: '报警设备',
installLocation: '地下一层',
status: '正常',
lastMaintenance: '2025-09-10',
},
{
key: '12',
id: '012',
deviceId: 'HQ-XF-01-016',
deviceName: '火警报警器',
modelSpec: '报警设备',
installLocation: '地下一层',
status: '已使用',
lastMaintenance: '2025-09-10',
},
{
key: '13',
id: '013',
deviceId: 'HQ-XF-01-017',
deviceName: '干粉灭火器',
modelSpec: '灭火设备',
installLocation: '2层西区',
status: '报废',
lastMaintenance: '2024-08-15',
},
{
key: '14',
id: '014',
deviceId: 'HQ-XF-02-018',
deviceName: '室内消火栓',
modelSpec: '灭火设备',
installLocation: '4层南区',
status: '报废',
lastMaintenance: '2024-07-20',
},
{
key: '15',
id: '015',
deviceId: 'HQ-XF-03-019',
deviceName: '火警报警器',
modelSpec: '报警设备',
installLocation: '地下二层',
status: '报废',
lastMaintenance: '2024-06-10',
},
{
key: '16',
id: '016',
deviceId: 'HQ-XF-01-020',
deviceName: '干粉灭火器',
modelSpec: '灭火设备',
installLocation: '5层北区',
status: '报废',
lastMaintenance: '2024-05-05',
},
key: 'discharge-permit-management',
label: '排污许可执行管理',
children: <DischargePermitManagement />
}
];
// 初始化数据
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 handleAddDevice = () => {
console.log('新增设备');
// TODO: 实现新增设备逻辑
};
// 导出数据按钮点击事件
const handleExportData = () => {
console.log('导出数据');
// TODO: 实现导出数据逻辑
};
// 分页变化处理
const handleTableChange = (pagination) => {
setPagination(prev => ({
...prev,
current: pagination.current,
pageSize: pagination.pageSize,
}));
};
// 搜索处理
const handleSearchChange = (e) => {
setSearchText(e.target.value);
console.log('搜索:', e.target.value);
// TODO: 实现搜索逻辑,根据设备名称、编号等筛选数据
// 标签页切换处理
const handleTabChange = (key) => {
setActiveTab(key);
};
return (
<div className={styles.Econtainer}>
{/* 第1个div - 高度39% */}
<div className={styles.EcontainerMiddle}>
<div className={styles.sectionContent}>
<div className={styles.middleBlock1}>
<div className={styles.block1Header}>
<div className={styles.block1Title}>
<div className={styles.titleIcon}></div>
设备使用频率分析
</div>
</div>
{/* 设备状态饼图 */}
<div className={styles.deviceStatusChart} ref={pieChartRef}>
</div>
</div>
<div className={styles.middleBlock12}>
<div className={styles.block1Header}>
<div className={styles.block1Title}>
<div className={styles.titleIcon}></div>
近一年维护费用趋势
</div>
</div>
{/* 维护费用趋势折线图 */}
<div className={styles.deviceStatusChart} ref={faultPieChartRef}>
</div>
</div>
<div className={styles.middleBlock2}>
<div className={styles.middleBlock2Title}>
<div className={styles.titleLeft}>
<div className={styles.titleIcon}></div>
<div>设备类型占比</div>
</div>
</div>
<div className={styles.middleBlock2Chart} ref={chartRef}>
</div>
</div>
</div>
</div>
{/* 第2个div - 占满剩余位置 */}
<div className={styles.EcontainerBottom}>
<div className={styles.sectionContent}>
<div className={styles.leftBlock}>
<div className={styles.maintenanceStack}>
<div className={styles.maintenanceSection}>
<div className={styles.maintenanceTitle}>
<div className={styles.titleIcon}></div>
<div>近期维护提醒</div>
</div>
<div className={styles.maintenanceContent1}>
<div className={styles.maintenanceItem}>
<div className={styles.maintenanceLeft}>
<div className={styles.maintenanceText1}>SH-MHQ-023-C 干粉灭火器</div>
<div className={styles.maintenanceText2}>位置: 4楼办公区丨维护类型: 季度检查</div>
<div className={styles.maintenanceText3}>负责人: 张三</div>
</div>
<div className={styles.maintenanceRight}>
<div className={styles.maintenanceStatus}>3天后到期</div>
</div>
</div>
<div className={styles.maintenanceItem}>
<div className={styles.maintenanceLeft}>
<div className={styles.maintenanceText1}>SH-XHS-045-D 室内消火栓</div>
<div className={styles.maintenanceText2}>位置: 2楼东侧走廊丨维护类型: 水压测试</div>
<div className={styles.maintenanceText3}>负责人: 李四</div>
</div>
<div className={styles.maintenanceRight2}>
<div className={styles.maintenanceStatus}>8天后到期</div>
</div>
</div>
</div>
</div>
<div className={styles.maintenanceSection}>
<div className={styles.maintenanceTitle}>
<div className={styles.titleIcon}></div>
<div>维护任务进度</div>
</div>
<div className={styles.maintenanceContent2}>
{/* 进度条区域 */}
<div className={styles.progressSection}>
<div className={styles.progressLabel}>月度维护计划</div>
<Progress percent={75} status="active" />
<div className={styles.progressLabel}>季度维护计划</div>
<Progress percent={60} status="active" />
<div className={styles.progressLabel}>年度维护计划</div>
<Progress percent={85} status="active" />
{/* 警告提示框 */}
<div className={styles.warningBox}>
<ExclamationCircleOutlined className={styles.warningIcon} />
<span className={styles.warningText}>本月有5项维护任务即将到期</span>
</div>
</div>
</div>
</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.tableActions}>
<div className={styles.leftActions}>
<Input
placeholder="搜索设备名称、编号..."
onChange={handleSearchChange}
value={searchText}
style={{ width: 250, fontSize: 12 }}
allowClear
suffix={<SearchOutlined />}
/>
</div>
<div className={styles.rightActions}>
<button className={styles.actionButton} onClick={handleAddDevice}>
<span className={styles.buttonIcon}>+</span>
<span>新增设备</span>
</button>
<button className={styles.actionButton} onClick={handleExportData}>
<span className={styles.buttonIcon}><ExportOutlined /></span>
<span>导出数据</span>
</button>
</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}`,
}}
/>
</div>
</div>
</div>
</div>
<div className={styles.container}>
<Tabs
activeKey={activeTab}
onChange={handleTabChange}
items={tabItems}
className={styles.tabs}
style={{
'--ant-tabs-tab-color': '#AFAFAF',
'--ant-tabs-tab-active-color': '#009D6F',
'--ant-tabs-tab-active-bg': '#fff'
}}
/>
</div>
);
};

@ -1,556 +1,91 @@
.Econtainer {
padding: 8px 6px 0px 6px;
.container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
gap: 10px;
// 第二个div - 高度35%
.EcontainerMiddle {
// height: 400px;
min-height: 35%;
border-radius: 4px;
display: flex;
flex-direction: column;
.sectionContent {
height: 100%;
display: flex;
display: flex;
gap: 10px;
height: 100%;
.middleBlock1 {
width: 30%;
height: 100%;
background: #fff;
border: 2px solid #fff;
position: relative;
padding: 0px 10px 10px 2px;
font-family: PingFang SC;
font-size: 14px;
color: #333333;
.block1Header {
position: absolute;
top: 5px;
left: 10px;
right: 10px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 10;
.block1Title {
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
margin-top: 5px;
color: #333333;
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
}
}
}
padding: 16px;
// background-color: #f5f5f5;
.tabs {
height: 100%;
background-color: transparent;
border-radius: 8px;
// box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
:global(.ant-tabs-nav) {
margin: 0;
padding: 0 20px;
background-color: transparent;
border-bottom: none;
}
.deviceStatusChart {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
z-index: 10;
min-height: 100%;
}
:global(.ant-tabs-tab) {
padding: 16px 24px !important;
font-size: 14px !important;
font-weight: 400 !important;
color: #AFAFAF !important;
background: transparent !important;
border: none !important;
position: relative;
&:hover {
color: #AFAFAF !important;
background-color: transparent !important;
}
.middleBlock12 {
flex: 1;
height: 100%;
background-color: #fff;
display: flex;
flex-direction: column;
font-family: PingFang SC;
font-size: 14px;
color: #333333;
padding: 5px 10px 5px 10px;
position: relative;
.block1Header {
position: absolute;
top: 5px;
left: 10px;
right: 10px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 10;
.block1Title {
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
margin-top: 5px;
color: #333333;
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
}
}
&.ant-tabs-tab-active {
color: #009D6F !important;
background-color: #fff !important;
border-bottom: none !important;
}
.deviceStatusChart {
&::after {
content: '';
position: absolute;
top: 10px;
left: 10px;
right: 10px;
// bottom: 10px;
z-index: 10;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 38.36132812500014px;
height: 3.3613271713256965px;
background-color: #009D6F;
border-radius: 2px;
z-index: 1;
}
}
}
.middleBlock12 {
width: 45%;
height: 100%;
background-color: #fff;
display: flex;
flex-direction: column;
font-family: PingFang SC;
font-size: 14px;
color: #333333;
padding: 5px 10px 5px 10px;
position: relative;
.block1Header {
position: absolute;
top: 5px;
left: 10px;
right: 10px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 10;
.block1Title {
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
color: #333333;
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
}
}
}
.deviceStatusChart {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
// bottom: 10px;
min-height: 100%;
z-index: 10;
}
}
.middleBlock2 {
// flex: 1;
width: calc(100% - 75% - 15px);
height: 100%;
// background: linear-gradient(170.5deg, #EBEFF4 6.87%, #FFFFFF 53.01%);
// border: 2px solid #fff;
background-color: #fff;
// border-radius: 4px;
display: flex;
flex-direction: column;
font-family: PingFang SC;
font-size: 14px;
color: #333333;
padding: 5px 10px 5px 10px;
.middleBlock2Title {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 5px;
.titleLeft {
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
color: #333333;
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
}
}
// 额外的全局样式覆盖,确保优先级足够高
:global(.ant-tabs-tab.ant-tabs-tab-active) {
color: #009D6F !important;
background-color: #fff !important;
border-bottom: none !important;
}
}
// 更强的选择器优先级
:global(.ant-tabs .ant-tabs-tab.ant-tabs-tab-active) {
color: #009D6F !important;
background-color: #fff !important;
border-bottom: none !important;
}
.middleBlock2Chart {
width: 100%;
height: 100%;
}
}
// 针对可能的嵌套结构
:global(.ant-tabs-nav .ant-tabs-tab.ant-tabs-tab-active) {
color: #009D6F !important;
background-color: #fff !important;
border-bottom: none !important;
}
}
// 第三个div - 占满剩余位置
.EcontainerBottom {
display: flex;
flex-direction: column;
flex-shrink: 0;
// 覆盖Ant Design的默认下划线
:global(.ant-tabs-ink-bar) {
display: none !important;
}
.sectionContent {
display: flex;
flex-direction: row;
flex: 1;
gap: 10px;
padding: 0;
:global(.ant-tabs-content-holder) {
height: calc(100% - 60px);
padding: 20px;
.leftBlock {
width: 30%;
flex-shrink: 0;
.ant-tabs-content {
height: 100%;
padding: 0;
display: flex;
flex-direction: column;
gap: 10px;
.leftBlockTitle {
display: flex;
align-items: center;
gap: 8px;
font-family: PingFang SC;
font-weight: 500;
font-size: 14px;
color: #333333;
margin-bottom: 10px;
.titleIcon {
width: 3px;
height: 16px;
background-color: #2E4CD4;
}
}
.maintenanceStack {
width: 100%;
.ant-tabs-tabpane {
height: 100%;
display: flex;
flex-direction: column;
gap: 10px;
.maintenanceSection {
width: 100%;
height: 50%;
background: #FFF;
border-radius: 4px;
display: flex;
flex-direction: column;
padding: 12px 14px;
.maintenanceTitle {
display: flex;
align-items: center;
gap: 8px;
font-family: PingFang SC;
font-weight: 500;
font-size: 14px;
color: #333333;
margin-bottom: 8px;
}
.titleIcon {
width: 3px;
height: 16px;
background-color: #2E4CD4;
}
.maintenanceContent {
flex: 1;
width: 100%;
}
.maintenanceContent1 {
flex: 1;
width: 100%;
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 8px;
.maintenanceItem {
display: flex;
align-items: center;
justify-content: space-between;
background-color: #F1F7FF;
border-radius: 4px;
padding: 16px 16px;
.maintenanceLeft {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
.maintenanceText1 {
font-size: 14px;
font-weight: 500;
color: #333333;
font-family: PingFang SC;
}
.maintenanceText2 {
font-size: 12px;
color: #666666;
font-family: PingFang SC;
}
.maintenanceText3 {
font-size: 12px;
color: #666666;
font-family: PingFang SC;
}
}
.maintenanceRight {
flex: 0 0 auto;
display: flex;
align-items: center;
justify-content: center;
.maintenanceStatus {
font-size: 12px;
color: #FF3E48;
font-weight: 500;
font-family: PingFang SC;
background-color: #FFE0E2;
padding: 4px 8px;
border-radius: 4px;
// border: 1px solid #FFE0E2;
}
}
.maintenanceRight2 {
flex: 0 0 auto;
display: flex;
align-items: center;
justify-content: center;
.maintenanceStatus {
font-size: 12px;
color: #FF8800;
font-weight: 500;
font-family: PingFang SC;
background-color: #FFF3E9;
padding: 4px 8px;
border-radius: 4px;
// padding-right: 2px;
}
}
}
}
.maintenanceContent2 {
flex: 1;
width: 100%;
display: flex;
flex-direction: column;
gap: 15px;
padding: 8px 0;
.warningBox {
display: flex;
align-items: center;
gap: 8px;
background-color: #FFF3CD;
border: 1px solid #F4E3AE;
border-radius: 4px;
padding: 8px 12px;
// margin-bottom: 8px;
// margin-top: 10px;
.warningIcon {
color: #8C6C0B;
font-size: 14px;
}
.warningText {
color: #8C6C0B;
font-size: 12px;
font-family: PingFang SC;
font-weight: 400;
}
}
.progressSection {
width: 100%;
display: flex;
flex-direction: column;
// gap: 12px;
padding: 0px 12px 12px 12px;
.progressLabel {
font-size: 12px;
color: #666666;
font-family: PingFang SC;
font-weight: 400;
}
// 自定义进度条样式
:global(.ant-progress) {
.ant-progress-bg {
background: linear-gradient(90deg, #2E4CD4 0%, #4B69F1 100%);
}
.ant-progress-text {
color: #2E4CD4;
font-weight: 500;
}
}
}
}
}
}
}
.rightBlock {
width: calc(100% - 28% - 10px);
height: 100%;
background-color: #fff;
padding: 0;
display: flex;
flex-direction: column;
.tableHeader {
display: flex;
justify-content: space-between;
align-items: center;
padding: 11px 15px 5px 15px;
.tableTitle {
display: flex;
align-items: center;
gap: 8px;
font-family: PingFang SC;
font-weight: 500;
font-size: 14px;
color: #333333;
.titleIcon {
width: 3px;
height: 16px;
background-color: #2E4CD4;
}
}
}
.tableActions {
display: flex;
justify-content: space-between;
align-items: center;
gap: 8px;
margin-top: 5px;
padding: 0px 15px;
.leftActions {
display: flex;
align-items: center;
}
.rightActions {
display: flex;
gap: 8px;
align-items: center;
}
.actionButton {
display: flex;
align-items: center;
gap: 4px;
height: 28px;
border: 1px solid #DFE4F6;
border-radius: 4px;
color: #2E4CD4;
font-weight: 500;
font-size: 12px;
padding: 0px 8px;
background: transparent;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
background-color: #f0f2ff;
border-color: #2E4CD4;
}
&:active {
background-color: #e6ebff;
}
.buttonIcon {
font-size: 14px;
font-weight: bold;
}
}
}
.tableContainer {
flex: 1;
overflow: hidden;
margin: 10px 15px 0 15px; // 上边距10px左右边距15px
:global(.ant-table) {
font-size: 12px;
}
:global(.ant-table-thead > tr > th) {
background-color: #f5f5fa;
font-weight: 500;
font-size: 14px;
color: #333333;
border-bottom: 1px solid #f0f0f0;
padding: 8px 12px;
text-align: center;
}
:global(.ant-table-tbody > tr > td) {
padding: 8px 12px;
border-bottom: 1px solid #f0f0f0;
text-align: center;
color: #666666;
}
:global(.ant-table-tbody > tr:hover > td) {
background-color: #f5f5f5;
}
:global(.ant-pagination) {
margin-top: 16px;
text-align: right;
}
}
}
}

@ -4,9 +4,7 @@ import styles from './PollutionSourceManagement.less';
const PollutionSourceManagement = () => {
return (
<div className={styles.container}>
<div className={styles.developingBox}>
<div className={styles.developingText}>开发中</div>
</div>
开发中
</div>
);
};

@ -0,0 +1,16 @@
import React from 'react';
import styles from './DischargePermitManagement.less';
const DischargePermitManagement = () => {
return (
<div className={styles.container}>
<div className={styles.content}>
<h2>排污许可执行管理</h2>
<p>此页面用于展示和管理排污许可的执行情况</p>
{/* 这里可以添加具体的排污许可管理表格和功能 */}
</div>
</div>
);
};
export default DischargePermitManagement;

@ -0,0 +1,26 @@
.container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
padding: 20px;
.content {
text-align: center;
h2 {
font-size: 24px;
color: #333;
margin-bottom: 16px;
font-weight: 500;
}
p {
font-size: 16px;
color: #666;
margin: 0;
}
}
}

@ -0,0 +1,16 @@
import React from 'react';
import styles from './EnvironmentalTaskList.less';
const EnvironmentalTaskList = () => {
return (
<div className={styles.container}>
<div className={styles.content}>
<h2>环保管理任务清单</h2>
<p>此页面用于展示和管理环保相关的任务清单</p>
{/* 这里可以添加具体的任务清单表格和功能 */}
</div>
</div>
);
};
export default EnvironmentalTaskList;

@ -0,0 +1,26 @@
.container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
padding: 20px;
.content {
text-align: center;
h2 {
font-size: 24px;
color: #333;
margin-bottom: 16px;
font-weight: 500;
}
p {
font-size: 16px;
color: #666;
margin: 0;
}
}
}

@ -0,0 +1,16 @@
import React from 'react';
import styles from './PermitStatistics.less';
const PermitStatistics = () => {
return (
<div className={styles.container}>
<div className={styles.content}>
<h2>许可证信息统计表</h2>
<p>此页面用于展示和管理各类许可证的统计信息</p>
{/* 这里可以添加具体的许可证统计表格和图表 */}
</div>
</div>
);
};
export default PermitStatistics;

@ -0,0 +1,26 @@
.container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
padding: 20px;
.content {
text-align: center;
h2 {
font-size: 24px;
color: #333;
margin-bottom: 16px;
font-weight: 500;
}
p {
font-size: 16px;
color: #666;
margin: 0;
}
}
}
Loading…
Cancel
Save