wangyunfei 1 week ago
commit c6c7afdc2e

@ -0,0 +1,11 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1534_20692)">
<path d="M4.10938 5.27158C4.10938 5.24177 4.12122 5.21318 4.1423 5.1921C4.16338 5.17102 4.19197 5.15918 4.22178 5.15918H5.12099C5.1508 5.15918 5.17939 5.17102 5.20047 5.1921C5.22155 5.21318 5.23339 5.24177 5.23339 5.27158V8.64362C5.23339 8.67343 5.22155 8.70202 5.20047 8.7231C5.17939 8.74418 5.1508 8.75602 5.12099 8.75602H4.22178C4.19197 8.75602 4.16338 8.74418 4.1423 8.7231C4.12122 8.70202 4.10938 8.67343 4.10938 8.64362V5.27158ZM7.81862 5.27158C7.81862 5.24177 7.80678 5.21318 7.7857 5.1921C7.76462 5.17102 7.73603 5.15918 7.70622 5.15918H6.80701C6.7772 5.15918 6.74861 5.17102 6.72753 5.1921C6.70645 5.21318 6.69461 5.24177 6.69461 5.27158V8.64362C6.69461 8.67343 6.70645 8.70202 6.72753 8.7231C6.74861 8.74418 6.7772 8.75602 6.80701 8.75602H7.70622C7.73603 8.75602 7.76462 8.74418 7.7857 8.7231C7.80678 8.70202 7.81862 8.67343 7.81862 8.64362V5.27158Z" fill="white"/>
<path d="M3.28042 1.85726V0.227437C3.28042 -0.0208712 3.48172 -0.222168 3.73003 -0.222168H8.22608C8.47439 -0.222168 8.67568 -0.0208712 8.67568 0.227437V1.85726H11.2469C11.2767 1.85726 11.3053 1.8691 11.3263 1.89018C11.3474 1.91126 11.3593 1.93985 11.3593 1.96966V2.86887C11.3593 2.89868 11.3474 2.92727 11.3263 2.94835C11.3053 2.96943 11.2767 2.98127 11.2469 2.98127H10.4741V11.9031C10.4741 12.1514 10.2728 12.3527 10.0245 12.3527H1.9316C1.6833 12.3527 1.482 12.1514 1.482 11.9031V2.98127H0.667089C0.637278 2.98127 0.608688 2.96943 0.587609 2.94835C0.56653 2.92727 0.554688 2.89868 0.554688 2.86887V1.96966C0.554688 1.93985 0.56653 1.91126 0.587609 1.89018C0.608688 1.8691 0.637278 1.85726 0.667089 1.85726H3.28042ZM4.40443 0.901845V1.85726H7.55167V0.901845H4.40443ZM2.60601 2.98127V11.2287H9.35009V2.98127H2.60601Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_1534_20692">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1,11 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1534_20696)">
<path d="M10.1425 0.0112305H1.8551C0.842488 0.0112305 0.0117188 0.842 0.0117188 1.85462V10.142C0.0117188 11.1574 0.842488 11.9854 1.8551 11.9854H10.1425C11.1551 11.9854 11.9859 11.1546 11.9859 10.142V1.85462C11.9842 1.36624 11.7894 0.89836 11.4441 0.553027C11.0987 0.207693 10.6309 0.0129334 10.1425 0.0112305ZM11.0656 10.142C11.0657 10.2631 11.0416 10.3829 10.9946 10.4945C10.9477 10.6061 10.8789 10.7072 10.7923 10.7918C10.7073 10.8777 10.606 10.9459 10.4945 10.9924C10.383 11.039 10.2633 11.0631 10.1425 11.0632H1.8551C1.73422 11.0632 1.61454 11.0392 1.50299 10.9927C1.39144 10.9461 1.29024 10.8778 1.20526 10.7918C1.11916 10.7069 1.05077 10.6057 1.00403 10.4942C0.957285 10.3826 0.933127 10.2629 0.93295 10.142V1.85462C0.93295 1.61 1.02803 1.38015 1.20526 1.20477C1.29041 1.11909 1.39166 1.05109 1.50318 1.00467C1.61471 0.958259 1.73431 0.934345 1.8551 0.934307H10.1425C10.2633 0.934193 10.383 0.958037 10.4945 1.00446C10.606 1.05089 10.7073 1.11897 10.7923 1.20477C10.9677 1.38015 11.0656 1.61185 11.0656 1.85462V10.142Z" fill="white"/>
<path d="M9.10688 2.91781L9.08842 2.90119C9.04018 2.85399 8.98196 2.81821 8.91807 2.79649C8.85417 2.77476 8.78621 2.76764 8.71919 2.77565H5.07765C4.96053 2.78307 4.85063 2.83483 4.77032 2.92039C4.69 3.00596 4.64529 3.11891 4.64529 3.23627C4.64529 3.35362 4.69 3.46657 4.77032 3.55214C4.85063 3.63771 4.96053 3.68946 5.07765 3.69688H7.64196L2.92688 8.41381C2.84109 8.50056 2.79297 8.61764 2.79297 8.73965C2.79297 8.86166 2.84109 8.97875 2.92688 9.0655L2.94535 9.08211C3.12442 9.26304 3.41612 9.26304 3.59612 9.08211L8.30288 4.3735V6.91934C8.30313 7.04143 8.35174 7.15845 8.43806 7.24478C8.52439 7.33111 8.64141 7.37972 8.7635 7.37996C8.88559 7.37972 9.0026 7.33111 9.08893 7.24478C9.17526 7.15845 9.22387 7.04143 9.22411 6.91934V3.33596C9.24178 3.26212 9.24037 3.18499 9.22002 3.11184C9.19968 3.0387 9.16106 2.97192 9.10781 2.91781H9.10688Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_1534_20696">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

