From 60bcc32a265259481fc26e98aa1798f72db47136 Mon Sep 17 00:00:00 2001 From: wangyunfei <1224056307@qq,com> Date: Wed, 15 Oct 2025 17:08:41 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E8=AF=81=E4=BB=B6=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/business_basic/icon_echart.svg | 4 + src/pages/business_basic/basic.js | 21 +- .../EvaluationReport.js | 2 +- .../EvaluationReport.less | 0 .../components/LicenseManagement.js | 301 ++++++++++++++++++ .../components/LicenseManagement.less | 191 +++++++++++ .../OnlineMonitoring.js | 0 .../OnlineMonitoring.less | 0 .../ResponsibilityImplementation.js | 0 .../ResponsibilityImplementation.less | 0 .../{module => components}/RiskAssessment.js | 0 .../RiskAssessment.less | 0 12 files changed, 509 insertions(+), 10 deletions(-) create mode 100644 src/assets/business_basic/icon_echart.svg rename src/pages/business_basic/{module => components}/EvaluationReport.js (99%) rename src/pages/business_basic/{module => components}/EvaluationReport.less (100%) create mode 100644 src/pages/business_basic/components/LicenseManagement.js create mode 100644 src/pages/business_basic/components/LicenseManagement.less rename src/pages/business_basic/{module => components}/OnlineMonitoring.js (100%) rename src/pages/business_basic/{module => components}/OnlineMonitoring.less (100%) rename src/pages/business_basic/{module => components}/ResponsibilityImplementation.js (100%) rename src/pages/business_basic/{module => components}/ResponsibilityImplementation.less (100%) rename src/pages/business_basic/{module => components}/RiskAssessment.js (100%) rename src/pages/business_basic/{module => components}/RiskAssessment.less (100%) diff --git a/src/assets/business_basic/icon_echart.svg b/src/assets/business_basic/icon_echart.svg new file mode 100644 index 0000000..7c08254 --- /dev/null +++ b/src/assets/business_basic/icon_echart.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/pages/business_basic/basic.js b/src/pages/business_basic/basic.js index 7a58125..dd93403 100644 --- a/src/pages/business_basic/basic.js +++ b/src/pages/business_basic/basic.js @@ -1,10 +1,11 @@ import React, { useState } from 'react'; import { Card, Row, Col, Statistic, Progress, Button, Space } from 'antd'; import styles from './basic.less'; -import ResponsibilityImplementation from './module/ResponsibilityImplementation'; //责任落实 -import OnlineMonitoring from './module/OnlineMonitoring'; //在线监测预警 -import RiskAssessment from './module/RiskAssessment'; //风险管控 -import EvaluationReport from './module/EvaluationReport'; //评估报告 +import ResponsibilityImplementation from './components/ResponsibilityImplementation'; +import OnlineMonitoring from './components/OnlineMonitoring'; +import RiskAssessment from './components/RiskAssessment'; +import EvaluationReport from './components/EvaluationReport'; +import LicenseManagement from './components/LicenseManagement'; @@ -20,6 +21,8 @@ const SafeMajorHazardList = () => { switch (activeModule) { case 'organization': return ; + case 'license': + return ; case 'equipment': return ; case 'firefighting': @@ -40,11 +43,11 @@ const SafeMajorHazardList = () => { onClick={() => handleModuleClick("organization")} >组织机构管理 - {/* */} + + + + ), + }, + ]; + + + return ( +
+
+ +
+
+
+ 证件类型分布 +
+
+
+
+
+ +
+
+
+ 证件类型分布 +
+
+ 需求 + + +
+
+ + +
+ 待开发 +
+
+ + + + {/* 证照列表区域 */} + + 证照列表 +
+ } + /> + + +
+ `共${total}条`, + }} + className={styles.licenseTable} + /> + + + ); +}; + +export default LicenseManagement; diff --git a/src/pages/business_basic/components/LicenseManagement.less b/src/pages/business_basic/components/LicenseManagement.less new file mode 100644 index 0000000..0fa0f53 --- /dev/null +++ b/src/pages/business_basic/components/LicenseManagement.less @@ -0,0 +1,191 @@ +.licenseManagementContainer { + height: 100vh; + + .topSectionContainer { + padding: 0; + margin: 15px 0px 15px 5px; + height: 35%; + display: flex; + gap: 15px; + align-items: stretch; + + .firstBlock { + width: 30%; + background-color: #fff; + display: flex; + flex-direction: column; + padding: 10px 16px; + border-radius: 2px; + + .chartHeader { + display: flex; + align-items: center; + margin-bottom: 16px; + + .colorBlock { + width: 2px; + height: 18px; + background-color: #2E4CD4; + margin-right: 8px; + border-radius: 1px; + } + + .chartTitle { + font-size: 16px; + font-weight: 500; + color: #333333; + line-height: 18px; + } + } + + .chartContainer { + flex: 1; + width: 100%; + position: relative; + + .chart { + width: 100%; + height: 100%; + min-height: 200px; + } + } + } + + .secondBlock { + + width: 30%; + background-color: #fff; + display: flex; + flex-direction: column; + padding: 10px 16px; + border-radius: 2px; + + .chartHeader { + display: flex; + align-items: center; + margin-bottom: 16px; + // height: 18px; + + .colorBlock { + width: 2px; + height: 18px; + background-color: #2E4CD4; + margin-right: 8px; + border-radius: 1px; + } + + .chartTitle { + font-size: 16px; + font-weight: 500; + color: #333333; + line-height: 18px; + } + } + + + } + + .thirdBlock { + flex: 1; + background-color: #fff; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + color: #333; + } + } + + + .listCard { + border: none; + border-radius: 8px; + box-shadow: none; + + .listTitle { + margin-bottom: 20px; + font-size: 16px; + font-weight: 600; + color: #333; + } + + .listToolbar { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 20px; + + .searchInput { + width: 300px; + } + + .typeFilter { + width: 120px; + } + + .addButton { + margin-left: auto; + } + } + + .licenseTable { + .ant-table-thead>tr>th { + background-color: #fafafa; + font-weight: 600; + color: #333; + } + + .ant-table-tbody>tr>td { + border-bottom: 1px solid #f0f0f0; + } + + .ant-pagination { + margin-top: 20px; + text-align: right; + } + } + } +} + +// 覆盖Ant Design默认样式 +.licenseManagementContainer { + .ant-card { + box-shadow: none; + } + + .ant-card-body { + padding: 20px; + } + + .ant-table { + font-size: 14px; + } + + .ant-tag { + border-radius: 4px; + font-size: 12px; + padding: 2px 8px; + } + + .ant-btn-link { + padding: 0; + height: auto; + font-size: 14px; + } + + .ant-input-search { + .ant-input { + border-radius: 6px; + } + } + + .ant-select { + .ant-select-selector { + border-radius: 6px; + } + } + + .ant-btn-primary { + border-radius: 6px; + } +} \ No newline at end of file diff --git a/src/pages/business_basic/module/OnlineMonitoring.js b/src/pages/business_basic/components/OnlineMonitoring.js similarity index 100% rename from src/pages/business_basic/module/OnlineMonitoring.js rename to src/pages/business_basic/components/OnlineMonitoring.js diff --git a/src/pages/business_basic/module/OnlineMonitoring.less b/src/pages/business_basic/components/OnlineMonitoring.less similarity index 100% rename from src/pages/business_basic/module/OnlineMonitoring.less rename to src/pages/business_basic/components/OnlineMonitoring.less diff --git a/src/pages/business_basic/module/ResponsibilityImplementation.js b/src/pages/business_basic/components/ResponsibilityImplementation.js similarity index 100% rename from src/pages/business_basic/module/ResponsibilityImplementation.js rename to src/pages/business_basic/components/ResponsibilityImplementation.js diff --git a/src/pages/business_basic/module/ResponsibilityImplementation.less b/src/pages/business_basic/components/ResponsibilityImplementation.less similarity index 100% rename from src/pages/business_basic/module/ResponsibilityImplementation.less rename to src/pages/business_basic/components/ResponsibilityImplementation.less diff --git a/src/pages/business_basic/module/RiskAssessment.js b/src/pages/business_basic/components/RiskAssessment.js similarity index 100% rename from src/pages/business_basic/module/RiskAssessment.js rename to src/pages/business_basic/components/RiskAssessment.js diff --git a/src/pages/business_basic/module/RiskAssessment.less b/src/pages/business_basic/components/RiskAssessment.less similarity index 100% rename from src/pages/business_basic/module/RiskAssessment.less rename to src/pages/business_basic/components/RiskAssessment.less From 741d91fdd3377787dad62910d06279e429820ed8 Mon Sep 17 00:00:00 2001 From: wangyunfei <1224056307@qq,com> Date: Wed, 15 Oct 2025 18:25:17 +0800 Subject: [PATCH 2/7] . --- src/assets/business_basic/background_lqyj.svg | 14 + .../components/LicenseManagement.js | 198 +++++++++--- .../components/LicenseManagement.less | 290 ++++++++++++++++-- 3 files changed, 427 insertions(+), 75 deletions(-) create mode 100644 src/assets/business_basic/background_lqyj.svg diff --git a/src/assets/business_basic/background_lqyj.svg b/src/assets/business_basic/background_lqyj.svg new file mode 100644 index 0000000..13c7204 --- /dev/null +++ b/src/assets/business_basic/background_lqyj.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/pages/business_basic/components/LicenseManagement.js b/src/pages/business_basic/components/LicenseManagement.js index 2e3f672..cbcb408 100644 --- a/src/pages/business_basic/components/LicenseManagement.js +++ b/src/pages/business_basic/components/LicenseManagement.js @@ -1,13 +1,10 @@ import React, { useEffect, useRef } from 'react'; -import { Card, Input, Select, Button, Table, Tag, Space, Typography } from 'antd'; -import { SearchOutlined, PlusOutlined } from '@ant-design/icons'; +import { Card, Table, Tag, Space, Typography, Progress, Row, Col, Button } from 'antd'; import * as echarts from 'echarts'; import styles from './LicenseManagement.less'; import icon_echart from '@/assets/business_basic/icon_echart.svg'; const { Title } = Typography; -const { Search } = Input; -const { Option } = Select; const LicenseManagement = () => { const chartRef = useRef(null); @@ -26,7 +23,7 @@ const LicenseManagement = () => { useEffect(() => { if (chartRef.current) { const chart = echarts.init(chartRef.current); - + const option = { tooltip: { trigger: 'item', @@ -204,8 +201,8 @@ const LicenseManagement = () => { key: 'status', width: 120, render: (text, record) => ( - + {text} ), @@ -226,59 +223,176 @@ const LicenseManagement = () => { return (
-
+
+ +
+
+
+ 证件类型分布 +
+
+
+
+
-
+
证件类型分布
-
+ {/* 上半部分:进度条和百分比 */} +
+
+
有效证照
+
+ + 50% +
+
+ +
+
即将到期
+
+ + 15% +
+
+ +
+
已过期
+
+ + 20% +
+
+ +
+
待审核材料
+
+ + 15% +
+
+
+ + {/* 下半部分:数字统计 */} +
+ +
+
+
42
+
总证照数
+
+ + +
+
8
+
即将过期
+
+ + +
+
6
+
已过期
+
+ + +
+
6
+
待审核材料
+
+ + + -
+ +
- 证件类型分布 + 临期预警
- 需求 - - + {/* 透明块容器 */} +
+ {/* 四个垂直分布的卡片 */} +
+
+
安全生产许可证
+
编号: AQXK-2023-0582
+
+
+ 15天后到期 +
+
+ +
+
+
安全评估报告
+
编号: AQPG-2023-0125
+
+
+ 30天后到期 +
+
+ +
+
+
施工资质证书
+
编号: SGZZ-2023-0089
+
+
+ 7天后到期 +
+
+ +
+
+
应急预案
+
编号: YJYA-2023-0045
+
+
+ 4天后到期 +
+
+
+
-
- 待开发 -
- - - {/* 证照列表区域 */} - - 证照列表 -
- } - /> - - +
+
+
+ 证照列表
{ }} className={styles.licenseTable} /> - + ); }; diff --git a/src/pages/business_basic/components/LicenseManagement.less b/src/pages/business_basic/components/LicenseManagement.less index 0fa0f53..96072ed 100644 --- a/src/pages/business_basic/components/LicenseManagement.less +++ b/src/pages/business_basic/components/LicenseManagement.less @@ -48,11 +48,77 @@ height: 100%; min-height: 200px; } + + // 进度条区域样式 + .progressSection { + margin-bottom: 20px; + + .progressItem { + margin-bottom: 16px; + + .progressLabel { + font-size: 12px; + color: #666; + margin-bottom: 8px; + font-weight: 400; + } + + .progressWrapper { + display: flex; + align-items: center; + gap: 12px; + + .customProgress { + flex: 1; + + :global(.ant-progress-bg) { + height: 8px !important; + border-radius: 4px; + } + + :global(.ant-progress-outer) { + .ant-progress-inner { + background-color: #F0F0F0; + border-radius: 4px; + } + } + } + + .progressPercent { + font-size: 12px; + color: #333; + font-weight: 500; + min-width: 30px; + text-align: right; + } + } + } + } + + // 数字统计区域样式 + .statsSection { + .statItem { + text-align: center; + padding: 8px; + + .statNumber { + font-size: 24px; + font-weight: 600; + line-height: 1.2; + margin-bottom: 4px; + } + + .statLabel { + font-size: 12px; + color: #666; + font-weight: 400; + } + } + } } } .secondBlock { - width: 30%; background-color: #fff; display: flex; @@ -63,8 +129,7 @@ .chartHeader { display: flex; align-items: center; - margin-bottom: 16px; - // height: 18px; + margin-bottom: 8px; .colorBlock { width: 2px; @@ -78,61 +143,220 @@ font-size: 16px; font-weight: 500; color: #333333; - line-height: 18px; + // line-height: 18px; } } + .chartContainer { + flex: 1; + width: 100%; + position: relative; + // 进度条区域样式 + .progressSection { + // margin-bottom: 20px; + + .progressItem { + // margin-bottom: 16px; + + .progressLabel { + font-size: 10px; + color: #666; + // margin-bottom: 8px; + font-weight: 400; + } + + .progressWrapper { + display: flex; + align-items: center; + gap: 5px; + + .customProgress { + flex: 1; + + :global(.ant-progress-bg) { + height: 8px !important; + border-radius: 4px; + } + + :global(.ant-progress-outer) { + .ant-progress-inner { + background-color: #F0F0F0; + border-radius: 4px; + } + } + } + + .progressPercent { + font-size: 12px; + color: #333; + font-weight: 500; + min-width: 30px; + text-align: right; + } + } + } + } + + // 数字统计区域样式 + .statsSection { + .statItem { + text-align: center; + padding: 0px 2px 2px 2px; + + .statNumber { + font-size: 22px; + font-weight: 600; + line-height: 1.2; + margin-bottom: 4px; + } + + .statLabel { + font-size: 12px; + color: #666; + font-weight: 400; + } + } + } + } } .thirdBlock { flex: 1; + background-image: url('@/assets/business_basic/background_lqyj.svg'); background-color: #fff; + background-repeat: no-repeat; + background-size: cover; + background-position: center; display: flex; - align-items: center; - justify-content: center; - font-size: 16px; - color: #333; + flex-direction: column; + padding: 10px 16px; + border-radius: 2px; + + .chartHeader { + display: flex; + align-items: center; + margin-bottom: 8px; + + .colorBlock { + width: 2px; + height: 18px; + background-color: #2E4CD4; + margin-right: 8px; + border-radius: 1px; + } + + .chartTitle { + font-size: 16px; + font-weight: 500; + color: #333333; + } + } + + .chartContainer { + flex: 1; + width: 100%; + position: relative; + + // 透明块容器样式 + .transparentBlock { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + gap: 8px; + padding: 4px 8px; + + .licenseCard { + width: 60%; + height: auto; + background-color: #FFF9F4; + border: 1px solid #FFD7BB; + border-radius: 2px; + padding: 5px 8px; + display: flex; + justify-content: space-between; + align-items: center; + // box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + + .cardContent { + flex: 1; + display: flex; + flex-direction: column; + gap: 4px; + + .licenseName { + font-size: 12px; + font-weight: 500; + color: #333; + line-height: 1.2; + } + + .licenseNumber { + font-size: 12px; + color: #666; + font-weight: 400; + } + } + + .expiryTag { + width: 38%; + background-color: #FFEDDE; + border-radius: 2px; + padding: 5px 12px; + margin-left: 12px; + + + .expiryText { + font-size: 12px; + font-weight: 500; + display: flex; + align-items: center; + color: #D46B08; + } + } + } + } + } } } .listCard { - border: none; - border-radius: 8px; - box-shadow: none; - - .listTitle { - margin-bottom: 20px; - font-size: 16px; - font-weight: 600; - color: #333; - } + padding: 0; + padding: 15px 5px 15px 20px; + height: 35%; + // display: flex; + gap: 15px; + background-color: #fff; + // align-items: stretch; - .listToolbar { + .chartHeader { display: flex; align-items: center; - gap: 12px; - margin-bottom: 20px; - - .searchInput { - width: 300px; + margin-bottom: 8px; + + .colorBlock { + width: 2px; + height: 18px; + background-color: #2E4CD4; + margin-right: 8px; + border-radius: 1px; } - .typeFilter { - width: 120px; - } - - .addButton { - margin-left: auto; + .chartTitle { + font-size: 14px; + font-weight: 500; + color: #333333; } } .licenseTable { .ant-table-thead>tr>th { - background-color: #fafafa; - font-weight: 600; - color: #333; + background-color: #F5F5FA; + font-weight: 200; + color: #333333; + } .ant-table-tbody>tr>td { From 1dd2639806705c0e007a3268443f47a3a8ea2f8b Mon Sep 17 00:00:00 2001 From: wangyunfei <1224056307@qq,com> Date: Thu, 16 Oct 2025 10:52:07 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E8=B5=84=E8=B4=A8=E8=AF=81=E7=85=A7?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/LicenseManagement.js | 317 ++++++++++++++---- .../components/LicenseManagement.less | 143 ++++++-- 2 files changed, 366 insertions(+), 94 deletions(-) diff --git a/src/pages/business_basic/components/LicenseManagement.js b/src/pages/business_basic/components/LicenseManagement.js index cbcb408..44bd7a5 100644 --- a/src/pages/business_basic/components/LicenseManagement.js +++ b/src/pages/business_basic/components/LicenseManagement.js @@ -1,13 +1,18 @@ -import React, { useEffect, useRef } from 'react'; -import { Card, Table, Tag, Space, Typography, Progress, Row, Col, Button } from 'antd'; +import React, { useEffect, useRef, useState } from 'react'; +import { Card, Table, Tag, Space, Typography, Progress, Row, Col, Button, Input, Select } from 'antd'; import * as echarts from 'echarts'; +import StandardTable from '@/components/StandardTable'; import styles from './LicenseManagement.less'; import icon_echart from '@/assets/business_basic/icon_echart.svg'; const { Title } = Typography; +const { Search } = Input; +const { Option } = Select; const LicenseManagement = () => { const chartRef = useRef(null); + const [searchValue, setSearchValue] = useState(''); + const [selectedType, setSelectedType] = useState('all'); // 图表数据 const chartData = [ @@ -23,7 +28,7 @@ const LicenseManagement = () => { useEffect(() => { if (chartRef.current) { const chart = echarts.init(chartRef.current); - + const option = { tooltip: { trigger: 'item', @@ -130,7 +135,7 @@ const LicenseManagement = () => { id: 'HQ-XF-02-015', authority: '第三方评估机构', validUntil: '2025-09-10', - status: '15天后到期', + status: '有效', statusType: 'warning' }, { @@ -154,6 +159,72 @@ const LicenseManagement = () => { validUntil: '2025-09-10', status: '有效', statusType: 'success' + }, + { + key: '5', + no: '05', + name: '消防验收合格证', + type: '消防证书', + id: 'HQ-XF-05-012', + authority: '消防局', + validUntil: '2026-03-15', + status: '有效', + statusType: 'success' + }, + { + key: '6', + no: '06', + name: '职业健康安全管理体系认证', + type: '管理体系认证', + id: 'HQ-XF-06-008', + authority: '认证机构', + validUntil: '2026-06-20', + status: '有效', + statusType: 'success' + }, + { + key: '7', + no: '07', + name: '环境管理体系认证', + type: '管理体系认证', + id: 'HQ-XF-07-009', + authority: '认证机构', + validUntil: '2026-08-25', + status: '有效', + statusType: 'success' + }, + { + key: '8', + no: '08', + name: '特种设备使用登记证', + type: '特种设备证书', + id: 'HQ-XF-08-011', + authority: '质量技术监督局', + validUntil: '2026-12-10', + status: '有效', + statusType: 'success' + }, + { + key: '9', + no: '09', + name: '危险化学品经营许可证', + type: '经营许可证', + id: 'HQ-XF-09-013', + authority: '应急管理局', + validUntil: '2027-01-30', + status: '有效', + statusType: 'success' + }, + { + key: '10', + no: '10', + name: '辐射安全许可证', + type: '辐射安全证书', + id: 'HQ-XF-10-014', + authority: '生态环境部', + validUntil: '2027-04-18', + status: '有效', + statusType: 'success' } ]; @@ -200,55 +271,128 @@ const LicenseManagement = () => { dataIndex: 'status', key: 'status', width: 120, - render: (text, record) => ( - - {text} - - ), + render: (text, record) => { + const getStatusStyle = (status) => { + if (status === '有效') { + return { + color: '#44BB5F', + backgroundColor: '#D8F7DE', + padding: '4px 8px', + borderRadius: '4px', + fontSize: '12px', + display: 'inline-block' + }; + } else if (status === '即将到期') { + return { + color: '#FF8800', + backgroundColor: '#FFF3E9', + padding: '4px 8px', + borderRadius: '4px', + fontSize: '12px', + display: 'inline-block' + }; + } else if (status === '已过期') { + return { + color: '#FF3E48', + backgroundColor: '#FFE0E2', + padding: '4px 8px', + borderRadius: '4px', + fontSize: '12px', + display: 'inline-block' + }; + } + return {}; + }; + + return ( + + {text} + + ); + } }, { title: '操作', + dataIndex: 'action', key: 'action', width: 120, - render: () => ( - - - - - ), + render: (text, record) => { + const handleEdit = (record) => { + console.log('编辑记录:', record); + }; + + const handleDelete = (record) => { + console.log('删除记录:', record); + }; + + return ( +
+ + +
+ ); + } }, ]; return (
-
- -
-
-
- 证件类型分布 -
-
-
-
-
+
-
+
证件类型分布
+
+
+
+
+ +
+
+
+ 证件状态概览 +
{/* 上半部分:进度条和百分比 */}
有效证照
- { 50%
- +
即将到期
- { 15%
- +
已过期
- { 20%
- +
待审核材料
- {
-
42
+
42
总证照数
-
8
+
8
即将过期
-
6
+
6
已过期
-
6
+
6
待审核材料
@@ -351,7 +495,7 @@ const LicenseManagement = () => { 15天后到期 - +
安全评估报告
@@ -361,51 +505,96 @@ const LicenseManagement = () => { 30天后到期
- +
施工资质证书
编号: SGZZ-2023-0089
-
- 7天后到期 +
+ 7天后到期
- +
应急预案
编号: YJYA-2023-0045
-
- 4天后到期 +
+ 4天后到期
- + {/* 证照列表区域 */}
-
- 证照列表 +
+
+ 证照列表 +
+
+ setSearchValue(e.target.value)} + onSearch={(value) => console.log('搜索:', value)} + className={styles.searchInput} + /> + + +
-
{ }} // ======== 行选择事件处理函数 ======== + onChange={() => { }} // ======== 表格变化事件处理函数 ======== pagination={{ - current: 3, - total: 48, - pageSize: 10, + currentPage: 1, + pageSize: 5, + total: tableData.length, showSizeChanger: false, showQuickJumper: true, - showTotal: (total) => `共${total}条`, + showTotal: (total, range) => + `共 ${total} 条`, + locale: { + jump_to: '前往', + page: '页', + items_per_page: '条/页', + } }} - className={styles.licenseTable} /> diff --git a/src/pages/business_basic/components/LicenseManagement.less b/src/pages/business_basic/components/LicenseManagement.less index 96072ed..c8c06a1 100644 --- a/src/pages/business_basic/components/LicenseManagement.less +++ b/src/pages/business_basic/components/LicenseManagement.less @@ -1,5 +1,5 @@ .licenseManagementContainer { - height: 100vh; + height: 90vh; .topSectionContainer { padding: 0; @@ -31,7 +31,7 @@ } .chartTitle { - font-size: 16px; + font-size: 14px; font-weight: 500; color: #333333; line-height: 18px; @@ -140,7 +140,7 @@ } .chartTitle { - font-size: 16px; + font-size: 14px; font-weight: 500; color: #333333; // line-height: 18px; @@ -247,7 +247,7 @@ } .chartTitle { - font-size: 16px; + font-size: 14px; font-weight: 500; color: #333333; } @@ -325,7 +325,7 @@ .listCard { padding: 0; padding: 15px 5px 15px 20px; - height: 35%; + flex: 1; // display: flex; gap: 15px; background-color: #fff; @@ -334,39 +334,122 @@ .chartHeader { display: flex; align-items: center; - margin-bottom: 8px; - - .colorBlock { - width: 2px; - height: 18px; - background-color: #2E4CD4; - margin-right: 8px; - border-radius: 1px; + justify-content: space-between; + margin-bottom: 16px; + + .headerLeft { + display: flex; + align-items: center; + + .colorBlock { + width: 2px; + height: 18px; + background-color: #2E4CD4; + margin-right: 8px; + border-radius: 1px; + } + + .chartTitle { + font-size: 14px; + font-weight: 500; + color: #333333; + line-height: 18px; + } } - .chartTitle { - font-size: 14px; - font-weight: 500; - color: #333333; + .headerRight { + display: flex; + align-items: center; + gap: 12px; + + .searchInput { + width: 280px; + + .ant-input { + border-radius: 2px; + border: 1px solid #d9d9d9; + + &:hover { + border-color: #40a9ff; + } + + &:focus { + border-color: #40a9ff; + box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); + } + } + } + + .typeSelector { + width: 120px; + + .ant-select-selector { + border-radius: 2px; + border: 1px solid #d9d9d9; + + &:hover { + border-color: #40a9ff; + } + } + + &.ant-select-focused .ant-select-selector { + border-color: #40a9ff; + box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); + } + } + + .addButton { + border-radius: 4px; + background-color: #2E4CD4; + // border-color: #1890ff; + height: 32px; + padding: 4px 15px; + font-size: 14px; + display: flex; + align-items: center; + justify-content: center; + + &:hover { + background-color: #2E4CD4; + // border-color: #40a9ff; + } + + &:focus { + background-color: #2E4CD4; + // border-color: #40a9ff; + } + } } } - .licenseTable { - .ant-table-thead>tr>th { - background-color: #F5F5FA; - font-weight: 200; - color: #333333; + // StandardTable 组件样式 + :global(.ant-table) { + font-size: 12px; + } + :global(.ant-pagination-options-quick-jumper input) { + text-align: center !important; + } - } + :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; + } - .ant-table-tbody>tr>td { - border-bottom: 1px solid #f0f0f0; - } + :global(.ant-table-tbody > tr > td) { + padding: 8px 12px; + border-bottom: 1px solid #f0f0f0; + text-align: center; + color: #666666; + } - .ant-pagination { - margin-top: 20px; - text-align: right; - } + :global(.ant-pagination) { + margin-top: 16px; + text-align: right; } } } From 8ea3aaff13eedd38b68ba5c3ebf37a39953fa359 Mon Sep 17 00:00:00 2001 From: wangyunfei <1224056307@qq,com> Date: Thu, 16 Oct 2025 10:53:18 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E9=AB=98=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/business_basic/components/LicenseManagement.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/business_basic/components/LicenseManagement.less b/src/pages/business_basic/components/LicenseManagement.less index c8c06a1..560fa0e 100644 --- a/src/pages/business_basic/components/LicenseManagement.less +++ b/src/pages/business_basic/components/LicenseManagement.less @@ -4,7 +4,7 @@ .topSectionContainer { padding: 0; margin: 15px 0px 15px 5px; - height: 35%; + height: 40%; display: flex; gap: 15px; align-items: stretch; From a1cd33dbf0fd19a42f96eebb944253b94a666761 Mon Sep 17 00:00:00 2001 From: wangyunfei <1224056307@qq,com> Date: Thu, 16 Oct 2025 10:56:50 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E5=AD=97=E4=BD=93=E9=A2=9C=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/business_basic/components/EvaluationReport.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/business_basic/components/EvaluationReport.js b/src/pages/business_basic/components/EvaluationReport.js index f8e0fc2..ce61baa 100644 --- a/src/pages/business_basic/components/EvaluationReport.js +++ b/src/pages/business_basic/components/EvaluationReport.js @@ -244,7 +244,7 @@ const EvaluationReport = () => { width: 1 }, itemStyle: { - color: '#FFFFF', + color: '#fff', borderColor: '#1269FF', borderWidth: 1 }, From b67427b18dbe704e61d7e3cfaaff08dd46298dae Mon Sep 17 00:00:00 2001 From: wangyunfei <1224056307@qq,com> Date: Thu, 16 Oct 2025 15:09:09 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E6=B6=88=E9=98=B2=E6=A3=80=E6=B5=8B?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/routes.js | 8 +- src/assets/img/icon_firewarning.svg | 3 + src/pages/business_firewarning/FireWarning.js | 48 + .../business_firewarning/FireWarning.less | 66 ++ .../components/DataAnalysisWarning.js | 922 ++++++++++++++++++ .../components/DataAnalysisWarning.less | 558 +++++++++++ .../components/RealtimeMonitoring.js | 715 ++++++++++++++ .../components/RealtimeMonitoring.less | 919 +++++++++++++++++ .../nav_system_content/SystemContentList.js | 16 +- src/pages/topnavbar/TopNavBar.js | 4 + 10 files changed, 3257 insertions(+), 2 deletions(-) create mode 100644 src/assets/img/icon_firewarning.svg create mode 100644 src/pages/business_firewarning/FireWarning.js create mode 100644 src/pages/business_firewarning/FireWarning.less create mode 100644 src/pages/business_firewarning/components/DataAnalysisWarning.js create mode 100644 src/pages/business_firewarning/components/DataAnalysisWarning.less create mode 100644 src/pages/business_firewarning/components/RealtimeMonitoring.js create mode 100644 src/pages/business_firewarning/components/RealtimeMonitoring.less diff --git a/config/routes.js b/config/routes.js index b2e1d63..f705a88 100644 --- a/config/routes.js +++ b/config/routes.js @@ -25,11 +25,17 @@ export default [ component: './nav_system_content/SystemContentList', routes: [ // 基础信息管理 - { + { path: '/topnavbar00/business/basic', name: 'basic', component: './business_basic/basic', }, + // 消防检测报警 + { + path: '/topnavbar00/business/fireWarning', + name: 'fireWarning', + component: './business_firewarning/FireWarning', + }, // 安全管理基础信息 { path: '/topnavbar00/business/basicinformation', diff --git a/src/assets/img/icon_firewarning.svg b/src/assets/img/icon_firewarning.svg new file mode 100644 index 0000000..013ecbe --- /dev/null +++ b/src/assets/img/icon_firewarning.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/pages/business_firewarning/FireWarning.js b/src/pages/business_firewarning/FireWarning.js new file mode 100644 index 0000000..f5201c1 --- /dev/null +++ b/src/pages/business_firewarning/FireWarning.js @@ -0,0 +1,48 @@ +import React, { useState } from 'react'; +import { Button } from 'antd'; +import styles from './FireWarning.less'; +import RealtimeMonitoring from './components/RealtimeMonitoring'; +import DataAnalysisWarning from './components/DataAnalysisWarning'; + +const Firewarning = () => { + const [activeModule, setActiveModule] = useState('realtime'); + + const handleModuleClick = (module) => { + setActiveModule(module); + }; + + const renderModule = () => { + switch (activeModule) { + case 'realtime': + return ; + case 'analysis': + return ; + default: + return ; + } + }; + + return ( +
+
+ + +
+
+ {renderModule()} +
+
+ ); +}; + +export default Firewarning; diff --git a/src/pages/business_firewarning/FireWarning.less b/src/pages/business_firewarning/FireWarning.less new file mode 100644 index 0000000..a0de3de --- /dev/null +++ b/src/pages/business_firewarning/FireWarning.less @@ -0,0 +1,66 @@ +.firewarningContainer { + background-color: transparent; + width: 100%; + height: 89vh; + overflow: hidden; + display: flex; + flex-direction: column; + + .firewarningTopButton { + background-color: white; + width: 100%; + padding: 10px 30px; + display: flex; + gap: 24px; + margin-left: 6px; + + .firewarningTopButtonItem { + background-color: transparent !important; + color: #333333 !important; + font-family: 'PingFang SC', sans-serif !important; + font-weight: 500 !important; + font-size: 14px !important; + line-height: 100% !important; + border-radius: 8px !important; + padding: 6px 10px !important; + height: auto !important; + border: none !important; + box-shadow: none !important; + position: relative !important; + + &:hover { + color: #333333 !important; + border: none !important; + } + + &:focus { + color: #2E4CD4 !important; + border: none !important; + } + + &.active { + color: #2E4CD4 !important; + + &::after { + content: ''; + position: absolute; + bottom: -10px; + left: 0; + right: 0; + width: 100%; + height: 4px; + background-color: #2E4CD4; + border-radius: 0; + opacity: 1; + } + } + } + } + + .firewarningContent { + // ======== 内容区域样式 ======== + flex: 1; // ======== 占据剩余空间 ======== + overflow-y: auto; // ======== 允许垂直滚动 ======== + padding: 0; // ======== 无内边距 ======== + } +} diff --git a/src/pages/business_firewarning/components/DataAnalysisWarning.js b/src/pages/business_firewarning/components/DataAnalysisWarning.js new file mode 100644 index 0000000..79c8258 --- /dev/null +++ b/src/pages/business_firewarning/components/DataAnalysisWarning.js @@ -0,0 +1,922 @@ +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 './DataAnalysisWarning.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 DataAnalysisWarning = () => { + 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}
使用次数: ${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: '#fff', + 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}
{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 ( + + {text} + + ); + } + }, + { + title: '最后维护时间', + dataIndex: 'lastMaintenance', + key: 'lastMaintenance', + width: 150, + }, + { + title: '操作', + key: 'action', + width: 140, + render: (_, record) => ( +
+ + +
+ ), + }, + ]; + + // 模拟数据 + 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 ( +
+ {/* 第1个div - 高度39% */} +
+
+
+
+
+
+ 设备使用频率分析 +
+
+ {/* 设备状态饼图 */} +
+
+
+ +
+
+
+
+ 近一年维护费用趋势 +
+
+ + {/* 维护费用趋势折线图 */} +
+
+
+ +
+
+
+
+
设备类型占比
+
+
+
+
+
+
+
+ + {/* 第2个div - 占满剩余位置 */} +
+
+
+
+
+
+
+
近期维护提醒
+
+
+
+
+
SH-MHQ-023-C 干粉灭火器
+
位置: 4楼办公区丨维护类型: 季度检查
+
负责人: 张三
+
+
+
3天后到期
+
+
+
+
+
SH-XHS-045-D 室内消火栓
+
位置: 2楼东侧走廊丨维护类型: 水压测试
+
负责人: 李四
+
+
+
8天后到期
+
+
+
+
+
+
+
+
维护任务进度
+
+
+ {/* 进度条区域 */} +
+ +
月度维护计划
+ + +
季度维护计划
+ + + +
年度维护计划
+ + + + {/* 警告提示框 */} +
+ + 本月有5项维护任务即将到期 +
+ +
+
+
+
+
+ +
+ {/* 表格 */} +
+
+
+
消防设施与器材列表
+
+
+ + + {/* 操作按钮 */} +
+
+ } + /> +
+
+ + +
+
+ + {/* 表格 */} +
+ + `共 ${total} 条`, + }} + /> +
+
+
+
+
+ ); +}; + +export default DataAnalysisWarning; diff --git a/src/pages/business_firewarning/components/DataAnalysisWarning.less b/src/pages/business_firewarning/components/DataAnalysisWarning.less new file mode 100644 index 0000000..b036170 --- /dev/null +++ b/src/pages/business_firewarning/components/DataAnalysisWarning.less @@ -0,0 +1,558 @@ +.analysisContainer { + padding: 8px 6px 0px 6px; + height: 100%; + display: flex; + flex-direction: column; + gap: 10px; + + // 第二个div - 高度35% + .analysisContainerMiddle { + // height: 400px; + min-height: 35%; + border-radius: 4px; + display: flex; + flex-direction: column; + + .analysisSectionContent { + height: 100%; + display: flex; + display: flex; + gap: 10px; + height: 100%; + + .analysisMiddleBlock1 { + 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; + + .analysisBlock1Header { + position: absolute; + top: 5px; + left: 10px; + right: 10px; + display: flex; + justify-content: space-between; + align-items: center; + z-index: 10; + + .analysisBlock1Title { + display: flex; + align-items: center; + gap: 8px; + font-weight: 500; + font-size: 14px; + margin-top: 5px; + color: #333333; + + .analysisTitleIcon { + width: 3px; + height: 14px; + background-color: #2E4CD4; + } + } + + } + + .analysisDeviceStatusChart { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + z-index: 10; + min-height: 100%; + } + } + + .analysisMiddleBlock12 { + 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; + + .analysisBlock1Header { + position: absolute; + top: 5px; + left: 10px; + right: 10px; + display: flex; + justify-content: space-between; + align-items: center; + z-index: 10; + + .analysisBlock1Title { + display: flex; + align-items: center; + gap: 8px; + font-weight: 500; + font-size: 14px; + margin-top: 5px; + color: #333333; + + .analysisTitleIcon { + width: 3px; + height: 14px; + background-color: #2E4CD4; + } + } + + } + + .analysisDeviceStatusChart { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + // bottom: 10px; + z-index: 10; + } + } + + .analysisMiddleBlock12 { + 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; + + .analysisBlock1Header { + position: absolute; + top: 5px; + left: 10px; + right: 10px; + display: flex; + justify-content: space-between; + align-items: center; + z-index: 10; + + .analysisBlock1Title { + display: flex; + align-items: center; + gap: 8px; + font-weight: 500; + font-size: 14px; + color: #333333; + + .analysisTitleIcon { + width: 3px; + height: 14px; + background-color: #2E4CD4; + } + } + } + + .analysisDeviceStatusChart { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + // bottom: 10px; + min-height: 100%; + z-index: 10; + } + } + + .analysisMiddleBlock2 { + // 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; + + .analysisMiddleBlock2Title { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 5px; + + .analysisTitleLeft { + display: flex; + align-items: center; + gap: 8px; + font-weight: 500; + font-size: 14px; + color: #333333; + + .analysisTitleIcon { + width: 3px; + height: 14px; + background-color: #2E4CD4; + } + } + + } + + .analysisMiddleBlock2Chart { + width: 100%; + height: 100%; + } + } + } + } + + // 第三个div - 占满剩余位置 + .analysisContainerBottom { + display: flex; + flex-direction: column; + flex-shrink: 0; + + .analysisSectionContent { + display: flex; + flex-direction: row; + flex: 1; + gap: 10px; + padding: 0; + + .analysisLeftBlock { + width: 30%; + flex-shrink: 0; + height: 100%; + padding: 0; + display: flex; + flex-direction: column; + gap: 10px; + + .analysisLeftBlockTitle { + display: flex; + align-items: center; + gap: 8px; + font-family: PingFang SC; + font-weight: 500; + font-size: 14px; + color: #333333; + margin-bottom: 10px; + + .analysisTitleIcon { + width: 3px; + height: 16px; + background-color: #2E4CD4; + } + } + + .analysisMaintenanceStack { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + gap: 10px; + + .analysisMaintenanceSection { + width: 100%; + height: 50%; + background: #FFF; + border-radius: 4px; + display: flex; + flex-direction: column; + padding: 12px 14px; + + .analysisMaintenanceTitle { + display: flex; + align-items: center; + gap: 8px; + font-family: PingFang SC; + font-weight: 500; + font-size: 14px; + color: #333333; + margin-bottom: 8px; + } + + .analysisTitleIcon { + width: 3px; + height: 16px; + background-color: #2E4CD4; + } + + .analysisMaintenanceContent { + flex: 1; + width: 100%; + } + + .analysisMaintenanceContent1 { + flex: 1; + width: 100%; + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 8px; + .analysisMaintenanceItem { + display: flex; + align-items: center; + justify-content: space-between; + background-color: #F1F7FF; + border-radius: 4px; + padding: 16px 16px; + + .analysisMaintenanceLeft { + flex: 1; + display: flex; + flex-direction: column; + gap: 4px; + + .analysisMaintenanceText1 { + font-size: 14px; + font-weight: 500; + color: #333333; + font-family: PingFang SC; + } + + .analysisMaintenanceText2 { + font-size: 12px; + color: #666666; + font-family: PingFang SC; + } + + .analysisMaintenanceText3 { + font-size: 12px; + color: #666666; + font-family: PingFang SC; + } + } + + .analysisMaintenanceRight { + flex: 0 0 auto; + display: flex; + align-items: center; + justify-content: center; + + .analysisMaintenanceStatus { + 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; + } + } + + .analysisMaintenanceRight2 { + flex: 0 0 auto; + display: flex; + align-items: center; + justify-content: center; + + .analysisMaintenanceStatus { + font-size: 12px; + color: #FF8800; + font-weight: 500; + font-family: PingFang SC; + background-color: #FFF3E9; + padding: 4px 8px; + border-radius: 4px; + // padding-right: 2px; + } + } + } + } + + .analysisMaintenanceContent2 { + flex: 1; + width: 100%; + display: flex; + flex-direction: column; + gap: 15px; + padding: 8px 0; + + .analysisWarningBox { + 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; + + .analysisWarningIcon { + color: #8C6C0B; + font-size: 14px; + } + + .analysisWarningText { + color: #8C6C0B; + font-size: 12px; + font-family: PingFang SC; + font-weight: 400; + } + } + + .analysisProgressSection { + width: 100%; + display: flex; + flex-direction: column; + // gap: 12px; + padding: 0px 12px 12px 12px; + + + .analysisProgressLabel { + 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; + } + } + + } + } + } + } + } + + .analysisRightBlock { + width: calc(100% - 28% - 10px); + height: 100%; + background-color: #fff; + padding: 0; + display: flex; + flex-direction: column; + + .analysisTableHeader { + display: flex; + justify-content: space-between; + align-items: center; + padding: 11px 15px 5px 15px; + + .analysisTableTitle { + display: flex; + align-items: center; + gap: 8px; + font-family: PingFang SC; + font-weight: 500; + font-size: 14px; + color: #333333; + + .analysisTitleIcon { + width: 3px; + height: 16px; + background-color: #2E4CD4; + } + } + } + + .analysisTableActions { + display: flex; + justify-content: space-between; + align-items: center; + gap: 8px; + margin-top: 5px; + padding: 0px 15px; + + .analysisLeftActions { + display: flex; + align-items: center; + } + + .analysisRightActions { + display: flex; + gap: 8px; + align-items: center; + } + + .analysisActionButton { + 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; + } + + .analysisButtonIcon { + font-size: 14px; + font-weight: bold; + } + } + } + + .analysisTableContainer { + 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; + } + } + } + } + } +} diff --git a/src/pages/business_firewarning/components/RealtimeMonitoring.js b/src/pages/business_firewarning/components/RealtimeMonitoring.js new file mode 100644 index 0000000..152033e --- /dev/null +++ b/src/pages/business_firewarning/components/RealtimeMonitoring.js @@ -0,0 +1,715 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Card, Result, Select, Button } from 'antd'; +import * as echarts from 'echarts'; +import StandardTable from '@/components/StandardTable'; +import styles from './RealtimeMonitoring.less'; + +import alarm0 from '@/assets/safe_majorHazard/online_monitoring/alarm0.png'; +import alarm1 from '@/assets/safe_majorHazard/online_monitoring/alarm1.png'; +import alarm2 from '@/assets/safe_majorHazard/online_monitoring/alarm2.png'; +import alarm3 from '@/assets/safe_majorHazard/online_monitoring/alarm3.png'; +import exportIcon from '@/assets/safe_majorHazard/online_monitoring/export.png'; +import deleteIcon from '@/assets/safe_majorHazard/online_monitoring/delete.png'; + +const RealtimeMonitoring = () => { + const chartRef = 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: 5, + total: 0, + }); + + useEffect(() => { + if (chartRef.current) { + const chart = echarts.init(chartRef.current); + + const option = { + color: ['#04A7F3', '#E7C42C', '#EC6941'], + + legend: { + data: ['液位', '温度', '压力'], + top: "-3px", + left: "center", + itemGap: 40, // 图例间距 + textStyle: { + fontSize: 10 + } + }, + grid: { + left: '2%', + right: '4%', + bottom: '2%', + top: '12%', + containLabel: true + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: ['0:00', '2:00', '4:00', '6:00', '8:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '24:00'], + axisLabel: { + fontSize: 10 + } + }, + yAxis: { + type: 'value', + min: 0, + max: 500, + axisLabel: { + formatter: '{value}', + fontSize: 10 + } + }, + series: [ + { + name: '液位', + type: 'line', + smooth: true, + lineStyle: { + width: 1.5, + color: '#04A7F3' + }, + areaStyle: { + color: { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 1, + colorStops: [ + { offset: 0, color: 'rgba(4, 167, 243, 0.3)' }, + { offset: 1, color: 'rgba(4, 167, 243, 0)' } + ] + } + }, + symbol: 'none', // 不显示数据点 + data: [120, 200, 150, 300, 250, 400, 350, 280, 320, 180, 220, 160, 140] + }, + { + name: '温度', + type: 'line', + smooth: true, + lineStyle: { + width: 1.5, + color: '#E7C42C' + }, + areaStyle: { + color: { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 1, + colorStops: [ + { offset: 0, color: 'rgba(231, 196, 44, 0.3)' }, + { offset: 1, color: 'rgba(231, 196, 44, 0)' } + ] + } + }, + symbol: 'none', + data: [80, 120, 100, 180, 160, 220, 200, 150, 170, 90, 110, 85, 75] + }, + { + name: '压力', + type: 'line', + smooth: true, + lineStyle: { + width: 1.5, + color: '#EC6941' + }, + areaStyle: { + color: { + type: 'linear', + x: 0, + y: 1, + x2: 0, + y2: 0, + colorStops: [ + { offset: 0, color: 'rgba(236, 105, 65, 0)' }, + { offset: 1, color: 'rgba(236, 105, 65, 0.3)' } + ] + } + }, + symbol: 'none', + data: [200, 300, 250, 450, 400, 430, 480, 420, 480, 280, 320, 260, 240] + } + ] + }; + + chart.setOption(option); + + // 响应式调整 - 使用ResizeObserver监听容器尺寸变化 + let resizeTimer = null; + const handleResize = () => { + // 防抖处理,避免频繁调用resize + if (resizeTimer) { + clearTimeout(resizeTimer); + } + resizeTimer = setTimeout(() => { + chart.resize(); + }, 100); + }; + + // 监听窗口大小变化 + window.addEventListener('resize', handleResize); + + // 监听容器尺寸变化(解决菜单栏伸缩时的自适应问题) + let resizeObserver = null; + if (window.ResizeObserver) { + resizeObserver = new ResizeObserver(() => { + // 使用setTimeout确保DOM更新完成后再调整图表 + setTimeout(() => { + handleResize(); + }, 0); + }); + resizeObserver.observe(chartRef.current); + } + + return () => { + window.removeEventListener('resize', handleResize); + if (resizeObserver) { + resizeObserver.disconnect(); + } + if (resizeTimer) { + clearTimeout(resizeTimer); + } + chart.dispose(); + }; + } + }, []); + + // 表格列定义 + const columns = [ + { + title: '编号', + dataIndex: 'id', + key: 'id', + width: 80, + render: (text, record, index) => { + const page = pagination.current || 1; + const pageSize = pagination.pageSize || 5; + const number = (page - 1) * pageSize + index + 1; + return `0${number}`.slice(-2); + } + }, + { + title: '报警时间', + dataIndex: 'alarmTime', + key: 'alarmTime', + width: 150, + }, + { + title: '报警传感器名称', + dataIndex: 'sensorName', + key: 'sensorName', + width: 150, + }, + { + title: '报警类型', + dataIndex: 'alarmType', + key: 'alarmType', + width: 120, + }, + { + title: '报警内容', + dataIndex: 'alarmContent', + key: 'alarmContent', + width: 200, + }, + { + title: '优先级', + dataIndex: 'priority', + key: 'priority', + width: 80, + render: (text) => { + const colorMap = { + '高': '#FF4D4F', + '中': '#FAAD14', + '低': '#52C41A' + }; + return {text}; + } + }, + { + title: '处理状态', + dataIndex: 'status', + key: 'status', + width: 100, + render: (text) => { + const statusMap = { + '未处理': { color: '#FF4D4F', bg: '#FFF2F0' }, + '处理中': { color: '#FAAD14', bg: '#FFFBE6' }, + '已处理': { color: '#52C41A', bg: '#F6FFED' } + }; + const status = statusMap[text] || { color: '#333', bg: '#F5F5F5' }; + return ( + + {text} + + ); + } + }, + { + title: '处理时间', + dataIndex: 'processTime', + key: 'processTime', + width: 150, + }, + { + title: '处理人', + dataIndex: 'processor', + key: 'processor', + width: 100, + }, + { + title: '操作', + key: 'action', + width: 120, + render: (_, record) => ( +
+ +
+ ), + }, + ]; + + // 模拟数据 + const mockData = [ + { + key: '1', + id: '001', + alarmTime: '2024-01-15 08:30:25', + sensorName: 'LNG储罐', + alarmType: '温度超限', + alarmContent: '储罐温度超过安全阈值', + priority: '高', + status: '未处理', + processTime: '-', + processor: '-', + }, + { + key: '2', + id: '002', + alarmTime: '2024-01-15 09:15:10', + sensorName: 'LNG储罐', + alarmType: '压力异常', + alarmContent: '管道压力异常波动', + priority: '中', + status: '处理中', + processTime: '2024-01-15 09:20:00', + processor: '张三', + }, + { + key: '3', + id: '003', + alarmTime: '2024-01-15 10:45:30', + sensorName: 'LNG储罐', + alarmType: '液位异常', + alarmContent: '储罐液位低于警戒线', + priority: '高', + status: '已处理', + processTime: '2024-01-15 11:00:15', + processor: '李四', + }, + { + key: '4', + id: '004', + alarmTime: '2024-01-15 11:20:45', + sensorName: 'LNG储罐', + alarmType: '气体泄漏', + alarmContent: '检测到可燃气体泄漏', + priority: '高', + status: '未处理', + processTime: '-', + processor: '-', + }, + { + key: '5', + id: '005', + alarmTime: '2024-01-15 12:10:20', + sensorName: 'LNG储罐', + alarmType: '设备振动', + alarmContent: '设备异常振动', + priority: '低', + status: '已处理', + processTime: '2024-01-15 12:30:00', + processor: '王五', + }, + { + key: '6', + id: '006', + alarmTime: '2024-01-15 13:25:15', + sensorName: 'LNG管道', + alarmType: '流量异常', + alarmContent: '管道流量异常波动', + priority: '中', + status: '未处理', + processTime: '-', + processor: '-', + }, + { + key: '7', + id: '007', + alarmTime: '2024-01-15 14:10:30', + sensorName: 'LNG储罐', + alarmType: '温度异常', + alarmContent: '储罐温度异常升高', + priority: '高', + status: '处理中', + processTime: '2024-01-15 14:15:00', + processor: '赵六', + }, + { + key: '8', + id: '008', + alarmTime: '2024-01-15 15:45:20', + sensorName: 'LNG管道', + alarmType: '压力超限', + alarmContent: '管道压力超过安全阈值', + priority: '高', + status: '已处理', + processTime: '2024-01-15 16:00:00', + processor: '孙七', + }, + { + key: '9', + id: '009', + alarmTime: '2024-01-15 16:30:45', + sensorName: 'LNG储罐', + alarmType: '液位超限', + alarmContent: '储罐液位超过警戒线', + priority: '中', + status: '未处理', + processTime: '-', + processor: '-', + }, + { + key: '10', + id: '010', + alarmTime: '2024-01-15 17:15:10', + sensorName: 'LNG管道', + alarmType: '泄漏检测', + alarmContent: '检测到轻微气体泄漏', + priority: '低', + status: '已处理', + processTime: '2024-01-15 17:30:00', + processor: '周八', + }, + { + key: '11', + id: '011', + alarmTime: '2024-01-15 18:20:35', + sensorName: 'LNG储罐', + alarmType: '设备故障', + alarmContent: '储罐阀门异常关闭', + priority: '高', + status: '处理中', + processTime: '2024-01-15 18:25:00', + processor: '吴九', + }, + { + key: '12', + id: '012', + alarmTime: '2024-01-15 19:05:50', + sensorName: 'LNG管道', + alarmType: '温度异常', + alarmContent: '管道温度异常下降', + priority: '中', + status: '未处理', + processTime: '-', + processor: '-', + }, + ]; + + // 初始化数据 + 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 handleTableChange = (pagination) => { + setPagination(prev => ({ + ...prev, + current: pagination.current, + pageSize: pagination.pageSize, + })); + }; + + // 导出功能 + const handleExport = () => { + console.log('导出数据'); + // 这里可以添加导出逻辑 + }; + + // 批量删除功能 + const handleBatchDelete = () => { + if (selectedRowKeys.length === 0) { + console.log('没有选中任何行'); + // 可以在这里添加提示用户选择行的逻辑 + return; + } + console.log('批量删除', selectedRowKeys); + // 这里可以添加批量删除逻辑 + }; + + return ( +
+
+
+
+
+
+ alarm0 +
+ +
+
总报警
+
1456
+
+
+ 未处理 6 +
+
+ 处理中 10 +
+
+
+
+
+
+ alarm1 +
+
+
一级报警
+
357
+
+
+ 未处理 6 +
+
+ 处理中 10 +
+
+
+
+
+
+ alarm2 +
+
+
二级报警
+
401
+
+
+ 未处理 6 +
+
+ 处理中 10 +
+
+
+
+
+
+ alarm3 +
+
+
三级报警
+
556
+
+
+ 未处理 6 +
+
+ 处理中 10 +
+
+
+
+
+
+
+
+
+
预警看板
+
+
+
检测对象
+ +
设备运行参数
-
- +
-
-
-
-
-
-
实时数据采集
+ + +
+
+
+
+ 设备状态分布 +
+
-
- 总数: 1378 + {/* 设备状态饼图 */} +
-
-
-
储罐液化装置区
-
R值: 1765
-
编号:XXXXXXXX
-
-
-
-
-
-
三级
-
危险等级
-
-
+ +
+
+
+
+ 设备故障类型分布
+