@ -3,7 +3,6 @@
display: flex;
flex-direction: column;
gap: 10px;
height: 200px;
margin: 35px 0 0 0;
overflow: auto;
}
@ -209,8 +208,6 @@
gap: 10px;
height: 100%;
.middleBlock1 {
// flex: 3;
width: 28%;
@ -290,23 +287,6 @@
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;
// }
// }
}
.middleBlock2 {
@ -327,6 +307,8 @@
display: flex;
justify-content: space-between;
align-items: center;
line-height: 28px;
height: 28px;
// margin-bottom: 10px;
.titleLeft {

@ -1,4 +1,3 @@
import React, { useEffect, useRef, useState } from 'react';
import { Card, Result, Select, Button, Segmented, Input } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
@ -6,6 +5,8 @@ import * as echarts from 'echarts';
import StandardTable from '@/components/StandardTable';
import styles from './EmergencyPlanAssociation.less';
import eqicon1 from '@/assets/business_firekeynotearea/eqicon1.png';
import ksdyIcon from '@/assets/business_firekeynotearea/ksdy.svg';
import deleteIcon from '@/assets/business_firekeynotearea/delete.svg';
import eqicon6 from '@/assets/business_firekeynotearea/eqicon6.png';
import eqicon7 from '@/assets/business_firekeynotearea/eqicon7.png';
import eqicon8 from '@/assets/business_firekeynotearea/eqicon8.png';
@ -172,84 +173,75 @@ const EmergencyPlanAssociation = () => {
}, 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',
data: [{
name: '调用次数',
icon: 'rect',
itemStyle: {
color: '#4B69F1'
}
}],
top: 0,
left: 'center',
itemWidth: 12,
itemHeight: 3,
textStyle: {
fontSize: 10
}
fontSize: 12,
color: '#333'
},
},
grid: {
left: '2%',
right: '4%',
bottom: '2%',
top: '12%',
containLabel: true
left: '3%',
right: '3%',
bottom: '3%',
top: 30,
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'],
data: ['电气火灾', '防水防潮', '人员疏散', '燃气泄漏', '油锅起火'],
axisLabel: {
fontSize: 10
fontSize: 12,
color: '#666666',
margin: 12,
},
axisLine: {
lineStyle: {
color: 'rgba(0, 0, 26, 0.15)',
type: 'solid', // 改为实线
},
},
axisTick: {
show: false
}
},
yAxis: {
type: 'value',
min: 0,
max: 30,
max: 25,
splitNumber: 5,
axisLabel: {
formatter: '{value}',
fontSize: 10
}
},
series: [
{
name: '消防水泵1',
type: 'line',
smooth: false,
fontSize: 12,
color: '#666666',
},
axisLine: {
show: false,
},
splitLine: {
lineStyle: {
width: 2,
color: '#8979FF'
color: 'rgba(0, 0, 26, 0.15)',
type: 'dashed',
},
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]
},
},
series: [
{
name: '消防水泵2',
type: 'line',
smooth: false,
lineStyle: {
width: 2,
color: '#3CC3DF'
},
areaStyle: {
name: '调用次数',
type: 'bar',
barWidth: 32,
data: [16, 22, 16, 16, 8],
itemStyle: {
// borderRadius: [4, 4, 0, 0],
color: {
type: 'linear',
x: 0,
@ -257,104 +249,24 @@ const EmergencyPlanAssociation = () => {
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(60, 195, 223, 0.3)' },
{ offset: 1, color: 'rgba(60, 195, 223, 0.05)' }
]
}
{ offset: 0, color: '#199BFB' },
{ offset: 1, color: '#1373FA' },
],
},
},
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);
if (chart && !chart.isDisposed()) {
chart.resize();
}
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();
}
@ -365,55 +277,43 @@ const EmergencyPlanAssociation = () => {
// 表格列定义(同步图片)
const columns = [
{
title: '演练编号',
dataIndex: 'drillId',
key: 'drillId',
title: '编号',
dataIndex: 'bh',
key: 'bh',
width: 140,
},
{
title: '演练时间',
dataIndex: 'drillTime',
key: 'drillTime',
title: '部位名称',
dataIndex: 'bwmc',
key: 'bwmc',
width: 180,
},
{
title: '演练类型',
dataIndex: 'drillType',
key: 'drillType',
title: '部位类型',
dataIndex: 'bwlx',
key: 'bwlx',
width: 120,
},
{
title: '关联部位',
dataIndex: 'relatedPart',
key: 'relatedPart',
title: '关联预案数',
dataIndex: 'glyans',
key: 'glyans',
width: 120,
},
{
title: '部位名称',
dataIndex: 'partName',
key: 'partName',
title: '最近更新',
dataIndex: 'zjgx',
key: 'zjgx',
width: 160,
},
{
title: '演练次数',
dataIndex: 'drillCount',
key: 'drillCount',
width: 100,
},
{
title: '参与人数',
dataIndex: 'participantCount',
key: 'participantCount',
width: 100,
},
{
title: '效果评估',
title: '状态',
dataIndex: 'effect',
key: 'effect',
width: 120,
render: (text) => {
let color = '#FFF3E9', fontColor = '#FF8800', label = text;
if (text === '优秀') {
if (text === '已更新') {
color = '#D8F7DE';
fontColor = '#44BB5F';
}
@ -425,7 +325,7 @@ const EmergencyPlanAssociation = () => {
padding: '3px 8px',
fontSize: 12,
fontWeight: 500
}}>{label}</span>
}}>{label}</span>
);
}
},
@ -436,7 +336,7 @@ const EmergencyPlanAssociation = () => {
render: (_, record) => (
<>
<span style={{ color: '#2E4CD4', cursor: 'pointer', marginRight: 16 }}>编辑</span>
<span style={{ color: '#FF2526', cursor: 'pointer' }}>删除</span>
<span style={{ color: '#44BB5F', cursor: 'pointer' }}>关联</span>
</>
),
},
@ -446,36 +346,30 @@ const EmergencyPlanAssociation = () => {
const mockData = [
{
key: '1',
drillId: 'YL202310001',
drillTime: '2025-09-10 14:23:45',
drillType: '实战演练',
relatedPart: '三楼东侧',
partName: '数据机房 A区',
drillCount: 5,
participantCount: 25,
effect: '良好',
bh: '01',
bwmc: '数据机房A区',
bwlx: '数据机房',
glyans: 5,
zjgx: '2025-09-10 14:23:45',
effect: '有更新',
},
{
key: '2',
drillId: 'YL202310002',
drillTime: '2025-09-10 14:23:45',
drillType: '桌面推演',
relatedPart: '二楼西侧',
partName: 'B区厨房',
drillCount: 6,
participantCount: 18,
effect: '良好',
bh: '02',
bwmc: 'B区厨房',
bwlx: '厨房区域',
glyans: 3,
zjgx: '2025-09-10 14:23:45',
effect: '有更新',
},
{
key: '3',
drillId: 'YL202310003',
drillTime: '2025-09-10 14:23:45',
drillType: '模拟演练',
relatedPart: '地下一层',
partName: '数据中心机房',
drillCount: 3,
participantCount: 32,
effect: '优秀',
bh: '03',
bwmc: '数据中心机房',
bwlx: '配电房',
glyans: 4,
zjgx: '2025-09-10 14:23:45',
effect: '已更新',
},
];
@ -550,51 +444,20 @@ const EmergencyPlanAssociation = () => {
{/* 第一个div - 高度20% */}
<div className={styles.RcontainerTop}>
<div className={styles.sectionContent}>
<div className={styles.blocksContainer}>
{/* 块1 */}
<div className={styles.blockItem + ' ' + styles.bgBlock1}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>演练记录总数</div>
<div className={styles.blockNumber}>120</div>
</div>
<div className={styles.blockRight}>
<img src={eqicon1} alt="演练记录总数" className={styles.blockImage} />
</div>
</div>
{/* 块2 */}
<div className={styles.blockItem + ' ' + styles.bgBlock2}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>重点部位数量</div>
<div className={styles.blockNumber}>32</div>
</div>
<div className={styles.blockRight}>
<img src={eqicon6} alt="重点部位数量" className={styles.blockImage} />
</div>
</div>
{/* 块3 */}
<div className={styles.blockItem + ' ' + styles.bgBlock3}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>参与演练人员</div>
<div className={styles.blockNumber}>69</div>
</div>
<div className={styles.blockRight}>
<img src={eqicon7} alt="参与演练人员" className={styles.blockImage} />
<div className={styles.topBlock}>
<div className={styles.topBlockTitle}>
<div className={styles.titleLeft}>
<div className={styles.titleIcon}></div>
<div>应急预案关联管理功能组成图</div>
</div>
</div>
{/* 块4 */}
<div className={styles.blockItem + ' ' + styles.bgBlock4}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>平均演练达标率</div>
<div className={styles.blockNumber}>72%</div>
</div>
<div className={styles.blockRight}>
<img src={eqicon8} alt="平均演练达标率" className={styles.blockImage} />
</div>
<div className={styles.topBlockBg}>
<img
src={require('@/assets/business_firekeynotearea/relation-group.png')}
alt="应急预案关联管理功能组成图"
style={{ width: '50%' }}
/>
</div>
</div>
</div>
</div>
@ -606,76 +469,103 @@ const EmergencyPlanAssociation = () => {
<div className={styles.middleBlock2Title}>
<div className={styles.titleLeft}>
<div className={styles.titleIcon}></div>
<div>重点部位分布图</div>
</div>
<div className={styles.titleRight}>
实时定位
<div>预案调用统计</div>
</div>
</div>
<div className={styles.middleBlock2Chart}>
{/* 地图图片 */}
<img
src={require('@/assets/business_firekeynotearea/map.png')}
alt="重点部位分布图"
style={{ width: '100%', height: '100%' }}
/>
</div>
<div className={styles.middleBlock2Chart} ref={chartRef}></div>
</div>
<div className={styles.middleBlock1}>
<div className={styles.block1Header}>
<div className={styles.block1Title}>
<div className={styles.titleIcon}></div>
重点部位类型分布
关联应急预案
</div>
<Segmented
className={styles.block1Segmented}
options={['月', '季', '年']}
onChange={(value) => {
console.log(value);
}}
/>
</div>
{/* 设备状态饼图 */}
<div className={styles.deviceStatusChart} ref={pieChartRef}>
{/* 关联应急预案列表 */}
<div className={styles.planListWrap}>
{[
{
title: '电气火灾应急预案',
desc: '适用场景: 电气短路、设备过载引发的火灾',
update: '2023-05-07',
user: '张正',
},
{
title: '精密设备防水防潮应急预案',
desc: '适用场景: 电气短路、设备过载引发的火灾',
update: '2023-05-07',
user: '张正',
},
{
title: '精密设备防水防潮应急预案',
desc: '适用场景: 电气短路、设备过载引发的火灾',
update: '2023-05-07',
user: '张正',
}
].map((item, idx) => (
<div className={styles.planCard} key={item.title}>
<div style={{ flex: 1 }}>
<div className={styles.planCardTitle}>{item.title}</div>
<div className={styles.planCardDesc}>{item.desc}</div>
<div className={styles.planCardUpdate}>上次修订{item.update} | 修订人{item.user}</div>
</div>
<div className={styles.planCardFooter}>
<div className={styles.planCardBtns}>
<Button className={styles.quickBtn} type="primary" size="small">
<img src={ksdyIcon} alt="快速调用" style={{ width: 12, height: 12, marginRight: 4, verticalAlign: 'middle' }} />
快速调用
</Button>
<Button className={styles.delBtn} type="danger" size="small">
<img src={deleteIcon} alt="删除" style={{ width: 12, height: 12, marginRight: 4, verticalAlign: 'middle' }} />
删除
</Button>
</div>
</div>
</div>
))}
</div>
</div>
<div className={styles.middleBlock1}>
<div className={styles.block1Header}>
<div className={styles.block1Title}>
<div className={styles.titleIcon}></div>
重点部位列表
预案更新通知
</div>
<div> 3 </div>
</div>
{/* 重点部位列表 */}
<div className={styles.keypartsList}>
{keypartsData.map((item, idx) => (
<div
key={item.name}
className={styles.keypartsCard + ' ' + (selectedKeypartIdx === idx ? styles.keypartsCardActive : '')}
onClick={() => setSelectedKeypartIdx(idx)}
style={{ cursor: 'pointer' }}
>
<div>
<div className={styles.keypartsCardHeader}>
<span className={styles.keypartsCardTitle}>{item.name}</span>
</div>
<div className={styles.keypartsCardSub}>{item.location}</div>
{/* 预案更新通知列表 */}
<div className={styles.planListWrap}>
{[
{
title: '电气火灾应急预案已更新',
desc: '该预案已修订涉及数据机房A区等3个重点部位需要同步更新',
time: '10分钟',
},
{
title: '仓库物品堆放安全管理预案已发布',
desc: '新预案适用于各类仓库区域,建议进行关联',
time: '20分钟',
},
{
title: '防汛应急预案年度修订提醒',
desc: '距离防汛应急预案下次修订时间还有30天',
time: '40分钟',
}
].map((item, idx) => (
<div className={styles.planCard} key={item.title}>
<div style={{ flex: 1 }}>
<div className={styles.planCardTitle}>{item.title}</div>
<div className={styles.planCardUpdate}>{item.desc}</div>
</div>
<div
className={styles.keypartsRiskTag}
style={{ background: item.riskColor, color: item.riskTextColor }}
>
{item.risk}
<div className={styles.planCardFooter}>
<div style={{color: '#FF2526', fontSize: 12}}>
{item.time}
</div>
</div>
</div>
))}
</div>
</div>
</div>
</div>
@ -688,7 +578,7 @@ const EmergencyPlanAssociation = () => {
<div className={styles.tableHeader}>
<div className={styles.tableTitle}>
<div className={styles.titleIcon}></div>
<div>演练记录录入</div>
<div>组织架构管理</div>
</div>
<div className={styles.tableActions}>
@ -697,7 +587,7 @@ const EmergencyPlanAssociation = () => {
<Input.Search
className={styles.searchInput}
style={{ width: 200 }}
placeholder="搜索部位名称..."
placeholder="搜索重点部位..."
allowClear
/>
</div>
@ -705,13 +595,13 @@ const EmergencyPlanAssociation = () => {
{/* 下拉选择 */}
<Select
className={styles.selectAll}
defaultValue="所属类别"
defaultValue="所有类型"
style={{ width: 100 }}
options={[{ value: '所属类别', label: '所属类别' }]}
options={[{ value: '所有类型', label: '所有类型' }]}
/>
{/* 新增按钮 */}
<Button className={styles.addBtn} type="primary">
<PlusOutlined /> 新增演练记录
<PlusOutlined /> 新增部位
</Button>
</div>
</div>
@ -746,4 +636,4 @@ const EmergencyPlanAssociation = () => {
);
};
export default EmergencyPlanAssociation;
export default EmergencyPlanAssociation;

@ -1,70 +1,96 @@
// 重点部位列表样式
.keypartsList {
// 关联应急预案卡片列表样式
.planListWrap {
display: flex;
flex-direction: column;
gap: 10px;
height: 200px;
gap: 8px;
margin: 35px 0 0 0;
height: 200px;
overflow: auto;
/* 隐藏滚动条但保留滚动效果 */
scrollbar-width: none;
}
.keypartsCard {
background: #f9fbff;
border: 1px solid #ECEDFC;
.planListWrap::-webkit-scrollbar {
display: none;
/* Chrome/Safari */
}
.planCard {
background: #F1F7FF;
// border: 1px solid #ecedfc;
border-radius: 4px;
padding: 8px 12px 6px 12px;
padding: 10px 12px;
box-shadow: 0 1px 4px 0 rgba(46, 76, 212, 0.03);
transition: border-color 0.2s, box-shadow 0.2s;
position: relative;
// min-height: 44px;
max-width: 300px;
width: 100%;
margin: 0 auto;
display: flex;
gap: 8px;
}
.planCardTitle {
font-size: 14px;
font-weight: 600;
color: #333;
margin-bottom: 6px;
}
.planCardDesc {
font-size: 12px;
color: #666;
margin-bottom: 6px;
}
.planCardFooter {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 6px;
}
.planCardUpdate {
font-size: 12px;
color: #666;
}
.keypartsCardActive {
border-color: #75A7FF;
background: #F6F7FF;
box-shadow: 0 2px 8px 0 rgba(46, 76, 212, 0.10);
.planCardBtns {
display: flex;
gap: 10px;
}
.keypartsCardHeader {
.quickBtn {
background: #1169FF !important;
color: #fff;
border: none;
border-radius: 4px;
font-size: 12px !important;
font-weight: 500;
padding: 0 12px;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 3px;
}
.keypartsCardTitle {
font-size: 12px;
font-weight: 600;
color: #333;
margin-bottom: 8px;
.quickBtn:hover {
background: #1169FF;
color: #fff;
}
.keypartsRiskTag {
display: inline-block;
min-width: 40px;
height: 30px;
line-height: 30px;
text-align: center;
font-size: 13px;
.delBtn {
background: #FE5F60 !important;
color: #fff;
border: none;
border-radius: 4px;
font-size: 12px !important;
font-weight: 500;
border-radius: 5px;
padding: 0 8px;
box-shadow: 0 1px 3px 0 rgba(46, 76, 212, 0.05);
padding: 0 12px;
display: flex;
align-items: center;
}
.keypartsCardSub {
font-size: 12px;
color: #666;
font-weight: 400;
letter-spacing: 0.5px;
.delBtn:hover {
background: #d9363e;
color: #fff;
}
// 重点部位列表样式
.Rcontainer {
padding: 8px 6px 0px 6px;
height: 100%;
@ -72,126 +98,71 @@
flex-direction: column;
gap: 10px;
// 第一个div - 高度20%
.RcontainerTop {
height: 16%;
// background-color: #fff;
height: 100%;
border-radius: 4px;
display: flex;
flex-direction: column;
// flex-direction: column;
background: url('@/assets/business_firekeynotearea/yj-bg.png') no-repeat center center;
background-size: cover;
.sectionContent {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
// padding: 15px;
gap: 10px;
.blocksContainer {
flex: 1;
display: flex;
gap: 10px;
.topBlock {
height: 100%;
display: flex;
flex-direction: column;
font-family: PingFang SC;
font-size: 14px;
color: #333333;
padding: 5px 10px 5px 10px;
.blockItem {
flex: 1;
height: 100%;
.topBlockTitle {
display: flex;
background: linear-gradient(170.5deg, #F5F7FF 6.87%, #FFFFFF 47.65%);
border-radius: 2px;
// border: 2px solid #FFFFFF;
&.bgBlock1 {
background: url('@/assets/business_firekeynotearea/keyparts_bg.png') no-repeat center center, linear-gradient(170.5deg, #F5F7FF 6.87%, #FFFFFF 47.65%);
background-size: cover;
}
&.bgBlock2 {
background: url('@/assets/business_firekeynotearea/keyparts_bg.png') no-repeat center center, linear-gradient(170.5deg, #F5F7FF 6.87%, #FFFFFF 47.65%);
background-size: cover;
}
&.bgBlock3 {
background: url('@/assets/business_firekeynotearea/keyparts_bg.png') no-repeat center center, linear-gradient(170.5deg, #F5F7FF 6.87%, #FFFFFF 47.65%);
background-size: cover;
}
&.bgBlock4 {
background: url('@/assets/business_firekeynotearea/keyparts_bg.png') no-repeat center center, linear-gradient(170.5deg, #F5F7FF 6.87%, #FFFFFF 47.65%);
background-size: cover;
}
&.bgBlock5 {
background: url('@/assets/business_firekeynotearea/keyparts_bg.png') no-repeat center center, linear-gradient(170.5deg, #F5F7FF 6.87%, #FFFFFF 47.65%);
background-size: cover;
}
justify-content: space-between;
align-items: center;
// margin-bottom: 10px;
.blockLeft {
width: 60%;
height: 100%;
.titleLeft {
display: flex;
flex-direction: column;
justify-content: center;
padding: 15px;
padding-left: 20px;
gap: 15px;
.blockTitle {
font-family: PingFang SC;
font-weight: 400;
font-size: 12px;
color: #333333;
line-height: 1.2;
}
.blockNumber {
font-family: PingFang SC;
font-weight: 700;
font-size: 24px;
color: #333333;
line-height: 1.2;
}
.blockChange {
font-family: PingFang SC;
font-weight: 400;
font-size: 12px;
color: #1269FF;
line-height: 1.2;
display: flex;
align-items: center;
gap: 4px;
.arrow {
font-size: 14px;
font-weight: bold;
}
align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
color: #333333;
.checkIcon {
font-size: 16px;
color: #1269FF;
}
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
}
}
.blockRight {
flex: 1;
height: 100%;
background-color: transparent;
border-radius: 0 4px 4px 0;
display: flex;
align-items: center;
justify-content: center;
.blockImage {
// width: 80%;
height: 65%;
// height: 80%;
object-fit: contain;
margin-right: -5px;
}
.titleRight {
font-size: 12px;
width: 60px;
height: 20px;
line-height: 20px;
background-color: #E6E9FB;
color: #2E4CD4;
text-align: center;
border-radius: 2px;
}
}
.topBlockBg {
width: 100%;
height: 100%;
padding: 5px;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
@ -205,22 +176,18 @@
.sectionContent {
height: 100%;
display: flex;
display: flex;
gap: 10px;
height: 100%;
.middleBlock1 {
// flex: 3;
width: 28%;
flex: 4;
// width: 28%;
height: 100%;
background: #fff;
border: 2px solid #fff;
// border-radius: 4px;
position: relative;
padding: 0px 10px 10px 2px;
padding: 0px 10px 10px 10px;
font-family: PingFang SC;
font-size: 14px;
color: #333333;
@ -290,27 +257,10 @@
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;
// }
// }
}
.middleBlock2 {
flex: 6;
flex: 4;
height: 100%;
// background: linear-gradient(170.5deg, #EBEFF4 6.87%, #FFFFFF 53.01%);
// border: 2px solid #fff;
@ -327,6 +277,8 @@
display: flex;
justify-content: space-between;
align-items: center;
line-height: 28px;
height: 28px;
// margin-bottom: 10px;
.titleLeft {

@ -1,922 +0,0 @@
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 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';
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('');
// 柱状图初始化
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);
}
},
{
title: '设备编号',
dataIndex: 'deviceId',
key: 'deviceId',
width: 140,
},
{
title: '设备名称',
dataIndex: 'deviceName',
key: 'deviceName',
width: 110,
},
{
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',
},
];
// 初始化数据
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: 实现搜索逻辑,根据设备名称、编号等筛选数据
};
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>
);
};
export default EvaluationReport;

@ -1,558 +0,0 @@
.Econtainer {
padding: 8px 6px 0px 6px;
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;
}
}
}
.deviceStatusChart {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
z-index: 10;
min-height: 100%;
}
}
.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;
}
}
}
.deviceStatusChart {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
// bottom: 10px;
z-index: 10;
}
}
.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;
}
}
}
.middleBlock2Chart {
width: 100%;
height: 100%;
}
}
}
}
// 第三个div - 占满剩余位置
.EcontainerBottom {
display: flex;
flex-direction: column;
flex-shrink: 0;
.sectionContent {
display: flex;
flex-direction: row;
flex: 1;
gap: 10px;
padding: 0;
.leftBlock {
width: 30%;
flex-shrink: 0;
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%;
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;
}
}
}
}
}
}

@ -8,11 +8,6 @@
.treeSearchInput {
width: 100%;
height: 36px;
// border-radius: 6px;
// border: 1px solid #E3E6EB;
// font-size: 14px;
// margin-bottom: 10px;
// background: #F7F8FA;
}
.customTree {
@ -70,7 +65,7 @@
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px 15px 0 15px;
margin: 0 15px;
height: 40px;
}
@ -123,7 +118,6 @@
flex-direction: column;
gap: 10px;
// 第一个div - 高度20%
.RcontainerTop {
height: 16%;
// background-color: #fff;
@ -246,265 +240,6 @@
}
}
// 第二个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 - 占满剩余空间
.RcontainerBottom {
flex: 1 1 0;
min-height: 0;
@ -533,7 +268,7 @@
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 15px 5px 15px;
padding: 8px 15px 0px 15px;
.tableTitle {
display: flex;
@ -543,7 +278,7 @@
font-weight: 500;
font-size: 14px;
color: #333333;
line-height: 32px;
.titleIcon {
width: 3px;
height: 16px;
@ -645,7 +380,8 @@
font-weight: 500;
font-size: 14px;
color: #333333;
margin-bottom: 10px;
padding-top: 8px;
line-height: 32px;
.titleIcon {
width: 3px;

@ -69,7 +69,7 @@
display: flex;
flex-direction: column;
height: 100vh;
overflow: auto;
overflow: hidden;
}
.leftMenu {

Loading…
Cancel
Save