From 4f05da26e7c4fc0fc4dad7fd8f3c8e4dde9c812c Mon Sep 17 00:00:00 2001
From: wangyunfei888 <1224056307@qq.com>
Date: Fri, 23 Jan 2026 10:05:13 +0800
Subject: [PATCH] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E9=87=87=E9=9B=86=E9=A1=B5?=
=?UTF-8?q?=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 1 +
config/routes.js | 18 +-
src/assets/basic_data/Component1.svg | 4 +
src/assets/basic_data/Component2.svg | 3 +
src/assets/basic_data/Component3.svg | 4 +
src/assets/basic_data/Iconfont.svg | 10 +
src/assets/data_icon.svg | 3 +
src/assets/menuBack.svg | 19 +
src/pages/business_data/basic.js | 74 ++
src/pages/business_data/basic.less | 69 ++
.../components/OnlineMonitoring.js | 716 ++++++++++++
.../components/OnlineMonitoring.less | 919 +++++++++++++++
.../ResponsibilityImplementation.js | 581 ++++++++++
.../ResponsibilityImplementation.less | 1000 +++++++++++++++++
.../components/RiskAssessment.js | 865 ++++++++++++++
.../components/RiskAssessment.less | 594 ++++++++++
src/pages/business_data/components/bmzstx.js | 265 +++++
.../business_data/components/bmzstx.less | 160 +++
src/pages/business_data/components/fgpsdsz.js | 290 +++++
.../business_data/components/fgpsdsz.less | 458 ++++++++
src/pages/business_data/components/jgfx.js | 253 +++++
src/pages/business_data/components/jgfx.less | 161 +++
src/pages/business_data/components/nhtj.js | 10 +
src/pages/business_data/components/nhtj.less | 4 +
src/pages/business_data/components/nhtjcs.js | 260 +++++
.../business_data/components/nhtjcs.less | 245 ++++
src/pages/business_data/components/nyfl.js | 295 +++++
src/pages/business_data/components/nyfl.less | 245 ++++
.../form/StaffSheetCreateForm.js | 271 +++++
.../form/StaffSheetRenderAdvancedForm.js | 113 ++
.../form/StaffSheetRenderSimpleForm.js | 81 ++
.../form/StaffSheetUpdateForm.js | 362 ++++++
.../business_data/form/StaffSheetViewForm.js | 299 +++++
src/pages/business_data/models/StaffSheet.js | 319 ++++++
src/pages/business_dataCollection/basic.js | 74 ++
src/pages/business_dataCollection/basic.less | 69 ++
.../components/Cjgl.js | 443 ++++++++
.../components/Cjgl.less | 603 ++++++++++
.../components/Cjrz.js | 325 ++++++
.../components/Cjrz.less | 277 +++++
.../components/Sglr.js | 318 ++++++
.../components/Sglr.less | 362 ++++++
.../components/Sjjy.js | 290 +++++
.../components/Sjjy.less | 248 ++++
.../components/Zdcj.js | 272 +++++
.../components/Zdcj.less | 3 +
.../form/StaffSheetCreateForm.js | 271 +++++
.../form/StaffSheetRenderAdvancedForm.js | 113 ++
.../form/StaffSheetRenderSimpleForm.js | 81 ++
.../form/StaffSheetUpdateForm.js | 362 ++++++
.../form/StaffSheetViewForm.js | 299 +++++
.../models/StaffSheet.js | 319 ++++++
.../FireKeynoteArea.js | 58 +-
src/pages/business_firewarning/FireWarning.js | 56 +-
src/pages/business_inspection/basic.js | 69 ++
src/pages/business_inspection/basic.less | 66 ++
.../components/EvaluationReport.js | 922 +++++++++++++++
.../components/EvaluationReport.less | 558 +++++++++
.../components/LicenseManagement.js | 604 ++++++++++
.../components/LicenseManagement.less | 498 ++++++++
.../components/OnlineMonitoring.js | 716 ++++++++++++
.../components/OnlineMonitoring.less | 919 +++++++++++++++
.../ResponsibilityImplementation.js | 581 ++++++++++
.../ResponsibilityImplementation.less | 1000 +++++++++++++++++
.../components/RiskAssessment.js | 865 ++++++++++++++
.../components/RiskAssessment.less | 594 ++++++++++
.../form/StaffSheetCreateForm.js | 271 +++++
.../form/StaffSheetRenderAdvancedForm.js | 113 ++
.../form/StaffSheetRenderSimpleForm.js | 81 ++
.../form/StaffSheetUpdateForm.js | 362 ++++++
.../form/StaffSheetViewForm.js | 299 +++++
.../business_inspection/models/StaffSheet.js | 319 ++++++
.../nav_system_content/SystemContentList.js | 39 +-
.../nav_system_content/SystemContentList.less | 12 +-
src/pages/systemMenu/SystemMenuList.js | 12 +-
src/pages/topnavbar/TopNavBar.js | 12 +-
76 files changed, 22581 insertions(+), 145 deletions(-)
create mode 100644 src/assets/basic_data/Component1.svg
create mode 100644 src/assets/basic_data/Component2.svg
create mode 100644 src/assets/basic_data/Component3.svg
create mode 100644 src/assets/basic_data/Iconfont.svg
create mode 100644 src/assets/data_icon.svg
create mode 100644 src/assets/menuBack.svg
create mode 100644 src/pages/business_data/basic.js
create mode 100644 src/pages/business_data/basic.less
create mode 100644 src/pages/business_data/components/OnlineMonitoring.js
create mode 100644 src/pages/business_data/components/OnlineMonitoring.less
create mode 100644 src/pages/business_data/components/ResponsibilityImplementation.js
create mode 100644 src/pages/business_data/components/ResponsibilityImplementation.less
create mode 100644 src/pages/business_data/components/RiskAssessment.js
create mode 100644 src/pages/business_data/components/RiskAssessment.less
create mode 100644 src/pages/business_data/components/bmzstx.js
create mode 100644 src/pages/business_data/components/bmzstx.less
create mode 100644 src/pages/business_data/components/fgpsdsz.js
create mode 100644 src/pages/business_data/components/fgpsdsz.less
create mode 100644 src/pages/business_data/components/jgfx.js
create mode 100644 src/pages/business_data/components/jgfx.less
create mode 100644 src/pages/business_data/components/nhtj.js
create mode 100644 src/pages/business_data/components/nhtj.less
create mode 100644 src/pages/business_data/components/nhtjcs.js
create mode 100644 src/pages/business_data/components/nhtjcs.less
create mode 100644 src/pages/business_data/components/nyfl.js
create mode 100644 src/pages/business_data/components/nyfl.less
create mode 100644 src/pages/business_data/form/StaffSheetCreateForm.js
create mode 100644 src/pages/business_data/form/StaffSheetRenderAdvancedForm.js
create mode 100644 src/pages/business_data/form/StaffSheetRenderSimpleForm.js
create mode 100644 src/pages/business_data/form/StaffSheetUpdateForm.js
create mode 100644 src/pages/business_data/form/StaffSheetViewForm.js
create mode 100644 src/pages/business_data/models/StaffSheet.js
create mode 100644 src/pages/business_dataCollection/basic.js
create mode 100644 src/pages/business_dataCollection/basic.less
create mode 100644 src/pages/business_dataCollection/components/Cjgl.js
create mode 100644 src/pages/business_dataCollection/components/Cjgl.less
create mode 100644 src/pages/business_dataCollection/components/Cjrz.js
create mode 100644 src/pages/business_dataCollection/components/Cjrz.less
create mode 100644 src/pages/business_dataCollection/components/Sglr.js
create mode 100644 src/pages/business_dataCollection/components/Sglr.less
create mode 100644 src/pages/business_dataCollection/components/Sjjy.js
create mode 100644 src/pages/business_dataCollection/components/Sjjy.less
create mode 100644 src/pages/business_dataCollection/components/Zdcj.js
create mode 100644 src/pages/business_dataCollection/components/Zdcj.less
create mode 100644 src/pages/business_dataCollection/form/StaffSheetCreateForm.js
create mode 100644 src/pages/business_dataCollection/form/StaffSheetRenderAdvancedForm.js
create mode 100644 src/pages/business_dataCollection/form/StaffSheetRenderSimpleForm.js
create mode 100644 src/pages/business_dataCollection/form/StaffSheetUpdateForm.js
create mode 100644 src/pages/business_dataCollection/form/StaffSheetViewForm.js
create mode 100644 src/pages/business_dataCollection/models/StaffSheet.js
create mode 100644 src/pages/business_inspection/basic.js
create mode 100644 src/pages/business_inspection/basic.less
create mode 100644 src/pages/business_inspection/components/EvaluationReport.js
create mode 100644 src/pages/business_inspection/components/EvaluationReport.less
create mode 100644 src/pages/business_inspection/components/LicenseManagement.js
create mode 100644 src/pages/business_inspection/components/LicenseManagement.less
create mode 100644 src/pages/business_inspection/components/OnlineMonitoring.js
create mode 100644 src/pages/business_inspection/components/OnlineMonitoring.less
create mode 100644 src/pages/business_inspection/components/ResponsibilityImplementation.js
create mode 100644 src/pages/business_inspection/components/ResponsibilityImplementation.less
create mode 100644 src/pages/business_inspection/components/RiskAssessment.js
create mode 100644 src/pages/business_inspection/components/RiskAssessment.less
create mode 100644 src/pages/business_inspection/form/StaffSheetCreateForm.js
create mode 100644 src/pages/business_inspection/form/StaffSheetRenderAdvancedForm.js
create mode 100644 src/pages/business_inspection/form/StaffSheetRenderSimpleForm.js
create mode 100644 src/pages/business_inspection/form/StaffSheetUpdateForm.js
create mode 100644 src/pages/business_inspection/form/StaffSheetViewForm.js
create mode 100644 src/pages/business_inspection/models/StaffSheet.js
diff --git a/README.md b/README.md
index af2f4dc..203d7d2 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
# dq-enms
+
能源管理系统
\ No newline at end of file
diff --git a/config/routes.js b/config/routes.js
index b6355f1..8cf784a 100644
--- a/config/routes.js
+++ b/config/routes.js
@@ -24,19 +24,19 @@ export default [
name: 'business',
component: './nav_system_content/SystemContentList',
routes: [
- // 基础信息管理
+ // 基础数据管理
{
- path: '/topnavbar00/business/basic',
- name: 'basic',
- component: './business_basic/basic',
+ path: '/topnavbar00/business/data',
+ name: 'basic_data',
+ component: './business_data/basic',
},
- // 消防重点部位管理
+ // 数据采集
{
- path: '/topnavbar00/business/firekeynotearea',
- name: 'firekeynotearea',
- component: './business_firekeynotearea/FireKeynoteArea',
+ path: '/topnavbar00/business/dataCollection',
+ name: 'dataCollection',
+ component: './business_dataCollection/basic',
},
- // 消防检测报警
+ // 能源监测
{
path: '/topnavbar00/business/fireWarning',
name: 'fireWarning',
diff --git a/src/assets/basic_data/Component1.svg b/src/assets/basic_data/Component1.svg
new file mode 100644
index 0000000..285a3e9
--- /dev/null
+++ b/src/assets/basic_data/Component1.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/basic_data/Component2.svg b/src/assets/basic_data/Component2.svg
new file mode 100644
index 0000000..a26205e
--- /dev/null
+++ b/src/assets/basic_data/Component2.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/basic_data/Component3.svg b/src/assets/basic_data/Component3.svg
new file mode 100644
index 0000000..da432d0
--- /dev/null
+++ b/src/assets/basic_data/Component3.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/basic_data/Iconfont.svg b/src/assets/basic_data/Iconfont.svg
new file mode 100644
index 0000000..3d42fa7
--- /dev/null
+++ b/src/assets/basic_data/Iconfont.svg
@@ -0,0 +1,10 @@
+
diff --git a/src/assets/data_icon.svg b/src/assets/data_icon.svg
new file mode 100644
index 0000000..a06d26e
--- /dev/null
+++ b/src/assets/data_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/menuBack.svg b/src/assets/menuBack.svg
new file mode 100644
index 0000000..3545556
--- /dev/null
+++ b/src/assets/menuBack.svg
@@ -0,0 +1,19 @@
+
diff --git a/src/pages/business_data/basic.js b/src/pages/business_data/basic.js
new file mode 100644
index 0000000..20abc46
--- /dev/null
+++ b/src/pages/business_data/basic.js
@@ -0,0 +1,74 @@
+import React, { useState } from 'react';
+import { Card, Row, Col, Statistic, Progress, Button, Space } from 'antd';
+import styles from './basic.less';
+import Nyfl from './components/nyfl';
+import Fgpsdsz from './components/fgpsdsz';
+import Jgfx from './components/jgfx';
+import Bmzstx from './components/bmzstx';
+import Nhtjcs from './components/nhtjcs';
+
+
+
+const SafeMajorHazardList = () => {
+ const [activeModule, setActiveModule] = useState('nyfl');
+
+ const handleModuleClick = (module) => {
+ setActiveModule(module)
+ }
+
+
+ const renderModule = () => {
+ switch (activeModule) {
+ case 'nyfl':
+ return ;
+ case 'fgpsdsz':
+ return ;
+ case 'jgtx':
+ return ;
+ case 'bmzstx':
+ return ;
+ case 'nhtjcs':
+ return ;
+ default:
+ return ;
+ }
+ };
+
+
+ return (
+
+
+
+
+
+
+
+
+
+ {renderModule()}
+
+
+ );
+};
+
+export default SafeMajorHazardList;
diff --git a/src/pages/business_data/basic.less b/src/pages/business_data/basic.less
new file mode 100644
index 0000000..a06febe
--- /dev/null
+++ b/src/pages/business_data/basic.less
@@ -0,0 +1,69 @@
+.container {
+ background-color: transparent;
+ width: 100%;
+ height: 89vh;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+
+ .TopButton {
+ background-color: white;
+ width: 100%;
+ padding: 10px 30px;
+ display: flex;
+ gap: 24px;
+ margin-left: 6px;
+
+ .TopButtonItem {
+ 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 {
+ background-color: rgba(72, 81, 255, 1) !important;
+ color: #fff !important;
+ border-radius: 20px !important;
+ padding: 6px 10px 10px !important;
+
+ &::after {
+ content: '';
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ bottom: 3px;
+ width: 16.573974609375px;
+ height: 2.615234375px;
+ background-color: rgba(255, 255, 255, 0.52);
+ border-radius: 15px;
+ opacity: 1;
+ }
+ }
+ }
+ }
+
+ .content {
+ // ======== 内容区域样式 ========
+ flex: 1; // ======== 占据剩余空间 ========
+ overflow-y: auto; // ======== 允许垂直滚动 ========
+ padding: 0; // ======== 无内边距 ========
+ }
+}
diff --git a/src/pages/business_data/components/OnlineMonitoring.js b/src/pages/business_data/components/OnlineMonitoring.js
new file mode 100644
index 0000000..3e4b6b5
--- /dev/null
+++ b/src/pages/business_data/components/OnlineMonitoring.js
@@ -0,0 +1,716 @@
+
+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 './OnlineMonitoring.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 OnlineMonitoring = () => {
+ 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 (
+
+
+
+
+
+
+

+
+
+
+
总报警
+
1456
+
+
+ 未处理 6
+
+
+ 处理中 10
+
+
+
+
+
+
+

+
+
+
一级报警
+
357
+
+
+ 未处理 6
+
+
+ 处理中 10
+
+
+
+
+
+
+

+
+
+
二级报警
+
401
+
+
+ 未处理 6
+
+
+ 处理中 10
+
+
+
+
+
+
+

+
+
+
三级报警
+
556
+
+
+ 未处理 6
+
+
+ 处理中 10
+
+
+
+
+
+
+
+
+
+
+
+
+
储罐液化装置区
+
R值: 1765
+
编号:XXXXXXXX
+
+
+
+
+
+
储罐液化装置区
+
R值: 1765
+
编号:XXXXXXXX
+
+
+
+
+
+
储罐液化装置区
+
R值: 1765
+
编号:XXXXXXXX
+
+
+
+
+
+
储罐液化装置区
+
R值: 1765
+
编号:XXXXXXXX
+
+
+
+
+
+ {/* 表格 */}
+
+ {/* 首行 左侧标题左对齐 右侧按钮右对齐 */}
+
+
+
+
+
+
+
+
+
+ {/* 表格 5行10列 带页码 每页5条数据 */}
+
+
+ `共 ${total} 条`,
+ }}
+ scroll={{ x: 1200 }}
+ />
+
+
+
+ );
+};
+
+export default OnlineMonitoring;
\ No newline at end of file
diff --git a/src/pages/business_data/components/OnlineMonitoring.less b/src/pages/business_data/components/OnlineMonitoring.less
new file mode 100644
index 0000000..283ce83
--- /dev/null
+++ b/src/pages/business_data/components/OnlineMonitoring.less
@@ -0,0 +1,919 @@
+.Ocontainer {
+ padding: 8px 6px 0px 6px;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+
+ .OcontainerTop {
+ display: flex;
+
+ height: 50%;
+ margin-bottom: 5px;
+
+ .OcontainerTopLeft {
+ width: 72%;
+ height: 100%;
+ // background-color: pink;
+ margin-right: 10px;
+ // display: flex;
+
+ .OcontainerTopLeftTop {
+ width: 100%;
+ height: 35%;
+ display: flex;
+ gap: 12px;
+
+ .alarmO {
+ flex: 1;
+ height: 100%;
+ background-color: #F4F7FF;
+ border: 1px solid #AED3FF;
+ border-bottom: 0px solid #AED3FF;
+ border-radius: 4px;
+ box-shadow: 0px 2px 31px 0px #5382FE33 inset;
+ display: flex;
+
+ .alarmOLeft {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .alarmORight {
+ flex: 1;
+ width: 35%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ margin-left: 2px;
+ gap: 18px;
+
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-style: Regular;
+ font-size: 12px;
+ line-height: 100%;
+ letter-spacing: 0%;
+ color: #333333;
+
+ .alarmORightText1 {
+ margin-top: 15px;
+ }
+
+
+ .alarmORightText2 {
+ font-weight: 700;
+ font-size: 16px;
+ }
+
+ .alarmORightText3 {
+ display: flex;
+ gap: 22px;
+ }
+
+ }
+
+
+
+ }
+
+ .alarmTw {
+ flex: 1;
+ height: 100%;
+ background-color: #FFF5f4;
+ border: 1px solid #FFC5BC;
+ border-bottom: 0px solid #FFC5BC;
+ border-radius: 4px;
+ box-shadow: 0px 2px 31px 0px #FE5F4C33 inset;
+ display: flex;
+
+ .alarmTwLeft {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .alarmTwRight {
+ flex: 1;
+ width: 35%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ margin-left: 2px;
+ gap: 18px;
+
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-style: Regular;
+ font-size: 12px;
+ line-height: 100%;
+ letter-spacing: 0%;
+ color: #333333;
+
+ .alarmTwRightText1 {
+ margin-top: 15px;
+ }
+
+ .alarmTwRightText2 {
+ font-weight: 700;
+ font-size: 16px;
+ }
+
+ .alarmTwRightText3 {
+ display: flex;
+ gap: 22px;
+ }
+ }
+ }
+
+ .alarmTh {
+ flex: 1;
+ height: 100%;
+ background-color: #FFF7F2;
+ border: 1px solid #FFD9B2;
+ border-bottom: 0px solid #FFD9B2;
+ border-radius: 4px;
+ box-shadow: 0px 2px 31px 0px #FD883C33 inset;
+ display: flex;
+
+ .alarmThLeft {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .alarmThRight {
+ flex: 1;
+ width: 35%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ margin-left: 2px;
+ gap: 18px;
+
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-style: Regular;
+ font-size: 12px;
+ line-height: 100%;
+ letter-spacing: 0%;
+ color: #333333;
+
+ .alarmThRightText1 {
+ margin-top: 15px;
+ }
+
+ .alarmThRightText2 {
+ font-weight: 700;
+ font-size: 16px;
+ }
+
+ .alarmThRightText3 {
+ display: flex;
+ gap: 22px;
+ }
+ }
+ }
+
+ .alarmF {
+ flex: 1;
+ height: 100%;
+ background-color: #EFF9FF;
+ border: 1px solid #89E1FF;
+ border-bottom: 0px solid #89E1FF;
+ border-radius: 4px;
+ box-shadow: 0px 2px 31px 0px #22A4FD33 inset;
+ display: flex;
+
+ .alarmFLeft {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .alarmFRight {
+ flex: 1;
+ width: 35%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ margin-left: 2px;
+ gap: 18px;
+
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-style: Regular;
+ font-size: 12px;
+ line-height: 100%;
+ letter-spacing: 0%;
+ color: #333333;
+
+ .alarmFRightText1 {
+ margin-top: 15px;
+ }
+
+ .alarmFRightText2 {
+ font-weight: 700;
+ font-size: 16px;
+ }
+
+ .alarmFRightText3 {
+ display: flex;
+ gap: 22px;
+ }
+ }
+ }
+ }
+
+ .OcontainerTopLeftBottom {
+ margin-top: 12px;
+ background-color: #fff;
+ width: 100%;
+ height: 60%;
+
+ .OcontainerTopLeftBottomTitle {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ // padding: 8px 15px;
+ padding: 8px 15px 0px 15px;
+
+ .titleLeft {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-family: PingFang SC;
+ font-weight: 500;
+ font-style: Medium;
+ font-size: 14px;
+ line-height: 100%;
+ letter-spacing: 0%;
+
+
+ .titleIcon {
+ width: 3px;
+ height: 16px;
+ background-color: #2E4CD4;
+ }
+ }
+
+ .titleRight {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+
+ font-family: PingFang SC;
+ font-style: Medium;
+ font-size: 13px;
+ line-height: 100%;
+ letter-spacing: 0%;
+
+
+ .selectBox {
+ padding: 4px 8px;
+ border: 1px solid #d9d9d9;
+ border-radius: 4px;
+ background-color: #fff;
+ font-size: 12px;
+ color: #333;
+ outline: none;
+
+ &:focus {
+ border-color: #2E4CD4;
+ }
+ }
+ }
+ }
+
+ .OcontainerTopLeftBottomChart {
+ flex: 1;
+ width: 100%;
+ height: 75%;
+ }
+ }
+ }
+
+ .OcontainerTopRight {
+ flex: 1;
+ height: calc(100% - 3.3px);
+ background-color: #fff;
+ background-image: url('@/assets/safe_majorHazard/online_monitoring/backTopRight.png');
+ background-size: 100% auto;
+ display: flex;
+ flex-direction: column;
+ overflow-y: auto;
+
+ .realTimeDataHeader {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 8px 15px;
+ margin-bottom: 10px;
+
+ .titleLeft {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-family: PingFang SC;
+ font-weight: 500;
+ font-style: Medium;
+ font-size: 14px;
+ line-height: 100%;
+ letter-spacing: 0%;
+
+ .titleIcon {
+ width: 3px;
+ height: 16px;
+ background-color: #2E4CD4;
+ }
+ }
+
+ .totalCount {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 13px;
+ color: #333333;
+ }
+ }
+
+ .dataItem {
+ height: 23%;
+ flex-shrink: 0;
+ border: 1px solid #89E1FF;
+ border-radius: 2px;
+ margin: 0 15px;
+ margin-bottom: 6px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-family: PingFang SC;
+ font-size: 14px;
+ // color: #666;
+ background-color: #EFF9FF;
+
+ &:last-child {
+ // margin-bottom: 1px;
+ }
+ }
+
+ .dataItem1 {
+ height: 25%;
+ flex-shrink: 0;
+ border: 1px solid #89E1FF;
+ border-radius: 4px;
+ margin: 0 15px;
+ margin-bottom: 6px;
+ display: flex;
+ align-items: center;
+ padding: 0px 15px;
+ background-color: #EFF9FF;
+
+ .dataItemLeft {
+ width: 65%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .areaName {
+
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 13px;
+ color: #333333;
+ line-height: 2.2;
+ }
+
+ .rValue {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 14px;
+ color: #666666;
+ line-height: 0.2;
+ }
+
+ .codeNumber {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 12px;
+ color: #666666;
+ }
+ }
+
+ .dataItemRight {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .circleContainer {
+ position: relative;
+ height: 80%;
+ aspect-ratio: 1; // 强制宽高比1:1
+
+ .outerCircle {
+
+ width: 100%;
+ height: 100%;
+ background-color: rgba(51, 176, 253, 0.3);
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .innerCircle {
+ width: 70%;
+ height: 70%;
+ background-color: rgba(4, 128, 251, 0.8);
+ border-radius: 50%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .levelText {
+ font-family: PingFang SC;
+ font-weight: 500;
+ font-size: 11px;
+ color: #FFFFFF;
+ line-height: 1.4;
+ margin-top: -4px;
+ }
+
+ .riskText {
+ font-family: PingFang SC;
+ font-weight: 300;
+ font-size: 8px;
+ color: #FFFFFF;
+ line-height: 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .dataItem2 {
+ height: 25%;
+ flex-shrink: 0;
+ border: 1px solid rgba(255, 197, 188, 1);
+ border-radius: 4px;
+ margin: 0 15px;
+ margin-bottom: 6px;
+ display: flex;
+ align-items: center;
+ padding: 0px 15px;
+ background-color: #fff5f4;
+
+ .dataItemLeft {
+ width: 65%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .areaName {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 13px;
+ color: #333333;
+ line-height: 2.2;
+ }
+
+ .rValue {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 14px;
+ color: #666666;
+ line-height: 0.2;
+ }
+
+ .codeNumber {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 12px;
+ color: #666666;
+ }
+ }
+
+ .dataItemRight {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .circleContainer {
+ position: relative;
+ height: 80%;
+ aspect-ratio: 1;
+
+ .outerCircle {
+ width: 100%;
+ height: 100%;
+ background-color: rgba(254, 214, 209, 1);
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .innerCircle {
+ width: 70%;
+ height: 70%;
+ background-color: rgba(253, 41, 14, 1);
+ border-radius: 50%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .levelText {
+ font-family: PingFang SC;
+ font-weight: 500;
+ font-size: 11px;
+ color: #FFFFFF;
+ line-height: 1.4;
+ margin-top: -4px;
+ }
+
+ .riskText {
+ font-family: PingFang SC;
+ font-weight: 300;
+ font-size: 8px;
+ color: #FFFFFF;
+ line-height: 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .dataItem3 {
+ height: 25%;
+ flex-shrink: 0;
+ border: 1px solid rgba(255, 217, 178, 1);
+ border-radius: 4px;
+ margin: 0 15px;
+ margin-bottom: 6px;
+ display: flex;
+ align-items: center;
+ padding: 0px 15px;
+ background-color: #fef6f1;
+
+ .dataItemLeft {
+ width: 65%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .areaName {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 13px;
+ color: #333333;
+ line-height: 2.2;
+ }
+
+ .rValue {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 14px;
+ color: #666666;
+ line-height: 0.2;
+ }
+
+ .codeNumber {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 12px;
+ color: #666666;
+ }
+ }
+
+ .dataItemRight {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .circleContainer {
+ position: relative;
+ height: 80%;
+ aspect-ratio: 1;
+
+ .outerCircle {
+ width: 100%;
+ height: 100%;
+ background-color: rgba(255, 234, 218, 1);
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .innerCircle {
+ width: 70%;
+ height: 70%;
+ background-color: rgba(252, 103, 18, 1);
+ border-radius: 50%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .levelText {
+ font-family: PingFang SC;
+ font-weight: 500;
+ font-size: 11px;
+ color: #FFFFFF;
+ line-height: 1.4;
+ margin-top: -4px;
+ }
+
+ .riskText {
+ font-family: PingFang SC;
+ font-weight: 300;
+ font-size: 8px;
+ color: #FFFFFF;
+ line-height: 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .dataItem4 {
+ height: 25%;
+ flex-shrink: 0;
+ border: 1px solid #89E1FF;
+ border-radius: 4px;
+ margin: 0 15px;
+ margin-bottom: 6px;
+ display: flex;
+ align-items: center;
+ padding: 0px 15px;
+ background-color: #EFF9FF;
+
+ .dataItemLeft {
+ width: 65%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .areaName {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 13px;
+ color: #333333;
+ line-height: 2.2;
+ }
+
+ .rValue {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 14px;
+ color: #666666;
+ line-height: 0.2;
+ }
+
+ .codeNumber {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 12px;
+ color: #666666;
+ }
+ }
+
+ .dataItemRight {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .circleContainer {
+ position: relative;
+ height: 80%;
+ aspect-ratio: 1;
+
+ .outerCircle {
+ width: 100%;
+ height: 100%;
+ background-color: rgba(51, 176, 253, 0.3);
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .innerCircle {
+ width: 70%;
+ height: 70%;
+ background-color: rgba(4, 128, 251, 0.8);
+ border-radius: 50%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .levelText {
+ font-family: PingFang SC;
+ font-weight: 500;
+ font-size: 11px;
+ color: #FFFFFF;
+ line-height: 1.4;
+ margin-top: -4px;
+ }
+
+ .riskText {
+ font-family: PingFang SC;
+ font-weight: 300;
+ font-size: 8px;
+ color: #FFFFFF;
+ line-height: 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ .OcontainerBottom {
+ background-color: #fff;
+ flex: 1;
+ padding: 8px 15px 5px 15px;
+ display: flex;
+ flex-direction: column;
+
+ .tableHeader {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ // margin-bottom: 15px;
+ padding-bottom: 5px;
+ // border-bottom: 1px solid #f0f0f0;
+
+ .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;
+ gap: 8px;
+
+ // 自定义按钮样式
+ :global(.ant-btn) {
+ background-color: #ffffff !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+
+ &:hover {
+ background-color: #f5f5f5 !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ &:focus {
+ background-color: #ffffff !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ &:active {
+ background-color: #e6e6e6 !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ // 主要按钮样式
+ &.ant-btn-primary {
+ background-color: #ffffff !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+
+ &:hover {
+ background-color: #f5f5f5 !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ &:focus {
+ background-color: #ffffff !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ &:active {
+ background-color: #e6e6e6 !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+ }
+
+ // 危险按钮样式
+ &.ant-btn-dangerous {
+ background-color: #ffffff !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+
+ &:hover {
+ background-color: #f5f5f5 !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ &:focus {
+ background-color: #ffffff !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ &:active {
+ background-color: #e6e6e6 !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+ }
+
+ // 禁用状态
+ &:disabled {
+ background-color: #f5f5f5 !important;
+ border-color: #d9d9d9 !important;
+ color: #bfbfbf !important;
+ box-shadow: none !important;
+ }
+ }
+ }
+ }
+
+ .tableContainer {
+ flex: 1;
+ overflow: hidden;
+
+ :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;
+ }
+
+ :global(.ant-table-tbody > tr:hover > td) {
+ background-color: #f5f5f5;
+ }
+
+ :global(.ant-pagination) {
+ margin-top: 16px;
+ text-align: right;
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/pages/business_data/components/ResponsibilityImplementation.js b/src/pages/business_data/components/ResponsibilityImplementation.js
new file mode 100644
index 0000000..5d9624b
--- /dev/null
+++ b/src/pages/business_data/components/ResponsibilityImplementation.js
@@ -0,0 +1,581 @@
+
+import React from 'react';
+import { Card, Statistic, Table,Row, Input,Button,Col, Select} from 'antd';
+import { PhoneOutlined, IdcardOutlined, PlusOutlined } from '@ant-design/icons';
+import StandardTable from '@/components/StandardTable';
+import styles from './ResponsibilityImplementation.less';
+
+import upload from '@/assets/business_basic/upload.png';
+import download from '@/assets/business_basic/download.png';
+import import1 from '@/assets/business_basic/import1.png';
+import fire_fighting1 from '@/assets/business_basic/fire_fighting1.png';
+import fire_fighting2 from '@/assets/business_basic/fire_fighting2.png';
+import fire_fighting3 from '@/assets/business_basic/fire_fighting3.png';
+import frameIcon from '@/assets/business_basic/Frame.png';
+import background1 from '@/assets/business_basic/background1.png';
+import export1 from '@/assets/business_basic/export1.png';
+
+
+
+const ResponsibilityImplementation = () => {
+
+ // 搜索处理函数
+ const onSearch = (value) => {
+ console.log('搜索内容:', value);
+ // 这里可以添加实际的搜索逻辑
+ };
+
+ const columns = [
+ {
+ title:"编号",
+ dataIndex:"id",
+ key:"id",
+ width:80,
+ },
+ {
+ title:"组织代码",
+ dataIndex:"orgCode",
+ key:"orgCode",
+ width:120,
+ },
+ {
+ title:"组织类型",
+ dataIndex:"orgType",
+ key:"orgType",
+ width:120,
+ },
+ {
+ title:"负责人",
+ dataIndex:"manager",
+ key:"manager",
+ width:100,
+ },
+ {
+ title:"所属部门",
+ dataIndex:"department",
+ key:"department",
+ width:120,
+ },
+ {
+ title:"创建时间",
+ dataIndex:"createTime",
+ key:"createTime",
+ width:120,
+ },
+ {
+ title:"人员规模",
+ dataIndex:"staffCount",
+ key:"staffCount",
+ width:100,
+ },
+ {
+ title:"状态",
+ dataIndex:"status",
+ key:"status",
+ width:80,
+ 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'
+ };
+ }
+ return {};
+ };
+
+ return (
+
+ {text}
+
+ );
+ }
+ },
+ {
+ title:"操作",
+ dataIndex:"action",
+ key:"action",
+ width:120,
+ render: (text, record) => {
+ const handleEdit = (record) => {
+ console.log('编辑记录:', record);
+ };
+
+ const handleDelete = (record) => {
+ console.log('删除记录:', record);
+ };
+
+ return (
+
+
+
+
+ );
+ }
+ }
+ ];
+
+ // 固定的假数据
+ const tableData = [
+ {
+ key: '1',
+ id: '01',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-19 14:32:15',
+ staffCount: '15人',
+ status: '正常'
+ },
+ {
+ key: '2',
+ id: '02',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-18 09:25:43',
+ staffCount: '20人',
+ status: '正常'
+ },
+ {
+ key: '3',
+ id: '03',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-17 16:48:22',
+ staffCount: '25人',
+ status: '信息不全'
+ },
+ {
+ key: '4',
+ id: '04',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-16 11:15:37',
+ staffCount: '18人',
+ status: '正常'
+ },
+ {
+ key: '5',
+ id: '05',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-15 08:42:56',
+ staffCount: '22人',
+ status: '正常'
+ },
+ {
+ key: '6',
+ id: '06',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-14 13:27:18',
+ staffCount: '16人',
+ status: '信息不全'
+ },
+ {
+ key: '7',
+ id: '07',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-13 15:33:29',
+ staffCount: '19人',
+ status: '正常'
+ },
+ {
+ key: '8',
+ id: '08',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-12 10:56:44',
+ staffCount: '21人',
+ status: '正常'
+ },
+ {
+ key: '9',
+ id: '09',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-11 17:19:52',
+ staffCount: '17人',
+ status: '信息不全'
+ },
+ {
+ key: '10',
+ id: '10',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-10 12:41:07',
+ staffCount: '23人',
+ status: '正常'
+ },
+ {
+ key: '11',
+ id: '11',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-09 14:08:33',
+ staffCount: '24人',
+ status: '正常'
+ },
+ {
+ key: '12',
+ id: '12',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-08 16:52:14',
+ staffCount: '26人',
+ status: '信息不全'
+ }
+ ];
+
+ return (
+
+ {/* 警告提示框 */}
+
+

+
+ 有5个消防设备需要维护,3个资质证书即将到期,请及时处理。
+
+
+
+
+
+
+ {/* 第一行:标题和按钮 */}
+
+
+
+
+
+
+
+
+ {/* 第二行:图片占位 */}
+
+
+
+
+
+ {/* 第一行:标题 + 搜索栏 + 下拉选择框 */}
+
+
+ {/* 第二行:三个小块 */}
+
+
+
+
+
+ {/* 第一个块:姓名和单位 */}
+
+
+ {/* 第二个块:电话 */}
+
+
+ {/* 第三个块:身份证 */}
+
+
+ 1304************10
+
+
+ {/* 第四个块:职位标签 */}
+
+
+ {/* 第五个块:证书状态 */}
+
+
+ {/* 第六个块:操作按钮 */}
+
+
+
+
+
+
+
+ {/* 第一个块:姓名和单位 */}
+
+ 李小明
+ 消防支队
+
+
+ {/* 第二个块:电话 */}
+
+
+ {/* 第三个块:身份证 */}
+
+
+ 1304************20
+
+
+ {/* 第四个块:职位标签 */}
+
+
+ {/* 第五个块:证书状态 */}
+
+
+ {/* 第六个块:操作按钮 */}
+
+
+
+
+
+
+
+ {/* 第一个块:姓名和单位 */}
+
+ 王小红
+ 消防中队
+
+
+ {/* 第二个块:电话 */}
+
+
+ {/* 第三个块:身份证 */}
+
+
+ 1304************30
+
+
+ {/* 第四个块:职位标签 */}
+
+
+ {/* 第五个块:证书状态 */}
+
+
+ {/* 第六个块:操作按钮 */}
+
+
+
+
+
+
+
+
+
+
+ {/* 第一块:标题 */}
+
+
+ {/* 第二个大块:搜索和按钮 */}
+
+
+
+
+
+
+
+
+
+
+
+ {/* 第三个大块:表格 */}
+
+ {}} // ======== 行选择事件处理函数 ========
+ onChange={() => {}} // ======== 表格变化事件处理函数 ========
+ pagination={{
+ currentPage: 1,
+ pageSize: 5,
+ total: tableData.length,
+ showSizeChanger: false,
+ showQuickJumper: true,
+ showTotal: (total, range) =>
+ `共 ${total} 条`,
+ locale: {
+ jump_to: '前往',
+ page: '页',
+ items_per_page: '条/页',
+ }
+ }}
+ />
+
+
+
+ );
+};
+export default ResponsibilityImplementation;
diff --git a/src/pages/business_data/components/ResponsibilityImplementation.less b/src/pages/business_data/components/ResponsibilityImplementation.less
new file mode 100644
index 0000000..d94eca3
--- /dev/null
+++ b/src/pages/business_data/components/ResponsibilityImplementation.less
@@ -0,0 +1,1000 @@
+.XcontainerR {
+ padding: 8px 6px;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+
+ .warningBox {
+ width: 100%;
+ background-color: #FFF3CD;
+ border: 1px solid #F4E3AE;
+ border-radius: 4px;
+ padding: 8px 20px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-bottom: 10px;
+
+ .warningIcon {
+ width: 18px;
+ height: 18px;
+ }
+
+ .warningText {
+ color: #8C6C0B;
+ font-size: 12px;
+ line-height: 1.4;
+ }
+ }
+
+ .containerOne {
+ height: 40%;
+ flex-shrink: 0;
+ display: flex;
+ margin-bottom: 10px;
+ gap: 10px;
+
+ .containerOneLeft {
+ background-color: white;
+ width: calc(50% - 5px);
+ display: flex;
+ flex-direction: column;
+ padding: 5px 15px;
+ border: 1px solid #f0f0f0;
+ border-radius: 4px;
+
+ .leftTopSection {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ // margin-bottom: 15px;
+
+ .titleLeft {
+ 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;
+ }
+ }
+
+ .buttonGroup {
+ display: flex;
+ gap: 8px;
+
+ .actionBtn {
+ 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;
+
+ &:hover {
+ background-color: #F0F2FF;
+ border-color: #2E4CD4;
+ }
+
+ .btnIcon {
+ width: 12px;
+ height: 12px;
+ }
+ }
+ }
+ }
+
+ .leftBottomSection {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ .imagePlaceholder {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ .imageIcon1 {
+ transform: scale(0.9) translateY(-5px); // 稍微向上移动
+ object-fit: contain;
+ }
+
+
+ .imageRow {
+ display: flex;
+ justify-content: space-between;
+ // width: 100%;
+ margin-bottom: 10px;
+ // padding-bottom: 20px;
+ // gap: 12px;
+
+ .imageIcon2 {
+ height: 55%;
+ transform: scale(0.7) translateY(-25%) translateX(20%); // 稍微向上移动
+ object-fit: contain;
+ background-color: #EFF5FE;
+ // padding-bottom: 20px;
+ }
+
+ .imageIcon3 {
+ height: 40%;
+ transform: scale(0.65) translateY(-32%) translateX(4%); // 向上移动10px
+ object-fit: contain;
+ padding-bottom: 20px;
+ // background-color: #EFF5FE;
+
+ }
+ }
+
+ .imageText {
+ font-size: 12px;
+ font-weight: 400;
+ }
+ }
+ }
+ }
+
+ .containerOneRight {
+ background-color: white;
+ width: calc(50% - 5px);
+ display: flex;
+ flex-direction: column;
+ padding: 5px 15px;
+ border: 1px solid #f0f0f0;
+ border-radius: 4px;
+
+ .rightTopSection {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 10px;
+
+ .rightTopLeft {
+ display: flex;
+ align-items: center;
+
+ .titleLeft {
+ 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;
+ }
+ }
+ }
+
+ .rightTopRight {
+ .searchGroup {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+
+ .searchInput {
+ width: 200px;
+ height: 32px;
+
+ :global(.ant-input) {
+ height: 32px;
+ border-radius: 4px;
+ border: 1px solid #d9d9d9;
+ font-size: 14px;
+
+ &:focus {
+ border-color: #2E4CD4;
+ box-shadow: 0 0 0 2px rgba(46, 76, 212, 0.2);
+ }
+ }
+
+ :global(.ant-input-suffix) {
+ color: #999999;
+ font-size: 14px;
+ }
+ }
+
+ .organizationSelect {
+ width: 120px;
+ height: 32px;
+
+ :global(.ant-select-selector) {
+ height: 32px !important;
+ border-radius: 4px !important;
+ border: 1px solid #d9d9d9 !important;
+
+ &:hover {
+ border-color: #2E4CD4 !important;
+ }
+
+ &:focus {
+ border-color: #2E4CD4 !important;
+ box-shadow: 0 0 0 2px rgba(46, 76, 212, 0.2) !important;
+ }
+ }
+
+ :global(.ant-select-selection-item) {
+ line-height: 30px !important;
+ font-size: 14px !important;
+ }
+ }
+ }
+ }
+ }
+
+ .rightBottomSection {
+ flex: 1;
+ padding: 5px 15px;
+ width: 100%;
+ height: 100%;
+
+ .threeBlocksContainer {
+ display: flex;
+ gap: 20px;
+ width: 100%;
+ height: 100%;
+
+ .blockItem {
+ width: 100%;
+ height: 100%;
+ flex: 1;
+ display: flex;
+ justify-content: center;
+ background: url('@/assets/business_basic/background1.png') no-repeat center center;
+ background-size: 100% auto;
+
+ .blockContent {
+ // background-color: pink;
+ font-size: 12px;
+ color: #666666;
+ font-weight: 400;
+ width: 100%;
+ height: 100%;
+ }
+
+ // 新的6个横向块样式
+ .backgroundContainer {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .infoBlock {
+ width: 100%;
+ display: flex;
+ justify-content: flex-start;
+ white-space: nowrap;
+
+ .nameText {
+ font-size: 12px;
+ font-weight: 500;
+ color: #333333;
+ margin-left: 10px;
+ margin-right: 10px;
+ margin-top: 15px;
+ }
+
+
+ .unitText {
+ font-size: 10px;
+ font-weight: 400;
+ color: #666666;
+ margin-top: 18px;
+ }
+
+ .infoIcon {
+ font-size: 10px;
+ color: #666666;
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+
+ .infoText {
+ font-size: 10px;
+ font-weight: 400;
+ color: #666666;
+
+ }
+
+ }
+
+ .tagContainer {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+ }
+
+ .tagBlue1 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ margin-left: 10px;
+ }
+
+ .tagBlue2 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+
+ }
+
+ .tagBlue3 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ margin-left: 10px;
+
+ }
+
+ .tagYellow {
+ background-color: #FFF8E2;
+ color: #FFC403;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ }
+
+ .actionBlock {
+ width: 100%;
+ height: 50%;
+ background-color: #BDD6FDCC;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .buttonContainer {
+ display: flex;
+ gap: 15px;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+
+ .editBtn {
+ height: 80%;
+ background-color: #1269FF;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 400;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 2px 15px;
+
+ &:hover {
+ background-color: #0f5ae0;
+ }
+ }
+
+ .deleteBtn {
+ height: 80%;
+ background-color: #FF5F60;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 400;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 2px 15px;
+
+ &:hover {
+ background-color: #ff4a4b;
+ }
+ }
+ }
+
+
+ }
+
+ // 第二个块的样式
+ .backgroundContainer2 {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .infoBlock2 {
+ width: 100%;
+ display: flex;
+ justify-content: flex-start;
+ white-space: nowrap;
+
+ .nameText2 {
+ font-size: 12px;
+ font-weight: 500;
+ color: #333333;
+ margin-left: 10px;
+ margin-right: 10px;
+ margin-top: 15px;
+ }
+
+ .unitText2 {
+ font-size: 10px;
+ font-weight: 400;
+ color: #666666;
+ margin-top: 18px;
+ }
+
+ .infoIcon2 {
+ font-size: 10px;
+ color: #666666;
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+
+ .infoText2 {
+ font-size: 10px;
+ font-weight: 400;
+ color: #666666;
+ }
+ }
+
+ .tagContainer2 {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+ }
+
+ .tagBlue4 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ margin-left: 10px;
+ }
+
+ .tagBlue5 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ }
+
+ .tagBlue6 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ margin-left: 10px;
+ }
+
+ .tagGreen {
+ background-color: #E8F5E8;
+ color: #52C41A;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ }
+
+ .actionBlock2 {
+ width: 100%;
+ height: 50%;
+ background-color: #BDD6FDCC;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .buttonContainer2 {
+ display: flex;
+ gap: 15px;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+
+ .editBtn2 {
+ height: 80%;
+ background-color: #1269FF;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 400;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 2px 15px;
+
+ &:hover {
+ background-color: #0f5ae0;
+ }
+ }
+
+ .deleteBtn2 {
+ height: 80%;
+ background-color: #FF5F60;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 400;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 2px 15px;
+
+ &:hover {
+ background-color: #ff4a4b;
+ }
+ }
+ }
+ }
+
+ // 第三个块的样式
+ .backgroundContainer3 {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .infoBlock3 {
+ width: 100%;
+ display: flex;
+ justify-content: flex-start;
+ white-space: nowrap;
+
+ .nameText3 {
+ font-size: 12px;
+ font-weight: 500;
+ color: #333333;
+ margin-left: 10px;
+ margin-right: 10px;
+ margin-top: 15px;
+ }
+
+ .unitText3 {
+ font-size: 10px;
+ font-weight: 400;
+ color: #666666;
+ margin-top: 18px;
+ }
+
+ .infoIcon3 {
+ font-size: 10px;
+ color: #666666;
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+
+ .infoText3 {
+ font-size: 10px;
+ font-weight: 400;
+ color: #666666;
+ }
+ }
+
+ .tagContainer3 {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+ }
+
+ .tagBlue7 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ margin-left: 10px;
+ }
+
+ .tagBlue8 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ }
+
+ .tagBlue9 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ margin-left: 10px;
+ }
+
+ .tagOrange {
+ background-color: #FFF2E8;
+ color: #FF7A00;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ }
+
+ .actionBlock3 {
+ width: 100%;
+ height: 50%;
+ background-color: #BDD6FDCC;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .buttonContainer3 {
+ display: flex;
+ gap: 15px;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+
+ .editBtn3 {
+ height: 80%;
+ background-color: #1269FF;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 400;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 2px 15px;
+
+ &:hover {
+ background-color: #0f5ae0;
+ }
+ }
+
+ .deleteBtn3 {
+ height: 80%;
+ background-color: #FF5F60;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 400;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 2px 15px;
+
+ &:hover {
+ background-color: #ff4a4b;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .containerTwo {
+ flex: 1;
+ background-color: white;
+ display: flex;
+ flex-direction: column;
+ padding: 5px 15px;
+ border: 1px solid #f0f0f0;
+ border-radius: 4px;
+
+ .containerTwoTitle {
+ margin-top: 5px;
+ margin-bottom: 15px;
+
+ .titleLeft {
+ 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;
+ }
+ }
+ }
+
+ .containerTwoActions {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 15px;
+ padding: 0px 20px;
+
+ .searchSection {
+ flex: 1;
+ max-width: 300px;
+
+ :global(.ant-input) {
+ height: 32px;
+ border-radius: 4px 0px 0px 4px;
+ border: 1px solid #d9d9d9;
+
+ &:focus {
+ border-color: #2E4CD4;
+ box-shadow: 0 0 0 2px rgba(46, 76, 212, 0.2);
+ }
+ }
+ }
+
+ .buttonSection {
+ display: flex;
+ gap: 8px;
+
+ :global(.ant-btn) {
+ height: 28px;
+ padding: 0 16px;
+ border-radius: 4px;
+ font-size: 14px;
+ border: 1px solid #d9d9d9;
+ background-color: #fff;
+ color: #333;
+
+ &:hover {
+ border-color: #2E4CD4;
+ color: #2E4CD4;
+ }
+
+ &:focus {
+ border-color: #2E4CD4;
+ color: #2E4CD4;
+ }
+ }
+
+ .addBtn {
+ 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;
+
+ &:hover {
+ background-color: #F0F2FF;
+ border-color: #2E4CD4;
+ }
+
+ .addIcon {
+ width: 12px;
+ height: 12px;
+ font-size: 12px;
+ }
+ }
+
+ .importBtn {
+ 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;
+
+ &:hover {
+ background-color: #F0F2FF;
+ border-color: #2E4CD4;
+ }
+
+ .importIcon {
+ width: 12px;
+ height: 12px;
+ }
+ }
+
+ .exportBtn {
+ 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;
+
+ &:hover {
+ background-color: #F0F2FF;
+ border-color: #2E4CD4;
+ }
+
+ .exportIcon {
+ width: 12px;
+ height: 12px;
+ }
+ }
+ }
+ }
+
+ .containerTwoTable {
+ flex: 1;
+ overflow: hidden;
+ padding: 0px 20px;
+
+ :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;
+ }
+
+ :global(.ant-table-tbody > tr > td) {
+ padding: 8px 12px;
+ border-bottom: 1px solid #f0f0f0;
+ text-align: center;
+ color: #666666;
+ // color: pink;
+ }
+
+ :global(.ant-table-tbody > tr:hover > td) {
+ // background-color: #f5f5f5;
+ }
+
+ :global(.ant-pagination) {
+ margin-top: 16px;
+ text-align: right;
+ }
+ }
+ }
+}
+
+
+.rightTopSelect {
+
+ // 下拉框本身的样式
+ :global(.ant-select-selector) {
+ background-color: #f8f9fa !important;
+ border: 1px solid #d9d9d9 !important;
+ border-radius: 6px !important;
+ height: 32px !important;
+ min-height: 32px !important;
+
+ &:hover {
+ border-color: #2E4CD4 !important;
+ }
+
+ &:focus {
+ border-color: #2E4CD4 !important;
+ box-shadow: 0 0 0 2px rgba(46, 76, 212, 0.2) !important;
+ }
+ }
+
+ // 下拉框内的文字样式
+ :global(.ant-select-selection-item) {
+ color: #333333 !important;
+ font-size: 14px !important;
+ font-weight: 500 !important;
+ line-height: 30px !important;
+ }
+
+ // 下拉箭头样式
+ :global(.ant-select-arrow) {
+ color: #666666 !important;
+ font-size: 12px !important;
+ }
+
+ // 下拉菜单容器样式
+ :global(.ant-select-dropdown) {
+ background-color: #ffffff !important;
+ border: 1px solid #e8e8e8 !important;
+ border-radius: 8px !important;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
+ padding: 4px 0 !important;
+ }
+
+ // 下拉选项样式
+ :global(.ant-select-item) {
+ color: #333333 !important;
+ font-size: 14px !important;
+ padding: 8px 12px !important;
+ border-radius: 4px !important;
+ margin: 2px 8px !important;
+
+ &:hover {
+ background-color: #f0f2ff !important;
+ color: #2E4CD4 !important;
+ }
+
+ &.ant-select-item-option-selected {
+ background-color: #e6f7ff !important;
+ color: #2E4CD4 !important;
+ font-weight: 600 !important;
+ }
+ }
+
+ // 选中状态的样式
+ :global(.ant-select-focused .ant-select-selector) {
+ border-color: #2E4CD4 !important;
+ box-shadow: 0 0 0 2px rgba(46, 76, 212, 0.2) !important;
+ }
+}
+
+// 自定义选项样式
+.customOption {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 4px 0;
+
+ .optionIcon {
+ font-size: 16px;
+ color: #2E4CD4;
+ }
+
+ .optionText {
+ font-size: 14px;
+ color: #333333;
+ font-weight: 500;
+ }
+}
+
diff --git a/src/pages/business_data/components/RiskAssessment.js b/src/pages/business_data/components/RiskAssessment.js
new file mode 100644
index 0000000..46d5b50
--- /dev/null
+++ b/src/pages/business_data/components/RiskAssessment.js
@@ -0,0 +1,865 @@
+
+import React, { useEffect, useRef, useState } from 'react';
+import { Card, Result, Select, Button, Segmented } from 'antd';
+import { CheckCircleOutlined, ExportOutlined } from '@ant-design/icons';
+import * as echarts from 'echarts';
+import StandardTable from '@/components/StandardTable';
+import styles from './RiskAssessment.less';
+// import './RiskAssessment.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 RiskAssessment = () => {
+ 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: 5,
+ total: 0,
+ });
+
+ // 饼图初始化
+ useEffect(() => {
+ if (pieChartRef.current) {
+ const pieChart = echarts.init(pieChartRef.current);
+
+ const pieOption = {
+ color: ['#44BB5F', '#F8C541', '#A493FB', '#4B69F1', '#949FD0'],
+ legend: {
+ orient: 'vertical',
+ right: '10%',
+ top: 'center',
+ itemWidth: 8,
+ itemHeight: 8,
+ textStyle: {
+ fontSize: 12,
+ color: '#333'
+ }
+ },
+ series: [{
+ name: '设备状态',
+ type: 'pie',
+ radius: ['40%', '70%'],
+ center: ['35%', '50%'],
+ avoidLabelOverlap: false,
+ label: {
+ show: false,
+ position: 'center'
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: '14',
+ fontWeight: 'bold'
+ }
+ },
+ labelLine: {
+ show: false
+ },
+ data: [
+ { value: 480, name: '正常' },
+ { value: 289, name: '故障' },
+ { value: 200, name: '维修中' },
+ { value: 150, name: '待验收' },
+ { value: 161, name: '停用' }
+ ]
+ }]
+ };
+
+ pieChart.setOption(pieOption);
+
+ // 响应式调整
+ const handlePieResize = () => {
+ if (pieChart && !pieChart.isDisposed()) {
+ pieChart.resize();
+ }
+ };
+
+ window.addEventListener('resize', handlePieResize);
+
+ return () => {
+ window.removeEventListener('resize', handlePieResize);
+ if (pieChart && !pieChart.isDisposed()) {
+ pieChart.dispose();
+ }
+ };
+ }
+ }, []);
+
+ // 故障类型饼图初始化
+ useEffect(() => {
+ if (faultPieChartRef.current) {
+ const faultPieChart = echarts.init(faultPieChartRef.current);
+
+ const faultPieOption = {
+ color: ['#FF3E48', '#FF8800', '#FFC403'],
+ legend: {
+ orient: 'vertical',
+ right: '10%',
+ top: 'center',
+ itemWidth: 8,
+ itemHeight: 8,
+ textStyle: {
+ fontSize: 12,
+ color: '#333'
+ }
+ },
+ series: [{
+ name: '设备故障类型',
+ type: 'pie',
+ radius: '70%',
+ center: ['35%', '50%'],
+ avoidLabelOverlap: false,
+ label: {
+ show: true,
+ position: 'outside',
+ formatter: '{b}: {c}',
+ fontSize: 12
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: '14',
+ fontWeight: 'bold'
+ }
+ },
+ labelLine: {
+ show: true
+ },
+ data: [
+ { value: 120, name: '紧急' },
+ { value: 80, name: '重要' },
+ { value: 60, name: '一般' }
+ ]
+ }]
+ };
+
+ faultPieChart.setOption(faultPieOption);
+
+ // 响应式调整
+ const handleFaultPieResize = () => {
+ if (faultPieChart && !faultPieChart.isDisposed()) {
+ faultPieChart.resize();
+ }
+ };
+
+ window.addEventListener('resize', handleFaultPieResize);
+
+ return () => {
+ window.removeEventListener('resize', handleFaultPieResize);
+ if (faultPieChart && !faultPieChart.isDisposed()) {
+ faultPieChart.dispose();
+ }
+ };
+ }
+ }, []);
+
+ useEffect(() => {
+ if (chartRef.current) {
+ const chart = echarts.init(chartRef.current);
+
+ // 强制初始化时调整大小
+ setTimeout(() => {
+ if (chart && !chart.isDisposed()) {
+ chart.resize();
+ }
+ }, 100);
+
+ const option = {
+ color: ['#8979FF', '#3CC3DF'],
+
+ legend: {
+ // data: ['消防水泵1', '消防水泵2'],
+ top: "-3px",
+ // left: "center",
+ // itemGap: 40,
+ itemWidth: 20,
+ itemHeight: 8,
+ // icon: 'path://M902 472.7H747.9c-19.1-113.3-117.7-200-236.4-200s-217.3 86.7-236.4 200H119.7c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h155.5c19.1 113.3 117.7 200 236.4 200S728.9 666 748 552.7h154c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8z m-390.5 200c-88.2 0-160-71.8-160-160s71.8-160 160-160 160 71.8 160 160-71.8 160-160 160z',
+ textStyle: {
+ fontSize: 10
+ }
+ },
+ grid: {
+ left: '2%',
+ right: '4%',
+ bottom: '2%',
+ top: '12%',
+ containLabel: true
+ },
+ xAxis: {
+ type: 'category',
+ boundaryGap: false,
+ data: ['9:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00'],
+ axisLabel: {
+ fontSize: 10
+ }
+ },
+ yAxis: {
+ type: 'value',
+ min: 0,
+ max: 30,
+ axisLabel: {
+ formatter: '{value}',
+ fontSize: 10
+ }
+ },
+ series: [
+ {
+ name: '消防水泵1',
+ type: 'line',
+ smooth: false,
+ lineStyle: {
+ width: 2,
+ color: '#8979FF'
+ },
+ areaStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ { offset: 0, color: 'rgba(137, 121, 255, 0.3)' },
+ { offset: 1, color: 'rgba(137, 121, 255, 0.05)' }
+ ]
+ }
+ },
+ symbol: 'circle',
+ symbolSize: 4,
+ itemStyle: {
+ color: '#fff',
+ borderColor: '#8979FF',
+ borderWidth: 1
+ },
+ data: [12, 15, 18, 14, 16, 20, 22, 19, 17, 21, 23, 25]
+ },
+ {
+ name: '消防水泵2',
+ type: 'line',
+ smooth: false,
+ lineStyle: {
+ width: 2,
+ color: '#3CC3DF'
+ },
+ areaStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ { offset: 0, color: 'rgba(60, 195, 223, 0.3)' },
+ { offset: 1, color: 'rgba(60, 195, 223, 0.05)' }
+ ]
+ }
+ },
+ symbol: 'circle',
+ symbolSize: 4,
+ itemStyle: {
+ color: '#fff',
+ borderColor: '#3CC3DF',
+ borderWidth: 1
+ },
+ data: [8, 11, 14, 10, 13, 17, 19, 16, 14, 18, 20, 22]
+ }
+ ]
+ };
+
+ chart.setOption(option);
+
+ // 响应式调整 - 使用多种方式监听容器尺寸变化
+ let resizeTimer = null;
+ const handleResize = () => {
+ // 防抖处理,避免频繁调用resize
+ if (resizeTimer) {
+ clearTimeout(resizeTimer);
+ }
+ resizeTimer = setTimeout(() => {
+ if (chart && !chart.isDisposed()) {
+ chart.resize();
+ }
+ }, 50); // 减少延迟时间
+ };
+
+ // 监听窗口大小变化
+ window.addEventListener('resize', handleResize);
+
+ // 监听容器尺寸变化(解决菜单栏伸缩时的自适应问题)
+ let resizeObserver = null;
+ if (window.ResizeObserver) {
+ resizeObserver = new ResizeObserver((entries) => {
+ for (let entry of entries) {
+ // 使用requestAnimationFrame确保在下一帧执行
+ requestAnimationFrame(() => {
+ handleResize();
+ });
+ }
+ });
+ resizeObserver.observe(chartRef.current);
+ }
+
+ // 额外监听父容器的尺寸变化
+ const parentContainer = chartRef.current?.parentElement;
+ let parentObserver = null;
+ if (parentContainer && window.ResizeObserver) {
+ parentObserver = new ResizeObserver((entries) => {
+ for (let entry of entries) {
+ requestAnimationFrame(() => {
+ handleResize();
+ });
+ }
+ });
+ parentObserver.observe(parentContainer);
+ }
+
+ // 使用MutationObserver监听DOM结构变化(菜单展开收起时)
+ const mutationObserver = new MutationObserver((mutations) => {
+ mutations.forEach((mutation) => {
+ if (mutation.type === 'attributes' &&
+ (mutation.attributeName === 'class' || mutation.attributeName === 'style')) {
+ // 延迟执行,确保DOM更新完成
+ setTimeout(() => {
+ handleResize();
+ }, 200);
+ }
+ });
+ });
+
+ // 监听整个页面的class和style变化
+ mutationObserver.observe(document.body, {
+ attributes: true,
+ attributeFilter: ['class', 'style'],
+ subtree: true
+ });
+
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ if (resizeObserver) {
+ resizeObserver.disconnect();
+ }
+ if (parentObserver) {
+ parentObserver.disconnect();
+ }
+ if (mutationObserver) {
+ mutationObserver.disconnect();
+ }
+ if (resizeTimer) {
+ clearTimeout(resizeTimer);
+ }
+ if (chart && !chart.isDisposed()) {
+ chart.dispose();
+ }
+ };
+ }
+ }, []);
+
+ // 表格列定义
+ const columns = [
+ {
+ title: '编号',
+ dataIndex: 'id',
+ key: 'id',
+ width: 60,
+ 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: 'deviceId',
+ key: 'deviceId',
+ width: 140,
+ },
+ {
+ title: '设备名称',
+ dataIndex: 'deviceName',
+ key: 'deviceName',
+ width: 110,
+ },
+ {
+ title: '型号规格',
+ dataIndex: 'modelSpec',
+ key: 'modelSpec',
+ width: 140,
+ },
+ {
+ title: '安装位置',
+ dataIndex: 'installLocation',
+ key: 'installLocation',
+ width: 200,
+ },
+ {
+ title: '状态',
+ dataIndex: 'status',
+ key: 'status',
+ width: 80,
+ render: (text) => {
+ const statusMap = {
+ '故障': { color: '#FF4D4F', bg: '#FFF2F0' },
+ '预警': { color: '#FAAD14', bg: '#FFF3E9' },
+ '正常': { 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: 'XBD5.0/30-125',
+ installLocation: '总部大楼1层大厅',
+ status: '故障',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '2',
+ id: '002',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼3层 东区',
+ status: '预警',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '3',
+ id: '003',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '正常',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '4',
+ id: '004',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '故障',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '5',
+ id: '005',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '正常',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '6',
+ id: '006',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '预警',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '7',
+ id: '007',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '故障',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '8',
+ id: '008',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '正常',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '9',
+ id: '009',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '预警',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '10',
+ id: '010',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '故障',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '11',
+ id: '011',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '正常',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '12',
+ id: '012',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '预警',
+ lastMaintenance: '2025-09-10',
+ },
+ ];
+
+ // 初始化数据
+ 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,
+ }));
+ };
+
+ return (
+
+ {/* 第一个div - 高度20% */}
+
+
+
+ {/* 块1 */}
+
+
+
+

+
+
+
+ {/* 块2 */}
+
+
+
+

+
+
+
+ {/* 块3 */}
+
+
+
+

+
+
+
+ {/* 块4 */}
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
{
+ console.log(value);
+ }}
+ />
+
+ {/* 设备状态饼图 */}
+
+
+
+
+
+
+
+
+ {/* 设备故障类型饼图 */}
+
+
+
+
+
+
+
+
+
+
+ {/* 第三个div - 占满剩余位置 */}
+
+
+
+ {/* 第一行块 - 蓝色方块加标题 */}
+
+
+
+
+
+
灭火器压力不足
+
2号楼3层 丨 15分钟前
+
+
+
+
+
+
烟雾探测器电池低电量
+
1号楼5层 丨 1小时前
+
+
+
+
+
+
消防栓维护到期
+
3号楼1层 丨 2小时前
+
+
+
+
+
+
应急照明故障
+
地下停车场 丨 3小时前
+
+
+
+
+
+
+
+ {/* 表格 */}
+
+
+
+
+
+
+
+
+
+ {/* 表格 */}
+
+
+ `共 ${total} 条`,
+ }}
+ // scroll={{ x: 1200 }}
+ />
+
+
+
+
+
+ );
+};
+
+export default RiskAssessment;
\ No newline at end of file
diff --git a/src/pages/business_data/components/RiskAssessment.less b/src/pages/business_data/components/RiskAssessment.less
new file mode 100644
index 0000000..db5b47e
--- /dev/null
+++ b/src/pages/business_data/components/RiskAssessment.less
@@ -0,0 +1,594 @@
+.Rcontainer {
+ padding: 8px 6px 0px 6px;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+
+ // 第一个div - 高度20%
+ .RcontainerTop {
+ height: 16%;
+ // background-color: #fff;
+ border-radius: 4px;
+ display: flex;
+ flex-direction: column;
+
+ .sectionContent {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ // padding: 15px;
+
+ .blocksContainer {
+ flex: 1;
+ display: flex;
+ gap: 10px;
+ height: 100%;
+
+ .blockItem {
+ flex: 1;
+ height: 100%;
+ display: flex;
+ background: linear-gradient(170.5deg, #F5F7FF 6.87%, #FFFFFF 47.65%);
+ border-radius: 4px;
+ border: 2px solid #FFFFFF;
+
+ .blockLeft {
+ width: 60%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ padding: 15px;
+ padding-left: 20px;
+ gap: 8px;
+
+ .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;
+ }
+
+ .checkIcon {
+ font-size: 16px;
+ color: #1269FF;
+ }
+ }
+ }
+
+ .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;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // 第二个div - 高度39%
+ .RcontainerMiddle {
+ height: 33%;
+ border-radius: 4px;
+ display: flex;
+ flex-direction: column;
+
+ .sectionContent {
+ height: 100%;
+ display: flex;
+ display: flex;
+ gap: 10px;
+ height: 100%;
+
+
+
+ .middleBlock1 {
+ // flex: 1;
+ width: 28%;
+ height: 100%;
+ background: #fff;
+
+ border: 2px solid #fff;
+ // border-radius: 4px;
+ position: relative;
+ padding: 0px 10px 10px 2px;
+ font-family: PingFang SC;
+ font-size: 14px;
+ color: #333333;
+
+ .block1Header {
+ position: absolute;
+ top: 5px;
+ left: 10px;
+ right: 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ z-index: 10;
+
+ .block1Title {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-weight: 500;
+ font-size: 14px;
+ color: #333333;
+
+ .titleIcon {
+ width: 3px;
+ height: 14px;
+ background-color: #2E4CD4;
+ }
+ }
+
+ .block1Segmented {
+ padding: 0;
+ margin: 0;
+ border: 1px solid #E3E3E3;
+ border-radius: 4px;
+ height: 28px;
+
+ :global(.ant-segmented) {
+ padding: 0;
+ margin: 0;
+ height: 28px;
+ }
+
+ :global(.ant-segmented-item) {
+ font-size: 12px;
+ padding: 2px 8px;
+ height: 26px;
+ line-height: 26px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ :global(.ant-segmented-item-selected) {
+ background-color: #1890ff;
+ color: #fff;
+ }
+ }
+ }
+
+ .deviceStatusChart {
+ position: absolute;
+ top: 35px;
+ left: 10px;
+ right: 10px;
+ bottom: 10px;
+ z-index: 10;
+ }
+
+ // .block1Chart {
+ // width: 100%;
+ // height: 100%;
+ // margin-top: 20px;
+
+ // .mapImage {
+ // margin-top: 7%;
+ // width: 90%;
+ // height: 77%;
+ // object-fit: cover;
+ // border-radius: 4px;
+ // display: block;
+ // margin-left: auto;
+ // margin-right: auto;
+ // }
+ // }
+ }
+
+ .middleBlock12 {
+ flex: 1;
+ height: 100%;
+ background-color: #fff;
+ display: flex;
+ flex-direction: column;
+ font-family: PingFang SC;
+ font-size: 14px;
+ color: #333333;
+ padding: 5px 10px 5px 10px;
+ position: relative;
+
+ .block1Header {
+ position: absolute;
+ top: 5px;
+ left: 10px;
+ right: 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ z-index: 10;
+
+ .block1Title {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-weight: 500;
+ font-size: 14px;
+ color: #333333;
+
+ .titleIcon {
+ width: 3px;
+ height: 14px;
+ background-color: #2E4CD4;
+ }
+ }
+
+ .block1Segmented {
+ padding: 0;
+ margin: 0;
+ border: 1px solid #E3E3E3;
+ border-radius: 4px;
+ height: 28px;
+
+ :global(.ant-segmented) {
+ padding: 0;
+ margin: 0;
+ height: 28px;
+ }
+
+ :global(.ant-segmented-item) {
+ font-size: 12px;
+ padding: 2px 8px;
+ height: 26px;
+ line-height: 26px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ :global(.ant-segmented-item-selected) {
+ background-color: #1890ff;
+ color: #fff;
+ }
+ }
+
+ .customSelect {
+ :global(.ant-select-single:not(.ant-select-customize-input) .ant-select-selector) {
+ height: 26px !important;
+ display: flex !important;
+ align-items: center !important;
+ }
+
+ :global(.ant-select-selection-item) {
+ line-height: 24px !important;
+ // height: 24px !important;
+ display: flex !important;
+ align-items: center !important;
+ }
+ }
+ }
+
+ .deviceStatusChart {
+ position: absolute;
+ top: 35px;
+ left: 10px;
+ right: 10px;
+ bottom: 10px;
+ z-index: 10;
+ }
+ }
+
+ .middleBlock2 {
+ flex: 1;
+ height: 100%;
+ // background: linear-gradient(170.5deg, #EBEFF4 6.87%, #FFFFFF 53.01%);
+ // border: 2px solid #fff;
+ background-color: #fff;
+ // border-radius: 4px;
+ display: flex;
+ flex-direction: column;
+ font-family: PingFang SC;
+ font-size: 14px;
+ color: #333333;
+ padding: 5px 10px 5px 10px;
+
+ .middleBlock2Title {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ // margin-bottom: 10px;
+
+ .titleLeft {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-weight: 500;
+ font-size: 14px;
+ color: #333333;
+
+ .titleIcon {
+ width: 3px;
+ height: 14px;
+ background-color: #2E4CD4;
+ }
+ }
+
+ .titleRight {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 12px;
+ color: #666;
+ }
+ }
+
+ .middleBlock2Chart {
+ width: 100%;
+ height: 100%;
+ // min-height: 200px;
+ }
+ }
+
+ }
+ }
+
+ // 第三个div - 高度不超过45%
+ .RcontainerBottom {
+ height: 45%; // 限制高度不超过45%
+ max-height: 45%; // 确保最大高度不超过45%
+ display: flex;
+ flex-direction: column;
+
+ .sectionContent {
+ display: flex;
+ flex-direction: row;
+ gap: 10px;
+ padding: 0;
+
+ .leftBlock {
+ width: 28%;
+ flex-shrink: 0;
+ height: 100%;
+ background: #fff;
+ // background-size: cover;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ padding: 15px;
+
+ .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;
+ }
+ }
+
+ .developmentContainer {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .developmentBlock1 {
+ flex: 1;
+ background-color: #F1F7FF;
+ border-radius: 4px;
+ padding: 15px 20px;
+ display: flex;
+ align-items: center;
+ width: 100%;
+
+ .leftContent {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ min-width: 0;
+
+ .mainText {
+ color: #333333;
+ font-size: 14px;
+ font-weight: 500;
+ font-family: PingFang SC;
+ width: 100%;
+ max-width: 500px;
+ }
+
+ .subText {
+ color: #666666;
+ font-size: 12px;
+ font-weight: 400;
+ font-family: PingFang SC;
+ width: 100%;
+ max-width: 400px;
+ }
+ }
+
+ .rightContent {
+ flex: 0 0 auto;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ padding-right: 10px;
+ min-width: 80px;
+
+ .importantTag {
+ background-color: #FFE0E2;
+ color: #FF3E48;
+ font-size: 14px;
+ font-weight: 500;
+ font-family: PingFang SC;
+ width: 45px;
+ height: 25px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+ }
+
+ .normalTag {
+ background-color: #DAF3FF;
+ color: #00AAFA;
+ font-size: 14px;
+ font-weight: 500;
+ font-family: PingFang SC;
+ width: 45px;
+ height: 25px;
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+ }
+ }
+ }
+ }
+ }
+
+ .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: 8px 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;
+ gap: 8px;
+ margin-top: 5px;
+
+ .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;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/pages/business_data/components/bmzstx.js b/src/pages/business_data/components/bmzstx.js
new file mode 100644
index 0000000..818a4a4
--- /dev/null
+++ b/src/pages/business_data/components/bmzstx.js
@@ -0,0 +1,265 @@
+import React, { useMemo, useState } from 'react';
+import { Button, message, Popconfirm, Select, Space, Table } from 'antd';
+import { DeleteOutlined, DownloadOutlined, EditOutlined, FileTextOutlined, PlusOutlined, UploadOutlined } from '@ant-design/icons';
+import styles from './jgfx.less';
+
+const Bmzstx = () => {
+ const [filterA, setFilterA] = useState(undefined);
+ const [filterB, setFilterB] = useState(undefined);
+ const [selectedRowKeys, setSelectedRowKeys] = useState([]);
+ const [pagination, setPagination] = useState({ current: 1, pageSize: 10 });
+
+ const selectOptionsA = useMemo(
+ () => [
+ { label: '千瓦时(kWh)', value: '千瓦时(kWh)' },
+ { label: '立方米(m³)', value: '立方米(m³)' },
+ { label: '吨(t)', value: '吨(t)' },
+ { label: '千克(kg)', value: '千克(kg)' },
+ ],
+ [],
+ );
+
+ const selectOptionsB = useMemo(
+ () => [
+ { label: '电能', value: '电能' },
+ { label: '燃气', value: '燃气' },
+ { label: '水', value: '水' },
+ { label: '汽油', value: '汽油' },
+ ],
+ [],
+ );
+
+ const rows = useMemo(
+ () => [
+ {
+ id: 1,
+ energyType: '电能',
+ unit: '千瓦时(kWh)',
+ unitPrice: 0.5,
+ priceUnit: 'kgce/kwh',
+ scope: '国标(2024 GB-282287)',
+ pricingUnit: '—',
+ latestUpdateTime: '2025-12-02 03:56:02',
+ },
+ {
+ id: 2,
+ energyType: '燃气',
+ unit: '立方米(m³)',
+ unitPrice: 2.5,
+ priceUnit: 'kgce/m³',
+ scope: '国标(2024 GB-282287)',
+ pricingUnit: '—',
+ latestUpdateTime: '2025-11-22 11:56:50',
+ },
+ {
+ id: 3,
+ energyType: '水',
+ unit: '吨(t)',
+ unitPrice: 1.2,
+ priceUnit: 'kgce/t',
+ scope: '行业标准(2024 GB-282287)',
+ pricingUnit: '—',
+ latestUpdateTime: '2025-12-04 21:12:20',
+ },
+ {
+ id: 4,
+ energyType: '汽油',
+ unit: '千克(kg)',
+ unitPrice: 1.5,
+ priceUnit: 'kgce/kg',
+ scope: '行业标准(2024 GB-282287)',
+ pricingUnit: '—',
+ latestUpdateTime: '2025-11-26 10:28:20',
+ },
+ ],
+ [],
+ );
+
+ const tableData = useMemo(() => {
+ return rows
+ .filter((r) => (filterA ? r.unit === filterA : true))
+ .filter((r) => (filterB ? r.energyType === filterB : true));
+ }, [filterA, filterB, rows]);
+
+ const pagedData = useMemo(() => {
+ const start = (pagination.current - 1) * pagination.pageSize;
+ return tableData.slice(start, start + pagination.pageSize);
+ }, [pagination.current, pagination.pageSize, tableData]);
+
+ const handleAdd = () => message.info('新增');
+ const handleUpload = () => message.info('上传');
+ const handleBatchDownload = () => message.info('批量下载');
+ const handleQuery = () => message.info('查询');
+
+ const handleEdit = (record) => message.info(`编辑:${record.energyType}`);
+ const handleView = (record) => message.info(`详情:${record.energyType}`);
+ const handleDelete = (record) => message.success(`已删除:${record.energyType}`);
+
+ const columns = useMemo(
+ () => [
+ {
+ title: '序号',
+ dataIndex: 'id',
+ key: 'id',
+ width: 70,
+ align: 'center',
+ },
+ {
+ title: '能源类型',
+ dataIndex: 'energyType',
+ key: 'energyType',
+ width: 120,
+ },
+ {
+ title: '单位',
+ dataIndex: 'unit',
+ key: 'unit',
+ width: 160,
+ },
+ {
+ title: '单价',
+ dataIndex: 'unitPrice',
+ key: 'unitPrice',
+ width: 110,
+ },
+ {
+ title: '价格单位',
+ dataIndex: 'priceUnit',
+ key: 'priceUnit',
+ width: 120,
+ },
+ {
+ title: '适用范围',
+ dataIndex: 'scope',
+ key: 'scope',
+ width: 120,
+ },
+ {
+ title: '定价单位',
+ dataIndex: 'pricingUnit',
+ key: 'pricingUnit',
+ width: 140,
+ },
+ {
+ title: '最后更新时间',
+ dataIndex: 'latestUpdateTime',
+ key: 'latestUpdateTime',
+ width: 210,
+ },
+ {
+ title: '操作',
+ key: 'action',
+ width: 140,
+ align: 'center',
+ render: (_, record) => (
+
+ }
+ onClick={() => handleEdit(record)}
+ />
+ }
+ onClick={() => handleView(record)}
+ />
+ handleDelete(record)}
+ >
+ } />
+
+
+ ),
+ },
+ ],
+ [],
+ );
+
+ return (
+
+
+
+ 说明:标准煤折算系数用于将不同能源消耗统一换算为标准煤当量,方便进行能耗对比和分析。
+
+
+
+
+ } onClick={handleAdd}>
+ 新增
+
+ } onClick={handleUpload}>
+ 上传
+
+ } onClick={handleBatchDownload}>
+ 批量下载
+
+
+
+
+
+
筛选条件
+
+
+
+
+
+
+
+
+
+
`共 ${total} 条`,
+ position: ['bottomRight'],
+ onChange: (current, pageSize) => setPagination({ current, pageSize }),
+ }}
+ rowSelection={{
+ selectedRowKeys,
+ onChange: (keys) => setSelectedRowKeys(keys),
+ columnWidth: 44,
+ }}
+ />
+
+
+ );
+};
+
+export default Bmzstx;
diff --git a/src/pages/business_data/components/bmzstx.less b/src/pages/business_data/components/bmzstx.less
new file mode 100644
index 0000000..65030ce
--- /dev/null
+++ b/src/pages/business_data/components/bmzstx.less
@@ -0,0 +1,160 @@
+.container {
+ width: 100%;
+ height: 100%;
+ min-height: 560px;
+ background: #fff;
+ border-radius: 14px;
+ padding: 14px 16px 12px;
+ overflow: hidden;
+}
+
+.toolbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 2px 0 14px;
+}
+
+.toolbarLeft {
+ display: flex;
+ align-items: center;
+}
+
+.toolbarRight {
+ display: flex;
+ align-items: center;
+}
+
+.filterLabel {
+ font-size: 12px;
+ color: #8d93a3;
+ margin-right: 10px;
+}
+
+.filterSelect {
+ width: 170px;
+
+ :global {
+ .ant-select-selector {
+ height: 32px !important;
+ border-radius: 999px !important;
+ border-color: #e7eaf2 !important;
+ display: flex !important;
+ align-items: center !important;
+ box-shadow: none !important;
+ }
+
+ .ant-select-selection-placeholder {
+ color: #b1b7c4;
+ }
+ }
+}
+
+.primaryBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ box-shadow: none !important;
+ background-color: rgba(72, 81, 255, 1);
+
+ :global {
+ .ant-btn-icon {
+ margin-right: 6px;
+ }
+ }
+}
+
+.ghostBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ border: 1px solid #e7eaf2 !important;
+ background: #fff !important;
+ color: #5b6070 !important;
+ box-shadow: none !important;
+}
+
+.queryBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ border: 1px solid #e7eaf2 !important;
+ background: #fff !important;
+ color: #5b6070 !important;
+ box-shadow: none !important;
+}
+
+.tableWrap {
+ width: 100%;
+
+ :global {
+ .ant-table {
+ border-radius: 10px;
+ }
+
+ .ant-table-thead > tr > th {
+ background: #f7f8fb;
+ color: #6d7383;
+ font-weight: 500;
+ height: 44px;
+ }
+
+ .ant-table-tbody > tr > td {
+ color: #2b2f3a;
+ height: 48px;
+ }
+
+ .ant-table-tbody > tr:hover > td {
+ background: #fafbff;
+ }
+
+ .ant-table-pagination {
+ margin: 14px 0 0;
+ }
+
+ .ant-pagination-total-text {
+ color: #8d93a3;
+ margin-right: 10px;
+ }
+
+ .ant-pagination-options {
+ margin-left: 10px;
+ }
+ }
+}
+
+.actionIconBtn {
+ padding: 0 !important;
+ height: 24px !important;
+ color: rgba(72, 81, 255, 1) !important;
+
+ :global {
+ .anticon {
+ font-size: 16px;
+ }
+ }
+}
+
+.actionIconBtnInfo {
+ padding: 0 !important;
+ height: 24px !important;
+ color: #13c2c2 !important;
+
+ :global {
+ .anticon {
+ font-size: 16px;
+ }
+ }
+}
+
+.actionIconBtnDanger {
+ padding: 0 !important;
+ height: 24px !important;
+ color: #ff4d4f !important;
+
+ :global {
+ .anticon {
+ font-size: 16px;
+ }
+ }
+}
diff --git a/src/pages/business_data/components/fgpsdsz.js b/src/pages/business_data/components/fgpsdsz.js
new file mode 100644
index 0000000..bf9240e
--- /dev/null
+++ b/src/pages/business_data/components/fgpsdsz.js
@@ -0,0 +1,290 @@
+import React, { useMemo, useState } from 'react';
+import { Button, Radio, Space, Tag } from 'antd';
+import { LeftOutlined, PlusOutlined, RightOutlined, SettingOutlined } from '@ant-design/icons';
+import styles from './fgpsdsz.less';
+import Component1 from '@/assets/basic_data/Component1.svg';
+import Component2 from '@/assets/basic_data/Component2.svg';
+import Component3 from '@/assets/basic_data/Component3.svg';
+
+const TIME_LABELS = [
+ '09:00',
+ '11:00',
+ '13:00',
+ '15:00',
+ '17:00',
+ '19:00',
+ '21:00',
+ '23:00',
+ '01:00',
+ '03:00',
+ '05:00',
+ '07:00',
+ '09:00',
+];
+
+const MONTH_LABEL = '2025年8月';
+
+const Fgpsdsz = () => {
+ const [activeEnergyKey, setActiveEnergyKey] = useState('electric');
+ const [viewMode, setViewMode] = useState('month');
+ const [periodType, setPeriodType] = useState('peak');
+
+ const energyTypes = useMemo(
+ () => [
+ { key: 'electric', label: '电能', icon: Component1 },
+ { key: 'water', label: '水', icon: Component2 },
+ { key: 'gas', label: '天然气', icon: Component3 },
+ ],
+ [],
+ );
+
+ const cards = useMemo(() => {
+ const byEnergyKey = {
+ electric: [
+ {
+ key: 'peak',
+ title: '高峰时段',
+ price: '1.58',
+ unit: '(元/度)',
+ tags: ['工作日', '周末', '节假日'],
+ periods: ['起止时刻1:09:00:00–12:00:00', '起止时刻2:09:00:00–12:00:00'],
+ },
+ {
+ key: 'flat',
+ title: '平时时段',
+ price: '0.58',
+ unit: '(元/度)',
+ tags: ['工作日', '周末', '节假日'],
+ periods: ['起止时刻1:09:00:00–12:00:00', '起止时刻2:09:00:00–12:00:00'],
+ },
+ {
+ key: 'valley',
+ title: '低谷时段',
+ price: '0.28',
+ unit: '(元/度)',
+ tags: ['工作日', '周末', '节假日'],
+ periods: ['起止时刻1:09:00:00–12:00:00', '起止时刻2:09:00:00–12:00:00'],
+ },
+ ],
+ water: [
+ {
+ key: 'peak',
+ title: '高峰时段',
+ price: '2.30',
+ unit: '(元/m³)',
+ tags: ['工作日', '周末', '节假日'],
+ periods: ['起止时刻1:09:00:00–12:00:00', '起止时刻2:09:00:00–12:00:00'],
+ },
+ {
+ key: 'flat',
+ title: '平时时段',
+ price: '1.30',
+ unit: '(元/m³)',
+ tags: ['工作日', '周末', '节假日'],
+ periods: ['起止时刻1:09:00:00–12:00:00', '起止时刻2:09:00:00–12:00:00'],
+ },
+ {
+ key: 'valley',
+ title: '低谷时段',
+ price: '0.80',
+ unit: '(元/m³)',
+ tags: ['工作日', '周末', '节假日'],
+ periods: ['起止时刻1:09:00:00–12:00:00', '起止时刻2:09:00:00–12:00:00'],
+ },
+ ],
+ gas: [
+ {
+ key: 'peak',
+ title: '高峰时段',
+ price: '3.80',
+ unit: '(元/m³)',
+ tags: ['工作日', '周末', '节假日'],
+ periods: ['起止时刻1:09:00:00–12:00:00', '起止时刻2:09:00:00–12:00:00'],
+ },
+ {
+ key: 'flat',
+ title: '平时时段',
+ price: '2.80',
+ unit: '(元/m³)',
+ tags: ['工作日', '周末', '节假日'],
+ periods: ['起止时刻1:09:00:00–12:00:00', '起止时刻2:09:00:00–12:00:00'],
+ },
+ {
+ key: 'valley',
+ title: '低谷时段',
+ price: '1.60',
+ unit: '(元/m³)',
+ tags: ['工作日', '周末', '节假日'],
+ periods: ['起止时刻1:09:00:00–12:00:00', '起止时刻2:09:00:00–12:00:00'],
+ },
+ ],
+ };
+
+ return byEnergyKey[activeEnergyKey] ?? byEnergyKey.electric;
+ }, [activeEnergyKey]);
+
+ const scheduleRows = useMemo(
+ () => [
+ { day: 1, weekday: '一', bars: [{ start: 0, end: 2, type: 'peak' }, { start: 9, end: 13, type: 'valley' }] },
+ { day: 2, weekday: '二', bars: [{ start: 0, end: 5, type: 'peak' }, { start: 11, end: 13, type: 'valley' }] },
+ { day: 3, weekday: '三', bars: [{ start: 0, end: 4, type: 'peak' }, { start: 10, end: 13, type: 'valley' }] },
+ { day: 4, weekday: '四', bars: [{ start: 0, end: 4, type: 'peak' }, { start: 9, end: 13, type: 'valley' }] },
+ { day: 5, weekday: '五', bars: [{ start: 0, end: 4, type: 'peak' }, { start: 8, end: 13, type: 'valley' }] },
+ { day: 6, weekday: '六', bars: [{ start: 0, end: 5, type: 'peak' }, { start: 11, end: 13, type: 'valley' }] },
+ { day: 7, weekday: '日', bars: [{ start: 0, end: 4, type: 'peak' }, { start: 9, end: 13, type: 'valley' }] },
+ { day: 8, weekday: '一', bars: [{ start: 0, end: 3, type: 'peak' }, { start: 8, end: 13, type: 'valley' }] },
+ { day: 9, weekday: '二', bars: [{ start: 0, end: 5, type: 'peak' }, { start: 10, end: 13, type: 'valley' }] },
+ { day: 10, weekday: '三', bars: [{ start: 0, end: 2, type: 'peak' }, { start: 8, end: 13, type: 'valley' }] },
+ { day: 11, weekday: '四', bars: [{ start: 0, end: 2, type: 'peak' }, { start: 8, end: 13, type: 'valley' }] },
+ { day: 12, weekday: '五', bars: [{ start: 0, end: 2, type: 'peak' }, { start: 8, end: 13, type: 'valley' }] },
+ ],
+ [],
+ );
+
+ const renderBarStyle = (bar) => {
+ const left = (bar.start / TIME_LABELS.length) * 100;
+ const width = ((bar.end - bar.start) / TIME_LABELS.length) * 100;
+ return { left: `${left}%`, width: `${width}%` };
+ };
+
+ return (
+
+
+
能源类型
+
+
+ {energyTypes.map((item) => {
+ const isActive = item.key === activeEnergyKey;
+ return (
+
+ );
+ })}
+
+
}>
+ 添加分类
+
+
+
+
+
+
+ {cards.map((card) => (
+
+
+
+
+
+
+
{card.title}
+
+ {card.tags.map((tag) => (
+ {tag}
+ ))}
+
+
+
+
+
+
单价
+
{card.price}
+
{card.unit}
+
+
+
+
+ {card.periods.map((text) => (
+
+ {text}
+
+ ))}
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+ } />
+ {MONTH_LABEL}
+ } />
+
+
+
setPeriodType(e.target.value)}
+ >
+ 高峰时段
+ 平时时段
+ 低谷时段
+
+
+
+
+
+
+ setViewMode(e.target.value)}
+ >
+ 月
+ 周
+
+
+
+
+ {TIME_LABELS.map((t) => (
+
+ {t}
+
+ ))}
+
+
+
+
+ {scheduleRows.map((row) => (
+
+
{row.day}
+
{row.weekday}
+
+
+ {row.bars.map((bar, idx) => {
+ const isDimmed = periodType && bar.type !== periodType;
+ return (
+
+ );
+ })}
+
+
+ ))}
+
+
+
+
+
+ );
+};
+
+export default Fgpsdsz;
diff --git a/src/pages/business_data/components/fgpsdsz.less b/src/pages/business_data/components/fgpsdsz.less
new file mode 100644
index 0000000..3564a6a
--- /dev/null
+++ b/src/pages/business_data/components/fgpsdsz.less
@@ -0,0 +1,458 @@
+.container {
+ display: flex;
+ gap: 15px;
+ width: 100%;
+ height: 100%;
+ min-height: 560px;
+ padding: 15px 10px;
+}
+
+.leftPanel {
+ width: 200px;
+ background: #fff;
+ border-radius: 12px;
+ padding: 15px 10px;
+}
+
+.leftTitle {
+ font-size: 15px;
+ font-weight: 500;
+ color: #2b2f3a;
+ padding: 2px 10px 14px;
+}
+
+.leftList {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ padding: 0 8px;
+}
+
+.leftItemBtn {
+ width: 100%;
+ height: 40px !important;
+ padding: 0 14px !important;
+ border-radius: 999px !important;
+ border: 1px solid #e8ecf3 !important;
+ background: #fff !important;
+ box-shadow: none !important;
+ display: flex !important;
+ align-items: center !important;
+ justify-content: flex-start !important;
+ color: #a5adbb !important;
+
+ &:hover {
+ border-color: rgba(72, 81, 255, 0.35) !important;
+ color: rgba(72, 81, 255, 1) !important;
+ }
+}
+
+.leftItemActive {
+ background: rgba(72, 81, 255, 1) !important;
+ border-color: rgba(72, 81, 255, 1) !important;
+ color: #fff !important;
+ box-shadow: 0 10px 20px rgba(72, 81, 255, 0.18) !important;
+
+ &:hover {
+ color: #fff !important;
+ }
+
+ .leftIconCircle {
+ background: rgba(255, 255, 255, 0.26);
+ color: #fff;
+ }
+}
+
+.leftIconCircle {
+ width: 18px;
+ height: 18px;
+ border-radius: 999px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(72, 81, 255, 0.12);
+ color: rgba(72, 81, 255, 1);
+ flex: none;
+
+ :global {
+ .anticon {
+ font-size: 12px;
+ line-height: 1;
+ }
+ }
+}
+
+.leftIconImg {
+ width: 18px;
+ height: 18px;
+ display: block;
+ object-fit: contain;
+}
+
+.leftItemText {
+ margin-left: 10px;
+ font-size: 14px;
+ font-weight: 500;
+}
+
+.leftAddBtn {
+ width: 100%;
+ height: 40px !important;
+ border-radius: 999px !important;
+ border: none !important;
+ background: #f2f4f8 !important;
+ color: #b7bdc9 !important;
+ display: flex !important;
+ align-items: center !important;
+ justify-content: center !important;
+ box-shadow: none !important;
+}
+
+.rightPanel {
+ flex: 1;
+ background: #fff;
+ border-radius: 12px;
+ padding: 14px 16px 12px;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ gap: 14px;
+}
+
+.cardsRow {
+ display: flex;
+ gap: 16px;
+}
+
+.priceCard {
+ flex: 1;
+ min-height: 118px;
+ padding: 14px 16px 12px;
+ border-radius: 14px;
+ color: #fff;
+ position: relative;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+}
+
+.priceCard_peak {
+ background: linear-gradient(135deg, #ff5e57 0%, #ffb1ae 100%);
+}
+
+.priceCard_flat {
+ background: linear-gradient(135deg, #ff9c3c 0%, #ffd8a8 100%);
+}
+
+.priceCard_valley {
+ background: linear-gradient(135deg, #4cc9ff 0%, #a7e9ff 100%);
+}
+
+.priceCardCorner {
+ position: absolute;
+ top: 12px;
+ right: 12px;
+ width: 26px;
+ height: 26px;
+ border-radius: 999px;
+ background: rgba(255, 255, 255, 0.35);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #fff;
+
+ :global {
+ .anticon {
+ font-size: 14px;
+ }
+ }
+}
+
+.priceCardTop {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 12px;
+}
+
+.priceCardTitle {
+ font-size: 16px;
+ font-weight: 600;
+ line-height: 1;
+ padding-top: 2px;
+}
+
+.priceCardTags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ margin-right: 28px;
+
+ :global {
+ .ant-tag {
+ margin: 0;
+ // margin-right: 30px;
+ border: none;
+ border-radius: 999px;
+ background: rgba(255, 255, 255, 0.26);
+ color: #fff;
+ font-size: 12px;
+ padding: 0 10px;
+ height: 22px;
+ line-height: 22px;
+ }
+ }
+}
+
+.priceCardBody {
+ display: flex;
+ align-items: flex-end;
+ justify-content: space-between;
+ gap: 12px;
+ margin-top: 8px;
+}
+
+.priceLeft {
+ min-width: 96px;
+}
+
+.priceLabel {
+ font-size: 12px;
+ opacity: 0.92;
+}
+
+.priceValue {
+ font-size: 36px;
+ font-weight: 700;
+ line-height: 1.05;
+ margin-top: 6px;
+}
+
+.priceUnit {
+ font-size: 12px;
+ opacity: 0.92;
+ margin-top: 4px;
+}
+
+.priceRight {
+ flex: 1;
+ display: flex;
+ justify-content: flex-end;
+}
+
+.pricePeriodBox {
+ width: 220px;
+ padding: 10px 12px;
+ border-radius: 12px;
+ background: rgba(255, 255, 255, 0.22);
+ backdrop-filter: blur(6px);
+}
+
+.pricePeriodLine {
+ font-size: 12px;
+ line-height: 18px;
+ opacity: 0.96;
+}
+
+.scheduleSection {
+ flex: 1;
+ background: #f7f9ff;
+ border-radius: 12px;
+ padding: 12px;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
+.scheduleTopBar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ padding: 0 4px 10px;
+}
+
+.scheduleTopLeft {
+ width: 88px;
+ flex: none;
+}
+
+.monthSwitcher {
+ flex: 1;
+ justify-content: center;
+ color: #3757ff;
+
+ :global {
+ .ant-btn {
+ padding: 0 6px;
+ }
+ }
+}
+
+.monthText {
+ font-size: 14px;
+ font-weight: 600;
+}
+
+.periodRadios {
+ :global {
+ .ant-radio-wrapper {
+ color: #6b7280;
+ font-size: 12px;
+ margin-inline-end: 10px;
+ }
+
+ .ant-radio-wrapper-checked {
+ color: #3757ff;
+ }
+ }
+}
+
+.scheduleGrid {
+ background: #fff;
+ border-radius: 12px;
+ padding: 10px 10px 12px;
+ overflow: auto;
+ min-height: 360px;
+}
+
+.scheduleHeaderRow {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 0 0 10px;
+}
+
+.scheduleHeaderLeft {
+ width: 88px;
+ flex: none;
+ display: flex;
+ align-items: center;
+
+ :global {
+ .ant-radio-group {
+ background: #eef3ff;
+ border-radius: 999px;
+ padding: 2px;
+ }
+
+ .ant-radio-button-wrapper {
+ border: none;
+ height: 24px;
+ line-height: 22px;
+ border-radius: 999px !important;
+ padding: 0 12px;
+ font-size: 12px;
+ color: #6b7280;
+ background: transparent;
+ box-shadow: none;
+ }
+
+ .ant-radio-button-wrapper-checked {
+ background: #3a66ff;
+ color: #fff;
+ box-shadow: none;
+ }
+ }
+}
+
+.timeHeader {
+ flex: 1;
+ min-width: 780px;
+ display: flex;
+ align-items: center;
+ height: 24px;
+ border-radius: 999px;
+ background: #f7f9ff;
+ position: relative;
+ overflow: hidden;
+
+ &::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-image: linear-gradient(to right, rgba(232, 236, 243, 0.9) 1px, transparent 1px);
+ background-size: calc(100% / 13) 100%;
+ pointer-events: none;
+ }
+}
+
+.timeHeaderCell {
+ flex: 1;
+ text-align: center;
+ font-size: 12px;
+ color: #6b7280;
+ position: relative;
+ z-index: 1;
+}
+
+.scheduleBody {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ padding-top: 6px;
+}
+
+.scheduleRow {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.dayCell {
+ width: 44px;
+ text-align: center;
+ color: #2b2f3a;
+ font-size: 13px;
+}
+
+.weekCell {
+ width: 44px;
+ text-align: center;
+ color: #8d93a3;
+ font-size: 12px;
+}
+
+.timeArea {
+ flex: 1;
+ min-width: 780px;
+ height: 28px;
+ border-radius: 12px;
+ background: #f7f9ff;
+ position: relative;
+ overflow: hidden;
+
+ &::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-image: linear-gradient(to right, rgba(232, 236, 243, 0.9) 1px, transparent 1px);
+ background-size: calc(100% / 13) 100%;
+ pointer-events: none;
+ }
+}
+
+.timeBar {
+ position: absolute;
+ top: 5px;
+ height: 18px;
+ border-radius: 999px;
+ z-index: 1;
+}
+
+.timeBar_peak {
+ background: rgba(255, 111, 111, 0.92);
+}
+
+.timeBar_flat {
+ background: rgba(255, 177, 61, 0.92);
+}
+
+.timeBar_valley {
+ background: rgba(120, 205, 255, 0.92);
+}
+
+.timeBarDim {
+ opacity: 0.25;
+}
diff --git a/src/pages/business_data/components/jgfx.js b/src/pages/business_data/components/jgfx.js
new file mode 100644
index 0000000..ca0f4a9
--- /dev/null
+++ b/src/pages/business_data/components/jgfx.js
@@ -0,0 +1,253 @@
+import React, { useMemo, useState } from 'react';
+import { Button, message, Popconfirm, Select, Space, Table } from 'antd';
+import { DeleteOutlined, DownloadOutlined, EditOutlined, FileTextOutlined, PlusOutlined, UploadOutlined } from '@ant-design/icons';
+import styles from './jgfx.less';
+
+const Jgfx = () => {
+ const [filterA, setFilterA] = useState(undefined);
+ const [filterB, setFilterB] = useState(undefined);
+ const [selectedRowKeys, setSelectedRowKeys] = useState([]);
+ const [pagination, setPagination] = useState({ current: 1, pageSize: 10 });
+
+ const selectOptionsA = useMemo(
+ () => [
+ { label: '千瓦时(kWh)', value: '千瓦时(kWh)' },
+ { label: '立方米(m³)', value: '立方米(m³)' },
+ { label: '吨(t)', value: '吨(t)' },
+ { label: 'kWh', value: 'kWh' },
+ ],
+ [],
+ );
+
+ const selectOptionsB = useMemo(
+ () => [
+ { label: '电能', value: '电能' },
+ { label: '燃气', value: '燃气' },
+ { label: '水', value: '水' },
+ { label: '汽油', value: '汽油' },
+ ],
+ [],
+ );
+
+ const rows = useMemo(
+ () => [
+ {
+ id: 1,
+ energyType: '电能',
+ unit: '千瓦时(kWh)',
+ unitPrice: 0.5,
+ priceUnit: '元',
+ scope: 'xxxx',
+ pricingUnit: 'xxxxxx',
+ latestUpdateTime: '2025-12-02 03:56:02',
+ },
+ {
+ id: 2,
+ energyType: '燃气',
+ unit: '立方米(m³)',
+ unitPrice: 2.5,
+ priceUnit: '元',
+ scope: 'xxxx',
+ pricingUnit: 'xxxxxx',
+ latestUpdateTime: '2025-11-22 11:56:50',
+ },
+ {
+ id: 3,
+ energyType: '水',
+ unit: '吨(t)',
+ unitPrice: 1.2,
+ priceUnit: '元',
+ scope: 'xxxx',
+ pricingUnit: 'xxxxxx',
+ latestUpdateTime: '2025-12-04 21:12:20',
+ },
+ {
+ id: 4,
+ energyType: '汽油',
+ unit: 'kWh',
+ unitPrice: 1.5,
+ priceUnit: '元',
+ scope: 'xxxx',
+ pricingUnit: 'xxxxxx',
+ latestUpdateTime: '2025-11-26 10:28:20',
+ },
+ ],
+ [],
+ );
+
+ const tableData = useMemo(() => {
+ return rows
+ .filter((r) => (filterA ? r.unit === filterA : true))
+ .filter((r) => (filterB ? r.energyType === filterB : true));
+ }, [filterA, filterB, rows]);
+
+ const pagedData = useMemo(() => {
+ const start = (pagination.current - 1) * pagination.pageSize;
+ return tableData.slice(start, start + pagination.pageSize);
+ }, [pagination.current, pagination.pageSize, tableData]);
+
+ const handleAdd = () => message.info('新增');
+ const handleUpload = () => message.info('上传');
+ const handleBatchDownload = () => message.info('批量下载');
+ const handleQuery = () => message.info('查询');
+
+ const handleEdit = (record) => message.info(`编辑:${record.energyType}`);
+ const handleView = (record) => message.info(`详情:${record.energyType}`);
+ const handleDelete = (record) => message.success(`已删除:${record.energyType}`);
+
+ const columns = useMemo(
+ () => [
+ {
+ title: '序号',
+ dataIndex: 'id',
+ key: 'id',
+ width: 70,
+ align: 'center',
+ },
+ {
+ title: '能源类型',
+ dataIndex: 'energyType',
+ key: 'energyType',
+ width: 120,
+ },
+ {
+ title: '单位',
+ dataIndex: 'unit',
+ key: 'unit',
+ width: 160,
+ },
+ {
+ title: '单价',
+ dataIndex: 'unitPrice',
+ key: 'unitPrice',
+ width: 110,
+ },
+ {
+ title: '价格单位',
+ dataIndex: 'priceUnit',
+ key: 'priceUnit',
+ width: 120,
+ },
+ {
+ title: '适用范围',
+ dataIndex: 'scope',
+ key: 'scope',
+ width: 120,
+ },
+ {
+ title: '定价单位',
+ dataIndex: 'pricingUnit',
+ key: 'pricingUnit',
+ width: 140,
+ },
+ {
+ title: '最后更新时间',
+ dataIndex: 'latestUpdateTime',
+ key: 'latestUpdateTime',
+ width: 210,
+ },
+ {
+ title: '操作',
+ key: 'action',
+ width: 140,
+ align: 'center',
+ render: (_, record) => (
+
+ }
+ onClick={() => handleEdit(record)}
+ />
+ }
+ onClick={() => handleView(record)}
+ />
+ handleDelete(record)}
+ >
+ } />
+
+
+ ),
+ },
+ ],
+ [],
+ );
+
+ return (
+
+
+
+
+ } onClick={handleAdd}>
+ 新增
+
+ } onClick={handleUpload}>
+ 上传
+
+ } onClick={handleBatchDownload}>
+ 批量下载
+
+
+
+
+
+
筛选条件
+
+
+
+
+
+
+
+
+
+
`共 ${total} 条`,
+ position: ['bottomRight'],
+ onChange: (current, pageSize) => setPagination({ current, pageSize }),
+ }}
+ rowSelection={{
+ selectedRowKeys,
+ onChange: (keys) => setSelectedRowKeys(keys),
+ columnWidth: 44,
+ }}
+ />
+
+
+ );
+};
+
+export default Jgfx;
diff --git a/src/pages/business_data/components/jgfx.less b/src/pages/business_data/components/jgfx.less
new file mode 100644
index 0000000..d233aeb
--- /dev/null
+++ b/src/pages/business_data/components/jgfx.less
@@ -0,0 +1,161 @@
+.container {
+ width: 100%;
+ height: 100%;
+ min-height: 560px;
+ background: #fff;
+ border-radius: 14px;
+ padding: 14px 16px 12px;
+ margin:15px 10px;
+ overflow: hidden;
+}
+
+.toolbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 2px 0 14px;
+}
+
+.toolbarLeft {
+ display: flex;
+ align-items: center;
+}
+
+.toolbarRight {
+ display: flex;
+ align-items: center;
+}
+
+.filterLabel {
+ font-size: 12px;
+ color: #8d93a3;
+ margin-right: 10px;
+}
+
+.filterSelect {
+ width: 170px;
+
+ :global {
+ .ant-select-selector {
+ height: 32px !important;
+ border-radius: 999px !important;
+ border-color: #e7eaf2 !important;
+ display: flex !important;
+ align-items: center !important;
+ box-shadow: none !important;
+ }
+
+ .ant-select-selection-placeholder {
+ color: #b1b7c4;
+ }
+ }
+}
+
+.primaryBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ box-shadow: none !important;
+ background-color: rgba(72, 81, 255, 1);
+
+ :global {
+ .ant-btn-icon {
+ margin-right: 6px;
+ }
+ }
+}
+
+.ghostBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ border: 1px solid #e7eaf2 !important;
+ background: #fff !important;
+ color: #5b6070 !important;
+ box-shadow: none !important;
+}
+
+.queryBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ border: 1px solid #e7eaf2 !important;
+ background: #fff !important;
+ color: #5b6070 !important;
+ box-shadow: none !important;
+}
+
+.tableWrap {
+ width: 100%;
+
+ :global {
+ .ant-table {
+ border-radius: 10px;
+ }
+
+ .ant-table-thead > tr > th {
+ background: #f7f8fb;
+ color: #6d7383;
+ font-weight: 500;
+ height: 44px;
+ }
+
+ .ant-table-tbody > tr > td {
+ color: #2b2f3a;
+ height: 48px;
+ }
+
+ .ant-table-tbody > tr:hover > td {
+ background: #fafbff;
+ }
+
+ .ant-table-pagination {
+ margin: 14px 0 0;
+ }
+
+ .ant-pagination-total-text {
+ color: #8d93a3;
+ margin-right: 10px;
+ }
+
+ .ant-pagination-options {
+ margin-left: 10px;
+ }
+ }
+}
+
+.actionIconBtn {
+ padding: 0 !important;
+ height: 24px !important;
+ color: rgba(72, 81, 255, 1) !important;
+
+ :global {
+ .anticon {
+ font-size: 16px;
+ }
+ }
+}
+
+.actionIconBtnInfo {
+ padding: 0 !important;
+ height: 24px !important;
+ color: #13c2c2 !important;
+
+ :global {
+ .anticon {
+ font-size: 16px;
+ }
+ }
+}
+
+.actionIconBtnDanger {
+ padding: 0 !important;
+ height: 24px !important;
+ color: #ff4d4f !important;
+
+ :global {
+ .anticon {
+ font-size: 16px;
+ }
+ }
+}
diff --git a/src/pages/business_data/components/nhtj.js b/src/pages/business_data/components/nhtj.js
new file mode 100644
index 0000000..7610cbe
--- /dev/null
+++ b/src/pages/business_data/components/nhtj.js
@@ -0,0 +1,10 @@
+import React from 'react';
+import styles from './nhtj.less';
+
+const Nhtj = () => {
+ return (
+ 待开发
+ );
+};
+
+export default Nhtj;
diff --git a/src/pages/business_data/components/nhtj.less b/src/pages/business_data/components/nhtj.less
new file mode 100644
index 0000000..014325f
--- /dev/null
+++ b/src/pages/business_data/components/nhtj.less
@@ -0,0 +1,4 @@
+.placeholder {
+ padding: 20px;
+ color: #999;
+}
diff --git a/src/pages/business_data/components/nhtjcs.js b/src/pages/business_data/components/nhtjcs.js
new file mode 100644
index 0000000..3c2cd76
--- /dev/null
+++ b/src/pages/business_data/components/nhtjcs.js
@@ -0,0 +1,260 @@
+import React, { useMemo, useState } from 'react';
+import { Button, message, Popconfirm, Select, Space, Table } from 'antd';
+import {
+ DeleteOutlined,
+ DownloadOutlined,
+ EditOutlined,
+ PlusOutlined,
+ UploadOutlined,
+} from '@ant-design/icons';
+import styles from './nyfl.less';
+import Component1 from '@/assets/basic_data/Component1.svg';
+import Component2 from '@/assets/basic_data/Component2.svg';
+import Component3 from '@/assets/basic_data/Component3.svg';
+
+const Nhtjcs = () => {
+ const [activeEnergyKey, setActiveEnergyKey] = useState('electric');
+ const [selectedRowKeys, setSelectedRowKeys] = useState([]);
+ const [filterA, setFilterA] = useState(undefined);
+ const [filterB, setFilterB] = useState(undefined);
+
+ const energyTypes = useMemo(
+ () => [
+ { key: 'electric', label: '电能', icon: Component1 },
+ { key: 'water', label: '水', icon: Component2 },
+ { key: 'gas', label: '天然气', icon: Component3 },
+ ],
+ [],
+ );
+
+ const [rows, setRows] = useState(() => [
+ {
+ id: 1,
+ energyKey: 'electric',
+ powerType: '泵类系统',
+ deviceCount: 28,
+ statisticMethod: '智能电表',
+ usageDesc: '用于油品输送的各类泵设备的耗电量。',
+ },
+ {
+ id: 2,
+ energyKey: 'electric',
+ powerType: '加热保温系统',
+ deviceCount: 23,
+ statisticMethod: '智能电表',
+ usageDesc: '用于油罐加热和管道保温的电加热设备的耗电量。',
+ },
+ {
+ id: 3,
+ energyKey: 'electric',
+ powerType: '照明系统',
+ deviceCount: 55,
+ statisticMethod: '手动抄表',
+ usageDesc: '油库区域内照明设备的耗电量,包括室内照明和室外照明。',
+ },
+ {
+ id: 4,
+ energyKey: 'electric',
+ powerType: '生活用电系统',
+ deviceCount: 21,
+ statisticMethod: '手动抄表',
+ usageDesc: '油库工作人员生活区的用电,如宿舍、办公区等的耗电量。',
+ },
+ ]);
+
+ const scopedRows = useMemo(() => {
+ return rows.filter((row) => row.energyKey === activeEnergyKey);
+ }, [activeEnergyKey, rows]);
+
+ const selectOptionsA = useMemo(() => {
+ const values = Array.from(new Set(scopedRows.map((r) => r.powerType).filter(Boolean)));
+ return values.map((value) => ({ label: value, value }));
+ }, [scopedRows]);
+
+ const selectOptionsB = useMemo(() => {
+ const values = Array.from(new Set(scopedRows.map((r) => r.statisticMethod).filter(Boolean)));
+ return values.map((value) => ({ label: value, value }));
+ }, [scopedRows]);
+
+ const tableData = useMemo(() => {
+ return scopedRows
+ .filter((row) => (filterA ? row.powerType === filterA : true))
+ .filter((row) => (filterB ? row.statisticMethod === filterB : true));
+ }, [filterA, filterB, scopedRows]);
+
+ const handleAdd = () => message.info('新增');
+ const handleUpload = () => message.info('上传');
+ const handleBatchDownload = () => message.info('批量下载');
+ const handleQuery = () => message.info('查询');
+
+ const handleEdit = (record) => message.info(`编辑:${record.powerType}`);
+ const handleDelete = (record) => message.success(`已删除:${record.powerType}`);
+
+ const columns = useMemo(
+ () => [
+ {
+ title: '序号',
+ dataIndex: 'id',
+ key: 'id',
+ width: 70,
+ align: 'center',
+ },
+ {
+ title: '耗电类型',
+ dataIndex: 'powerType',
+ key: 'powerType',
+ width: 180,
+ },
+ {
+ title: '设备数量',
+ dataIndex: 'deviceCount',
+ key: 'deviceCount',
+ width: 120,
+ align: 'center',
+ },
+ {
+ title: '统计方式',
+ dataIndex: 'statisticMethod',
+ key: 'statisticMethod',
+ width: 140,
+ },
+ {
+ title: '用途描述',
+ dataIndex: 'usageDesc',
+ key: 'usageDesc',
+ ellipsis: true,
+ },
+ {
+ title: '操作',
+ key: 'action',
+ width: 120,
+ align: 'center',
+ render: (_, record) => (
+
+ }
+ onClick={() => handleEdit(record)}
+ />
+ handleDelete(record)}
+ >
+ } />
+
+
+ ),
+ },
+ ],
+ [],
+ );
+
+ return (
+
+
+
能源类型
+
+
+ {energyTypes.map((item) => {
+ const isActive = item.key === activeEnergyKey;
+ return (
+
+ );
+ })}
+
+
}>
+ 添加分类
+
+
+
+
+
+
+
+
+ }
+ onClick={handleAdd}
+ >
+ 新增
+
+ } onClick={handleUpload}>
+ 上传
+
+ } onClick={handleBatchDownload}>
+ 批量下载
+
+
+
+
+
+
+
筛选条件
+
+
+
+
+
+
+
+
+
+
setSelectedRowKeys(keys),
+ columnWidth: 44,
+ }}
+ />
+
+
+
+ );
+};
+
+export default Nhtjcs;
diff --git a/src/pages/business_data/components/nhtjcs.less b/src/pages/business_data/components/nhtjcs.less
new file mode 100644
index 0000000..373bb7a
--- /dev/null
+++ b/src/pages/business_data/components/nhtjcs.less
@@ -0,0 +1,245 @@
+.container {
+ display: flex;
+ gap: 15px;
+ width: 100%;
+ height: 100%;
+ min-height: 560px;
+ padding: 15px 10px
+}
+
+.leftPanel {
+ width: 200px;
+ background: #fff;
+ border-radius: 12px;
+ padding: 15px 10px;
+}
+
+.leftTitle {
+ font-size: 15px;
+ font-weight: 500;
+ color: #2b2f3a;
+ padding: 2px 10px 14px;
+}
+
+.leftList {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ padding: 0 8px;
+}
+
+.leftItemBtn {
+ width: 100%;
+ height: 40px !important;
+ padding: 0 14px !important;
+ border-radius: 999px !important;
+ border: 1px solid #e8ecf3 !important;
+ background: #fff !important;
+ box-shadow: none !important;
+ display: flex !important;
+ align-items: center !important;
+ justify-content: flex-start !important;
+ color: #a5adbb !important;
+
+ &:hover {
+ border-color: rgba(72, 81, 255, 0.35) !important;
+ color: rgba(72, 81, 255, 1) !important;
+ }
+}
+
+.leftItemActive {
+ background: rgba(72, 81, 255, 1) !important;
+ border-color: rgba(72, 81, 255, 1) !important;
+ color: #fff !important;
+ box-shadow: 0 10px 20px rgba(72, 81, 255, 0.18) !important;
+
+ &:hover {
+ color: #fff !important;
+ }
+
+ .leftIconCircle {
+ background: rgba(255, 255, 255, 0.26);
+ color: #fff;
+ }
+}
+
+.leftIconCircle {
+ width: 18px;
+ height: 18px;
+ border-radius: 999px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(72, 81, 255, 0.12);
+ color: rgba(72, 81, 255, 1);
+ flex: none;
+
+ :global {
+ .anticon {
+ font-size: 12px;
+ line-height: 1;
+ }
+ }
+}
+
+.leftIconImg {
+ width: 18px;
+ height: 18px;
+ display: block;
+ object-fit: contain;
+}
+
+.leftItemText {
+ margin-left: 10px;
+ font-size: 14px;
+ font-weight: 500;
+}
+
+.leftAddBtn {
+ width: 100%;
+ height: 40px !important;
+ border-radius: 999px !important;
+ border: none !important;
+ background: #f2f4f8 !important;
+ color: #b7bdc9 !important;
+ display: flex !important;
+ align-items: center !important;
+ justify-content: center !important;
+ box-shadow: none !important;
+}
+
+.rightPanel {
+ flex: 1;
+ background: #fff;
+ border-radius: 12px;
+ padding: 14px 16px 12px;
+ overflow: hidden;
+}
+
+.toolbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 2px 0 14px;
+}
+
+.toolbarLeft {
+ display: flex;
+ align-items: center;
+}
+
+.toolbarRight {
+ display: flex;
+ align-items: center;
+}
+
+.filterLabel {
+ font-size: 12px;
+ color: #8d93a3;
+ margin-right: 10px;
+}
+
+.filterSelect {
+ width: 150px;
+
+ :global {
+ .ant-select-selector {
+ height: 32px !important;
+ border-radius: 999px !important;
+ border-color: #e7eaf2 !important;
+ display: flex !important;
+ align-items: center !important;
+ box-shadow: none !important;
+ }
+
+ .ant-select-selection-placeholder {
+ color: #b1b7c4;
+ }
+ }
+}
+
+.primaryBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ box-shadow: none !important;
+ background-color: rgba(72, 81, 255, 1);
+
+ :global {
+ .ant-btn-icon {
+ margin-right: 6px;
+ }
+ }
+}
+
+.ghostBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ border: 1px solid #e7eaf2 !important;
+ background: #fff !important;
+ color: #5b6070 !important;
+ box-shadow: none !important;
+}
+
+.queryBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ border: 1px solid #e7eaf2 !important;
+ background: #fff !important;
+ color: #5b6070 !important;
+ box-shadow: none !important;
+}
+
+.tableWrap {
+ width: 100%;
+
+ :global {
+ .ant-table {
+ border-radius: 10px;
+ }
+
+ .ant-table-thead > tr > th {
+ background: #f7f8fb;
+ color: #2b2f3a;
+ // font-weight: 500;
+ }
+
+ .ant-table-tbody > tr > td {
+ color: #2b2f3a;
+ }
+
+ .ant-table-tbody > tr:hover > td {
+ background: #fafbff;
+ }
+
+ .ant-table-pagination {
+ margin: 12px 0 0;
+ }
+ }
+}
+
+.actionIconBtn {
+ padding: 0 !important;
+ height: 24px !important;
+ color: rgba(72, 81, 255, 1) !important;
+
+ :global {
+ .anticon {
+ font-size: 16px;
+ }
+ }
+}
+
+.actionIconBtnDanger {
+ padding: 0 !important;
+ height: 24px !important;
+ color: #ff4d4f !important;
+
+ :global {
+ .anticon {
+ font-size: 16px;
+ }
+ }
+}
diff --git a/src/pages/business_data/components/nyfl.js b/src/pages/business_data/components/nyfl.js
new file mode 100644
index 0000000..2d782af
--- /dev/null
+++ b/src/pages/business_data/components/nyfl.js
@@ -0,0 +1,295 @@
+import React, { useMemo, useState } from 'react';
+import { Button, message, Popconfirm, Select, Space, Switch, Table } from 'antd';
+import {
+ DeleteOutlined,
+ DownloadOutlined,
+ EditOutlined,
+ PlusOutlined,
+ UploadOutlined,
+} from '@ant-design/icons';
+import styles from './nyfl.less';
+import Component1 from '@/assets/basic_data/Component1.svg';
+import Component2 from '@/assets/basic_data/Component2.svg';
+import Component3 from '@/assets/basic_data/Component3.svg';
+
+const Nyfl = () => {
+ const [activeEnergyKey, setActiveEnergyKey] = useState('electric');
+ const [filterUnit, setFilterUnit] = useState(undefined);
+ const [filterCollection, setFilterCollection] = useState(undefined);
+ const [selectedRowKeys, setSelectedRowKeys] = useState([]);
+
+ const energyTypes = useMemo(
+ () => [
+ { key: 'electric', label: '电能', icon: Component1 },
+ { key: 'water', label: '水', icon: Component2 },
+ { key: 'gas', label: '天然气', icon: Component3 },
+ ],
+ [],
+ );
+
+ const unitOptions = useMemo(
+ () => [
+ { label: 'kWh', value: 'kWh' },
+ { label: 'm³', value: 'm³' },
+ { label: 't', value: 't' },
+ ],
+ [],
+ );
+
+ const collectionOptions = useMemo(
+ () => [
+ { label: '市电', value: '市电' },
+ { label: '光伏发电', value: '光伏发电' },
+ { label: '自备发电', value: '自备发电' },
+ ],
+ [],
+ );
+
+ const [rows, setRows] = useState(() => [
+ {
+ id: 1,
+ energyKey: 'electric',
+ energyType: '电能',
+ unit: 'kWh',
+ collectionType: '市电',
+ enabled: true,
+ latestUpdateTime: '2025-12-02 03:56:02',
+ },
+ {
+ id: 2,
+ energyKey: 'electric',
+ energyType: '电能',
+ unit: 'kWh',
+ collectionType: '光伏发电',
+ enabled: false,
+ latestUpdateTime: '2025-11-22 11:56:50',
+ },
+ {
+ id: 3,
+ energyKey: 'electric',
+ energyType: '电能',
+ unit: 'kWh',
+ collectionType: '自备发电',
+ enabled: true,
+ latestUpdateTime: '2025-12-04 21:12:20',
+ },
+ {
+ id: 4,
+ energyKey: 'electric',
+ energyType: '电能',
+ unit: 'kWh',
+ collectionType: 'xxxxxx',
+ enabled: false,
+ latestUpdateTime: '2025-11-26 10:28:20',
+ },
+ {
+ id: 5,
+ energyKey: 'water',
+ energyType: '水',
+ unit: 'm³',
+ collectionType: '市政供水',
+ enabled: true,
+ latestUpdateTime: '2025-12-06 09:12:10',
+ },
+ {
+ id: 6,
+ energyKey: 'gas',
+ energyType: '天然气',
+ unit: 'm³',
+ collectionType: '管网供气',
+ enabled: true,
+ latestUpdateTime: '2025-12-01 16:08:45',
+ },
+ ]);
+
+ const tableData = useMemo(() => {
+ return rows
+ .filter((row) => row.energyKey === activeEnergyKey)
+ .filter((row) => (filterUnit ? row.unit === filterUnit : true))
+ .filter((row) => (filterCollection ? row.collectionType === filterCollection : true));
+ }, [activeEnergyKey, filterCollection, filterUnit, rows]);
+
+ const handleAdd = () => message.info('新增');
+ const handleUpload = () => message.info('上传');
+ const handleBatchDownload = () => message.info('批量下载');
+ const handleQuery = () => message.info('查询');
+
+ const handleEdit = (record) => message.info(`编辑:${record.energyType}`);
+ const handleDelete = (record) => message.success(`已删除:${record.energyType}`);
+
+ const columns = useMemo(
+ () => [
+ {
+ title: '序号',
+ dataIndex: 'id',
+ key: 'id',
+ width: 70,
+ align: 'center',
+ },
+ {
+ title: '能源类型',
+ dataIndex: 'energyType',
+ key: 'energyType',
+ width: 120,
+ },
+ {
+ title: '单位',
+ dataIndex: 'unit',
+ key: 'unit',
+ width: 120,
+ },
+ {
+ title: '采集类型',
+ dataIndex: 'collectionType',
+ key: 'collectionType',
+ width: 180,
+ },
+ {
+ title: '状态',
+ dataIndex: 'enabled',
+ key: 'enabled',
+ width: 120,
+ align: 'center',
+ render: (value, record) => (
+ {
+ setRows((prev) =>
+ prev.map((item) => (item.id === record.id ? { ...item, enabled: checked } : item)),
+ );
+ message.success(checked ? '已启用' : '已停用');
+ }}
+ />
+ ),
+ },
+ {
+ title: '最后更新时间',
+ dataIndex: 'latestUpdateTime',
+ key: 'latestUpdateTime',
+ width: 200,
+ },
+ {
+ title: '操作',
+ key: 'action',
+ width: 120,
+ align: 'center',
+ render: (_, record) => (
+
+ }
+ onClick={() => handleEdit(record)}
+ />
+ handleDelete(record)}
+ >
+ } />
+
+
+ ),
+ },
+ ],
+ [],
+ );
+
+ return (
+
+
+
能源类型
+
+
+ {energyTypes.map((item) => {
+ const isActive = item.key === activeEnergyKey;
+ return (
+
+ );
+ })}
+
+
}>
+ 添加分类
+
+
+
+
+
+
+
+
+ } onClick={handleAdd}>
+ 新增
+
+ } onClick={handleUpload}>
+ 上传
+
+ } onClick={handleBatchDownload}>
+ 批量下载
+
+
+
+
+
+
筛选条件
+
+
+
+
+
+
+
+
+
+
setSelectedRowKeys(keys),
+ columnWidth: 44,
+ }}
+ />
+
+
+
+ );
+};
+
+export default Nyfl;
diff --git a/src/pages/business_data/components/nyfl.less b/src/pages/business_data/components/nyfl.less
new file mode 100644
index 0000000..7dca2b9
--- /dev/null
+++ b/src/pages/business_data/components/nyfl.less
@@ -0,0 +1,245 @@
+.container {
+ display: flex;
+ gap: 15px;
+ width: 100%;
+ height: 100%;
+ min-height: 560px;
+ padding: 15px 10px
+}
+
+.leftPanel {
+ width: 200px;
+ background: #fff;
+ border-radius: 12px;
+ padding: 15px 10px;
+}
+
+.leftTitle {
+ font-size: 15px;
+ font-weight: 500;
+ color: #2b2f3a;
+ padding: 2px 10px 14px;
+}
+
+.leftList {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ padding: 0 8px;
+}
+
+.leftItemBtn {
+ width: 100%;
+ height: 40px !important;
+ padding: 0 14px !important;
+ border-radius: 999px !important;
+ border: 1px solid #e8ecf3 !important;
+ background: #fff !important;
+ box-shadow: none !important;
+ display: flex !important;
+ align-items: center !important;
+ justify-content: flex-start !important;
+ color: #a5adbb !important;
+
+ &:hover {
+ border-color: rgba(72, 81, 255, 0.35) !important;
+ color: rgba(72, 81, 255, 1) !important;
+ }
+}
+
+.leftItemActive {
+ background: rgba(72, 81, 255, 1) !important;
+ border-color: rgba(72, 81, 255, 1) !important;
+ color: #fff !important;
+ box-shadow: 0 10px 20px rgba(72, 81, 255, 0.18) !important;
+
+ &:hover {
+ color: #fff !important;
+ }
+
+ .leftIconCircle {
+ background: rgba(255, 255, 255, 0.26);
+ color: #fff;
+ }
+}
+
+.leftIconCircle {
+ width: 18px;
+ height: 18px;
+ border-radius: 999px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(72, 81, 255, 0.12);
+ color: rgba(72, 81, 255, 1);
+ flex: none;
+
+ :global {
+ .anticon {
+ font-size: 12px;
+ line-height: 1;
+ }
+ }
+}
+
+.leftIconImg {
+ width: 18px;
+ height: 18px;
+ display: block;
+ object-fit: contain;
+}
+
+.leftItemText {
+ margin-left: 10px;
+ font-size: 14px;
+ font-weight: 500;
+}
+
+.leftAddBtn {
+ width: 100%;
+ height: 40px !important;
+ border-radius: 999px !important;
+ border: none !important;
+ background: #f2f4f8 !important;
+ color: #b7bdc9 !important;
+ display: flex !important;
+ align-items: center !important;
+ justify-content: center !important;
+ box-shadow: none !important;
+}
+
+.rightPanel {
+ flex: 1;
+ background: #fff;
+ border-radius: 12px;
+ padding: 14px 16px 12px;
+ overflow: hidden;
+}
+
+.toolbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 2px 0 14px;
+}
+
+.toolbarLeft {
+ display: flex;
+ align-items: center;
+}
+
+.toolbarRight {
+ display: flex;
+ align-items: center;
+}
+
+.filterLabel {
+ font-size: 12px;
+ color: #8d93a3;
+ margin-right: 10px;
+}
+
+.filterSelect {
+ width: 150px;
+
+ :global {
+ .ant-select-selector {
+ height: 32px !important;
+ border-radius: 999px !important;
+ border-color: #e7eaf2 !important;
+ display: flex !important;
+ align-items: center !important;
+ box-shadow: none !important;
+ }
+
+ .ant-select-selection-placeholder {
+ color: #b1b7c4;
+ }
+ }
+}
+
+.primaryBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ box-shadow: none !important;
+ background-color: rgba(72, 81, 255, 1);
+
+ :global {
+ .ant-btn-icon {
+ margin-right: 6px;
+ }
+ }
+}
+
+.ghostBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ border: 1px solid #e7eaf2 !important;
+ background: #fff !important;
+ color: #5b6070 !important;
+ box-shadow: none !important;
+}
+
+.queryBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ border: 1px solid #e7eaf2 !important;
+ background: #fff !important;
+ color: #5b6070 !important;
+ box-shadow: none !important;
+}
+
+.tableWrap {
+ width: 100%;
+
+ :global {
+ .ant-table {
+ border-radius: 10px;
+ }
+
+ .ant-table-thead > tr > th {
+ background: #f7f8fb;
+ color: #6d7383;
+ font-weight: 500;
+ }
+
+ .ant-table-tbody > tr > td {
+ color: #2b2f3a;
+ }
+
+ .ant-table-tbody > tr:hover > td {
+ background: #fafbff;
+ }
+
+ .ant-table-pagination {
+ margin: 12px 0 0;
+ }
+ }
+}
+
+.actionIconBtn {
+ padding: 0 !important;
+ height: 24px !important;
+ color: rgba(72, 81, 255, 1) !important;
+
+ :global {
+ .anticon {
+ font-size: 16px;
+ }
+ }
+}
+
+.actionIconBtnDanger {
+ padding: 0 !important;
+ height: 24px !important;
+ color: #ff4d4f !important;
+
+ :global {
+ .anticon {
+ font-size: 16px;
+ }
+ }
+}
diff --git a/src/pages/business_data/form/StaffSheetCreateForm.js b/src/pages/business_data/form/StaffSheetCreateForm.js
new file mode 100644
index 0000000..6bdce8d
--- /dev/null
+++ b/src/pages/business_data/form/StaffSheetCreateForm.js
@@ -0,0 +1,271 @@
+import { useState, useEffect } from 'react'
+import { Col, DatePicker, Form, Input, Modal, Row, Select } from 'antd'
+import SelectDeptTree from '@/components/SelectDeptTree'
+import SelectOrganTree from '@/components/SelectOrganTree'
+import datadictionary from '@/utils/dataDictionary'
+import { formatDictOptions, verifyPhone } from '@/utils/globalCommon'
+import { NumberInput } from '@/components/NumberInput'
+import styles from '../StaffSheetList.less'
+import style from '@/global.less'
+import dayjs from 'dayjs'
+import { formatDate } from '@/utils/formatUtils'
+
+const { Item: FormItem } = Form
+const { TextArea } = Input
+const dictData = datadictionary
+
+//新增表单
+let getDeptTreeBySelectTree
+let getOrganTreeBySelectTree
+
+const StaffSheetCreateForm = (props => {
+ const [form] = Form.useForm()
+ const [jobStatus, setJobStatus] = useState('1')
+
+ const {
+ modalVisible,
+ handleAdd,
+ handleModalVisible,
+ loading,
+ dispatch,
+ selectDeptTree,
+ selectOrganTree
+ } = props
+
+ useEffect(() => {
+ form.setFieldsValue({
+ user_type: 'employee',
+ job_status: '1',
+ mgr_type: '0'
+ })
+ }, [])
+
+ const selectedDeptTreeValue = (deptRecord) => {
+ getDeptTreeBySelectTree = deptRecord
+ }
+
+ const selectedOrganTreeValue = (orgRecord) => {
+ getOrganTreeBySelectTree = orgRecord
+ }
+
+ const parentDeptTreeMethod = {
+ dispatch: dispatch,
+ selectDeptTree: selectDeptTree,
+ selectedDeptTreeValue: selectedDeptTreeValue,
+ }
+
+ const parentOrganTreeMethod = {
+ dispatch: dispatch,
+ selectOrganTree: selectOrganTree,
+ selectedOrganTreeValue: selectedOrganTreeValue
+ }
+
+ const okHandle = () => {
+ form.validateFields()
+ .then(fieldsValue => {
+ form.resetFields()
+ fieldsValue.birthday = formatDate(fieldsValue.birthday, 'YYYY-MM-DD')
+ fieldsValue.hiredate = formatDate(fieldsValue.hiredate, 'YYYY-MM-DD')
+ fieldsValue.departure_time = formatDate(fieldsValue.departure_time, 'YYYY-MM-DD')
+ fieldsValue.posts = fieldsValue.posts ? JSON.stringify(fieldsValue.posts) : null
+
+ // if (getDeptTreeBySelectTree) {
+ // fieldsValue.dept_code = getDeptTreeBySelectTree.dept_code
+ // fieldsValue.dept_name = getDeptTreeBySelectTree.title
+ // }
+
+ if (getOrganTreeBySelectTree) {
+ fieldsValue.org_code = getOrganTreeBySelectTree.org_code
+ fieldsValue.org_name = getOrganTreeBySelectTree.title
+ }
+
+ handleAdd(fieldsValue)
+ })
+ .catch(errInfo => {})
+ }
+
+ const afterClose = () =>{
+ form.resetFields();
+ }
+
+ const handleJobStatusChange = (value) => {
+ setJobStatus(value)
+ }
+
+ return (
+ handleModalVisible()}
+ afterClose={() => afterClose()}
+ confirmLoading={loading}
+ >
+
+
+ )
+})
+
+export default StaffSheetCreateForm
diff --git a/src/pages/business_data/form/StaffSheetRenderAdvancedForm.js b/src/pages/business_data/form/StaffSheetRenderAdvancedForm.js
new file mode 100644
index 0000000..2625938
--- /dev/null
+++ b/src/pages/business_data/form/StaffSheetRenderAdvancedForm.js
@@ -0,0 +1,113 @@
+import { useEffect } from 'react'
+import { Button, Col, Form, Input, Row } from 'antd'
+import { UpOutlined, SearchOutlined, RedoOutlined } from '@ant-design/icons'
+import SelectDeptTree from '@/components/SelectDeptTree'
+import SelectOrganTree from '@/components/SelectOrganTree'
+import style from '@/global.less'
+
+const { Item: FormItem } = Form
+let getDeptTreeBySelectTree
+let getOrganTreeBySelectTree
+
+const StaffSheetRenderAdvancedForm = (props) => {
+ const [form] = Form.useForm()
+ const { dispatch, handleSearch, handleFormReset, toggleForm, selectDeptTree, selectOrganTree, params } = props
+
+ useEffect(() => {
+ form.setFieldsValue({
+ user_name: params?.user_name,
+ user_name_cn: params?.user_name_cn,
+ deptname: params?.deptname,
+ orgname: params?.orgname,
+ })
+ }, [params])
+
+ const onFinish = values => {
+ // if (getDeptTreeBySelectTree) {
+ // values.dept_code = getDeptTreeBySelectTree.dept_code
+ // values.deptname = getDeptTreeBySelectTree.title
+ // }
+
+ if (getOrganTreeBySelectTree) {
+ values.org_code = getOrganTreeBySelectTree.org_code
+ values.orgname = getOrganTreeBySelectTree.title
+ }
+
+ handleSearch(values)
+ }
+
+ const myHandleFormReset = () => {
+ form.resetFields()
+ handleFormReset()
+ }
+
+ const selectedDeptTreeValue = (deptRecord) => {
+ getDeptTreeBySelectTree = deptRecord
+ }
+
+ const selectedOrganTreeValue = (orgRecord) => {
+ getOrganTreeBySelectTree = orgRecord
+ }
+
+ const parentDeptTreeMethod = {
+ dispatch: dispatch,
+ selectDeptTree: selectDeptTree,
+ selectedDeptTreeValue: selectedDeptTreeValue
+ }
+
+ const parentOrganTreeMethod = {
+ dispatch: dispatch,
+ selectOrganTree: selectOrganTree,
+ selectedOrganTreeValue: selectedOrganTreeValue
+ }
+
+ return (
+
+ )
+}
+
+export default StaffSheetRenderAdvancedForm
diff --git a/src/pages/business_data/form/StaffSheetRenderSimpleForm.js b/src/pages/business_data/form/StaffSheetRenderSimpleForm.js
new file mode 100644
index 0000000..0468e76
--- /dev/null
+++ b/src/pages/business_data/form/StaffSheetRenderSimpleForm.js
@@ -0,0 +1,81 @@
+import { useEffect } from 'react'
+import {Button, Col, Form, Input, Row, DatePicker, Select} from 'antd'
+import {DownOutlined, RedoOutlined, SearchOutlined} from '@ant-design/icons'
+import style from '@/global.less'
+import dayjs from 'dayjs'
+const { Item: FormItem } = Form
+
+const StaffSheetRenderSimpleForm = (props) => {
+ const [form] = Form.useForm()
+ const { handleSearch, handleFormReset, toggleForm, params } = props
+
+ useEffect(() => {
+ form.setFieldsValue({
+ user_name: params?.user_name,
+ user_name_cn: params?.user_name_cn,
+ })
+ }, [params])
+
+ const onFinish = values => {
+ handleSearch(values)
+ }
+
+ const myHandleFormReset = () => {
+ form.resetFields()
+ handleFormReset()
+ }
+
+ return (
+
+ )
+}
+
+export default StaffSheetRenderSimpleForm
diff --git a/src/pages/business_data/form/StaffSheetUpdateForm.js b/src/pages/business_data/form/StaffSheetUpdateForm.js
new file mode 100644
index 0000000..f33d64b
--- /dev/null
+++ b/src/pages/business_data/form/StaffSheetUpdateForm.js
@@ -0,0 +1,362 @@
+import { useState, useEffect } from 'react'
+import { Col, DatePicker, Form, Input, Modal, Row, Select } from 'antd'
+import SelectOrganTree from '@/components/SelectOrganTree'
+import datadictionary from '@/utils/dataDictionary'
+import { formatDictOptions, verifyPhone } from '@/utils/globalCommon'
+import { NumberInput } from '@/components/NumberInput'
+import styles from '../StaffSheetList.less'
+import style from '@/global.less'
+import dayjs from 'dayjs'
+import { formatDate, formatDateObject } from '@/utils/formatUtils'
+
+const { Item: FormItem } = Form
+const { TextArea } = Input
+const dictData = datadictionary
+
+//新增表单
+let getDeptTreeBySelectTree
+let getOrganTreeBySelectTree
+
+const StaffSheetUpdateForm = (props) => {
+ const [form] = Form.useForm()
+ const [jobStatus, setJobStatus] = useState('1')
+ const [userStatus, setUserStatus] = useState('0')
+
+ const {
+ handleUpdate,
+ updateModalVisible,
+ handleUpdateModalVisible,
+ values,
+ loading,
+ dispatch,
+ selectDeptTree,
+ selectOrganTree
+ } = props
+
+ const selectedDeptTreeValue = (deptRecord) => {
+ getDeptTreeBySelectTree = deptRecord
+ }
+
+ const selectedOrganTreeValue = (orgRecord) => {
+ getOrganTreeBySelectTree = orgRecord
+ }
+
+ const parentDeptTreeMethod = {
+ dispatch: dispatch,
+ selectDeptTree: selectDeptTree,
+ selectedDeptTreeValue: selectedDeptTreeValue,
+ }
+
+ const parentOrganTreeMethod = {
+ dispatch: dispatch,
+ selectOrganTree: selectOrganTree,
+ selectedOrganTreeValue: selectedOrganTreeValue
+ }
+
+ useEffect(() => {
+ setJobStatus(values.job_status)
+ setUserStatus(values.status)
+
+ form.setFieldsValue({
+ user_id: values.user_id,
+ user_name: values.user_name,
+ user_name_cn: values.user_name_cn,
+ user_name_en: values.user_name_en,
+ password: values.password,
+ email: values.email,
+ phone: values.phone,
+ landline: values.landline,
+ sex: values.sex,
+ avatar: values.avatar,
+ sign: values.sign,
+ tags: values.tags,
+ id_card: values.id_card,
+ birthday: formatDateObject(values.birthday, 'YYYY-MM-DD'),
+ job_status: values.job_status,
+ hiredate: formatDateObject(values.hiredate, 'YYYY-MM-DD'),
+ departure_time: formatDateObject(values.departure_time, 'YYYY-MM-DD'),
+ user_type: values.user_type,
+ emp_no: values.emp_no,
+ access_card_no: values.access_card_no,
+ country: values.country,
+ province: values.province,
+ city: values.city,
+ address: values.address,
+ work_addr: values.work_addr,
+ floor: values.floor,
+ inprovince: values.inprovince,
+ // dept_code: values.dept_code,
+ // dept_name: values.dept_name,
+ inner_dept_code: values.inner_dept_code,
+ org_code: values.org_code,
+ org_name: values.org_name,
+ inner_org_code: values.inner_org_code,
+ posts: values.posts ? JSON.parse(values.posts) : [],
+ wx_openid: values.wx_openid,
+ wx_mpopenid: values.wx_mpopenid,
+ wx_miniopenid: values.wx_miniopenid,
+ wx_unionid: values.wx_unionid,
+ mobile_imei: values.mobile_imei,
+ device_num: values.device_num,
+ al_taobao: values.al_taobao,
+ al_alipay: values.al_alipay,
+ al_dingding: values.al_dingding,
+ is_system_user: values.is_system_user,
+ mgr_type: values.mgr_type,
+ pwd_security_level: values.pwd_security_level,
+ pwd_update_date: values.pwd_update_date,
+ last_login_ip: values.last_login_ip,
+ last_login_date: values.last_login_date,
+ freeze_date: values.freeze_date,
+ freeze_cause: values.freeze_cause,
+ zindex: values.zindex,
+ wx_msg: values.wx_msg,
+ email_msg: values.email_msg,
+ system_msg: values.system_msg,
+ remarks: values.remarks,
+ status: values.status,
+ creator: values.creator,
+ create_date: values.create_date,
+ updater: values.updater,
+ update_date: values.update_date
+ })
+ }, [])
+
+ const handleLocalUpdate = () => {
+ form
+ .validateFields()
+ .then(fieldsValue => {
+ const formVals = {...values, ...fieldsValue}
+ formVals.birthday = formatDate(formVals.birthday, 'YYYY-MM-DD')
+ formVals.hiredate = formatDate(formVals.hiredate, 'YYYY-MM-DD')
+ formVals.departure_time = formatDate(formVals.departure_time, 'YYYY-MM-DD')
+ formVals.posts = formVals.posts ? JSON.stringify(formVals.posts) : null
+ formVals.freeze_date = '3' === formVals.status ? formatDate(dayjs().endOf('day'), 'YYYY-MM-DD') : null
+ formVals.freeze_cause = '3' === formVals.status ? formVals.freeze_cause : null
+
+ // if (getDeptTreeBySelectTree) {
+ // formVals.dept_code = getDeptTreeBySelectTree.dept_code
+ // formVals.dept_name = getDeptTreeBySelectTree.title
+ // }
+
+ if (getOrganTreeBySelectTree) {
+ formVals.org_code = getOrganTreeBySelectTree.org_code
+ formVals.org_name = getOrganTreeBySelectTree.title
+ }
+
+ handleUpdate(formVals)
+
+ })
+ .catch(errInfo => {})
+ }
+
+ const afterClose = () =>{
+ form.resetFields();
+ }
+
+ const handleJobStatusChange = (value) => {
+ setJobStatus(value)
+ }
+
+ const handleUserStatusChange = (value) => {
+ setUserStatus(value)
+ }
+
+ return (
+ handleLocalUpdate()}
+ onCancel={() => handleUpdateModalVisible()}
+ afterClose={() => afterClose()}
+ confirmLoading={loading}
+ >
+
+
+ )
+}
+
+export default StaffSheetUpdateForm
diff --git a/src/pages/business_data/form/StaffSheetViewForm.js b/src/pages/business_data/form/StaffSheetViewForm.js
new file mode 100644
index 0000000..9acb9c4
--- /dev/null
+++ b/src/pages/business_data/form/StaffSheetViewForm.js
@@ -0,0 +1,299 @@
+import { useState, useEffect } from 'react'
+import {Col, DatePicker, Form, Input, Modal, Row, Select} from 'antd'
+import datadictionary from '@/utils/dataDictionary'
+import style from "@/global.less";
+import {formatDictOptions, verifyPhone} from "@/utils/globalCommon";
+import {NumberInput} from "@/components/NumberInput";
+import dayjs from "dayjs";
+import SelectOrganTree from "@/components/SelectOrganTree";
+import {formatDateObject} from "@/utils/formatUtils";
+
+const { Item: FormItem } = Form
+const { TextArea } = Input
+const dictData = datadictionary
+
+const StaffSheetViewForm = (props) => {
+ const [form] = Form.useForm()
+ const [jobStatus, setJobStatus] = useState('1')
+ const [userStatus, setUserStatus] = useState('0')
+
+ const { viewModalVisible, handleViewModalVisible, values } = props
+
+ useEffect(() => {
+ setJobStatus(values.job_status)
+ setUserStatus(values.status)
+
+ form.setFieldsValue({
+ user_id: values.user_id,
+ user_name: values.user_name,
+ user_name_cn: values.user_name_cn,
+ user_name_en: values.user_name_en,
+ password: values.password,
+ email: values.email,
+ phone: values.phone,
+ landline: values.landline,
+ sex: values.sex,
+ avatar: values.avatar,
+ sign: values.sign,
+ tags: values.tags,
+ id_card: values.id_card,
+ birthday: formatDateObject(values.birthday, 'YYYY-MM-DD'),
+ job_status: values.job_status,
+ hiredate: formatDateObject(values.hiredate, 'YYYY-MM-DD'),
+ departure_time: formatDateObject(values.departure_time, 'YYYY-MM-DD'),
+ user_type: values.user_type,
+ emp_no: values.emp_no,
+ access_card_no: values.access_card_no,
+ country: values.country,
+ province: values.province,
+ city: values.city,
+ address: values.address,
+ work_addr: values.work_addr,
+ floor: values.floor,
+ inprovince: values.inprovince,
+ // dept_code: values.dept_code,
+ // dept_name: values.dept_name,
+ inner_dept_code: values.inner_dept_code,
+ org_code: values.org_code,
+ org_name: values.org_name,
+ inner_org_code: values.inner_org_code,
+ posts: values.posts ? JSON.parse(values.posts) : [],
+ wx_openid: values.wx_openid,
+ wx_mpopenid: values.wx_mpopenid,
+ wx_miniopenid: values.wx_miniopenid,
+ wx_unionid: values.wx_unionid,
+ mobile_imei: values.mobile_imei,
+ device_num: values.device_num,
+ al_taobao: values.al_taobao,
+ al_alipay: values.al_alipay,
+ al_dingding: values.al_dingding,
+ is_system_user: values.is_system_user,
+ mgr_type: values.mgr_type,
+ pwd_security_level: values.pwd_security_level,
+ pwd_update_date: values.pwd_update_date,
+ last_login_ip: values.last_login_ip,
+ last_login_date: values.last_login_date,
+ freeze_date: values.freeze_date,
+ freeze_cause: values.freeze_cause,
+ zindex: values.zindex,
+ wx_msg: values.wx_msg,
+ email_msg: values.email_msg,
+ system_msg: values.system_msg,
+ remarks: values.remarks,
+ status: values.status,
+ creator: values.creator,
+ create_date: values.create_date,
+ updater: values.updater,
+ update_date: values.update_date
+ })
+ }, [])
+
+ const afterClose = () =>{
+ form.resetFields();
+ }
+
+ const handleJobStatusChange = (value) => {
+ setJobStatus(value)
+ }
+
+ const handleUserStatusChange = (value) => {
+ setUserStatus(value)
+ }
+
+ return (
+ handleViewModalVisible()}
+ onCancel={() => handleViewModalVisible()}
+ afterClose={() => afterClose()}
+ >
+
+
+ )
+}
+
+export default StaffSheetViewForm
diff --git a/src/pages/business_data/models/StaffSheet.js b/src/pages/business_data/models/StaffSheet.js
new file mode 100644
index 0000000..57aa1b8
--- /dev/null
+++ b/src/pages/business_data/models/StaffSheet.js
@@ -0,0 +1,319 @@
+import { deleteByPrimaryKeyForProUser, selectByPrimaryKeyForProUser, insertForProUser, updateForProUser, deleteByMapForProUser,updateByMapForProUser, getOneForProUser,getAllForProUser,queryPageForProUser, countForProUser, insertBatchForProUser, deleteBatchForProUser,updateBatchForProUser, resetPwdForProUser } from '@/services/system/api_prouser';
+
+export default {
+ namespace: 'safemajorha33zard',
+
+ state: {
+ params: {},
+ data: {
+ list: [],
+ pagination: {},
+ },
+ },
+
+ effects: {
+ *delete_by_primarykey_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(deleteByPrimaryKeyForProUser, payload)
+ yield put({
+ type: 'deleteByPrimaryKeyForProUser',
+ payload: response
+ })
+
+ if (!response.success) {
+ callback && callback(response)
+ return
+ }
+
+ const params = yield select(state => state.prouser.params)
+ const responseData = yield call(queryPageForProUser, params)
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responseData
+ })
+
+ if (callback) callback(response)
+ },
+ *select_by_primarykey_for_prouser({ payload, callback }, { call, put }) {
+ const response = yield call(selectByPrimaryKeyForProUser, payload)
+ yield put({
+ type: 'selectByPrimaryKeyForProUser',
+ payload: response
+ })
+
+ if (callback) callback(response)
+ },
+ *insert_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(insertForProUser, payload)
+ yield put({
+ type: 'insertForProUser',
+ payload: response
+ })
+
+ if (!response.success) {
+ callback && callback(response)
+ return
+ }
+
+ const params = yield select(state => state.prouser.params)
+ const responseData = yield call(queryPageForProUser, params)
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responseData
+ })
+
+ if (callback) callback(response)
+ },
+ *update_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(updateForProUser, payload)
+ yield put({
+ type: 'updateForProUser',
+ payload: response
+ })
+
+ if (!response.success) {
+ callback && callback(response)
+ return
+ }
+
+ const params = yield select(state => state.prouser.params)
+ const responseData = yield call(queryPageForProUser, params)
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responseData
+ })
+
+ if (callback) callback(response)
+ },
+ *delete_by_map_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(deleteByMapForProUser, payload);
+ yield put({
+ type: 'deleteByMapForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *update_by_map_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(updateByMapForProUser, payload);
+ yield put({
+ type: 'updateByMapForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *get_one_for_prouser({ payload, callback }, { call, put }) {
+ const response = yield call(getOneForProUser, payload);
+ yield put({
+ type: 'getOneForProUser',
+ payload: response,
+ });
+
+ if (callback) callback(response);
+ },
+ *get_all_for_prouser({ payload, callback }, { call, put }) {
+ const response = yield call(getAllForProUser, payload);
+ yield put({
+ type: 'getAllForProUser',
+ payload: response,
+ });
+
+ if (callback) callback(response);
+ },
+ *query_page_for_prouser({ payload, callback }, { select, call, put }) {
+ const params = yield select(state => state.prouser.params);
+ const newParams = payload?.resetFlag ? payload : {...params, ...payload};
+ yield put({
+ type: 'setQueryPageByParams',
+ payload: newParams,
+ });
+ const response = yield call(queryPageForProUser, newParams);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: response,
+ });
+
+ if (callback) callback(response);
+ },
+ *count_for_prouser({ payload, callback }, { call, put }) {
+ const response = yield call(countForProUser, payload);
+ yield put({
+ type: 'countForProUser',
+ payload: response,
+ });
+
+ if (callback) callback(response);
+ },
+ *insert_batch_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(insertBatchForProUser, payload);
+ yield put({
+ type: 'insertBatchForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *delete_batch_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(deleteBatchForProUser, payload);
+ yield put({
+ type: 'deleteBatchForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *update_batch_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(updateBatchForProUser, payload);
+ yield put({
+ type: 'updateBatchForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *resetpwd_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(resetPwdForProUser, payload);
+ yield put({
+ type: 'resetPwdForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ },
+
+ reducers: {
+ setQueryPageByParams(state, { payload }) {
+ return {
+ ...state,
+ params: {...payload},
+ };
+ },
+ deleteByPrimaryKeyForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ selectByPrimaryKeyForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ insertForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ updateForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ deleteByMapForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ updateByMapForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ getOneForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ getAllForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ queryPageForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ countForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ insertBatchForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ deleteBatchForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ updateBatchForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ resetPwdForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ },
+};
diff --git a/src/pages/business_dataCollection/basic.js b/src/pages/business_dataCollection/basic.js
new file mode 100644
index 0000000..f3905e5
--- /dev/null
+++ b/src/pages/business_dataCollection/basic.js
@@ -0,0 +1,74 @@
+import React, { useState } from 'react';
+import { Card, Row, Col, Statistic, Progress, Button, Space } from 'antd';
+import styles from './basic.less';
+
+import Cjgl from './components/Cjgl';
+import Zdcj from './components/Zdcj';
+import Sglr from './components/Sglr';
+import Sjjy from './components/Sjjy';
+import Cjrz from './components/Cjrz';
+
+
+const SafeMajorHazardList = () => {
+ const [activeModule, setActiveModule] = useState('Cjgl');
+
+ const handleModuleClick = (module) => {
+ setActiveModule(module)
+ }
+
+
+ const renderModule = () => {
+ switch (activeModule) {
+ case 'Cjgl':
+ return ;
+ case 'Zdcj':
+ return ;
+ case 'Sglr':
+ return ;
+ case 'Sjjy':
+ return ;
+ case 'Cjrz':
+ return ;
+ default:
+ return ;
+ }
+ };
+
+
+ return (
+
+
+
+
+
+
+
+
+
+ {renderModule()}
+
+
+ );
+};
+
+export default SafeMajorHazardList;
diff --git a/src/pages/business_dataCollection/basic.less b/src/pages/business_dataCollection/basic.less
new file mode 100644
index 0000000..a06febe
--- /dev/null
+++ b/src/pages/business_dataCollection/basic.less
@@ -0,0 +1,69 @@
+.container {
+ background-color: transparent;
+ width: 100%;
+ height: 89vh;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+
+ .TopButton {
+ background-color: white;
+ width: 100%;
+ padding: 10px 30px;
+ display: flex;
+ gap: 24px;
+ margin-left: 6px;
+
+ .TopButtonItem {
+ 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 {
+ background-color: rgba(72, 81, 255, 1) !important;
+ color: #fff !important;
+ border-radius: 20px !important;
+ padding: 6px 10px 10px !important;
+
+ &::after {
+ content: '';
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ bottom: 3px;
+ width: 16.573974609375px;
+ height: 2.615234375px;
+ background-color: rgba(255, 255, 255, 0.52);
+ border-radius: 15px;
+ opacity: 1;
+ }
+ }
+ }
+ }
+
+ .content {
+ // ======== 内容区域样式 ========
+ flex: 1; // ======== 占据剩余空间 ========
+ overflow-y: auto; // ======== 允许垂直滚动 ========
+ padding: 0; // ======== 无内边距 ========
+ }
+}
diff --git a/src/pages/business_dataCollection/components/Cjgl.js b/src/pages/business_dataCollection/components/Cjgl.js
new file mode 100644
index 0000000..ab8871b
--- /dev/null
+++ b/src/pages/business_dataCollection/components/Cjgl.js
@@ -0,0 +1,443 @@
+import React, { useMemo, useState } from 'react';
+import {
+ Badge,
+ Button,
+ Card,
+ Col,
+ List,
+ Progress,
+ Row,
+ Space,
+ Statistic,
+ Tag,
+ Typography,
+} from 'antd';
+import {
+ CloudSyncOutlined,
+ DatabaseOutlined,
+ ExclamationCircleOutlined,
+ HddOutlined,
+ ReloadOutlined,
+} from '@ant-design/icons';
+import styles from './Cjgl.less';
+
+const { Text } = Typography;
+
+const formatNumber = (value) => {
+ if (value === null || value === undefined) return '--';
+ const str = String(value);
+ return str.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
+};
+
+const buildConicGradient = (segments) => {
+ const total = segments.reduce((sum, s) => sum + (Number(s.value) || 0), 0) || 1;
+ let start = 0;
+ const stops = segments
+ .map((s) => {
+ const ratio = (Number(s.value) || 0) / total;
+ const end = start + ratio;
+ const result = `${s.color} ${Math.round(start * 360)}deg ${Math.round(end * 360)}deg`;
+ start = end;
+ return result;
+ })
+ .join(', ');
+ return `conic-gradient(${stops})`;
+};
+
+const Cjgl = () => {
+ const [activeAnomaly, setActiveAnomaly] = useState('missing');
+
+ const overviewMetrics = useMemo(
+ () => [
+ {
+ key: 'deviceTotal',
+ label: '采集设备',
+ value: 52,
+ suffix: '台',
+ tone: 'primary',
+ icon: ,
+ },
+ {
+ key: 'deviceOnline',
+ label: '在线设备',
+ value: 45,
+ suffix: '台',
+ tone: 'primary',
+ icon: ,
+ },
+ {
+ key: 'todayCount',
+ label: '今日采集量',
+ value: 151235,
+ suffix: '',
+ tone: 'primary',
+ icon: ,
+ },
+ {
+ key: 'manualCount',
+ label: '手工录入',
+ value: 87,
+ suffix: '条',
+ tone: 'primary',
+ icon: ,
+ },
+ {
+ key: 'successRate',
+ label: '采集成功率',
+ value: 68,
+ suffix: '%',
+ tone: 'success',
+ icon: ,
+ },
+ {
+ key: 'storageRate',
+ label: '存储使用率',
+ value: 89,
+ suffix: '%',
+ tone: 'warning',
+ icon: ,
+ },
+ ],
+ [],
+ );
+
+ const realtimeSummary = useMemo(
+ () => [
+ { label: '运行中', value: 52, unit: '台', tone: 'primary' },
+ { label: '设备类型', value: 5, unit: '种', tone: 'primary' },
+ { label: '警告数', value: 3, unit: '条', tone: 'danger' },
+ ],
+ [],
+ );
+
+ const devices = useMemo(
+ () =>
+ new Array(8).fill(0).map((_, idx) => ({
+ id: `SDO292938387-${idx + 1}`,
+ name: `变压器#${(idx % 3) + 1}`, // 仅作演示
+ frequency: '1分钟',
+ lastTime: '2024-06-10 14:29:30',
+ status: idx === 5 ? '异常' : '正常',
+ })),
+ [],
+ );
+
+ const anomalyTypes = useMemo(
+ () => [
+ { key: 'missing', title: '数据缺失', desc: '范围超限', badge: 5 },
+ { key: 'logic', title: '逻辑矛盾', desc: '', badge: 0 },
+ { key: 'time', title: '时间异常', desc: '', badge: 0 },
+ ],
+ [],
+ );
+
+ const anomalyCards = useMemo(
+ () =>
+ new Array(3).fill(0).map((_, idx) => ({
+ id: `anomaly-${activeAnomaly}-${idx}`,
+ deviceName: '变压器#1 (TR-001)',
+ missingTime: '14:20:00 至 14:25:00',
+ duration: '5分钟',
+ frequency: '10秒/次',
+ missingCount: '30条记录',
+ status: idx === 2 ? '待处理' : '已自动恢复',
+ })),
+ [activeAnomaly],
+ );
+
+ const sourceSegments = useMemo(
+ () => [
+ { name: '自动采集', value: 23, color: '#3b82f6' },
+ { name: '手工录入', value: 39, color: '#22c55e' },
+ { name: '手工补录', value: 48, color: '#f59e0b' },
+ ],
+ [],
+ );
+
+ const donutBg = useMemo(() => buildConicGradient(sourceSegments), [sourceSegments]);
+ const updateTime = useMemo(() => '2024-05-10 14:00:00', []);
+
+ return (
+
+
+
+
+
+ 更新时间:{updateTime}
+
+
+
+
+ {overviewMetrics.map((m) => (
+
+
+
+
{m.icon}
+
+
+ {formatNumber(m.value)}
+ {m.suffix}
+
+
{m.label}
+
+
+
+
+ ))}
+
+
+
+
+
+ 实时采集状态}
+ extra={
+ } className={styles.iconBtn} />
+ }
+ >
+
+ {realtimeSummary.map((s) => (
+
+
+ {s.value}
+ {s.unit}
+
+
{s.label}
+
+ ))}
+
+
+
+
(
+
+
+
+
+ {item.name}
+
+ #{item.id}
+
+
+
+
+ 采集频率:
+ {item.frequency}
+
+
+ 最后采集时间:
+ {item.lastTime}
+
+
+
+
+
+ {item.status}
+
+
+
+
+ )}
+ />
+
+
+
+
+
+ 今日数据异常统计}
+ extra={
+
+
+
+
+
+ }
+ >
+
+
+ {anomalyTypes.map((t) => (
+
setActiveAnomaly(t.key)}
+ role="button"
+ tabIndex={0}
+ >
+
+ {t.title}
+ {t.badge ? (
+
+ ) : null}
+
+ {t.desc ?
{t.desc}
: null}
+
+ ))}
+
+
+
+
+ {anomalyCards.map((c) => (
+
+
+
+
+ 设备:{c.deviceName}
+
+
+
+
+
+ 缺失时间:
+ {c.missingTime}
+
+
+ 持续时间:
+ {c.duration}
+
+
+ 采集频率:
+ {c.frequency}
+
+
+ 缺失数据量:
+ {c.missingCount}
+
+
+ 处理状态:
+
+
+ {c.status}
+
+
+
+
+
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+ 数据来源分布}>
+
+
+
+ {sourceSegments.map((s) => (
+
+
+ {s.name}
+ {s.value}%
+
+ ))}
+
+
+
+
+
+
+ 存储空间使用预测}
+ extra={已用总量}
+ >
+
+
+
+
+ 已用总量
+ 54TB
+
+
+
+ 近30天预测
+ 54TB
+
+
+
+ 近60天预测
+ 54TB
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Cjgl;
diff --git a/src/pages/business_dataCollection/components/Cjgl.less b/src/pages/business_dataCollection/components/Cjgl.less
new file mode 100644
index 0000000..c8cdb63
--- /dev/null
+++ b/src/pages/business_dataCollection/components/Cjgl.less
@@ -0,0 +1,603 @@
+.container {
+ padding: 12px;
+ background: linear-gradient(180deg, rgba(241, 248, 255, 1) 0%, rgba(246, 250, 255, 1) 100%);
+ min-height: 100%;
+
+ .overview {
+ background: rgba(255, 255, 255, 0.75);
+ border-radius: 14px;
+ padding: 14px;
+ box-shadow: 0 8px 24px rgba(15, 23, 42, 0.06);
+ backdrop-filter: blur(8px);
+ border: 1px solid rgba(226, 232, 240, 0.7);
+ margin-bottom: 12px;
+
+ .overviewHeader {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 12px;
+
+ .overviewTitle {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+
+ .overviewIcon {
+ width: 44px;
+ height: 44px;
+ border-radius: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: linear-gradient(135deg, rgba(59, 130, 246, 0.16), rgba(99, 102, 241, 0.10));
+ color: #2f66ff;
+ font-size: 20px;
+ }
+
+ .overviewText {
+ .overviewMainTitle {
+ font-size: 16px;
+ font-weight: 700;
+ color: #0f172a;
+ line-height: 20px;
+ }
+
+ .overviewSubTitle {
+ font-size: 12px;
+ color: rgba(15, 23, 42, 0.55);
+ line-height: 16px;
+ margin-top: 2px;
+ }
+ }
+ }
+
+ .overviewTime {
+ font-size: 12px;
+ color: rgba(15, 23, 42, 0.55);
+ }
+ }
+
+ .overviewCards {
+ margin-top: 2px;
+ }
+
+ .metricCard {
+ border-radius: 14px;
+ padding: 12px;
+ background: rgba(255, 255, 255, 0.85);
+ border: 1px solid rgba(226, 232, 240, 0.7);
+ box-shadow: 0 10px 20px rgba(15, 23, 42, 0.05);
+ transition: transform 150ms ease, box-shadow 150ms ease;
+ height: 78px;
+
+ &:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 14px 30px rgba(15, 23, 42, 0.08);
+ }
+
+ .metricInner {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ }
+
+ .metricIcon {
+ width: 38px;
+ height: 38px;
+ border-radius: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 18px;
+ flex: 0 0 auto;
+ }
+
+ .metricContent {
+ flex: 1 1 auto;
+ min-width: 0;
+
+ .metricValue {
+ font-size: 22px;
+ font-weight: 800;
+ letter-spacing: 0.3px;
+ color: #0f172a;
+ line-height: 26px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+
+ .metricSuffix {
+ margin-left: 2px;
+ font-size: 12px;
+ font-weight: 700;
+ color: rgba(15, 23, 42, 0.55);
+ }
+ }
+
+ .metricLabel {
+ margin-top: 4px;
+ font-size: 12px;
+ color: rgba(15, 23, 42, 0.6);
+ }
+ }
+ }
+
+ .metricCard_primary {
+ .metricIcon {
+ background: linear-gradient(135deg, rgba(59, 130, 246, 0.18), rgba(37, 99, 235, 0.10));
+ color: #2563eb;
+ }
+ }
+
+ .metricCard_success {
+ background: linear-gradient(135deg, rgba(34, 197, 94, 0.12), rgba(255, 255, 255, 0.85));
+
+ .metricIcon {
+ background: linear-gradient(135deg, rgba(34, 197, 94, 0.18), rgba(34, 197, 94, 0.08));
+ color: #16a34a;
+ }
+ }
+
+ .metricCard_warning {
+ background: linear-gradient(135deg, rgba(245, 158, 11, 0.12), rgba(255, 255, 255, 0.85));
+
+ .metricIcon {
+ background: linear-gradient(135deg, rgba(245, 158, 11, 0.18), rgba(245, 158, 11, 0.08));
+ color: #d97706;
+ }
+ }
+ }
+
+ .panelCard {
+ border-radius: 14px;
+ overflow: hidden;
+ border: 1px solid rgba(226, 232, 240, 0.7);
+ box-shadow: 0 10px 24px rgba(15, 23, 42, 0.06);
+
+ :global(.ant-card-head) {
+ border-bottom: 1px solid rgba(226, 232, 240, 0.6);
+ background: rgba(255, 255, 255, 0.75);
+ backdrop-filter: blur(8px);
+ }
+
+ :global(.ant-card-body) {
+ background: rgba(255, 255, 255, 0.9);
+ }
+
+ .panelTitle {
+ font-weight: 700;
+ color: #0f172a;
+ }
+
+ .iconBtn {
+ color: rgba(15, 23, 42, 0.55);
+ }
+ }
+
+ .middle {
+ .realtimeSummary {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 10px;
+ margin-bottom: 10px;
+
+ .summaryItem {
+ border-radius: 12px;
+ padding: 12px;
+ border: 1px solid rgba(226, 232, 240, 0.7);
+ background: rgba(248, 250, 252, 0.8);
+
+ .summaryValue {
+ font-size: 22px;
+ font-weight: 800;
+ color: #0f172a;
+ line-height: 26px;
+
+ .summaryUnit {
+ margin-left: 2px;
+ font-size: 12px;
+ color: rgba(15, 23, 42, 0.55);
+ font-weight: 700;
+ }
+ }
+
+ .summaryLabel {
+ margin-top: 4px;
+ font-size: 12px;
+ color: rgba(15, 23, 42, 0.6);
+ }
+ }
+
+ .summaryItem_primary {
+ background: linear-gradient(135deg, rgba(59, 130, 246, 0.10), rgba(248, 250, 252, 0.85));
+ }
+
+ .summaryItem_danger {
+ background: linear-gradient(135deg, rgba(239, 68, 68, 0.10), rgba(248, 250, 252, 0.85));
+
+ .summaryValue {
+ color: #ef4444;
+ }
+ }
+ }
+
+ .deviceListWrap {
+ max-height: 420px;
+ overflow: auto;
+ padding-right: 4px;
+
+ &::-webkit-scrollbar {
+ width: 6px;
+ }
+ &::-webkit-scrollbar-thumb {
+ background: rgba(148, 163, 184, 0.5);
+ border-radius: 8px;
+ }
+ &::-webkit-scrollbar-track {
+ background: transparent;
+ }
+ }
+
+ .deviceList {
+ :global(.ant-list-item) {
+ padding: 10px 0;
+ border-bottom: 1px dashed rgba(226, 232, 240, 0.9);
+ }
+ }
+
+ .deviceItem {
+ .deviceRow {
+ width: 100%;
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 10px;
+ }
+
+ .deviceMain {
+ flex: 1 1 auto;
+ min-width: 0;
+ }
+
+ .deviceTitle {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-bottom: 4px;
+
+ .deviceName {
+ font-weight: 700;
+ color: #0f172a;
+ }
+
+ .deviceId {
+ border-radius: 999px;
+ margin: 0;
+ }
+ }
+
+ .deviceMeta {
+ display: flex;
+ gap: 12px;
+ flex-wrap: wrap;
+ color: rgba(15, 23, 42, 0.72);
+ font-size: 12px;
+ }
+
+ .deviceStatus {
+ flex: 0 0 auto;
+ margin-top: 2px;
+ }
+ }
+
+ .anomalyBody {
+ display: grid;
+ grid-template-columns: 150px 1fr;
+ gap: 12px;
+ min-height: 360px;
+
+ .anomalyTabs {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ }
+
+ .anomalyTab {
+ border-radius: 12px;
+ padding: 12px 12px;
+ border: 1px solid rgba(226, 232, 240, 0.7);
+ background: rgba(248, 250, 252, 0.7);
+ cursor: pointer;
+ transition: background 150ms ease, transform 150ms ease, box-shadow 150ms ease;
+
+ &:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 10px 20px rgba(15, 23, 42, 0.06);
+ }
+
+ .anomalyTabTitleRow {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+ }
+
+ .anomalyTabTitle {
+ font-weight: 800;
+ color: #0f172a;
+ }
+
+ .anomalyTabDesc {
+ margin-top: 6px;
+ font-size: 12px;
+ color: rgba(15, 23, 42, 0.55);
+ }
+
+ .anomalyBadge {
+ :global(.ant-badge-count) {
+ background: #2563eb;
+ }
+ }
+ }
+
+ .anomalyTabActive {
+ background: linear-gradient(135deg, rgba(59, 130, 246, 0.18), rgba(255, 255, 255, 0.7));
+ border-color: rgba(59, 130, 246, 0.25);
+ }
+
+ .anomalyContent {
+ overflow: hidden;
+ }
+
+ .anomalyCards {
+ display: flex;
+ gap: 12px;
+ overflow-x: auto;
+ padding-bottom: 6px;
+
+ &::-webkit-scrollbar {
+ height: 6px;
+ }
+ &::-webkit-scrollbar-thumb {
+ background: rgba(148, 163, 184, 0.5);
+ border-radius: 8px;
+ }
+ &::-webkit-scrollbar-track {
+ background: transparent;
+ }
+ }
+
+ .anomalyCard {
+ min-width: 260px;
+ max-width: 300px;
+ border-radius: 14px;
+ border: 1px solid rgba(226, 232, 240, 0.8);
+ background: rgba(255, 255, 255, 0.9);
+ box-shadow: 0 10px 22px rgba(15, 23, 42, 0.06);
+ overflow: hidden;
+
+ .anomalyCardHeader {
+ padding: 10px 12px;
+ background: linear-gradient(135deg, rgba(59, 130, 246, 0.18), rgba(255, 255, 255, 0.5));
+ border-bottom: 1px solid rgba(226, 232, 240, 0.7);
+
+ .anomalyCardHeaderLeft {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .anomalyCardHeaderIcon {
+ color: #2563eb;
+ }
+
+ .anomalyCardHeaderTitle {
+ font-weight: 700;
+ color: #0f172a;
+ font-size: 12px;
+ }
+ }
+
+ .anomalyCardBody {
+ padding: 10px 12px;
+
+ .anomalyField {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 10px;
+ padding: 6px 0;
+ border-bottom: 1px dashed rgba(226, 232, 240, 0.8);
+
+ &:last-child {
+ border-bottom: none;
+ }
+ }
+
+ .anomalyLabel {
+ color: rgba(15, 23, 42, 0.55);
+ font-size: 12px;
+ white-space: nowrap;
+ }
+
+ .anomalyValue {
+ color: rgba(15, 23, 42, 0.82);
+ font-size: 12px;
+ text-align: right;
+ flex: 1 1 auto;
+ }
+ }
+
+ .anomalyCardFooter {
+ padding: 6px 12px 10px;
+ display: flex;
+ justify-content: center;
+ }
+ }
+ }
+ }
+
+ .bottom {
+ .donutSection {
+ display: grid;
+ grid-template-columns: 220px 1fr;
+ gap: 12px;
+ align-items: center;
+
+ .donut {
+ width: 200px;
+ height: 200px;
+ border-radius: 999px;
+ background: var(--donut-bg);
+ position: relative;
+ margin: 4px 0;
+ box-shadow: inset 0 0 0 10px rgba(255, 255, 255, 0.85);
+
+ &::after {
+ content: '';
+ position: absolute;
+ inset: -10px;
+ border-radius: 999px;
+ background: radial-gradient(circle at 30% 20%, rgba(59, 130, 246, 0.22), transparent 55%),
+ radial-gradient(circle at 70% 80%, rgba(34, 197, 94, 0.18), transparent 55%);
+ filter: blur(10px);
+ z-index: 0;
+ }
+
+ .donutInner {
+ position: absolute;
+ inset: 42px;
+ background: rgba(255, 255, 255, 0.95);
+ border-radius: 999px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid rgba(226, 232, 240, 0.8);
+ z-index: 1;
+
+ .donutCenterTitle {
+ font-size: 12px;
+ color: rgba(15, 23, 42, 0.55);
+ }
+
+ .donutCenterValue {
+ margin-top: 2px;
+ font-size: 18px;
+ font-weight: 800;
+ color: #0f172a;
+ }
+ }
+ }
+
+ .donutLegends {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+
+ .legendItem {
+ display: grid;
+ grid-template-columns: 10px 1fr auto;
+ gap: 10px;
+ align-items: center;
+ padding: 10px;
+ border-radius: 12px;
+ border: 1px solid rgba(226, 232, 240, 0.7);
+ background: rgba(248, 250, 252, 0.7);
+ }
+
+ .legendDot {
+ width: 10px;
+ height: 10px;
+ border-radius: 999px;
+ }
+
+ .legendName {
+ color: rgba(15, 23, 42, 0.75);
+ font-weight: 700;
+ }
+
+ .legendValue {
+ color: rgba(15, 23, 42, 0.85);
+ font-weight: 800;
+ }
+ }
+ }
+
+ .storageSection {
+ display: grid;
+ grid-template-columns: 1fr 220px;
+ gap: 12px;
+ align-items: center;
+
+ .storageLegend {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+
+ .storageLegendItem {
+ display: grid;
+ grid-template-columns: 10px 1fr auto;
+ gap: 10px;
+ align-items: center;
+ padding: 10px;
+ border-radius: 12px;
+ border: 1px solid rgba(226, 232, 240, 0.7);
+ background: rgba(248, 250, 252, 0.7);
+ }
+ }
+
+ .storageRings {
+ position: relative;
+ width: 220px;
+ height: 220px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ .storageRingLayer {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ :global(.ant-progress-text) {
+ font-weight: 900;
+ color: rgba(15, 23, 42, 0.75);
+ }
+ }
+
+ .storageRingLayer_mid {
+ transform: translateY(0);
+ }
+
+ .storageRingLayer_inner {
+ transform: translateY(0);
+ }
+ }
+ }
+ }
+
+ @media (max-width: 992px) {
+ .middle {
+ .anomalyBody {
+ grid-template-columns: 1fr;
+ }
+ }
+
+ .bottom {
+ .donutSection {
+ grid-template-columns: 1fr;
+ justify-items: center;
+ }
+
+ .storageSection {
+ grid-template-columns: 1fr;
+ justify-items: center;
+ }
+ }
+ }
+}
diff --git a/src/pages/business_dataCollection/components/Cjrz.js b/src/pages/business_dataCollection/components/Cjrz.js
new file mode 100644
index 0000000..f81998f
--- /dev/null
+++ b/src/pages/business_dataCollection/components/Cjrz.js
@@ -0,0 +1,325 @@
+import React, { useMemo, useState } from 'react';
+import { Button, Checkbox, DatePicker, message, Popconfirm, Select, Space, Table } from 'antd';
+import {
+ DeleteOutlined,
+ DownloadOutlined,
+ EyeOutlined,
+ PlusOutlined,
+ ReloadOutlined,
+ SearchOutlined,
+ UploadOutlined,
+} from '@ant-design/icons';
+import styles from './Cjrz.less';
+
+const { RangePicker } = DatePicker;
+
+const Cjrz = () => {
+ const [levelAll, setLevelAll] = useState(true);
+ const [levels, setLevels] = useState(['信息', '警告']);
+ const [deviceType, setDeviceType] = useState('全部');
+ const [meterAll, setMeterAll] = useState(true);
+ const [meterTypes, setMeterTypes] = useState(['电表']);
+ const [taskAll, setTaskAll] = useState(true);
+ const [taskTypes, setTaskTypes] = useState(['自动']);
+ const [timeRangePreset, setTimeRangePreset] = useState('本月');
+
+ const [timeRange, setTimeRange] = useState(null);
+
+ const [pagination, setPagination] = useState({ current: 1, pageSize: 10 });
+
+ const levelOptions = useMemo(() => ['信息', '警告', '错误', '严重'], []);
+ const meterOptions = useMemo(() => ['电表', '水表', '燃气表'], []);
+ const taskOptions = useMemo(() => ['自动', '手工'], []);
+
+ const rows = useMemo(
+ () => [
+ {
+ id: 1,
+ time: '2025-11-25 01:07:46',
+ level: '信息',
+ device: '变压器1#',
+ opType: '自动采集',
+ detail: 'xxxxxxxxxxxxxxxxxxxx',
+ },
+ {
+ id: 2,
+ time: '2025-11-29 01:15:57',
+ level: '信息',
+ device: 'SCADA',
+ opType: '自动采集',
+ detail: 'xxxxxxxxxxxxxxxxxxxx',
+ },
+ {
+ id: 3,
+ time: '2025-11-30 02:21:41',
+ level: '信息',
+ device: '燃气表B',
+ opType: '自动采集',
+ detail: 'xxxxxxxxxxxxxxxxxxxx',
+ },
+ {
+ id: 4,
+ time: '2025-12-04 20:10:27',
+ level: '警告',
+ device: '水表A',
+ opType: '手动录入',
+ detail: 'xxxxxxxxxxxxxxxxxxxx',
+ },
+ {
+ id: 5,
+ time: '2025-12-12 04:35:20',
+ level: '警告',
+ device: '数据校验',
+ opType: '手动录入',
+ detail: 'xxxxxxxxxxxxxxxxxxxx',
+ },
+ ],
+ [],
+ );
+
+ const filteredRows = useMemo(() => {
+ return rows
+ .filter((r) => (levelAll ? true : levels.includes(r.level)))
+ .filter((r) => (deviceType === '全部' ? true : r.device.includes(deviceType)))
+ .filter((r) => (meterAll ? true : meterTypes.some((m) => r.device.includes(m))))
+ .filter((r) => (taskAll ? true : taskTypes.some((t) => r.opType.includes(t))));
+ }, [deviceType, levelAll, levels, meterAll, meterTypes, rows, taskAll, taskTypes]);
+
+ const handleQuery = () => message.info('查询');
+ const handleReset = () => {
+ setLevelAll(true);
+ setLevels(['信息', '警告']);
+ setDeviceType('全部');
+ setMeterAll(true);
+ setMeterTypes(['电表']);
+ setTaskAll(true);
+ setTaskTypes(['自动']);
+ setTimeRangePreset('本月');
+ setTimeRange(null);
+ setPagination({ current: 1, pageSize: pagination.pageSize });
+ message.success('已重置');
+ };
+
+ const handleAdd = () => message.info('新增');
+ const handleUpload = () => message.info('上传');
+ const handleBatchDownload = () => message.info('批量下载');
+
+ const handleView = (record) => message.info(`查看:${record.device}`);
+ const handleDelete = (record) => message.success(`已删除:${record.device}`);
+
+ const columns = useMemo(
+ () => [
+ {
+ title: '序号',
+ dataIndex: 'id',
+ key: 'id',
+ width: 70,
+ align: 'center',
+ },
+ {
+ title: '时间',
+ dataIndex: 'time',
+ key: 'time',
+ sorter: (a, b) => String(a.time).localeCompare(String(b.time)),
+ width: 180,
+ },
+ {
+ title: '级别',
+ dataIndex: 'level',
+ key: 'level',
+ width: 90,
+ },
+ {
+ title: '设备',
+ dataIndex: 'device',
+ key: 'device',
+ width: 160,
+ },
+ {
+ title: '操作类型',
+ dataIndex: 'opType',
+ key: 'opType',
+ width: 130,
+ filters: [
+ { text: '自动采集', value: '自动采集' },
+ { text: '手动录入', value: '手动录入' },
+ ],
+ onFilter: (value, record) => String(record.opType).includes(String(value)),
+ },
+ {
+ title: '详情',
+ dataIndex: 'detail',
+ key: 'detail',
+ },
+ {
+ title: '操作',
+ key: 'action',
+ width: 110,
+ align: 'center',
+ render: (_, record) => (
+
+ }
+ onClick={() => handleView(record)}
+ />
+ handleDelete(record)}
+ >
+ }
+ />
+
+
+ ),
+ },
+ ],
+ [],
+ );
+
+ return (
+
+
+
+
+
+
日志级别
+
+ setLevelAll(e.target.checked)}>
+ 全部
+
+ setLevels(next)}
+ />
+
+
+
+
+
+
+
电表
+
+ setMeterAll(e.target.checked)}>
+ 全部
+
+ setMeterTypes(next)}
+ />
+
+
+
+
+
任务状态
+
+ setTaskAll(e.target.checked)}>
+ 全部
+
+ setTaskTypes(next)}
+ />
+
+
+
+
+
+ }
+ className={styles.queryBtn}
+ onClick={handleQuery}
+ >
+ 查询
+
+ } className={styles.resetBtn} onClick={handleReset}>
+ 重置
+
+
+
+
+
+
+ } className={styles.primaryBtn} onClick={handleAdd}>
+ 新增
+
+ } className={styles.ghostBtn} onClick={handleUpload}>
+ 上传
+
+ } className={styles.ghostBtn} onClick={handleBatchDownload}>
+ 批量下载
+
+
+
+
+
+
+
+
+
`共 ${total} 条`,
+ onChange: (current, pageSize) => setPagination({ current, pageSize }),
+ }}
+ />
+
+
+ );
+};
+
+export default Cjrz;
diff --git a/src/pages/business_dataCollection/components/Cjrz.less b/src/pages/business_dataCollection/components/Cjrz.less
new file mode 100644
index 0000000..f48d330
--- /dev/null
+++ b/src/pages/business_dataCollection/components/Cjrz.less
@@ -0,0 +1,277 @@
+.container {
+ width: 100%;
+ height: 100%;
+ min-height: 560px;
+ background: #fff;
+ border-radius: 14px;
+ padding: 14px 16px 16px;
+ margin: 15px 10px;
+ overflow: hidden;
+}
+
+.panel {
+ background: #f6f8fc;
+ border-radius: 12px;
+ padding: 10px 12px;
+}
+
+.rowTop {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 14px;
+}
+
+.filters {
+ flex: 1 1 auto;
+ min-width: 0;
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 10px 22px;
+}
+
+.filterItem {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.filterLabel {
+ font-size: 12px;
+ color: #6b7280;
+ white-space: nowrap;
+}
+
+.checkGroup {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ flex-wrap: wrap;
+
+ :global {
+ .ant-checkbox-wrapper {
+ margin-inline-start: 0 !important;
+ font-size: 12px;
+ color: #4b5563;
+ }
+
+ .ant-checkbox-group {
+ display: inline-flex;
+ align-items: center;
+ gap: 12px;
+ flex-wrap: wrap;
+ }
+ }
+}
+
+.topActions {
+ flex: 0 0 auto;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.rowSecond {
+ margin-top: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+}
+
+.toolbarLeft {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.timeRange {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ flex-wrap: wrap;
+ justify-content: flex-end;
+}
+
+.pillSelect {
+ width: 120px;
+
+ :global {
+ .ant-select-selector {
+ height: 32px !important;
+ border-radius: 999px !important;
+ border-color: #dfe5f2 !important;
+ display: flex !important;
+ align-items: center !important;
+ box-shadow: none !important;
+ background: #fff !important;
+ }
+
+ .ant-select-selection-item {
+ font-size: 12px;
+ color: #111827;
+ }
+ }
+}
+
+.presetSelect {
+ width: 92px;
+
+ :global {
+ .ant-select-selector {
+ height: 32px !important;
+ border-radius: 999px !important;
+ border-color: #dfe5f2 !important;
+ display: flex !important;
+ align-items: center !important;
+ box-shadow: none !important;
+ background: #fff !important;
+ }
+
+ .ant-select-selection-item {
+ font-size: 12px;
+ color: #111827;
+ }
+ }
+}
+
+.pillRange {
+ width: 300px;
+
+ :global {
+ .ant-picker {
+ height: 32px !important;
+ border-radius: 999px !important;
+ border-color: #dfe5f2 !important;
+ box-shadow: none !important;
+ background: #fff !important;
+ }
+
+ .ant-picker-input > input {
+ font-size: 12px;
+ color: #111827;
+ }
+
+ .ant-picker-separator {
+ color: #9ca3af;
+ }
+ }
+}
+
+.queryBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 18px !important;
+ box-shadow: none !important;
+ background: #3b5bfd;
+ border-color: #3b5bfd;
+
+ :global {
+ .ant-btn-icon {
+ margin-right: 6px;
+ }
+ }
+}
+
+.resetBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 18px !important;
+ border: 1px solid #dfe5f2 !important;
+ background: #fff !important;
+ color: #4b5563 !important;
+ box-shadow: none !important;
+
+ :global {
+ .ant-btn-icon {
+ margin-right: 6px;
+ }
+ }
+}
+
+.primaryBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ box-shadow: none !important;
+ background: #3b5bfd;
+ border-color: #3b5bfd;
+
+ :global {
+ .ant-btn-icon {
+ margin-right: 6px;
+ }
+ }
+}
+
+.ghostBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ border: 1px solid #dfe5f2 !important;
+ background: #fff !important;
+ color: #374151 !important;
+ box-shadow: none !important;
+
+ :global {
+ .ant-btn-icon {
+ margin-right: 6px;
+ }
+ }
+}
+
+.tableWrap {
+ width: 100%;
+ margin-top: 12px;
+
+ :global {
+ .ant-table {
+ border-radius: 10px;
+ }
+
+ .ant-table-thead > tr > th {
+ background: #f3f5f9;
+ color: #6b7280;
+ font-weight: 500;
+ height: 44px;
+ }
+
+ .ant-table-tbody > tr > td {
+ color: #111827;
+ height: 48px;
+ }
+
+ .ant-table-tbody > tr:hover > td {
+ background: #f7f9ff;
+ }
+
+ .ant-table-pagination {
+ margin: 14px 0 0;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ }
+
+ .ant-pagination-total-text {
+ color: #6b7280;
+ margin-right: auto;
+ }
+ }
+}
+
+.actionCell {
+ :global {
+ .ant-btn {
+ padding: 0 4px;
+ }
+ }
+}
+
+.actionBtnView {
+ color: #22c55e;
+}
+
+.actionBtnDelete {
+ color: #ef4444;
+}
diff --git a/src/pages/business_dataCollection/components/Sglr.js b/src/pages/business_dataCollection/components/Sglr.js
new file mode 100644
index 0000000..df68398
--- /dev/null
+++ b/src/pages/business_dataCollection/components/Sglr.js
@@ -0,0 +1,318 @@
+import React, { useMemo, useState } from 'react';
+import {
+ Button,
+ Card,
+ Col,
+ DatePicker,
+ Form,
+ Input,
+ InputNumber,
+ Pagination,
+ Radio,
+ Row,
+ Select,
+ Space,
+ Table,
+ Tag,
+ TimePicker,
+ Upload,
+} from 'antd';
+import { CloudUploadOutlined, FileTextOutlined, PlusOutlined } from '@ant-design/icons';
+import styles from './Sglr.less';
+
+const { TextArea } = Input;
+
+const energyTypeOptions = [
+ { label: '电表', value: 'electric' },
+ { label: '燃气表', value: 'gas' },
+ { label: '水表', value: 'water' },
+ { label: '蒸汽表', value: 'steam' },
+ { label: '其他', value: 'other' },
+];
+
+const templateList = [
+ { key: 'tpl-1', title: '电表日常', icon: },
+ { key: 'tpl-2', title: '水表日常', icon: },
+ { key: 'tpl-3', title: '电表日常', icon: },
+ { key: 'tpl-4', title: '电表日常', icon: },
+ { key: 'tpl-5', title: '电表日常', icon: },
+ { key: 'tpl-6', title: '电表日常', icon: },
+ { key: 'tpl-7', title: '电表日常', icon: },
+ { key: 'tpl-8', title: '电表日常', icon: },
+];
+
+const pendingCardsSeed = [
+ {
+ id: 'TR-001',
+ deviceName: '变压器1#',
+ submitTime: '14:20:00',
+ energyType: '天然气',
+ submitter: '张三',
+ status: '待审核',
+ },
+ {
+ id: 'TR-001-2',
+ deviceName: '变压器1#',
+ submitTime: '14:20:00',
+ energyType: '天然气',
+ submitter: '张三',
+ status: '待审核',
+ },
+ {
+ id: 'TR-001-3',
+ deviceName: '变压器1#',
+ submitTime: '14:20:00',
+ energyType: '天然气',
+ submitter: '张三',
+ status: '待审核',
+ },
+];
+
+const todayRowsSeed = Array.from({ length: 10 }).map((_, idx) => ({
+ key: String(idx + 1),
+ time: '14:30:00',
+ device: '水表A',
+ energyType: '水表',
+ reading: 123.5,
+ status: idx === 1 ? '未审核' : '已审核',
+}));
+
+const Sglr = () => {
+ const [form] = Form.useForm();
+ const [todayCount] = useState(15);
+ const [page, setPage] = useState(1);
+ const [pageSize, setPageSize] = useState(10);
+
+ const pendingCards = useMemo(() => pendingCardsSeed, []);
+ const todayRows = useMemo(() => todayRowsSeed, []);
+
+ const tableColumns = useMemo(
+ () => [
+ { title: '时间', dataIndex: 'time', key: 'time', width: 120 },
+ { title: '设备', dataIndex: 'device', key: 'device', width: 160 },
+ { title: '能源类型', dataIndex: 'energyType', key: 'energyType', width: 140 },
+ { title: '读数', dataIndex: 'reading', key: 'reading', width: 120 },
+ {
+ title: '状态',
+ dataIndex: 'status',
+ key: 'status',
+ width: 120,
+ render: (value) =>
+ value === '已审核' ? (
+ 已审核
+ ) : (
+ 未审核
+ ),
+ },
+ ],
+ [],
+ );
+
+ const handleSubmit = async () => {
+ await form.validateFields();
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ } />
+
+
+
+
+
+
+
+
+ false}
+ accept=".doc,.docx,.pdf,.png,.jpg,.jpeg"
+ showUploadList={false}
+ >
+
+
+
+
+
+
支持 word、pdf、png、jpeg、jpg 格式文件
+
+
+
+
+
+
+
+
+
+
+
+
+
日常抄表数据
+
+ {templateList.map((item) => (
+
+
{item.icon}
+
{item.title}
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+ {pendingCards.map((item) => (
+
+
+
+
+ 提交时间:
+ {item.submitTime}
+
+
+ 能源类型:
+ {item.energyType}
+
+
+ 提交人:
+ {item.submitter}
+
+
+ 处理状态:
+
+ {item.status}
+
+
+
+
+
+
+ ))}
+
+
+
+
+
今日录入
+
+ 已录入:{todayCount}条
+
+
+
+
+
+
+
+
{
+ setPage(nextPage);
+ setPageSize(nextSize);
+ }}
+ showSizeChanger
+ size="small"
+ />
+
+
+
+
+
+
+ );
+};
+
+export default Sglr;
diff --git a/src/pages/business_dataCollection/components/Sglr.less b/src/pages/business_dataCollection/components/Sglr.less
new file mode 100644
index 0000000..e67bdc1
--- /dev/null
+++ b/src/pages/business_dataCollection/components/Sglr.less
@@ -0,0 +1,362 @@
+.container {
+ padding: 16px;
+ background: #f6f8fc;
+ min-height: calc(89vh - 0px);
+
+ .grid {
+ height: 100%;
+ }
+
+ .panel {
+ background: #ffffff;
+ border-radius: 14px;
+ box-shadow: 0 6px 18px rgba(12, 24, 52, 0.06);
+ overflow: hidden;
+ }
+
+ .panelHeader {
+ padding: 14px 18px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ border-bottom: 1px solid #eef2f7;
+
+ .panelTitle {
+ font-size: 16px;
+ font-weight: 600;
+ color: #1f2a37;
+ }
+
+ .headerBtn {
+ border-radius: 18px;
+ height: 32px;
+ padding: 0 12px;
+ }
+ }
+
+ .leftBody {
+ display: flex;
+ gap: 14px;
+ padding: 14px;
+
+ .formWrap {
+ flex: 1;
+ min-width: 0;
+ padding-right: 6px;
+
+ .form {
+ :global {
+ .ant-form-item {
+ margin-bottom: 12px;
+ }
+ .ant-radio-group {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ }
+ .ant-radio-button-wrapper {
+ border-radius: 16px;
+ overflow: hidden;
+ }
+ }
+
+ .fullWidth {
+ width: 100%;
+ }
+
+ .valueRow {
+ width: 100%;
+
+ .valueSelect {
+ width: 110px;
+ }
+
+ .valueInput {
+ width: 100%;
+ }
+
+ .addBtn {
+ width: 36px;
+ border-radius: 10px;
+ border-color: #c7d2fe;
+ color: #2f54eb;
+ }
+ }
+
+ .uploader {
+ border-radius: 12px;
+
+ :global {
+ .ant-upload-drag {
+ border-radius: 12px;
+ border: 1px dashed #cbd5e1;
+ background: #fbfcfe;
+ }
+ .ant-upload-drag:hover {
+ border-color: #5b7cff;
+ }
+ }
+
+ .uploadInner {
+ padding: 14px 12px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 8px;
+
+ .uploadIcon {
+ width: 44px;
+ height: 44px;
+ border-radius: 12px;
+ background: rgba(91, 124, 255, 0.12);
+ color: #2f54eb;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 20px;
+ }
+
+ .uploadBtn {
+ border-radius: 18px;
+ height: 30px;
+ padding: 0 14px;
+ }
+
+ .uploadHint {
+ font-size: 12px;
+ color: #94a3b8;
+ line-height: 18px;
+ }
+ }
+ }
+
+ .formActions {
+ display: flex;
+ gap: 10px;
+ padding-top: 6px;
+
+ .primaryAction {
+ border-radius: 18px;
+ height: 34px;
+ padding: 0 22px;
+ background: #4b63ff;
+ }
+
+ .secondaryAction {
+ border-radius: 18px;
+ height: 34px;
+ padding: 0 22px;
+ }
+ }
+ }
+ }
+
+ .templateWrap {
+ width: 200px;
+ border-left: 1px solid #eef2f7;
+ padding-left: 12px;
+
+ .templateTitle {
+ font-size: 13px;
+ font-weight: 600;
+ color: #6b7280;
+ padding: 2px 2px 10px;
+ }
+
+ .templateList {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ max-height: 560px;
+ overflow: auto;
+ padding-right: 6px;
+ }
+
+ .templateItem {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 10px 10px;
+ border-radius: 12px;
+ background: #f7faff;
+ border: 1px solid #eef2f7;
+ cursor: pointer;
+
+ &:hover {
+ border-color: #c7d2fe;
+ background: #f3f6ff;
+ }
+
+ .templateIcon {
+ width: 30px;
+ height: 30px;
+ border-radius: 10px;
+ background: rgba(47, 84, 235, 0.12);
+ color: #2f54eb;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .templateText {
+ font-size: 13px;
+ color: #334155;
+ font-weight: 500;
+ }
+ }
+ }
+ }
+
+ .pendingRow {
+ padding: 14px;
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 12px;
+
+ .pendingCard {
+ border-radius: 14px;
+ background: #f5f9ff;
+ border: 1px solid #cfe0ff;
+ box-shadow: none;
+
+ :global {
+ .ant-card-body {
+ padding: 12px;
+ }
+ }
+
+ .pendingDevice {
+ font-size: 12px;
+ color: #475569;
+
+ .deviceLink {
+ color: #2f54eb;
+ }
+ }
+
+ .pendingMeta {
+ padding-top: 8px;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+
+ .metaLine {
+ font-size: 12px;
+ color: #64748b;
+ display: flex;
+ align-items: center;
+
+ .metaKey {
+ width: 66px;
+ color: #94a3b8;
+ flex: 0 0 auto;
+ }
+
+ .metaVal {
+ color: #475569;
+ }
+
+ .statusDot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: #22c55e;
+ margin-right: 6px;
+ }
+
+ .statusText {
+ color: #16a34a;
+ font-weight: 600;
+ }
+ }
+ }
+
+ .pendingActions {
+ padding-top: 10px;
+ display: flex;
+ justify-content: center;
+
+ .detailBtn {
+ width: 100%;
+ border-radius: 18px;
+ height: 32px;
+ background: #4b63ff;
+ }
+ }
+ }
+ }
+
+ .todaySection {
+ padding: 0 14px 14px;
+
+ .todayHeader {
+ padding: 8px 0 10px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+
+ .todayTitle {
+ font-size: 14px;
+ font-weight: 600;
+ color: #1f2a37;
+ }
+
+ .todayRight {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+
+ .todayCount {
+ color: #64748b;
+ font-size: 12px;
+ }
+
+ .auditBtn {
+ border-radius: 18px;
+ height: 32px;
+ background: #4b63ff;
+ }
+ }
+ }
+
+ .table {
+ :global {
+ .ant-table {
+ border-radius: 12px;
+ overflow: hidden;
+ }
+ .ant-table-thead > tr > th {
+ background: #f2f6ff;
+ color: #475569;
+ font-weight: 600;
+ }
+ }
+ }
+
+ .paginationWrap {
+ padding-top: 10px;
+ display: flex;
+ justify-content: flex-end;
+ }
+ }
+}
+
+@media (max-width: 1200px) {
+ .container {
+ .leftBody {
+ flex-direction: column;
+
+ .templateWrap {
+ width: 100%;
+ border-left: none;
+ border-top: 1px solid #eef2f7;
+ padding-left: 0;
+ padding-top: 12px;
+ }
+ }
+
+ .pendingRow {
+ grid-template-columns: 1fr;
+ }
+ }
+}
diff --git a/src/pages/business_dataCollection/components/Sjjy.js b/src/pages/business_dataCollection/components/Sjjy.js
new file mode 100644
index 0000000..ea1456d
--- /dev/null
+++ b/src/pages/business_dataCollection/components/Sjjy.js
@@ -0,0 +1,290 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import {
+ Button,
+ Divider,
+ Form,
+ Input,
+ InputNumber,
+ Pagination,
+ Radio,
+ Select,
+ Space,
+ Switch,
+ Table,
+ Tabs,
+ Typography,
+ message,
+} from 'antd';
+import { EditOutlined, PlusOutlined } from '@ant-design/icons';
+import styles from './Sjjy.less';
+
+const { TextArea } = Input;
+
+const ruleTypeOptions = [
+ { label: '一致性', value: '一致性' },
+ { label: '完整性', value: '完整性' },
+ { label: '准确性', value: '准确性' },
+ { label: '其他', value: '其他' },
+];
+
+const deviceOptions = [
+ { label: 'Lucy', value: 'Lucy' },
+ { label: '变压器1#', value: '变压器1#' },
+ { label: '水表A', value: '水表A' },
+];
+
+const paramKeyOptions = [
+ { label: '容错率', value: '容错率' },
+ { label: '检查周期', value: '检查周期' },
+ { label: '异常级别', value: '异常级别' },
+];
+
+const seedRules = Array.from({ length: 23 }).map((_, idx) => ({
+ id: idx + 1,
+ name: '电表巡检检查',
+ type: '一致性',
+ enabled: true,
+ lastRun: '2025-10-15 14:30:00',
+}));
+
+const Sjjy = () => {
+ const [activeTab, setActiveTab] = useState('rules');
+ const [editing, setEditing] = useState(false);
+ const [page, setPage] = useState(1);
+ const [pageSize, setPageSize] = useState(8);
+
+ const [selectedRowKeys, setSelectedRowKeys] = useState([]);
+ const [rules, setRules] = useState(() => seedRules);
+ const [activeRuleId, setActiveRuleId] = useState(() => seedRules[0]?.id);
+ const [form] = Form.useForm();
+
+ const activeRule = useMemo(() => rules.find((r) => r.id === activeRuleId) || rules[0], [activeRuleId, rules]);
+
+ const pageData = useMemo(() => {
+ const start = (page - 1) * pageSize;
+ return rules.slice(start, start + pageSize);
+ }, [page, pageSize, rules]);
+
+ useEffect(() => {
+ if (!activeRule) return;
+ form.setFieldsValue({
+ ruleName: activeRule.name,
+ ruleType: activeRule.type,
+ device: 'Lucy',
+ ruleLogic: '内容信息',
+ params: [
+ { key: '容错率', value: 3 },
+ { key: '检查周期', value: 3 },
+ { key: '异常级别', value: 3 },
+ ],
+ autoHandle: 'useLast',
+ notify: 'system',
+ });
+ }, [activeRule, form]);
+
+ const handleAdd = () => message.info('新增');
+ const handleBatchToggle = () => message.info('批量启用/禁用');
+ const handleTemplate = () => message.info('规则模板');
+
+ const columns = useMemo(
+ () => [
+ {
+ title: '规则名称',
+ dataIndex: 'name',
+ key: 'name',
+ width: 220,
+ render: (val) => {val},
+ },
+ {
+ title: '类型',
+ dataIndex: 'type',
+ key: 'type',
+ width: 110,
+ },
+ {
+ title: '状态',
+ dataIndex: 'enabled',
+ key: 'enabled',
+ width: 110,
+ render: (val, record) => (
+ {
+ setRules((prev) => prev.map((r) => (r.id === record.id ? { ...r, enabled: checked } : r)));
+ }}
+ />
+ ),
+ },
+ {
+ title: '最后执行',
+ dataIndex: 'lastRun',
+ key: 'lastRun',
+ width: 180,
+ },
+ ],
+ [],
+ );
+
+ return (
+
+
+
+
+ {activeTab !== 'rules' ? (
+
模块待开发
+ ) : (
+ <>
+
+
+
+ } onClick={handleAdd}>
+ 新增
+
+
+
+
+
+
+ 当前生效规则(条): 12
+
+
+
+
+
setSelectedRowKeys(keys),
+ columnWidth: 44,
+ }}
+ rowClassName={(record) => (record.id === activeRuleId ? styles.rowActive : '')}
+ onRow={(record) => ({
+ onClick: () => setActiveRuleId(record.id),
+ })}
+ />
+
+
+
{
+ setPage(nextPage);
+ if (nextPageSize && nextPageSize !== pageSize) setPageSize(nextPageSize);
+ }}
+ />
+
+
+ >
+ )}
+
+
+
+
+
详情
+
}
+ className={styles.editBtn}
+ onClick={() => setEditing((v) => !v)}
+ >
+ 编辑
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {(fields) => (
+
+ {fields.map((field, index) => (
+
+
{`参数${index + 1}`}
+
+
+
+
+
+
+
+
+
+ ))}
+
+ )}
+
+
+
+
+
异常处理
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Sjjy;
diff --git a/src/pages/business_dataCollection/components/Sjjy.less b/src/pages/business_dataCollection/components/Sjjy.less
new file mode 100644
index 0000000..440321f
--- /dev/null
+++ b/src/pages/business_dataCollection/components/Sjjy.less
@@ -0,0 +1,248 @@
+.container {
+ display: flex;
+ gap: 14px;
+ width: 100%;
+ height: 100%;
+ min-height: 560px;
+ padding: 12px;
+ background: linear-gradient(180deg, rgba(241, 248, 255, 1) 0%, rgba(246, 250, 255, 1) 100%);
+}
+
+.leftPanel {
+ flex: 1.15;
+ min-width: 560px;
+ background: rgba(255, 255, 255, 0.92);
+ border-radius: 14px;
+ border: 1px solid rgba(226, 232, 240, 0.7);
+ box-shadow: 0 10px 24px rgba(15, 23, 42, 0.06);
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
+.rightPanel {
+ flex: 1;
+ min-width: 420px;
+ background: rgba(255, 255, 255, 0.92);
+ border-radius: 14px;
+ border: 1px solid rgba(226, 232, 240, 0.7);
+ box-shadow: 0 10px 24px rgba(15, 23, 42, 0.06);
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
+.topTabs {
+ padding: 6px 14px 0;
+
+ :global {
+ .ant-tabs-nav {
+ margin: 0;
+ }
+
+ .ant-tabs-tab {
+ padding: 12px 2px 10px;
+ font-weight: 600;
+ color: rgba(15, 23, 42, 0.65);
+ }
+
+ .ant-tabs-tab-active {
+ .ant-tabs-tab-btn {
+ color: rgba(15, 23, 42, 0.95);
+ }
+ }
+ }
+}
+
+.placeholder {
+ padding: 18px 16px;
+ color: rgba(15, 23, 42, 0.55);
+}
+
+.leftToolbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 12px 14px 10px;
+}
+
+.leftToolbarLeft {
+ display: flex;
+ align-items: center;
+}
+
+.leftToolbarRight {
+ display: flex;
+ align-items: center;
+}
+
+.counterText {
+ font-size: 12px;
+ color: rgba(15, 23, 42, 0.55);
+}
+
+.primaryBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ box-shadow: none !important;
+ background-color: rgba(72, 81, 255, 1);
+
+ :global {
+ .ant-btn-icon {
+ margin-right: 6px;
+ }
+ }
+}
+
+.ghostBtn {
+ height: 32px !important;
+ border-radius: 999px !important;
+ padding: 0 16px !important;
+ border: 1px solid #e7eaf2 !important;
+ background: #fff !important;
+ color: #5b6070 !important;
+ box-shadow: none !important;
+}
+
+.listWrap {
+ padding: 0 14px 12px;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+.paginationBar {
+ display: flex;
+ justify-content: flex-end;
+ padding: 12px 0 0;
+}
+
+.rowActive {
+ :global {
+ td {
+ background: rgba(72, 81, 255, 0.06) !important;
+ }
+ }
+}
+
+.ruleNameCell {
+ color: rgba(15, 23, 42, 0.9);
+}
+
+:global {
+ .ant-table {
+ border-radius: 10px;
+ overflow: hidden;
+ }
+
+ .ant-table-thead > tr > th {
+ background: #f7f8fb;
+ color: #6d7383;
+ font-weight: 500;
+ }
+
+ .ant-table-tbody > tr > td {
+ color: #2b2f3a;
+ }
+
+ .ant-table-tbody > tr:hover > td {
+ background: #fafbff;
+ }
+}
+
+.rightHeader {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 14px 16px;
+ border-bottom: 1px solid rgba(226, 232, 240, 0.6);
+ background: rgba(255, 255, 255, 0.78);
+ backdrop-filter: blur(8px);
+}
+
+.rightTitle {
+ font-size: 16px;
+ font-weight: 700;
+ color: rgba(15, 23, 42, 0.95);
+}
+
+.editBtn {
+ padding: 0 4px !important;
+}
+
+.detailBody {
+ padding: 12px 16px 16px;
+ overflow: auto;
+}
+
+.detailForm {
+ :global {
+ .ant-form-item {
+ margin-bottom: 14px;
+ }
+
+ .ant-form-item-label > label {
+ color: rgba(15, 23, 42, 0.65);
+ font-weight: 500;
+ }
+
+ .ant-input,
+ .ant-input-affix-wrapper,
+ .ant-select-selector {
+ border-radius: 8px !important;
+ }
+ }
+}
+
+.divider {
+ margin: 8px 0 12px !important;
+}
+
+.sectionTitle {
+ font-size: 13px;
+ font-weight: 700;
+ color: rgba(15, 23, 42, 0.85);
+ margin: 0 0 10px;
+}
+
+.paramList {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.paramRow {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.paramLabel {
+ width: 52px;
+ color: rgba(15, 23, 42, 0.55);
+}
+
+.paramCompact {
+ flex: 1;
+}
+
+.paramSelect {
+ width: 160px;
+}
+
+.paramNumber {
+ width: 90px;
+}
+
+@media (max-width: 1200px) {
+ .container {
+ flex-direction: column;
+ }
+
+ .leftPanel,
+ .rightPanel {
+ min-width: 0;
+ }
+}
diff --git a/src/pages/business_dataCollection/components/Zdcj.js b/src/pages/business_dataCollection/components/Zdcj.js
new file mode 100644
index 0000000..2434e4b
--- /dev/null
+++ b/src/pages/business_dataCollection/components/Zdcj.js
@@ -0,0 +1,272 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import {
+ Button,
+ Card,
+ Checkbox,
+ Form,
+ Input,
+ InputNumber,
+ Radio,
+ Select,
+ Space,
+ Switch,
+ Table,
+ Tabs,
+ Typography,
+} from 'antd';
+import { PlusOutlined } from '@ant-design/icons';
+import styles from './Zdcj.less';
+
+const { Text } = Typography;
+
+const ruleTypeLabel = {
+ consistency: '一致性',
+ completeness: '完整性',
+ accuracy: '准确性',
+ other: '其他',
+};
+
+const Zdcj = () => {
+ const [activeTab, setActiveTab] = useState('rules');
+ const [selectedRowKeys, setSelectedRowKeys] = useState([]);
+ const [selectedRuleId, setSelectedRuleId] = useState('r-4');
+ const [form] = Form.useForm();
+
+ const ruleList = useMemo(
+ () =>
+ new Array(9).fill(0).map((_, idx) => {
+ const id = `r-${idx + 1}`;
+ return {
+ id,
+ name: '电表漏电增值查',
+ type: 'consistency',
+ enabled: idx !== 1,
+ lastRun: '2025-10-15 14:30:00',
+ device: 'Lucy',
+ logic: '内容信息',
+ params: [
+ { key: '告警阈值', value: 3 },
+ { key: '检查周期', value: 3 },
+ { key: '异常级别', value: 3 },
+ ],
+ autoAction: 'lastValid',
+ notify: ['system'],
+ };
+ }),
+ [],
+ );
+
+ const currentRule = useMemo(
+ () => ruleList.find((r) => r.id === selectedRuleId) || ruleList[0],
+ [ruleList, selectedRuleId],
+ );
+
+ useEffect(() => {
+ if (!currentRule) return;
+ form.setFieldsValue({
+ ruleName: currentRule.name,
+ ruleType: currentRule.type,
+ applyDevice: currentRule.device,
+ checkLogic: currentRule.logic,
+ params: currentRule.params,
+ autoAction: currentRule.autoAction,
+ notify: currentRule.notify,
+ });
+ }, [currentRule, form]);
+
+ const columns = useMemo(
+ () => [
+ {
+ title: '规则名称',
+ dataIndex: 'name',
+ key: 'name',
+ ellipsis: true,
+ },
+ {
+ title: '类型',
+ dataIndex: 'type',
+ key: 'type',
+ width: 100,
+ render: (v) => ruleTypeLabel[v] || '--',
+ },
+ {
+ title: '状态',
+ dataIndex: 'enabled',
+ key: 'enabled',
+ width: 90,
+ align: 'center',
+ render: (v) => e?.stopPropagation?.()} />,
+ },
+ {
+ title: '最后执行',
+ dataIndex: 'lastRun',
+ key: 'lastRun',
+ width: 170,
+ },
+ ],
+ [],
+ );
+
+ const leftContent = useMemo(() => {
+ if (activeTab !== 'rules') {
+ return 该功能待接入接口/页面
;
+ }
+
+ return (
+ <>
+
+
+ }>
+ 新增
+
+
+
+
+ 当前生效规则/总计:12
+
+
+
+
setSelectedRowKeys(keys),
+ columnWidth: 44,
+ }}
+ rowClassName={(record) =>
+ record.id === selectedRuleId ? styles.selectedRow : ''
+ }
+ onRow={(record) => ({
+ onClick: () => setSelectedRuleId(record.id),
+ })}
+ />
+
+ >
+ );
+ }, [activeTab, columns, ruleList, selectedRowKeys, selectedRuleId]);
+
+ return (
+
+
+
+
+ }
+ >
+ {leftContent}
+
+
+
+
+
详情}
+ extra={
+
+ }
+ bodyStyle={{ padding: 16 }}
+ >
+
+
+
+
+
+
+ 一致性
+ 完整性
+ 准确性
+ 其他
+
+
+
+
+
+
+
+
+
+
+
+ 参数设置
+ {[0, 1, 2].map((idx) => (
+
+
{`参数${idx + 1}:`}
+
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+ 异常处理
+
+
+ 使用上次有效值
+ 重新设置
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Zdcj;
diff --git a/src/pages/business_dataCollection/components/Zdcj.less b/src/pages/business_dataCollection/components/Zdcj.less
new file mode 100644
index 0000000..e436511
--- /dev/null
+++ b/src/pages/business_dataCollection/components/Zdcj.less
@@ -0,0 +1,3 @@
+.container {
+ padding: 16px;
+}
diff --git a/src/pages/business_dataCollection/form/StaffSheetCreateForm.js b/src/pages/business_dataCollection/form/StaffSheetCreateForm.js
new file mode 100644
index 0000000..6bdce8d
--- /dev/null
+++ b/src/pages/business_dataCollection/form/StaffSheetCreateForm.js
@@ -0,0 +1,271 @@
+import { useState, useEffect } from 'react'
+import { Col, DatePicker, Form, Input, Modal, Row, Select } from 'antd'
+import SelectDeptTree from '@/components/SelectDeptTree'
+import SelectOrganTree from '@/components/SelectOrganTree'
+import datadictionary from '@/utils/dataDictionary'
+import { formatDictOptions, verifyPhone } from '@/utils/globalCommon'
+import { NumberInput } from '@/components/NumberInput'
+import styles from '../StaffSheetList.less'
+import style from '@/global.less'
+import dayjs from 'dayjs'
+import { formatDate } from '@/utils/formatUtils'
+
+const { Item: FormItem } = Form
+const { TextArea } = Input
+const dictData = datadictionary
+
+//新增表单
+let getDeptTreeBySelectTree
+let getOrganTreeBySelectTree
+
+const StaffSheetCreateForm = (props => {
+ const [form] = Form.useForm()
+ const [jobStatus, setJobStatus] = useState('1')
+
+ const {
+ modalVisible,
+ handleAdd,
+ handleModalVisible,
+ loading,
+ dispatch,
+ selectDeptTree,
+ selectOrganTree
+ } = props
+
+ useEffect(() => {
+ form.setFieldsValue({
+ user_type: 'employee',
+ job_status: '1',
+ mgr_type: '0'
+ })
+ }, [])
+
+ const selectedDeptTreeValue = (deptRecord) => {
+ getDeptTreeBySelectTree = deptRecord
+ }
+
+ const selectedOrganTreeValue = (orgRecord) => {
+ getOrganTreeBySelectTree = orgRecord
+ }
+
+ const parentDeptTreeMethod = {
+ dispatch: dispatch,
+ selectDeptTree: selectDeptTree,
+ selectedDeptTreeValue: selectedDeptTreeValue,
+ }
+
+ const parentOrganTreeMethod = {
+ dispatch: dispatch,
+ selectOrganTree: selectOrganTree,
+ selectedOrganTreeValue: selectedOrganTreeValue
+ }
+
+ const okHandle = () => {
+ form.validateFields()
+ .then(fieldsValue => {
+ form.resetFields()
+ fieldsValue.birthday = formatDate(fieldsValue.birthday, 'YYYY-MM-DD')
+ fieldsValue.hiredate = formatDate(fieldsValue.hiredate, 'YYYY-MM-DD')
+ fieldsValue.departure_time = formatDate(fieldsValue.departure_time, 'YYYY-MM-DD')
+ fieldsValue.posts = fieldsValue.posts ? JSON.stringify(fieldsValue.posts) : null
+
+ // if (getDeptTreeBySelectTree) {
+ // fieldsValue.dept_code = getDeptTreeBySelectTree.dept_code
+ // fieldsValue.dept_name = getDeptTreeBySelectTree.title
+ // }
+
+ if (getOrganTreeBySelectTree) {
+ fieldsValue.org_code = getOrganTreeBySelectTree.org_code
+ fieldsValue.org_name = getOrganTreeBySelectTree.title
+ }
+
+ handleAdd(fieldsValue)
+ })
+ .catch(errInfo => {})
+ }
+
+ const afterClose = () =>{
+ form.resetFields();
+ }
+
+ const handleJobStatusChange = (value) => {
+ setJobStatus(value)
+ }
+
+ return (
+ handleModalVisible()}
+ afterClose={() => afterClose()}
+ confirmLoading={loading}
+ >
+
+
+ )
+})
+
+export default StaffSheetCreateForm
diff --git a/src/pages/business_dataCollection/form/StaffSheetRenderAdvancedForm.js b/src/pages/business_dataCollection/form/StaffSheetRenderAdvancedForm.js
new file mode 100644
index 0000000..2625938
--- /dev/null
+++ b/src/pages/business_dataCollection/form/StaffSheetRenderAdvancedForm.js
@@ -0,0 +1,113 @@
+import { useEffect } from 'react'
+import { Button, Col, Form, Input, Row } from 'antd'
+import { UpOutlined, SearchOutlined, RedoOutlined } from '@ant-design/icons'
+import SelectDeptTree from '@/components/SelectDeptTree'
+import SelectOrganTree from '@/components/SelectOrganTree'
+import style from '@/global.less'
+
+const { Item: FormItem } = Form
+let getDeptTreeBySelectTree
+let getOrganTreeBySelectTree
+
+const StaffSheetRenderAdvancedForm = (props) => {
+ const [form] = Form.useForm()
+ const { dispatch, handleSearch, handleFormReset, toggleForm, selectDeptTree, selectOrganTree, params } = props
+
+ useEffect(() => {
+ form.setFieldsValue({
+ user_name: params?.user_name,
+ user_name_cn: params?.user_name_cn,
+ deptname: params?.deptname,
+ orgname: params?.orgname,
+ })
+ }, [params])
+
+ const onFinish = values => {
+ // if (getDeptTreeBySelectTree) {
+ // values.dept_code = getDeptTreeBySelectTree.dept_code
+ // values.deptname = getDeptTreeBySelectTree.title
+ // }
+
+ if (getOrganTreeBySelectTree) {
+ values.org_code = getOrganTreeBySelectTree.org_code
+ values.orgname = getOrganTreeBySelectTree.title
+ }
+
+ handleSearch(values)
+ }
+
+ const myHandleFormReset = () => {
+ form.resetFields()
+ handleFormReset()
+ }
+
+ const selectedDeptTreeValue = (deptRecord) => {
+ getDeptTreeBySelectTree = deptRecord
+ }
+
+ const selectedOrganTreeValue = (orgRecord) => {
+ getOrganTreeBySelectTree = orgRecord
+ }
+
+ const parentDeptTreeMethod = {
+ dispatch: dispatch,
+ selectDeptTree: selectDeptTree,
+ selectedDeptTreeValue: selectedDeptTreeValue
+ }
+
+ const parentOrganTreeMethod = {
+ dispatch: dispatch,
+ selectOrganTree: selectOrganTree,
+ selectedOrganTreeValue: selectedOrganTreeValue
+ }
+
+ return (
+
+ )
+}
+
+export default StaffSheetRenderAdvancedForm
diff --git a/src/pages/business_dataCollection/form/StaffSheetRenderSimpleForm.js b/src/pages/business_dataCollection/form/StaffSheetRenderSimpleForm.js
new file mode 100644
index 0000000..0468e76
--- /dev/null
+++ b/src/pages/business_dataCollection/form/StaffSheetRenderSimpleForm.js
@@ -0,0 +1,81 @@
+import { useEffect } from 'react'
+import {Button, Col, Form, Input, Row, DatePicker, Select} from 'antd'
+import {DownOutlined, RedoOutlined, SearchOutlined} from '@ant-design/icons'
+import style from '@/global.less'
+import dayjs from 'dayjs'
+const { Item: FormItem } = Form
+
+const StaffSheetRenderSimpleForm = (props) => {
+ const [form] = Form.useForm()
+ const { handleSearch, handleFormReset, toggleForm, params } = props
+
+ useEffect(() => {
+ form.setFieldsValue({
+ user_name: params?.user_name,
+ user_name_cn: params?.user_name_cn,
+ })
+ }, [params])
+
+ const onFinish = values => {
+ handleSearch(values)
+ }
+
+ const myHandleFormReset = () => {
+ form.resetFields()
+ handleFormReset()
+ }
+
+ return (
+
+ )
+}
+
+export default StaffSheetRenderSimpleForm
diff --git a/src/pages/business_dataCollection/form/StaffSheetUpdateForm.js b/src/pages/business_dataCollection/form/StaffSheetUpdateForm.js
new file mode 100644
index 0000000..f33d64b
--- /dev/null
+++ b/src/pages/business_dataCollection/form/StaffSheetUpdateForm.js
@@ -0,0 +1,362 @@
+import { useState, useEffect } from 'react'
+import { Col, DatePicker, Form, Input, Modal, Row, Select } from 'antd'
+import SelectOrganTree from '@/components/SelectOrganTree'
+import datadictionary from '@/utils/dataDictionary'
+import { formatDictOptions, verifyPhone } from '@/utils/globalCommon'
+import { NumberInput } from '@/components/NumberInput'
+import styles from '../StaffSheetList.less'
+import style from '@/global.less'
+import dayjs from 'dayjs'
+import { formatDate, formatDateObject } from '@/utils/formatUtils'
+
+const { Item: FormItem } = Form
+const { TextArea } = Input
+const dictData = datadictionary
+
+//新增表单
+let getDeptTreeBySelectTree
+let getOrganTreeBySelectTree
+
+const StaffSheetUpdateForm = (props) => {
+ const [form] = Form.useForm()
+ const [jobStatus, setJobStatus] = useState('1')
+ const [userStatus, setUserStatus] = useState('0')
+
+ const {
+ handleUpdate,
+ updateModalVisible,
+ handleUpdateModalVisible,
+ values,
+ loading,
+ dispatch,
+ selectDeptTree,
+ selectOrganTree
+ } = props
+
+ const selectedDeptTreeValue = (deptRecord) => {
+ getDeptTreeBySelectTree = deptRecord
+ }
+
+ const selectedOrganTreeValue = (orgRecord) => {
+ getOrganTreeBySelectTree = orgRecord
+ }
+
+ const parentDeptTreeMethod = {
+ dispatch: dispatch,
+ selectDeptTree: selectDeptTree,
+ selectedDeptTreeValue: selectedDeptTreeValue,
+ }
+
+ const parentOrganTreeMethod = {
+ dispatch: dispatch,
+ selectOrganTree: selectOrganTree,
+ selectedOrganTreeValue: selectedOrganTreeValue
+ }
+
+ useEffect(() => {
+ setJobStatus(values.job_status)
+ setUserStatus(values.status)
+
+ form.setFieldsValue({
+ user_id: values.user_id,
+ user_name: values.user_name,
+ user_name_cn: values.user_name_cn,
+ user_name_en: values.user_name_en,
+ password: values.password,
+ email: values.email,
+ phone: values.phone,
+ landline: values.landline,
+ sex: values.sex,
+ avatar: values.avatar,
+ sign: values.sign,
+ tags: values.tags,
+ id_card: values.id_card,
+ birthday: formatDateObject(values.birthday, 'YYYY-MM-DD'),
+ job_status: values.job_status,
+ hiredate: formatDateObject(values.hiredate, 'YYYY-MM-DD'),
+ departure_time: formatDateObject(values.departure_time, 'YYYY-MM-DD'),
+ user_type: values.user_type,
+ emp_no: values.emp_no,
+ access_card_no: values.access_card_no,
+ country: values.country,
+ province: values.province,
+ city: values.city,
+ address: values.address,
+ work_addr: values.work_addr,
+ floor: values.floor,
+ inprovince: values.inprovince,
+ // dept_code: values.dept_code,
+ // dept_name: values.dept_name,
+ inner_dept_code: values.inner_dept_code,
+ org_code: values.org_code,
+ org_name: values.org_name,
+ inner_org_code: values.inner_org_code,
+ posts: values.posts ? JSON.parse(values.posts) : [],
+ wx_openid: values.wx_openid,
+ wx_mpopenid: values.wx_mpopenid,
+ wx_miniopenid: values.wx_miniopenid,
+ wx_unionid: values.wx_unionid,
+ mobile_imei: values.mobile_imei,
+ device_num: values.device_num,
+ al_taobao: values.al_taobao,
+ al_alipay: values.al_alipay,
+ al_dingding: values.al_dingding,
+ is_system_user: values.is_system_user,
+ mgr_type: values.mgr_type,
+ pwd_security_level: values.pwd_security_level,
+ pwd_update_date: values.pwd_update_date,
+ last_login_ip: values.last_login_ip,
+ last_login_date: values.last_login_date,
+ freeze_date: values.freeze_date,
+ freeze_cause: values.freeze_cause,
+ zindex: values.zindex,
+ wx_msg: values.wx_msg,
+ email_msg: values.email_msg,
+ system_msg: values.system_msg,
+ remarks: values.remarks,
+ status: values.status,
+ creator: values.creator,
+ create_date: values.create_date,
+ updater: values.updater,
+ update_date: values.update_date
+ })
+ }, [])
+
+ const handleLocalUpdate = () => {
+ form
+ .validateFields()
+ .then(fieldsValue => {
+ const formVals = {...values, ...fieldsValue}
+ formVals.birthday = formatDate(formVals.birthday, 'YYYY-MM-DD')
+ formVals.hiredate = formatDate(formVals.hiredate, 'YYYY-MM-DD')
+ formVals.departure_time = formatDate(formVals.departure_time, 'YYYY-MM-DD')
+ formVals.posts = formVals.posts ? JSON.stringify(formVals.posts) : null
+ formVals.freeze_date = '3' === formVals.status ? formatDate(dayjs().endOf('day'), 'YYYY-MM-DD') : null
+ formVals.freeze_cause = '3' === formVals.status ? formVals.freeze_cause : null
+
+ // if (getDeptTreeBySelectTree) {
+ // formVals.dept_code = getDeptTreeBySelectTree.dept_code
+ // formVals.dept_name = getDeptTreeBySelectTree.title
+ // }
+
+ if (getOrganTreeBySelectTree) {
+ formVals.org_code = getOrganTreeBySelectTree.org_code
+ formVals.org_name = getOrganTreeBySelectTree.title
+ }
+
+ handleUpdate(formVals)
+
+ })
+ .catch(errInfo => {})
+ }
+
+ const afterClose = () =>{
+ form.resetFields();
+ }
+
+ const handleJobStatusChange = (value) => {
+ setJobStatus(value)
+ }
+
+ const handleUserStatusChange = (value) => {
+ setUserStatus(value)
+ }
+
+ return (
+ handleLocalUpdate()}
+ onCancel={() => handleUpdateModalVisible()}
+ afterClose={() => afterClose()}
+ confirmLoading={loading}
+ >
+
+
+ )
+}
+
+export default StaffSheetUpdateForm
diff --git a/src/pages/business_dataCollection/form/StaffSheetViewForm.js b/src/pages/business_dataCollection/form/StaffSheetViewForm.js
new file mode 100644
index 0000000..9acb9c4
--- /dev/null
+++ b/src/pages/business_dataCollection/form/StaffSheetViewForm.js
@@ -0,0 +1,299 @@
+import { useState, useEffect } from 'react'
+import {Col, DatePicker, Form, Input, Modal, Row, Select} from 'antd'
+import datadictionary from '@/utils/dataDictionary'
+import style from "@/global.less";
+import {formatDictOptions, verifyPhone} from "@/utils/globalCommon";
+import {NumberInput} from "@/components/NumberInput";
+import dayjs from "dayjs";
+import SelectOrganTree from "@/components/SelectOrganTree";
+import {formatDateObject} from "@/utils/formatUtils";
+
+const { Item: FormItem } = Form
+const { TextArea } = Input
+const dictData = datadictionary
+
+const StaffSheetViewForm = (props) => {
+ const [form] = Form.useForm()
+ const [jobStatus, setJobStatus] = useState('1')
+ const [userStatus, setUserStatus] = useState('0')
+
+ const { viewModalVisible, handleViewModalVisible, values } = props
+
+ useEffect(() => {
+ setJobStatus(values.job_status)
+ setUserStatus(values.status)
+
+ form.setFieldsValue({
+ user_id: values.user_id,
+ user_name: values.user_name,
+ user_name_cn: values.user_name_cn,
+ user_name_en: values.user_name_en,
+ password: values.password,
+ email: values.email,
+ phone: values.phone,
+ landline: values.landline,
+ sex: values.sex,
+ avatar: values.avatar,
+ sign: values.sign,
+ tags: values.tags,
+ id_card: values.id_card,
+ birthday: formatDateObject(values.birthday, 'YYYY-MM-DD'),
+ job_status: values.job_status,
+ hiredate: formatDateObject(values.hiredate, 'YYYY-MM-DD'),
+ departure_time: formatDateObject(values.departure_time, 'YYYY-MM-DD'),
+ user_type: values.user_type,
+ emp_no: values.emp_no,
+ access_card_no: values.access_card_no,
+ country: values.country,
+ province: values.province,
+ city: values.city,
+ address: values.address,
+ work_addr: values.work_addr,
+ floor: values.floor,
+ inprovince: values.inprovince,
+ // dept_code: values.dept_code,
+ // dept_name: values.dept_name,
+ inner_dept_code: values.inner_dept_code,
+ org_code: values.org_code,
+ org_name: values.org_name,
+ inner_org_code: values.inner_org_code,
+ posts: values.posts ? JSON.parse(values.posts) : [],
+ wx_openid: values.wx_openid,
+ wx_mpopenid: values.wx_mpopenid,
+ wx_miniopenid: values.wx_miniopenid,
+ wx_unionid: values.wx_unionid,
+ mobile_imei: values.mobile_imei,
+ device_num: values.device_num,
+ al_taobao: values.al_taobao,
+ al_alipay: values.al_alipay,
+ al_dingding: values.al_dingding,
+ is_system_user: values.is_system_user,
+ mgr_type: values.mgr_type,
+ pwd_security_level: values.pwd_security_level,
+ pwd_update_date: values.pwd_update_date,
+ last_login_ip: values.last_login_ip,
+ last_login_date: values.last_login_date,
+ freeze_date: values.freeze_date,
+ freeze_cause: values.freeze_cause,
+ zindex: values.zindex,
+ wx_msg: values.wx_msg,
+ email_msg: values.email_msg,
+ system_msg: values.system_msg,
+ remarks: values.remarks,
+ status: values.status,
+ creator: values.creator,
+ create_date: values.create_date,
+ updater: values.updater,
+ update_date: values.update_date
+ })
+ }, [])
+
+ const afterClose = () =>{
+ form.resetFields();
+ }
+
+ const handleJobStatusChange = (value) => {
+ setJobStatus(value)
+ }
+
+ const handleUserStatusChange = (value) => {
+ setUserStatus(value)
+ }
+
+ return (
+ handleViewModalVisible()}
+ onCancel={() => handleViewModalVisible()}
+ afterClose={() => afterClose()}
+ >
+
+
+ )
+}
+
+export default StaffSheetViewForm
diff --git a/src/pages/business_dataCollection/models/StaffSheet.js b/src/pages/business_dataCollection/models/StaffSheet.js
new file mode 100644
index 0000000..80ebb78
--- /dev/null
+++ b/src/pages/business_dataCollection/models/StaffSheet.js
@@ -0,0 +1,319 @@
+import { deleteByPrimaryKeyForProUser, selectByPrimaryKeyForProUser, insertForProUser, updateForProUser, deleteByMapForProUser,updateByMapForProUser, getOneForProUser,getAllForProUser,queryPageForProUser, countForProUser, insertBatchForProUser, deleteBatchForProUser,updateBatchForProUser, resetPwdForProUser } from '@/services/system/api_prouser';
+
+export default {
+ namespace: 'dataCollection',
+
+ state: {
+ params: {},
+ data: {
+ list: [],
+ pagination: {},
+ },
+ },
+
+ effects: {
+ *delete_by_primarykey_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(deleteByPrimaryKeyForProUser, payload)
+ yield put({
+ type: 'deleteByPrimaryKeyForProUser',
+ payload: response
+ })
+
+ if (!response.success) {
+ callback && callback(response)
+ return
+ }
+
+ const params = yield select(state => state.prouser.params)
+ const responseData = yield call(queryPageForProUser, params)
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responseData
+ })
+
+ if (callback) callback(response)
+ },
+ *select_by_primarykey_for_prouser({ payload, callback }, { call, put }) {
+ const response = yield call(selectByPrimaryKeyForProUser, payload)
+ yield put({
+ type: 'selectByPrimaryKeyForProUser',
+ payload: response
+ })
+
+ if (callback) callback(response)
+ },
+ *insert_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(insertForProUser, payload)
+ yield put({
+ type: 'insertForProUser',
+ payload: response
+ })
+
+ if (!response.success) {
+ callback && callback(response)
+ return
+ }
+
+ const params = yield select(state => state.prouser.params)
+ const responseData = yield call(queryPageForProUser, params)
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responseData
+ })
+
+ if (callback) callback(response)
+ },
+ *update_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(updateForProUser, payload)
+ yield put({
+ type: 'updateForProUser',
+ payload: response
+ })
+
+ if (!response.success) {
+ callback && callback(response)
+ return
+ }
+
+ const params = yield select(state => state.prouser.params)
+ const responseData = yield call(queryPageForProUser, params)
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responseData
+ })
+
+ if (callback) callback(response)
+ },
+ *delete_by_map_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(deleteByMapForProUser, payload);
+ yield put({
+ type: 'deleteByMapForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *update_by_map_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(updateByMapForProUser, payload);
+ yield put({
+ type: 'updateByMapForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *get_one_for_prouser({ payload, callback }, { call, put }) {
+ const response = yield call(getOneForProUser, payload);
+ yield put({
+ type: 'getOneForProUser',
+ payload: response,
+ });
+
+ if (callback) callback(response);
+ },
+ *get_all_for_prouser({ payload, callback }, { call, put }) {
+ const response = yield call(getAllForProUser, payload);
+ yield put({
+ type: 'getAllForProUser',
+ payload: response,
+ });
+
+ if (callback) callback(response);
+ },
+ *query_page_for_prouser({ payload, callback }, { select, call, put }) {
+ const params = yield select(state => state.prouser.params);
+ const newParams = payload?.resetFlag ? payload : {...params, ...payload};
+ yield put({
+ type: 'setQueryPageByParams',
+ payload: newParams,
+ });
+ const response = yield call(queryPageForProUser, newParams);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: response,
+ });
+
+ if (callback) callback(response);
+ },
+ *count_for_prouser({ payload, callback }, { call, put }) {
+ const response = yield call(countForProUser, payload);
+ yield put({
+ type: 'countForProUser',
+ payload: response,
+ });
+
+ if (callback) callback(response);
+ },
+ *insert_batch_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(insertBatchForProUser, payload);
+ yield put({
+ type: 'insertBatchForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *delete_batch_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(deleteBatchForProUser, payload);
+ yield put({
+ type: 'deleteBatchForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *update_batch_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(updateBatchForProUser, payload);
+ yield put({
+ type: 'updateBatchForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *resetpwd_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(resetPwdForProUser, payload);
+ yield put({
+ type: 'resetPwdForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ },
+
+ reducers: {
+ setQueryPageByParams(state, { payload }) {
+ return {
+ ...state,
+ params: {...payload},
+ };
+ },
+ deleteByPrimaryKeyForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ selectByPrimaryKeyForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ insertForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ updateForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ deleteByMapForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ updateByMapForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ getOneForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ getAllForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ queryPageForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ countForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ insertBatchForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ deleteBatchForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ updateBatchForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ resetPwdForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ },
+};
diff --git a/src/pages/business_firekeynotearea/FireKeynoteArea.js b/src/pages/business_firekeynotearea/FireKeynoteArea.js
index e4ac73b..682a2c8 100644
--- a/src/pages/business_firekeynotearea/FireKeynoteArea.js
+++ b/src/pages/business_firekeynotearea/FireKeynoteArea.js
@@ -1,56 +1,12 @@
-import React, { useState } from 'react';
-import { Card, Row, Col, Statistic, Progress, Button, Space } from 'antd';
-import styles from './FireKeynoteArea.less';
-import KeypartsBasicInformation from './components/KeypartsBasicInformation'; //重点部位基础信息管理
-import EmergencyPlanAssociation from './components/EmergencyPlanAssociation'; //应急预案关联管理
-import EmergencyDrillRecordAssociation from './components/EmergencyDrillRecordAssociation'; //应急演练记录关联管理
+import React from 'react';
const FireKeynoteArea = () => {
- const [activeModule, setActiveModule] = useState('1');
-
- const handleModuleClick = (module) => {
- setActiveModule(module)
- }
-
-
- const renderModule = () => {
- switch (activeModule) {
- case '1':
- return ;
- case '2':
- return ;
- case '3':
- return ;
- default:
- return ;
- }
- };
-
-
- return (
-
-
-
-
-
-
-
- {renderModule()}
-
-
- );
+ return (
+
+ );
};
export default FireKeynoteArea;
diff --git a/src/pages/business_firewarning/FireWarning.js b/src/pages/business_firewarning/FireWarning.js
index f5201c1..9ba9bf7 100644
--- a/src/pages/business_firewarning/FireWarning.js
+++ b/src/pages/business_firewarning/FireWarning.js
@@ -1,48 +1,12 @@
-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()}
-
-
- );
+import React from 'react';
+
+const FireWarning = () => {
+ return (
+
+ );
};
-export default Firewarning;
+export default FireWarning;
diff --git a/src/pages/business_inspection/basic.js b/src/pages/business_inspection/basic.js
new file mode 100644
index 0000000..dd93403
--- /dev/null
+++ b/src/pages/business_inspection/basic.js
@@ -0,0 +1,69 @@
+import React, { useState } from 'react';
+import { Card, Row, Col, Statistic, Progress, Button, Space } from 'antd';
+import styles from './basic.less';
+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';
+
+
+
+const SafeMajorHazardList = () => {
+ const [activeModule, setActiveModule] = useState('organization');
+
+ const handleModuleClick = (module) => {
+ setActiveModule(module)
+ }
+
+
+ const renderModule = () => {
+ switch (activeModule) {
+ case 'organization':
+ return ;
+ case 'license':
+ return ;
+ case 'equipment':
+ return ;
+ case 'firefighting':
+ return ;
+ case 'other':
+ return ;
+ default:
+ return ;
+ }
+ };
+
+
+ return (
+
+
+
+
+
+
+
+
+ {renderModule()}
+
+
+ );
+};
+
+export default SafeMajorHazardList;
diff --git a/src/pages/business_inspection/basic.less b/src/pages/business_inspection/basic.less
new file mode 100644
index 0000000..b479169
--- /dev/null
+++ b/src/pages/business_inspection/basic.less
@@ -0,0 +1,66 @@
+.container {
+ background-color: transparent;
+ width: 100%;
+ height: 89vh;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+
+ .TopButton {
+ background-color: white;
+ width: 100%;
+ padding: 10px 30px;
+ display: flex;
+ gap: 24px;
+ margin-left: 6px;
+
+ .TopButtonItem {
+ 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;
+ }
+ }
+ }
+ }
+
+ .content {
+ // ======== 内容区域样式 ========
+ flex: 1; // ======== 占据剩余空间 ========
+ overflow-y: auto; // ======== 允许垂直滚动 ========
+ padding: 0; // ======== 无内边距 ========
+ }
+}
\ No newline at end of file
diff --git a/src/pages/business_inspection/components/EvaluationReport.js b/src/pages/business_inspection/components/EvaluationReport.js
new file mode 100644
index 0000000..ce61baa
--- /dev/null
+++ b/src/pages/business_inspection/components/EvaluationReport.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 './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}
使用次数: ${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楼办公区丨维护类型: 季度检查
+
负责人: 张三
+
+
+
+
+
+
SH-XHS-045-D 室内消火栓
+
位置: 2楼东侧走廊丨维护类型: 水压测试
+
负责人: 李四
+
+
+
+
+
+
+
+
+ {/* 进度条区域 */}
+
+
+
月度维护计划
+
+
+
季度维护计划
+
+
+
+
年度维护计划
+
+
+
+ {/* 警告提示框 */}
+
+
+ 本月有5项维护任务即将到期
+
+
+
+
+
+
+
+
+
+ {/* 表格 */}
+
+
+
+ {/* 操作按钮 */}
+
+
+ }
+ />
+
+
+
+
+
+
+
+ {/* 表格 */}
+
+
+ `共 ${total} 条`,
+ }}
+ />
+
+
+
+
+
+ );
+};
+
+export default EvaluationReport;
diff --git a/src/pages/business_inspection/components/EvaluationReport.less b/src/pages/business_inspection/components/EvaluationReport.less
new file mode 100644
index 0000000..e62182a
--- /dev/null
+++ b/src/pages/business_inspection/components/EvaluationReport.less
@@ -0,0 +1,558 @@
+.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;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/pages/business_inspection/components/LicenseManagement.js b/src/pages/business_inspection/components/LicenseManagement.js
new file mode 100644
index 0000000..44bd7a5
--- /dev/null
+++ b/src/pages/business_inspection/components/LicenseManagement.js
@@ -0,0 +1,604 @@
+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 = [
+ { name: '安全生产许可证', value: 35, itemStyle: { color: '#3C7DFF' } },
+ { name: '安全评估报告', value: 25, itemStyle: { color: '#FF8800' } },
+ { name: '安全三同时材料', value: 20, itemStyle: { color: '#FF3E48' } },
+ { name: '施工资质证书', value: 15, itemStyle: { color: '#FFC403' } },
+ { name: '应急预案', value: 10, itemStyle: { color: '#22C55E' } },
+ { name: '其他', value: 5, itemStyle: { color: '#31BCFF' } }
+ ];
+
+ // 初始化图表
+ useEffect(() => {
+ if (chartRef.current) {
+ const chart = echarts.init(chartRef.current);
+
+ const option = {
+ tooltip: {
+ trigger: 'item',
+ formatter: '{a}
{b}: {c} ({d}%)'
+ },
+ legend: {
+ orient: 'horizontal',
+ bottom: 0,
+ left: 'center',
+ itemWidth: 14,
+ itemHeight: 4,
+ itemGap: 10,
+ textStyle: {
+ fontSize: 12,
+ color: '#333',
+ width: 100
+ },
+ formatter: function (name) {
+ return name;
+ },
+ data: (() => {
+ // 找到最长的名称长度
+ const maxLength = Math.max(...chartData.map(item => item.name.length));
+ // 将所有名称填充到相同长度
+ return chartData.map(item => {
+ const paddingLength = maxLength - item.name.length;
+ return item.name + ' '.repeat(paddingLength);
+ });
+ })()
+ },
+ series: [
+ {
+ name: '证件类型分布',
+ type: 'pie',
+ radius: ['20%', '65%'],
+ center: ['50%', '38%'],
+ avoidLabelOverlap: false,
+ itemStyle: {
+ borderRadius: 5,
+ // color:"red",/
+ borderColor: '#fff',
+ borderWidth: 2
+ },
+ label: {
+ show: false,
+ position: 'center'
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: '16',
+ fontWeight: 'bold'
+ }
+ },
+ labelLine: {
+ show: false
+ },
+ data: (() => {
+ // 找到最长的名称长度
+ const maxLength = Math.max(...chartData.map(item => item.name.length));
+ // 将所有名称填充到相同长度
+ return chartData.map(item => ({
+ ...item,
+ name: item.name + ' '.repeat(maxLength - item.name.length)
+ }));
+ })()
+ }
+ ]
+ };
+
+ chart.setOption(option);
+
+ // 响应式处理
+ const handleResize = () => {
+ chart.resize();
+ };
+ window.addEventListener('resize', handleResize);
+
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ chart.dispose();
+ };
+ }
+ }, []);
+
+ // 表格数据
+ const tableData = [
+ {
+ key: '1',
+ no: '01',
+ name: '安全生产许可证',
+ type: '资质证书',
+ id: 'HQ-XF-01-001',
+ authority: '应急管理部',
+ validUntil: '2025-09-10',
+ status: '已过期',
+ statusType: 'error'
+ },
+ {
+ key: '2',
+ no: '02',
+ name: '安全预评估报告',
+ type: '安全三同时',
+ id: 'HQ-XF-02-015',
+ authority: '第三方评估机构',
+ validUntil: '2025-09-10',
+ status: '有效',
+ statusType: 'warning'
+ },
+ {
+ key: '3',
+ no: '03',
+ name: '施工资质证书',
+ type: '资质证书',
+ id: 'HQ-XF-03-007',
+ authority: '3设计院',
+ validUntil: '2025-09-10',
+ status: '有效',
+ statusType: 'success'
+ },
+ {
+ key: '4',
+ no: '04',
+ name: '安全标准化证书',
+ type: '资质证书',
+ id: 'HQ-XF-03-007',
+ authority: '第三方评估机构',
+ 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'
+ }
+ ];
+
+ // 表格列定义
+ const columns = [
+ {
+ title: '编号',
+ dataIndex: 'no',
+ key: 'no',
+ width: 80,
+ },
+ {
+ title: '证照名称',
+ dataIndex: 'name',
+ key: 'name',
+ width: 150,
+ },
+ {
+ title: '类型',
+ dataIndex: 'type',
+ key: 'type',
+ width: 120,
+ },
+ {
+ title: '编号',
+ dataIndex: 'id',
+ key: 'id',
+ width: 150,
+ },
+ {
+ title: '发证机关',
+ dataIndex: 'authority',
+ key: 'authority',
+ width: 150,
+ },
+ {
+ title: '有效期至',
+ dataIndex: 'validUntil',
+ key: 'validUntil',
+ width: 120,
+ },
+ {
+ title: '状态',
+ dataIndex: 'status',
+ key: 'status',
+ width: 120,
+ 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: (text, record) => {
+ const handleEdit = (record) => {
+ console.log('编辑记录:', record);
+ };
+
+ const handleDelete = (record) => {
+ console.log('删除记录:', record);
+ };
+
+ return (
+
+
+
+
+ );
+ }
+ },
+ ];
+
+
+ return (
+
+
+
+
+
+
+
+
+ {/* 上半部分:进度条和百分比 */}
+
+
+ {/* 下半部分:数字统计 */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* 透明块容器 */}
+
+ {/* 四个垂直分布的卡片 */}
+
+
+
安全生产许可证
+
编号: AQXK-2023-0582
+
+
+ 15天后到期
+
+
+
+
+
+
安全评估报告
+
编号: AQPG-2023-0125
+
+
+ 30天后到期
+
+
+
+
+
+
施工资质证书
+
编号: SGZZ-2023-0089
+
+
+ 7天后到期
+
+
+
+
+
+
应急预案
+
编号: YJYA-2023-0045
+
+
+ 4天后到期
+
+
+
+
+
+
+
+
+
+ {/* 证照列表区域 */}
+
+
+
+
+ setSearchValue(e.target.value)}
+ onSearch={(value) => console.log('搜索:', value)}
+ className={styles.searchInput}
+ />
+
+
+
+
+
{ }} // ======== 行选择事件处理函数 ========
+ onChange={() => { }} // ======== 表格变化事件处理函数 ========
+ pagination={{
+ currentPage: 1,
+ pageSize: 5,
+ total: tableData.length,
+ showSizeChanger: false,
+ showQuickJumper: true,
+ showTotal: (total, range) =>
+ `共 ${total} 条`,
+ locale: {
+ jump_to: '前往',
+ page: '页',
+ items_per_page: '条/页',
+ }
+ }}
+ />
+
+
+ );
+};
+
+export default LicenseManagement;
diff --git a/src/pages/business_inspection/components/LicenseManagement.less b/src/pages/business_inspection/components/LicenseManagement.less
new file mode 100644
index 0000000..560fa0e
--- /dev/null
+++ b/src/pages/business_inspection/components/LicenseManagement.less
@@ -0,0 +1,498 @@
+.licenseManagementContainer {
+ height: 90vh;
+
+ .topSectionContainer {
+ padding: 0;
+ margin: 15px 0px 15px 5px;
+ height: 40%;
+ 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: 14px;
+ font-weight: 500;
+ color: #333333;
+ line-height: 18px;
+ }
+ }
+
+ .chartContainer {
+ flex: 1;
+ width: 100%;
+ position: relative;
+
+ .chart {
+ width: 100%;
+ 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;
+ 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: 14px;
+ font-weight: 500;
+ color: #333333;
+ // 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;
+ 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: 14px;
+ 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 {
+ padding: 0;
+ padding: 15px 5px 15px 20px;
+ flex: 1;
+ // display: flex;
+ gap: 15px;
+ background-color: #fff;
+ // align-items: stretch;
+
+ .chartHeader {
+ display: flex;
+ align-items: center;
+ 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;
+ }
+ }
+
+ .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;
+ }
+ }
+ }
+ }
+
+ // 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;
+ }
+
+ :global(.ant-table-tbody > tr > td) {
+ padding: 8px 12px;
+ border-bottom: 1px solid #f0f0f0;
+ text-align: center;
+ color: #666666;
+ }
+
+ :global(.ant-pagination) {
+ margin-top: 16px;
+ 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_inspection/components/OnlineMonitoring.js b/src/pages/business_inspection/components/OnlineMonitoring.js
new file mode 100644
index 0000000..3e4b6b5
--- /dev/null
+++ b/src/pages/business_inspection/components/OnlineMonitoring.js
@@ -0,0 +1,716 @@
+
+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 './OnlineMonitoring.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 OnlineMonitoring = () => {
+ 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 (
+
+
+
+
+
+
+

+
+
+
+
总报警
+
1456
+
+
+ 未处理 6
+
+
+ 处理中 10
+
+
+
+
+
+
+

+
+
+
一级报警
+
357
+
+
+ 未处理 6
+
+
+ 处理中 10
+
+
+
+
+
+
+

+
+
+
二级报警
+
401
+
+
+ 未处理 6
+
+
+ 处理中 10
+
+
+
+
+
+
+

+
+
+
三级报警
+
556
+
+
+ 未处理 6
+
+
+ 处理中 10
+
+
+
+
+
+
+
+
+
+
+
+
+
储罐液化装置区
+
R值: 1765
+
编号:XXXXXXXX
+
+
+
+
+
+
储罐液化装置区
+
R值: 1765
+
编号:XXXXXXXX
+
+
+
+
+
+
储罐液化装置区
+
R值: 1765
+
编号:XXXXXXXX
+
+
+
+
+
+
储罐液化装置区
+
R值: 1765
+
编号:XXXXXXXX
+
+
+
+
+
+ {/* 表格 */}
+
+ {/* 首行 左侧标题左对齐 右侧按钮右对齐 */}
+
+
+
+
+
+
+
+
+
+ {/* 表格 5行10列 带页码 每页5条数据 */}
+
+
+ `共 ${total} 条`,
+ }}
+ scroll={{ x: 1200 }}
+ />
+
+
+
+ );
+};
+
+export default OnlineMonitoring;
\ No newline at end of file
diff --git a/src/pages/business_inspection/components/OnlineMonitoring.less b/src/pages/business_inspection/components/OnlineMonitoring.less
new file mode 100644
index 0000000..283ce83
--- /dev/null
+++ b/src/pages/business_inspection/components/OnlineMonitoring.less
@@ -0,0 +1,919 @@
+.Ocontainer {
+ padding: 8px 6px 0px 6px;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+
+ .OcontainerTop {
+ display: flex;
+
+ height: 50%;
+ margin-bottom: 5px;
+
+ .OcontainerTopLeft {
+ width: 72%;
+ height: 100%;
+ // background-color: pink;
+ margin-right: 10px;
+ // display: flex;
+
+ .OcontainerTopLeftTop {
+ width: 100%;
+ height: 35%;
+ display: flex;
+ gap: 12px;
+
+ .alarmO {
+ flex: 1;
+ height: 100%;
+ background-color: #F4F7FF;
+ border: 1px solid #AED3FF;
+ border-bottom: 0px solid #AED3FF;
+ border-radius: 4px;
+ box-shadow: 0px 2px 31px 0px #5382FE33 inset;
+ display: flex;
+
+ .alarmOLeft {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .alarmORight {
+ flex: 1;
+ width: 35%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ margin-left: 2px;
+ gap: 18px;
+
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-style: Regular;
+ font-size: 12px;
+ line-height: 100%;
+ letter-spacing: 0%;
+ color: #333333;
+
+ .alarmORightText1 {
+ margin-top: 15px;
+ }
+
+
+ .alarmORightText2 {
+ font-weight: 700;
+ font-size: 16px;
+ }
+
+ .alarmORightText3 {
+ display: flex;
+ gap: 22px;
+ }
+
+ }
+
+
+
+ }
+
+ .alarmTw {
+ flex: 1;
+ height: 100%;
+ background-color: #FFF5f4;
+ border: 1px solid #FFC5BC;
+ border-bottom: 0px solid #FFC5BC;
+ border-radius: 4px;
+ box-shadow: 0px 2px 31px 0px #FE5F4C33 inset;
+ display: flex;
+
+ .alarmTwLeft {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .alarmTwRight {
+ flex: 1;
+ width: 35%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ margin-left: 2px;
+ gap: 18px;
+
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-style: Regular;
+ font-size: 12px;
+ line-height: 100%;
+ letter-spacing: 0%;
+ color: #333333;
+
+ .alarmTwRightText1 {
+ margin-top: 15px;
+ }
+
+ .alarmTwRightText2 {
+ font-weight: 700;
+ font-size: 16px;
+ }
+
+ .alarmTwRightText3 {
+ display: flex;
+ gap: 22px;
+ }
+ }
+ }
+
+ .alarmTh {
+ flex: 1;
+ height: 100%;
+ background-color: #FFF7F2;
+ border: 1px solid #FFD9B2;
+ border-bottom: 0px solid #FFD9B2;
+ border-radius: 4px;
+ box-shadow: 0px 2px 31px 0px #FD883C33 inset;
+ display: flex;
+
+ .alarmThLeft {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .alarmThRight {
+ flex: 1;
+ width: 35%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ margin-left: 2px;
+ gap: 18px;
+
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-style: Regular;
+ font-size: 12px;
+ line-height: 100%;
+ letter-spacing: 0%;
+ color: #333333;
+
+ .alarmThRightText1 {
+ margin-top: 15px;
+ }
+
+ .alarmThRightText2 {
+ font-weight: 700;
+ font-size: 16px;
+ }
+
+ .alarmThRightText3 {
+ display: flex;
+ gap: 22px;
+ }
+ }
+ }
+
+ .alarmF {
+ flex: 1;
+ height: 100%;
+ background-color: #EFF9FF;
+ border: 1px solid #89E1FF;
+ border-bottom: 0px solid #89E1FF;
+ border-radius: 4px;
+ box-shadow: 0px 2px 31px 0px #22A4FD33 inset;
+ display: flex;
+
+ .alarmFLeft {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .alarmFRight {
+ flex: 1;
+ width: 35%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ margin-left: 2px;
+ gap: 18px;
+
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-style: Regular;
+ font-size: 12px;
+ line-height: 100%;
+ letter-spacing: 0%;
+ color: #333333;
+
+ .alarmFRightText1 {
+ margin-top: 15px;
+ }
+
+ .alarmFRightText2 {
+ font-weight: 700;
+ font-size: 16px;
+ }
+
+ .alarmFRightText3 {
+ display: flex;
+ gap: 22px;
+ }
+ }
+ }
+ }
+
+ .OcontainerTopLeftBottom {
+ margin-top: 12px;
+ background-color: #fff;
+ width: 100%;
+ height: 60%;
+
+ .OcontainerTopLeftBottomTitle {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ // padding: 8px 15px;
+ padding: 8px 15px 0px 15px;
+
+ .titleLeft {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-family: PingFang SC;
+ font-weight: 500;
+ font-style: Medium;
+ font-size: 14px;
+ line-height: 100%;
+ letter-spacing: 0%;
+
+
+ .titleIcon {
+ width: 3px;
+ height: 16px;
+ background-color: #2E4CD4;
+ }
+ }
+
+ .titleRight {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+
+ font-family: PingFang SC;
+ font-style: Medium;
+ font-size: 13px;
+ line-height: 100%;
+ letter-spacing: 0%;
+
+
+ .selectBox {
+ padding: 4px 8px;
+ border: 1px solid #d9d9d9;
+ border-radius: 4px;
+ background-color: #fff;
+ font-size: 12px;
+ color: #333;
+ outline: none;
+
+ &:focus {
+ border-color: #2E4CD4;
+ }
+ }
+ }
+ }
+
+ .OcontainerTopLeftBottomChart {
+ flex: 1;
+ width: 100%;
+ height: 75%;
+ }
+ }
+ }
+
+ .OcontainerTopRight {
+ flex: 1;
+ height: calc(100% - 3.3px);
+ background-color: #fff;
+ background-image: url('@/assets/safe_majorHazard/online_monitoring/backTopRight.png');
+ background-size: 100% auto;
+ display: flex;
+ flex-direction: column;
+ overflow-y: auto;
+
+ .realTimeDataHeader {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 8px 15px;
+ margin-bottom: 10px;
+
+ .titleLeft {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-family: PingFang SC;
+ font-weight: 500;
+ font-style: Medium;
+ font-size: 14px;
+ line-height: 100%;
+ letter-spacing: 0%;
+
+ .titleIcon {
+ width: 3px;
+ height: 16px;
+ background-color: #2E4CD4;
+ }
+ }
+
+ .totalCount {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 13px;
+ color: #333333;
+ }
+ }
+
+ .dataItem {
+ height: 23%;
+ flex-shrink: 0;
+ border: 1px solid #89E1FF;
+ border-radius: 2px;
+ margin: 0 15px;
+ margin-bottom: 6px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-family: PingFang SC;
+ font-size: 14px;
+ // color: #666;
+ background-color: #EFF9FF;
+
+ &:last-child {
+ // margin-bottom: 1px;
+ }
+ }
+
+ .dataItem1 {
+ height: 25%;
+ flex-shrink: 0;
+ border: 1px solid #89E1FF;
+ border-radius: 4px;
+ margin: 0 15px;
+ margin-bottom: 6px;
+ display: flex;
+ align-items: center;
+ padding: 0px 15px;
+ background-color: #EFF9FF;
+
+ .dataItemLeft {
+ width: 65%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .areaName {
+
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 13px;
+ color: #333333;
+ line-height: 2.2;
+ }
+
+ .rValue {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 14px;
+ color: #666666;
+ line-height: 0.2;
+ }
+
+ .codeNumber {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 12px;
+ color: #666666;
+ }
+ }
+
+ .dataItemRight {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .circleContainer {
+ position: relative;
+ height: 80%;
+ aspect-ratio: 1; // 强制宽高比1:1
+
+ .outerCircle {
+
+ width: 100%;
+ height: 100%;
+ background-color: rgba(51, 176, 253, 0.3);
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .innerCircle {
+ width: 70%;
+ height: 70%;
+ background-color: rgba(4, 128, 251, 0.8);
+ border-radius: 50%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .levelText {
+ font-family: PingFang SC;
+ font-weight: 500;
+ font-size: 11px;
+ color: #FFFFFF;
+ line-height: 1.4;
+ margin-top: -4px;
+ }
+
+ .riskText {
+ font-family: PingFang SC;
+ font-weight: 300;
+ font-size: 8px;
+ color: #FFFFFF;
+ line-height: 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .dataItem2 {
+ height: 25%;
+ flex-shrink: 0;
+ border: 1px solid rgba(255, 197, 188, 1);
+ border-radius: 4px;
+ margin: 0 15px;
+ margin-bottom: 6px;
+ display: flex;
+ align-items: center;
+ padding: 0px 15px;
+ background-color: #fff5f4;
+
+ .dataItemLeft {
+ width: 65%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .areaName {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 13px;
+ color: #333333;
+ line-height: 2.2;
+ }
+
+ .rValue {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 14px;
+ color: #666666;
+ line-height: 0.2;
+ }
+
+ .codeNumber {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 12px;
+ color: #666666;
+ }
+ }
+
+ .dataItemRight {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .circleContainer {
+ position: relative;
+ height: 80%;
+ aspect-ratio: 1;
+
+ .outerCircle {
+ width: 100%;
+ height: 100%;
+ background-color: rgba(254, 214, 209, 1);
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .innerCircle {
+ width: 70%;
+ height: 70%;
+ background-color: rgba(253, 41, 14, 1);
+ border-radius: 50%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .levelText {
+ font-family: PingFang SC;
+ font-weight: 500;
+ font-size: 11px;
+ color: #FFFFFF;
+ line-height: 1.4;
+ margin-top: -4px;
+ }
+
+ .riskText {
+ font-family: PingFang SC;
+ font-weight: 300;
+ font-size: 8px;
+ color: #FFFFFF;
+ line-height: 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .dataItem3 {
+ height: 25%;
+ flex-shrink: 0;
+ border: 1px solid rgba(255, 217, 178, 1);
+ border-radius: 4px;
+ margin: 0 15px;
+ margin-bottom: 6px;
+ display: flex;
+ align-items: center;
+ padding: 0px 15px;
+ background-color: #fef6f1;
+
+ .dataItemLeft {
+ width: 65%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .areaName {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 13px;
+ color: #333333;
+ line-height: 2.2;
+ }
+
+ .rValue {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 14px;
+ color: #666666;
+ line-height: 0.2;
+ }
+
+ .codeNumber {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 12px;
+ color: #666666;
+ }
+ }
+
+ .dataItemRight {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .circleContainer {
+ position: relative;
+ height: 80%;
+ aspect-ratio: 1;
+
+ .outerCircle {
+ width: 100%;
+ height: 100%;
+ background-color: rgba(255, 234, 218, 1);
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .innerCircle {
+ width: 70%;
+ height: 70%;
+ background-color: rgba(252, 103, 18, 1);
+ border-radius: 50%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .levelText {
+ font-family: PingFang SC;
+ font-weight: 500;
+ font-size: 11px;
+ color: #FFFFFF;
+ line-height: 1.4;
+ margin-top: -4px;
+ }
+
+ .riskText {
+ font-family: PingFang SC;
+ font-weight: 300;
+ font-size: 8px;
+ color: #FFFFFF;
+ line-height: 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .dataItem4 {
+ height: 25%;
+ flex-shrink: 0;
+ border: 1px solid #89E1FF;
+ border-radius: 4px;
+ margin: 0 15px;
+ margin-bottom: 6px;
+ display: flex;
+ align-items: center;
+ padding: 0px 15px;
+ background-color: #EFF9FF;
+
+ .dataItemLeft {
+ width: 65%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .areaName {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 13px;
+ color: #333333;
+ line-height: 2.2;
+ }
+
+ .rValue {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 14px;
+ color: #666666;
+ line-height: 0.2;
+ }
+
+ .codeNumber {
+ font-family: PingFang SC;
+ font-weight: 400;
+ font-size: 12px;
+ color: #666666;
+ }
+ }
+
+ .dataItemRight {
+ width: 35%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .circleContainer {
+ position: relative;
+ height: 80%;
+ aspect-ratio: 1;
+
+ .outerCircle {
+ width: 100%;
+ height: 100%;
+ background-color: rgba(51, 176, 253, 0.3);
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .innerCircle {
+ width: 70%;
+ height: 70%;
+ background-color: rgba(4, 128, 251, 0.8);
+ border-radius: 50%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .levelText {
+ font-family: PingFang SC;
+ font-weight: 500;
+ font-size: 11px;
+ color: #FFFFFF;
+ line-height: 1.4;
+ margin-top: -4px;
+ }
+
+ .riskText {
+ font-family: PingFang SC;
+ font-weight: 300;
+ font-size: 8px;
+ color: #FFFFFF;
+ line-height: 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ .OcontainerBottom {
+ background-color: #fff;
+ flex: 1;
+ padding: 8px 15px 5px 15px;
+ display: flex;
+ flex-direction: column;
+
+ .tableHeader {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ // margin-bottom: 15px;
+ padding-bottom: 5px;
+ // border-bottom: 1px solid #f0f0f0;
+
+ .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;
+ gap: 8px;
+
+ // 自定义按钮样式
+ :global(.ant-btn) {
+ background-color: #ffffff !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+
+ &:hover {
+ background-color: #f5f5f5 !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ &:focus {
+ background-color: #ffffff !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ &:active {
+ background-color: #e6e6e6 !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ // 主要按钮样式
+ &.ant-btn-primary {
+ background-color: #ffffff !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+
+ &:hover {
+ background-color: #f5f5f5 !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ &:focus {
+ background-color: #ffffff !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ &:active {
+ background-color: #e6e6e6 !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+ }
+
+ // 危险按钮样式
+ &.ant-btn-dangerous {
+ background-color: #ffffff !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+
+ &:hover {
+ background-color: #f5f5f5 !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ &:focus {
+ background-color: #ffffff !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+
+ &:active {
+ background-color: #e6e6e6 !important;
+ border-color: #DFE4F6 !important;
+ color: #333333 !important;
+ box-shadow: none !important;
+ }
+ }
+
+ // 禁用状态
+ &:disabled {
+ background-color: #f5f5f5 !important;
+ border-color: #d9d9d9 !important;
+ color: #bfbfbf !important;
+ box-shadow: none !important;
+ }
+ }
+ }
+ }
+
+ .tableContainer {
+ flex: 1;
+ overflow: hidden;
+
+ :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;
+ }
+
+ :global(.ant-table-tbody > tr:hover > td) {
+ background-color: #f5f5f5;
+ }
+
+ :global(.ant-pagination) {
+ margin-top: 16px;
+ text-align: right;
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/pages/business_inspection/components/ResponsibilityImplementation.js b/src/pages/business_inspection/components/ResponsibilityImplementation.js
new file mode 100644
index 0000000..5d9624b
--- /dev/null
+++ b/src/pages/business_inspection/components/ResponsibilityImplementation.js
@@ -0,0 +1,581 @@
+
+import React from 'react';
+import { Card, Statistic, Table,Row, Input,Button,Col, Select} from 'antd';
+import { PhoneOutlined, IdcardOutlined, PlusOutlined } from '@ant-design/icons';
+import StandardTable from '@/components/StandardTable';
+import styles from './ResponsibilityImplementation.less';
+
+import upload from '@/assets/business_basic/upload.png';
+import download from '@/assets/business_basic/download.png';
+import import1 from '@/assets/business_basic/import1.png';
+import fire_fighting1 from '@/assets/business_basic/fire_fighting1.png';
+import fire_fighting2 from '@/assets/business_basic/fire_fighting2.png';
+import fire_fighting3 from '@/assets/business_basic/fire_fighting3.png';
+import frameIcon from '@/assets/business_basic/Frame.png';
+import background1 from '@/assets/business_basic/background1.png';
+import export1 from '@/assets/business_basic/export1.png';
+
+
+
+const ResponsibilityImplementation = () => {
+
+ // 搜索处理函数
+ const onSearch = (value) => {
+ console.log('搜索内容:', value);
+ // 这里可以添加实际的搜索逻辑
+ };
+
+ const columns = [
+ {
+ title:"编号",
+ dataIndex:"id",
+ key:"id",
+ width:80,
+ },
+ {
+ title:"组织代码",
+ dataIndex:"orgCode",
+ key:"orgCode",
+ width:120,
+ },
+ {
+ title:"组织类型",
+ dataIndex:"orgType",
+ key:"orgType",
+ width:120,
+ },
+ {
+ title:"负责人",
+ dataIndex:"manager",
+ key:"manager",
+ width:100,
+ },
+ {
+ title:"所属部门",
+ dataIndex:"department",
+ key:"department",
+ width:120,
+ },
+ {
+ title:"创建时间",
+ dataIndex:"createTime",
+ key:"createTime",
+ width:120,
+ },
+ {
+ title:"人员规模",
+ dataIndex:"staffCount",
+ key:"staffCount",
+ width:100,
+ },
+ {
+ title:"状态",
+ dataIndex:"status",
+ key:"status",
+ width:80,
+ 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'
+ };
+ }
+ return {};
+ };
+
+ return (
+
+ {text}
+
+ );
+ }
+ },
+ {
+ title:"操作",
+ dataIndex:"action",
+ key:"action",
+ width:120,
+ render: (text, record) => {
+ const handleEdit = (record) => {
+ console.log('编辑记录:', record);
+ };
+
+ const handleDelete = (record) => {
+ console.log('删除记录:', record);
+ };
+
+ return (
+
+
+
+
+ );
+ }
+ }
+ ];
+
+ // 固定的假数据
+ const tableData = [
+ {
+ key: '1',
+ id: '01',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-19 14:32:15',
+ staffCount: '15人',
+ status: '正常'
+ },
+ {
+ key: '2',
+ id: '02',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-18 09:25:43',
+ staffCount: '20人',
+ status: '正常'
+ },
+ {
+ key: '3',
+ id: '03',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-17 16:48:22',
+ staffCount: '25人',
+ status: '信息不全'
+ },
+ {
+ key: '4',
+ id: '04',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-16 11:15:37',
+ staffCount: '18人',
+ status: '正常'
+ },
+ {
+ key: '5',
+ id: '05',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-15 08:42:56',
+ staffCount: '22人',
+ status: '正常'
+ },
+ {
+ key: '6',
+ id: '06',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-14 13:27:18',
+ staffCount: '16人',
+ status: '信息不全'
+ },
+ {
+ key: '7',
+ id: '07',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-13 15:33:29',
+ staffCount: '19人',
+ status: '正常'
+ },
+ {
+ key: '8',
+ id: '08',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-12 10:56:44',
+ staffCount: '21人',
+ status: '正常'
+ },
+ {
+ key: '9',
+ id: '09',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-11 17:19:52',
+ staffCount: '17人',
+ status: '信息不全'
+ },
+ {
+ key: '10',
+ id: '10',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-10 12:41:07',
+ staffCount: '23人',
+ status: '正常'
+ },
+ {
+ key: '11',
+ id: '11',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-09 14:08:33',
+ staffCount: '24人',
+ status: '正常'
+ },
+ {
+ key: '12',
+ id: '12',
+ orgCode: 'DH002',
+ orgType: '义务消防队',
+ manager: '张明',
+ department: '安全管理部',
+ createTime: '2024-12-08 16:52:14',
+ staffCount: '26人',
+ status: '信息不全'
+ }
+ ];
+
+ return (
+
+ {/* 警告提示框 */}
+
+

+
+ 有5个消防设备需要维护,3个资质证书即将到期,请及时处理。
+
+
+
+
+
+
+ {/* 第一行:标题和按钮 */}
+
+
+
+
+
+
+
+
+ {/* 第二行:图片占位 */}
+
+
+
+
+
+ {/* 第一行:标题 + 搜索栏 + 下拉选择框 */}
+
+
+ {/* 第二行:三个小块 */}
+
+
+
+
+
+ {/* 第一个块:姓名和单位 */}
+
+
+ {/* 第二个块:电话 */}
+
+
+ {/* 第三个块:身份证 */}
+
+
+ 1304************10
+
+
+ {/* 第四个块:职位标签 */}
+
+
+ {/* 第五个块:证书状态 */}
+
+
+ {/* 第六个块:操作按钮 */}
+
+
+
+
+
+
+
+ {/* 第一个块:姓名和单位 */}
+
+ 李小明
+ 消防支队
+
+
+ {/* 第二个块:电话 */}
+
+
+ {/* 第三个块:身份证 */}
+
+
+ 1304************20
+
+
+ {/* 第四个块:职位标签 */}
+
+
+ {/* 第五个块:证书状态 */}
+
+
+ {/* 第六个块:操作按钮 */}
+
+
+
+
+
+
+
+ {/* 第一个块:姓名和单位 */}
+
+ 王小红
+ 消防中队
+
+
+ {/* 第二个块:电话 */}
+
+
+ {/* 第三个块:身份证 */}
+
+
+ 1304************30
+
+
+ {/* 第四个块:职位标签 */}
+
+
+ {/* 第五个块:证书状态 */}
+
+
+ {/* 第六个块:操作按钮 */}
+
+
+
+
+
+
+
+
+
+
+ {/* 第一块:标题 */}
+
+
+ {/* 第二个大块:搜索和按钮 */}
+
+
+
+
+
+
+
+
+
+
+
+ {/* 第三个大块:表格 */}
+
+ {}} // ======== 行选择事件处理函数 ========
+ onChange={() => {}} // ======== 表格变化事件处理函数 ========
+ pagination={{
+ currentPage: 1,
+ pageSize: 5,
+ total: tableData.length,
+ showSizeChanger: false,
+ showQuickJumper: true,
+ showTotal: (total, range) =>
+ `共 ${total} 条`,
+ locale: {
+ jump_to: '前往',
+ page: '页',
+ items_per_page: '条/页',
+ }
+ }}
+ />
+
+
+
+ );
+};
+export default ResponsibilityImplementation;
diff --git a/src/pages/business_inspection/components/ResponsibilityImplementation.less b/src/pages/business_inspection/components/ResponsibilityImplementation.less
new file mode 100644
index 0000000..d94eca3
--- /dev/null
+++ b/src/pages/business_inspection/components/ResponsibilityImplementation.less
@@ -0,0 +1,1000 @@
+.XcontainerR {
+ padding: 8px 6px;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+
+ .warningBox {
+ width: 100%;
+ background-color: #FFF3CD;
+ border: 1px solid #F4E3AE;
+ border-radius: 4px;
+ padding: 8px 20px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-bottom: 10px;
+
+ .warningIcon {
+ width: 18px;
+ height: 18px;
+ }
+
+ .warningText {
+ color: #8C6C0B;
+ font-size: 12px;
+ line-height: 1.4;
+ }
+ }
+
+ .containerOne {
+ height: 40%;
+ flex-shrink: 0;
+ display: flex;
+ margin-bottom: 10px;
+ gap: 10px;
+
+ .containerOneLeft {
+ background-color: white;
+ width: calc(50% - 5px);
+ display: flex;
+ flex-direction: column;
+ padding: 5px 15px;
+ border: 1px solid #f0f0f0;
+ border-radius: 4px;
+
+ .leftTopSection {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ // margin-bottom: 15px;
+
+ .titleLeft {
+ 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;
+ }
+ }
+
+ .buttonGroup {
+ display: flex;
+ gap: 8px;
+
+ .actionBtn {
+ 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;
+
+ &:hover {
+ background-color: #F0F2FF;
+ border-color: #2E4CD4;
+ }
+
+ .btnIcon {
+ width: 12px;
+ height: 12px;
+ }
+ }
+ }
+ }
+
+ .leftBottomSection {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ .imagePlaceholder {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ .imageIcon1 {
+ transform: scale(0.9) translateY(-5px); // 稍微向上移动
+ object-fit: contain;
+ }
+
+
+ .imageRow {
+ display: flex;
+ justify-content: space-between;
+ // width: 100%;
+ margin-bottom: 10px;
+ // padding-bottom: 20px;
+ // gap: 12px;
+
+ .imageIcon2 {
+ height: 55%;
+ transform: scale(0.7) translateY(-25%) translateX(20%); // 稍微向上移动
+ object-fit: contain;
+ background-color: #EFF5FE;
+ // padding-bottom: 20px;
+ }
+
+ .imageIcon3 {
+ height: 40%;
+ transform: scale(0.65) translateY(-32%) translateX(4%); // 向上移动10px
+ object-fit: contain;
+ padding-bottom: 20px;
+ // background-color: #EFF5FE;
+
+ }
+ }
+
+ .imageText {
+ font-size: 12px;
+ font-weight: 400;
+ }
+ }
+ }
+ }
+
+ .containerOneRight {
+ background-color: white;
+ width: calc(50% - 5px);
+ display: flex;
+ flex-direction: column;
+ padding: 5px 15px;
+ border: 1px solid #f0f0f0;
+ border-radius: 4px;
+
+ .rightTopSection {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 10px;
+
+ .rightTopLeft {
+ display: flex;
+ align-items: center;
+
+ .titleLeft {
+ 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;
+ }
+ }
+ }
+
+ .rightTopRight {
+ .searchGroup {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+
+ .searchInput {
+ width: 200px;
+ height: 32px;
+
+ :global(.ant-input) {
+ height: 32px;
+ border-radius: 4px;
+ border: 1px solid #d9d9d9;
+ font-size: 14px;
+
+ &:focus {
+ border-color: #2E4CD4;
+ box-shadow: 0 0 0 2px rgba(46, 76, 212, 0.2);
+ }
+ }
+
+ :global(.ant-input-suffix) {
+ color: #999999;
+ font-size: 14px;
+ }
+ }
+
+ .organizationSelect {
+ width: 120px;
+ height: 32px;
+
+ :global(.ant-select-selector) {
+ height: 32px !important;
+ border-radius: 4px !important;
+ border: 1px solid #d9d9d9 !important;
+
+ &:hover {
+ border-color: #2E4CD4 !important;
+ }
+
+ &:focus {
+ border-color: #2E4CD4 !important;
+ box-shadow: 0 0 0 2px rgba(46, 76, 212, 0.2) !important;
+ }
+ }
+
+ :global(.ant-select-selection-item) {
+ line-height: 30px !important;
+ font-size: 14px !important;
+ }
+ }
+ }
+ }
+ }
+
+ .rightBottomSection {
+ flex: 1;
+ padding: 5px 15px;
+ width: 100%;
+ height: 100%;
+
+ .threeBlocksContainer {
+ display: flex;
+ gap: 20px;
+ width: 100%;
+ height: 100%;
+
+ .blockItem {
+ width: 100%;
+ height: 100%;
+ flex: 1;
+ display: flex;
+ justify-content: center;
+ background: url('@/assets/business_basic/background1.png') no-repeat center center;
+ background-size: 100% auto;
+
+ .blockContent {
+ // background-color: pink;
+ font-size: 12px;
+ color: #666666;
+ font-weight: 400;
+ width: 100%;
+ height: 100%;
+ }
+
+ // 新的6个横向块样式
+ .backgroundContainer {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .infoBlock {
+ width: 100%;
+ display: flex;
+ justify-content: flex-start;
+ white-space: nowrap;
+
+ .nameText {
+ font-size: 12px;
+ font-weight: 500;
+ color: #333333;
+ margin-left: 10px;
+ margin-right: 10px;
+ margin-top: 15px;
+ }
+
+
+ .unitText {
+ font-size: 10px;
+ font-weight: 400;
+ color: #666666;
+ margin-top: 18px;
+ }
+
+ .infoIcon {
+ font-size: 10px;
+ color: #666666;
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+
+ .infoText {
+ font-size: 10px;
+ font-weight: 400;
+ color: #666666;
+
+ }
+
+ }
+
+ .tagContainer {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+ }
+
+ .tagBlue1 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ margin-left: 10px;
+ }
+
+ .tagBlue2 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+
+ }
+
+ .tagBlue3 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ margin-left: 10px;
+
+ }
+
+ .tagYellow {
+ background-color: #FFF8E2;
+ color: #FFC403;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ }
+
+ .actionBlock {
+ width: 100%;
+ height: 50%;
+ background-color: #BDD6FDCC;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .buttonContainer {
+ display: flex;
+ gap: 15px;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+
+ .editBtn {
+ height: 80%;
+ background-color: #1269FF;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 400;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 2px 15px;
+
+ &:hover {
+ background-color: #0f5ae0;
+ }
+ }
+
+ .deleteBtn {
+ height: 80%;
+ background-color: #FF5F60;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 400;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 2px 15px;
+
+ &:hover {
+ background-color: #ff4a4b;
+ }
+ }
+ }
+
+
+ }
+
+ // 第二个块的样式
+ .backgroundContainer2 {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .infoBlock2 {
+ width: 100%;
+ display: flex;
+ justify-content: flex-start;
+ white-space: nowrap;
+
+ .nameText2 {
+ font-size: 12px;
+ font-weight: 500;
+ color: #333333;
+ margin-left: 10px;
+ margin-right: 10px;
+ margin-top: 15px;
+ }
+
+ .unitText2 {
+ font-size: 10px;
+ font-weight: 400;
+ color: #666666;
+ margin-top: 18px;
+ }
+
+ .infoIcon2 {
+ font-size: 10px;
+ color: #666666;
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+
+ .infoText2 {
+ font-size: 10px;
+ font-weight: 400;
+ color: #666666;
+ }
+ }
+
+ .tagContainer2 {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+ }
+
+ .tagBlue4 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ margin-left: 10px;
+ }
+
+ .tagBlue5 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ }
+
+ .tagBlue6 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ margin-left: 10px;
+ }
+
+ .tagGreen {
+ background-color: #E8F5E8;
+ color: #52C41A;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ }
+
+ .actionBlock2 {
+ width: 100%;
+ height: 50%;
+ background-color: #BDD6FDCC;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .buttonContainer2 {
+ display: flex;
+ gap: 15px;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+
+ .editBtn2 {
+ height: 80%;
+ background-color: #1269FF;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 400;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 2px 15px;
+
+ &:hover {
+ background-color: #0f5ae0;
+ }
+ }
+
+ .deleteBtn2 {
+ height: 80%;
+ background-color: #FF5F60;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 400;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 2px 15px;
+
+ &:hover {
+ background-color: #ff4a4b;
+ }
+ }
+ }
+ }
+
+ // 第三个块的样式
+ .backgroundContainer3 {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .infoBlock3 {
+ width: 100%;
+ display: flex;
+ justify-content: flex-start;
+ white-space: nowrap;
+
+ .nameText3 {
+ font-size: 12px;
+ font-weight: 500;
+ color: #333333;
+ margin-left: 10px;
+ margin-right: 10px;
+ margin-top: 15px;
+ }
+
+ .unitText3 {
+ font-size: 10px;
+ font-weight: 400;
+ color: #666666;
+ margin-top: 18px;
+ }
+
+ .infoIcon3 {
+ font-size: 10px;
+ color: #666666;
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+
+ .infoText3 {
+ font-size: 10px;
+ font-weight: 400;
+ color: #666666;
+ }
+ }
+
+ .tagContainer3 {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+ }
+
+ .tagBlue7 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ margin-left: 10px;
+ }
+
+ .tagBlue8 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ }
+
+ .tagBlue9 {
+ background-color: #D5E5FF;
+ color: #1269FF;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ margin-left: 10px;
+ }
+
+ .tagOrange {
+ background-color: #FFF2E8;
+ color: #FF7A00;
+ font-size: 10px;
+ font-weight: 400;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ }
+
+ .actionBlock3 {
+ width: 100%;
+ height: 50%;
+ background-color: #BDD6FDCC;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .buttonContainer3 {
+ display: flex;
+ gap: 15px;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+
+ .editBtn3 {
+ height: 80%;
+ background-color: #1269FF;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 400;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 2px 15px;
+
+ &:hover {
+ background-color: #0f5ae0;
+ }
+ }
+
+ .deleteBtn3 {
+ height: 80%;
+ background-color: #FF5F60;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 400;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 2px 15px;
+
+ &:hover {
+ background-color: #ff4a4b;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .containerTwo {
+ flex: 1;
+ background-color: white;
+ display: flex;
+ flex-direction: column;
+ padding: 5px 15px;
+ border: 1px solid #f0f0f0;
+ border-radius: 4px;
+
+ .containerTwoTitle {
+ margin-top: 5px;
+ margin-bottom: 15px;
+
+ .titleLeft {
+ 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;
+ }
+ }
+ }
+
+ .containerTwoActions {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 15px;
+ padding: 0px 20px;
+
+ .searchSection {
+ flex: 1;
+ max-width: 300px;
+
+ :global(.ant-input) {
+ height: 32px;
+ border-radius: 4px 0px 0px 4px;
+ border: 1px solid #d9d9d9;
+
+ &:focus {
+ border-color: #2E4CD4;
+ box-shadow: 0 0 0 2px rgba(46, 76, 212, 0.2);
+ }
+ }
+ }
+
+ .buttonSection {
+ display: flex;
+ gap: 8px;
+
+ :global(.ant-btn) {
+ height: 28px;
+ padding: 0 16px;
+ border-radius: 4px;
+ font-size: 14px;
+ border: 1px solid #d9d9d9;
+ background-color: #fff;
+ color: #333;
+
+ &:hover {
+ border-color: #2E4CD4;
+ color: #2E4CD4;
+ }
+
+ &:focus {
+ border-color: #2E4CD4;
+ color: #2E4CD4;
+ }
+ }
+
+ .addBtn {
+ 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;
+
+ &:hover {
+ background-color: #F0F2FF;
+ border-color: #2E4CD4;
+ }
+
+ .addIcon {
+ width: 12px;
+ height: 12px;
+ font-size: 12px;
+ }
+ }
+
+ .importBtn {
+ 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;
+
+ &:hover {
+ background-color: #F0F2FF;
+ border-color: #2E4CD4;
+ }
+
+ .importIcon {
+ width: 12px;
+ height: 12px;
+ }
+ }
+
+ .exportBtn {
+ 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;
+
+ &:hover {
+ background-color: #F0F2FF;
+ border-color: #2E4CD4;
+ }
+
+ .exportIcon {
+ width: 12px;
+ height: 12px;
+ }
+ }
+ }
+ }
+
+ .containerTwoTable {
+ flex: 1;
+ overflow: hidden;
+ padding: 0px 20px;
+
+ :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;
+ }
+
+ :global(.ant-table-tbody > tr > td) {
+ padding: 8px 12px;
+ border-bottom: 1px solid #f0f0f0;
+ text-align: center;
+ color: #666666;
+ // color: pink;
+ }
+
+ :global(.ant-table-tbody > tr:hover > td) {
+ // background-color: #f5f5f5;
+ }
+
+ :global(.ant-pagination) {
+ margin-top: 16px;
+ text-align: right;
+ }
+ }
+ }
+}
+
+
+.rightTopSelect {
+
+ // 下拉框本身的样式
+ :global(.ant-select-selector) {
+ background-color: #f8f9fa !important;
+ border: 1px solid #d9d9d9 !important;
+ border-radius: 6px !important;
+ height: 32px !important;
+ min-height: 32px !important;
+
+ &:hover {
+ border-color: #2E4CD4 !important;
+ }
+
+ &:focus {
+ border-color: #2E4CD4 !important;
+ box-shadow: 0 0 0 2px rgba(46, 76, 212, 0.2) !important;
+ }
+ }
+
+ // 下拉框内的文字样式
+ :global(.ant-select-selection-item) {
+ color: #333333 !important;
+ font-size: 14px !important;
+ font-weight: 500 !important;
+ line-height: 30px !important;
+ }
+
+ // 下拉箭头样式
+ :global(.ant-select-arrow) {
+ color: #666666 !important;
+ font-size: 12px !important;
+ }
+
+ // 下拉菜单容器样式
+ :global(.ant-select-dropdown) {
+ background-color: #ffffff !important;
+ border: 1px solid #e8e8e8 !important;
+ border-radius: 8px !important;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
+ padding: 4px 0 !important;
+ }
+
+ // 下拉选项样式
+ :global(.ant-select-item) {
+ color: #333333 !important;
+ font-size: 14px !important;
+ padding: 8px 12px !important;
+ border-radius: 4px !important;
+ margin: 2px 8px !important;
+
+ &:hover {
+ background-color: #f0f2ff !important;
+ color: #2E4CD4 !important;
+ }
+
+ &.ant-select-item-option-selected {
+ background-color: #e6f7ff !important;
+ color: #2E4CD4 !important;
+ font-weight: 600 !important;
+ }
+ }
+
+ // 选中状态的样式
+ :global(.ant-select-focused .ant-select-selector) {
+ border-color: #2E4CD4 !important;
+ box-shadow: 0 0 0 2px rgba(46, 76, 212, 0.2) !important;
+ }
+}
+
+// 自定义选项样式
+.customOption {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 4px 0;
+
+ .optionIcon {
+ font-size: 16px;
+ color: #2E4CD4;
+ }
+
+ .optionText {
+ font-size: 14px;
+ color: #333333;
+ font-weight: 500;
+ }
+}
+
diff --git a/src/pages/business_inspection/components/RiskAssessment.js b/src/pages/business_inspection/components/RiskAssessment.js
new file mode 100644
index 0000000..46d5b50
--- /dev/null
+++ b/src/pages/business_inspection/components/RiskAssessment.js
@@ -0,0 +1,865 @@
+
+import React, { useEffect, useRef, useState } from 'react';
+import { Card, Result, Select, Button, Segmented } from 'antd';
+import { CheckCircleOutlined, ExportOutlined } from '@ant-design/icons';
+import * as echarts from 'echarts';
+import StandardTable from '@/components/StandardTable';
+import styles from './RiskAssessment.less';
+// import './RiskAssessment.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 RiskAssessment = () => {
+ 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: 5,
+ total: 0,
+ });
+
+ // 饼图初始化
+ useEffect(() => {
+ if (pieChartRef.current) {
+ const pieChart = echarts.init(pieChartRef.current);
+
+ const pieOption = {
+ color: ['#44BB5F', '#F8C541', '#A493FB', '#4B69F1', '#949FD0'],
+ legend: {
+ orient: 'vertical',
+ right: '10%',
+ top: 'center',
+ itemWidth: 8,
+ itemHeight: 8,
+ textStyle: {
+ fontSize: 12,
+ color: '#333'
+ }
+ },
+ series: [{
+ name: '设备状态',
+ type: 'pie',
+ radius: ['40%', '70%'],
+ center: ['35%', '50%'],
+ avoidLabelOverlap: false,
+ label: {
+ show: false,
+ position: 'center'
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: '14',
+ fontWeight: 'bold'
+ }
+ },
+ labelLine: {
+ show: false
+ },
+ data: [
+ { value: 480, name: '正常' },
+ { value: 289, name: '故障' },
+ { value: 200, name: '维修中' },
+ { value: 150, name: '待验收' },
+ { value: 161, name: '停用' }
+ ]
+ }]
+ };
+
+ pieChart.setOption(pieOption);
+
+ // 响应式调整
+ const handlePieResize = () => {
+ if (pieChart && !pieChart.isDisposed()) {
+ pieChart.resize();
+ }
+ };
+
+ window.addEventListener('resize', handlePieResize);
+
+ return () => {
+ window.removeEventListener('resize', handlePieResize);
+ if (pieChart && !pieChart.isDisposed()) {
+ pieChart.dispose();
+ }
+ };
+ }
+ }, []);
+
+ // 故障类型饼图初始化
+ useEffect(() => {
+ if (faultPieChartRef.current) {
+ const faultPieChart = echarts.init(faultPieChartRef.current);
+
+ const faultPieOption = {
+ color: ['#FF3E48', '#FF8800', '#FFC403'],
+ legend: {
+ orient: 'vertical',
+ right: '10%',
+ top: 'center',
+ itemWidth: 8,
+ itemHeight: 8,
+ textStyle: {
+ fontSize: 12,
+ color: '#333'
+ }
+ },
+ series: [{
+ name: '设备故障类型',
+ type: 'pie',
+ radius: '70%',
+ center: ['35%', '50%'],
+ avoidLabelOverlap: false,
+ label: {
+ show: true,
+ position: 'outside',
+ formatter: '{b}: {c}',
+ fontSize: 12
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: '14',
+ fontWeight: 'bold'
+ }
+ },
+ labelLine: {
+ show: true
+ },
+ data: [
+ { value: 120, name: '紧急' },
+ { value: 80, name: '重要' },
+ { value: 60, name: '一般' }
+ ]
+ }]
+ };
+
+ faultPieChart.setOption(faultPieOption);
+
+ // 响应式调整
+ const handleFaultPieResize = () => {
+ if (faultPieChart && !faultPieChart.isDisposed()) {
+ faultPieChart.resize();
+ }
+ };
+
+ window.addEventListener('resize', handleFaultPieResize);
+
+ return () => {
+ window.removeEventListener('resize', handleFaultPieResize);
+ if (faultPieChart && !faultPieChart.isDisposed()) {
+ faultPieChart.dispose();
+ }
+ };
+ }
+ }, []);
+
+ useEffect(() => {
+ if (chartRef.current) {
+ const chart = echarts.init(chartRef.current);
+
+ // 强制初始化时调整大小
+ setTimeout(() => {
+ if (chart && !chart.isDisposed()) {
+ chart.resize();
+ }
+ }, 100);
+
+ const option = {
+ color: ['#8979FF', '#3CC3DF'],
+
+ legend: {
+ // data: ['消防水泵1', '消防水泵2'],
+ top: "-3px",
+ // left: "center",
+ // itemGap: 40,
+ itemWidth: 20,
+ itemHeight: 8,
+ // icon: 'path://M902 472.7H747.9c-19.1-113.3-117.7-200-236.4-200s-217.3 86.7-236.4 200H119.7c-4.4 0-8 3.6-8 8v64c0 4.4 3.6 8 8 8h155.5c19.1 113.3 117.7 200 236.4 200S728.9 666 748 552.7h154c4.4 0 8-3.6 8-8v-64c0-4.4-3.6-8-8-8z m-390.5 200c-88.2 0-160-71.8-160-160s71.8-160 160-160 160 71.8 160 160-71.8 160-160 160z',
+ textStyle: {
+ fontSize: 10
+ }
+ },
+ grid: {
+ left: '2%',
+ right: '4%',
+ bottom: '2%',
+ top: '12%',
+ containLabel: true
+ },
+ xAxis: {
+ type: 'category',
+ boundaryGap: false,
+ data: ['9:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00'],
+ axisLabel: {
+ fontSize: 10
+ }
+ },
+ yAxis: {
+ type: 'value',
+ min: 0,
+ max: 30,
+ axisLabel: {
+ formatter: '{value}',
+ fontSize: 10
+ }
+ },
+ series: [
+ {
+ name: '消防水泵1',
+ type: 'line',
+ smooth: false,
+ lineStyle: {
+ width: 2,
+ color: '#8979FF'
+ },
+ areaStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ { offset: 0, color: 'rgba(137, 121, 255, 0.3)' },
+ { offset: 1, color: 'rgba(137, 121, 255, 0.05)' }
+ ]
+ }
+ },
+ symbol: 'circle',
+ symbolSize: 4,
+ itemStyle: {
+ color: '#fff',
+ borderColor: '#8979FF',
+ borderWidth: 1
+ },
+ data: [12, 15, 18, 14, 16, 20, 22, 19, 17, 21, 23, 25]
+ },
+ {
+ name: '消防水泵2',
+ type: 'line',
+ smooth: false,
+ lineStyle: {
+ width: 2,
+ color: '#3CC3DF'
+ },
+ areaStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [
+ { offset: 0, color: 'rgba(60, 195, 223, 0.3)' },
+ { offset: 1, color: 'rgba(60, 195, 223, 0.05)' }
+ ]
+ }
+ },
+ symbol: 'circle',
+ symbolSize: 4,
+ itemStyle: {
+ color: '#fff',
+ borderColor: '#3CC3DF',
+ borderWidth: 1
+ },
+ data: [8, 11, 14, 10, 13, 17, 19, 16, 14, 18, 20, 22]
+ }
+ ]
+ };
+
+ chart.setOption(option);
+
+ // 响应式调整 - 使用多种方式监听容器尺寸变化
+ let resizeTimer = null;
+ const handleResize = () => {
+ // 防抖处理,避免频繁调用resize
+ if (resizeTimer) {
+ clearTimeout(resizeTimer);
+ }
+ resizeTimer = setTimeout(() => {
+ if (chart && !chart.isDisposed()) {
+ chart.resize();
+ }
+ }, 50); // 减少延迟时间
+ };
+
+ // 监听窗口大小变化
+ window.addEventListener('resize', handleResize);
+
+ // 监听容器尺寸变化(解决菜单栏伸缩时的自适应问题)
+ let resizeObserver = null;
+ if (window.ResizeObserver) {
+ resizeObserver = new ResizeObserver((entries) => {
+ for (let entry of entries) {
+ // 使用requestAnimationFrame确保在下一帧执行
+ requestAnimationFrame(() => {
+ handleResize();
+ });
+ }
+ });
+ resizeObserver.observe(chartRef.current);
+ }
+
+ // 额外监听父容器的尺寸变化
+ const parentContainer = chartRef.current?.parentElement;
+ let parentObserver = null;
+ if (parentContainer && window.ResizeObserver) {
+ parentObserver = new ResizeObserver((entries) => {
+ for (let entry of entries) {
+ requestAnimationFrame(() => {
+ handleResize();
+ });
+ }
+ });
+ parentObserver.observe(parentContainer);
+ }
+
+ // 使用MutationObserver监听DOM结构变化(菜单展开收起时)
+ const mutationObserver = new MutationObserver((mutations) => {
+ mutations.forEach((mutation) => {
+ if (mutation.type === 'attributes' &&
+ (mutation.attributeName === 'class' || mutation.attributeName === 'style')) {
+ // 延迟执行,确保DOM更新完成
+ setTimeout(() => {
+ handleResize();
+ }, 200);
+ }
+ });
+ });
+
+ // 监听整个页面的class和style变化
+ mutationObserver.observe(document.body, {
+ attributes: true,
+ attributeFilter: ['class', 'style'],
+ subtree: true
+ });
+
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ if (resizeObserver) {
+ resizeObserver.disconnect();
+ }
+ if (parentObserver) {
+ parentObserver.disconnect();
+ }
+ if (mutationObserver) {
+ mutationObserver.disconnect();
+ }
+ if (resizeTimer) {
+ clearTimeout(resizeTimer);
+ }
+ if (chart && !chart.isDisposed()) {
+ chart.dispose();
+ }
+ };
+ }
+ }, []);
+
+ // 表格列定义
+ const columns = [
+ {
+ title: '编号',
+ dataIndex: 'id',
+ key: 'id',
+ width: 60,
+ 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: 'deviceId',
+ key: 'deviceId',
+ width: 140,
+ },
+ {
+ title: '设备名称',
+ dataIndex: 'deviceName',
+ key: 'deviceName',
+ width: 110,
+ },
+ {
+ title: '型号规格',
+ dataIndex: 'modelSpec',
+ key: 'modelSpec',
+ width: 140,
+ },
+ {
+ title: '安装位置',
+ dataIndex: 'installLocation',
+ key: 'installLocation',
+ width: 200,
+ },
+ {
+ title: '状态',
+ dataIndex: 'status',
+ key: 'status',
+ width: 80,
+ render: (text) => {
+ const statusMap = {
+ '故障': { color: '#FF4D4F', bg: '#FFF2F0' },
+ '预警': { color: '#FAAD14', bg: '#FFF3E9' },
+ '正常': { 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: 'XBD5.0/30-125',
+ installLocation: '总部大楼1层大厅',
+ status: '故障',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '2',
+ id: '002',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼3层 东区',
+ status: '预警',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '3',
+ id: '003',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '正常',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '4',
+ id: '004',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '故障',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '5',
+ id: '005',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '正常',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '6',
+ id: '006',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '预警',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '7',
+ id: '007',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '故障',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '8',
+ id: '008',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '正常',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '9',
+ id: '009',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '预警',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '10',
+ id: '010',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '故障',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '11',
+ id: '011',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '正常',
+ lastMaintenance: '2025-09-10',
+ },
+ {
+ key: '12',
+ id: '012',
+ deviceId: 'HQ-XF-01-001',
+ deviceName: '消防水泵',
+ modelSpec: 'XBD5.0/30-125',
+ installLocation: '总部大楼地下一层',
+ status: '预警',
+ lastMaintenance: '2025-09-10',
+ },
+ ];
+
+ // 初始化数据
+ 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,
+ }));
+ };
+
+ return (
+
+ {/* 第一个div - 高度20% */}
+
+
+
+ {/* 块1 */}
+
+
+
+

+
+
+
+ {/* 块2 */}
+
+
+
+

+
+
+
+ {/* 块3 */}
+
+
+
+

+
+
+
+ {/* 块4 */}
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
{
+ console.log(value);
+ }}
+ />
+
+ {/* 设备状态饼图 */}
+
+
+
+
+
+
+
+
+ {/* 设备故障类型饼图 */}
+
+
+
+
+
+
+
+
+
+
+ {/* 第三个div - 占满剩余位置 */}
+
+
+
+ {/* 第一行块 - 蓝色方块加标题 */}
+
+
+
+
+
+
灭火器压力不足
+
2号楼3层 丨 15分钟前
+
+
+
+
+
+
烟雾探测器电池低电量
+
1号楼5层 丨 1小时前
+
+
+
+
+
+
消防栓维护到期
+
3号楼1层 丨 2小时前
+
+
+
+
+
+
应急照明故障
+
地下停车场 丨 3小时前
+
+
+
+
+
+
+
+ {/* 表格 */}
+
+
+
+
+
+
+
+
+
+ {/* 表格 */}
+
+
+ `共 ${total} 条`,
+ }}
+ // scroll={{ x: 1200 }}
+ />
+
+
+
+
+
+ );
+};
+
+export default RiskAssessment;
\ No newline at end of file
diff --git a/src/pages/business_inspection/components/RiskAssessment.less b/src/pages/business_inspection/components/RiskAssessment.less
new file mode 100644
index 0000000..db5b47e
--- /dev/null
+++ b/src/pages/business_inspection/components/RiskAssessment.less
@@ -0,0 +1,594 @@
+.Rcontainer {
+ padding: 8px 6px 0px 6px;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+
+ // 第一个div - 高度20%
+ .RcontainerTop {
+ height: 16%;
+ // background-color: #fff;
+ border-radius: 4px;
+ display: flex;
+ flex-direction: column;
+
+ .sectionContent {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ // padding: 15px;
+
+ .blocksContainer {
+ flex: 1;
+ display: flex;
+ gap: 10px;
+ height: 100%;
+
+ .blockItem {
+ flex: 1;
+ height: 100%;
+ display: flex;
+ background: linear-gradient(170.5deg, #F5F7FF 6.87%, #FFFFFF 47.65%);
+ border-radius: 4px;
+ border: 2px solid #FFFFFF;
+
+ .blockLeft {
+ width: 60%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ padding: 15px;
+ padding-left: 20px;
+ gap: 8px;
+
+ .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;
+ }
+
+ .checkIcon {
+ font-size: 16px;
+ color: #1269FF;
+ }
+ }
+ }
+
+ .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;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // 第二个div - 高度39%
+ .RcontainerMiddle {
+ height: 33%;
+ border-radius: 4px;
+ display: flex;
+ flex-direction: column;
+
+ .sectionContent {
+ height: 100%;
+ display: flex;
+ display: flex;
+ gap: 10px;
+ height: 100%;
+
+
+
+ .middleBlock1 {
+ // flex: 1;
+ width: 28%;
+ height: 100%;
+ background: #fff;
+
+ border: 2px solid #fff;
+ // border-radius: 4px;
+ position: relative;
+ padding: 0px 10px 10px 2px;
+ font-family: PingFang SC;
+ font-size: 14px;
+ color: #333333;
+
+ .block1Header {
+ position: absolute;
+ top: 5px;
+ left: 10px;
+ right: 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ z-index: 10;
+
+ .block1Title {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-weight: 500;
+ font-size: 14px;
+ color: #333333;
+
+ .titleIcon {
+ width: 3px;
+ height: 14px;
+ background-color: #2E4CD4;
+ }
+ }
+
+ .block1Segmented {
+ padding: 0;
+ margin: 0;
+ border: 1px solid #E3E3E3;
+ border-radius: 4px;
+ height: 28px;
+
+ :global(.ant-segmented) {
+ padding: 0;
+ margin: 0;
+ height: 28px;
+ }
+
+ :global(.ant-segmented-item) {
+ font-size: 12px;
+ padding: 2px 8px;
+ height: 26px;
+ line-height: 26px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ :global(.ant-segmented-item-selected) {
+ background-color: #1890ff;
+ color: #fff;
+ }
+ }
+ }
+
+ .deviceStatusChart {
+ position: absolute;
+ top: 35px;
+ left: 10px;
+ right: 10px;
+ bottom: 10px;
+ z-index: 10;
+ }
+
+ // .block1Chart {
+ // width: 100%;
+ // height: 100%;
+ // margin-top: 20px;
+
+ // .mapImage {
+ // margin-top: 7%;
+ // width: 90%;
+ // height: 77%;
+ // object-fit: cover;
+ // border-radius: 4px;
+ // display: block;
+ // margin-left: auto;
+ // margin-right: auto;
+ // }
+ // }
+ }
+
+ .middleBlock12 {
+ flex: 1;
+ height: 100%;
+ background-color: #fff;
+ display: flex;
+ flex-direction: column;
+ font-family: PingFang SC;
+ font-size: 14px;
+ color: #333333;
+ padding: 5px 10px 5px 10px;
+ position: relative;
+
+ .block1Header {
+ position: absolute;
+ top: 5px;
+ left: 10px;
+ right: 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ z-index: 10;
+
+ .block1Title {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-weight: 500;
+ font-size: 14px;
+ color: #333333;
+
+ .titleIcon {
+ width: 3px;
+ height: 14px;
+ background-color: #2E4CD4;
+ }
+ }
+
+ .block1Segmented {
+ padding: 0;
+ margin: 0;
+ border: 1px solid #E3E3E3;
+ border-radius: 4px;
+ height: 28px;
+
+ :global(.ant-segmented) {
+ padding: 0;
+ margin: 0;
+ height: 28px;
+ }
+
+ :global(.ant-segmented-item) {
+ font-size: 12px;
+ padding: 2px 8px;
+ height: 26px;
+ line-height: 26px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ :global(.ant-segmented-item-selected) {
+ background-color: #1890ff;
+ color: #fff;
+ }
+ }
+
+ .customSelect {
+ :global(.ant-select-single:not(.ant-select-customize-input) .ant-select-selector) {
+ height: 26px !important;
+ display: flex !important;
+ align-items: center !important;
+ }
+
+ :global(.ant-select-selection-item) {
+ line-height: 24px !important;
+ // height: 24px !important;
+ display: flex !important;
+ align-items: center !important;
+ }
+ }
+ }
+
+ .deviceStatusChart {
+ position: absolute;
+ top: 35px;
+ left: 10px;
+ right: 10px;
+ bottom: 10px;
+ z-index: 10;
+ }
+ }
+
+ .middleBlock2 {
+ flex: 1;
+ height: 100%;
+ // background: linear-gradient(170.5deg, #EBEFF4 6.87%, #FFFFFF 53.01%);
+ // border: 2px solid #fff;
+ background-color: #fff;
+ // border-radius: 4px;
+ display: flex;
+ flex-direction: column;
+ font-family: PingFang SC;
+ font-size: 14px;
+ color: #333333;
+ padding: 5px 10px 5px 10px;
+
+ .middleBlock2Title {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ // margin-bottom: 10px;
+
+ .titleLeft {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-weight: 500;
+ font-size: 14px;
+ color: #333333;
+
+ .titleIcon {
+ width: 3px;
+ height: 14px;
+ background-color: #2E4CD4;
+ }
+ }
+
+ .titleRight {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 12px;
+ color: #666;
+ }
+ }
+
+ .middleBlock2Chart {
+ width: 100%;
+ height: 100%;
+ // min-height: 200px;
+ }
+ }
+
+ }
+ }
+
+ // 第三个div - 高度不超过45%
+ .RcontainerBottom {
+ height: 45%; // 限制高度不超过45%
+ max-height: 45%; // 确保最大高度不超过45%
+ display: flex;
+ flex-direction: column;
+
+ .sectionContent {
+ display: flex;
+ flex-direction: row;
+ gap: 10px;
+ padding: 0;
+
+ .leftBlock {
+ width: 28%;
+ flex-shrink: 0;
+ height: 100%;
+ background: #fff;
+ // background-size: cover;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ padding: 15px;
+
+ .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;
+ }
+ }
+
+ .developmentContainer {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+
+ .developmentBlock1 {
+ flex: 1;
+ background-color: #F1F7FF;
+ border-radius: 4px;
+ padding: 15px 20px;
+ display: flex;
+ align-items: center;
+ width: 100%;
+
+ .leftContent {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ min-width: 0;
+
+ .mainText {
+ color: #333333;
+ font-size: 14px;
+ font-weight: 500;
+ font-family: PingFang SC;
+ width: 100%;
+ max-width: 500px;
+ }
+
+ .subText {
+ color: #666666;
+ font-size: 12px;
+ font-weight: 400;
+ font-family: PingFang SC;
+ width: 100%;
+ max-width: 400px;
+ }
+ }
+
+ .rightContent {
+ flex: 0 0 auto;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ padding-right: 10px;
+ min-width: 80px;
+
+ .importantTag {
+ background-color: #FFE0E2;
+ color: #FF3E48;
+ font-size: 14px;
+ font-weight: 500;
+ font-family: PingFang SC;
+ width: 45px;
+ height: 25px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+ }
+
+ .normalTag {
+ background-color: #DAF3FF;
+ color: #00AAFA;
+ font-size: 14px;
+ font-weight: 500;
+ font-family: PingFang SC;
+ width: 45px;
+ height: 25px;
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+ }
+ }
+ }
+ }
+ }
+
+ .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: 8px 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;
+ gap: 8px;
+ margin-top: 5px;
+
+ .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;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/pages/business_inspection/form/StaffSheetCreateForm.js b/src/pages/business_inspection/form/StaffSheetCreateForm.js
new file mode 100644
index 0000000..6bdce8d
--- /dev/null
+++ b/src/pages/business_inspection/form/StaffSheetCreateForm.js
@@ -0,0 +1,271 @@
+import { useState, useEffect } from 'react'
+import { Col, DatePicker, Form, Input, Modal, Row, Select } from 'antd'
+import SelectDeptTree from '@/components/SelectDeptTree'
+import SelectOrganTree from '@/components/SelectOrganTree'
+import datadictionary from '@/utils/dataDictionary'
+import { formatDictOptions, verifyPhone } from '@/utils/globalCommon'
+import { NumberInput } from '@/components/NumberInput'
+import styles from '../StaffSheetList.less'
+import style from '@/global.less'
+import dayjs from 'dayjs'
+import { formatDate } from '@/utils/formatUtils'
+
+const { Item: FormItem } = Form
+const { TextArea } = Input
+const dictData = datadictionary
+
+//新增表单
+let getDeptTreeBySelectTree
+let getOrganTreeBySelectTree
+
+const StaffSheetCreateForm = (props => {
+ const [form] = Form.useForm()
+ const [jobStatus, setJobStatus] = useState('1')
+
+ const {
+ modalVisible,
+ handleAdd,
+ handleModalVisible,
+ loading,
+ dispatch,
+ selectDeptTree,
+ selectOrganTree
+ } = props
+
+ useEffect(() => {
+ form.setFieldsValue({
+ user_type: 'employee',
+ job_status: '1',
+ mgr_type: '0'
+ })
+ }, [])
+
+ const selectedDeptTreeValue = (deptRecord) => {
+ getDeptTreeBySelectTree = deptRecord
+ }
+
+ const selectedOrganTreeValue = (orgRecord) => {
+ getOrganTreeBySelectTree = orgRecord
+ }
+
+ const parentDeptTreeMethod = {
+ dispatch: dispatch,
+ selectDeptTree: selectDeptTree,
+ selectedDeptTreeValue: selectedDeptTreeValue,
+ }
+
+ const parentOrganTreeMethod = {
+ dispatch: dispatch,
+ selectOrganTree: selectOrganTree,
+ selectedOrganTreeValue: selectedOrganTreeValue
+ }
+
+ const okHandle = () => {
+ form.validateFields()
+ .then(fieldsValue => {
+ form.resetFields()
+ fieldsValue.birthday = formatDate(fieldsValue.birthday, 'YYYY-MM-DD')
+ fieldsValue.hiredate = formatDate(fieldsValue.hiredate, 'YYYY-MM-DD')
+ fieldsValue.departure_time = formatDate(fieldsValue.departure_time, 'YYYY-MM-DD')
+ fieldsValue.posts = fieldsValue.posts ? JSON.stringify(fieldsValue.posts) : null
+
+ // if (getDeptTreeBySelectTree) {
+ // fieldsValue.dept_code = getDeptTreeBySelectTree.dept_code
+ // fieldsValue.dept_name = getDeptTreeBySelectTree.title
+ // }
+
+ if (getOrganTreeBySelectTree) {
+ fieldsValue.org_code = getOrganTreeBySelectTree.org_code
+ fieldsValue.org_name = getOrganTreeBySelectTree.title
+ }
+
+ handleAdd(fieldsValue)
+ })
+ .catch(errInfo => {})
+ }
+
+ const afterClose = () =>{
+ form.resetFields();
+ }
+
+ const handleJobStatusChange = (value) => {
+ setJobStatus(value)
+ }
+
+ return (
+ handleModalVisible()}
+ afterClose={() => afterClose()}
+ confirmLoading={loading}
+ >
+
+
+ )
+})
+
+export default StaffSheetCreateForm
diff --git a/src/pages/business_inspection/form/StaffSheetRenderAdvancedForm.js b/src/pages/business_inspection/form/StaffSheetRenderAdvancedForm.js
new file mode 100644
index 0000000..2625938
--- /dev/null
+++ b/src/pages/business_inspection/form/StaffSheetRenderAdvancedForm.js
@@ -0,0 +1,113 @@
+import { useEffect } from 'react'
+import { Button, Col, Form, Input, Row } from 'antd'
+import { UpOutlined, SearchOutlined, RedoOutlined } from '@ant-design/icons'
+import SelectDeptTree from '@/components/SelectDeptTree'
+import SelectOrganTree from '@/components/SelectOrganTree'
+import style from '@/global.less'
+
+const { Item: FormItem } = Form
+let getDeptTreeBySelectTree
+let getOrganTreeBySelectTree
+
+const StaffSheetRenderAdvancedForm = (props) => {
+ const [form] = Form.useForm()
+ const { dispatch, handleSearch, handleFormReset, toggleForm, selectDeptTree, selectOrganTree, params } = props
+
+ useEffect(() => {
+ form.setFieldsValue({
+ user_name: params?.user_name,
+ user_name_cn: params?.user_name_cn,
+ deptname: params?.deptname,
+ orgname: params?.orgname,
+ })
+ }, [params])
+
+ const onFinish = values => {
+ // if (getDeptTreeBySelectTree) {
+ // values.dept_code = getDeptTreeBySelectTree.dept_code
+ // values.deptname = getDeptTreeBySelectTree.title
+ // }
+
+ if (getOrganTreeBySelectTree) {
+ values.org_code = getOrganTreeBySelectTree.org_code
+ values.orgname = getOrganTreeBySelectTree.title
+ }
+
+ handleSearch(values)
+ }
+
+ const myHandleFormReset = () => {
+ form.resetFields()
+ handleFormReset()
+ }
+
+ const selectedDeptTreeValue = (deptRecord) => {
+ getDeptTreeBySelectTree = deptRecord
+ }
+
+ const selectedOrganTreeValue = (orgRecord) => {
+ getOrganTreeBySelectTree = orgRecord
+ }
+
+ const parentDeptTreeMethod = {
+ dispatch: dispatch,
+ selectDeptTree: selectDeptTree,
+ selectedDeptTreeValue: selectedDeptTreeValue
+ }
+
+ const parentOrganTreeMethod = {
+ dispatch: dispatch,
+ selectOrganTree: selectOrganTree,
+ selectedOrganTreeValue: selectedOrganTreeValue
+ }
+
+ return (
+
+ )
+}
+
+export default StaffSheetRenderAdvancedForm
diff --git a/src/pages/business_inspection/form/StaffSheetRenderSimpleForm.js b/src/pages/business_inspection/form/StaffSheetRenderSimpleForm.js
new file mode 100644
index 0000000..0468e76
--- /dev/null
+++ b/src/pages/business_inspection/form/StaffSheetRenderSimpleForm.js
@@ -0,0 +1,81 @@
+import { useEffect } from 'react'
+import {Button, Col, Form, Input, Row, DatePicker, Select} from 'antd'
+import {DownOutlined, RedoOutlined, SearchOutlined} from '@ant-design/icons'
+import style from '@/global.less'
+import dayjs from 'dayjs'
+const { Item: FormItem } = Form
+
+const StaffSheetRenderSimpleForm = (props) => {
+ const [form] = Form.useForm()
+ const { handleSearch, handleFormReset, toggleForm, params } = props
+
+ useEffect(() => {
+ form.setFieldsValue({
+ user_name: params?.user_name,
+ user_name_cn: params?.user_name_cn,
+ })
+ }, [params])
+
+ const onFinish = values => {
+ handleSearch(values)
+ }
+
+ const myHandleFormReset = () => {
+ form.resetFields()
+ handleFormReset()
+ }
+
+ return (
+
+ )
+}
+
+export default StaffSheetRenderSimpleForm
diff --git a/src/pages/business_inspection/form/StaffSheetUpdateForm.js b/src/pages/business_inspection/form/StaffSheetUpdateForm.js
new file mode 100644
index 0000000..f33d64b
--- /dev/null
+++ b/src/pages/business_inspection/form/StaffSheetUpdateForm.js
@@ -0,0 +1,362 @@
+import { useState, useEffect } from 'react'
+import { Col, DatePicker, Form, Input, Modal, Row, Select } from 'antd'
+import SelectOrganTree from '@/components/SelectOrganTree'
+import datadictionary from '@/utils/dataDictionary'
+import { formatDictOptions, verifyPhone } from '@/utils/globalCommon'
+import { NumberInput } from '@/components/NumberInput'
+import styles from '../StaffSheetList.less'
+import style from '@/global.less'
+import dayjs from 'dayjs'
+import { formatDate, formatDateObject } from '@/utils/formatUtils'
+
+const { Item: FormItem } = Form
+const { TextArea } = Input
+const dictData = datadictionary
+
+//新增表单
+let getDeptTreeBySelectTree
+let getOrganTreeBySelectTree
+
+const StaffSheetUpdateForm = (props) => {
+ const [form] = Form.useForm()
+ const [jobStatus, setJobStatus] = useState('1')
+ const [userStatus, setUserStatus] = useState('0')
+
+ const {
+ handleUpdate,
+ updateModalVisible,
+ handleUpdateModalVisible,
+ values,
+ loading,
+ dispatch,
+ selectDeptTree,
+ selectOrganTree
+ } = props
+
+ const selectedDeptTreeValue = (deptRecord) => {
+ getDeptTreeBySelectTree = deptRecord
+ }
+
+ const selectedOrganTreeValue = (orgRecord) => {
+ getOrganTreeBySelectTree = orgRecord
+ }
+
+ const parentDeptTreeMethod = {
+ dispatch: dispatch,
+ selectDeptTree: selectDeptTree,
+ selectedDeptTreeValue: selectedDeptTreeValue,
+ }
+
+ const parentOrganTreeMethod = {
+ dispatch: dispatch,
+ selectOrganTree: selectOrganTree,
+ selectedOrganTreeValue: selectedOrganTreeValue
+ }
+
+ useEffect(() => {
+ setJobStatus(values.job_status)
+ setUserStatus(values.status)
+
+ form.setFieldsValue({
+ user_id: values.user_id,
+ user_name: values.user_name,
+ user_name_cn: values.user_name_cn,
+ user_name_en: values.user_name_en,
+ password: values.password,
+ email: values.email,
+ phone: values.phone,
+ landline: values.landline,
+ sex: values.sex,
+ avatar: values.avatar,
+ sign: values.sign,
+ tags: values.tags,
+ id_card: values.id_card,
+ birthday: formatDateObject(values.birthday, 'YYYY-MM-DD'),
+ job_status: values.job_status,
+ hiredate: formatDateObject(values.hiredate, 'YYYY-MM-DD'),
+ departure_time: formatDateObject(values.departure_time, 'YYYY-MM-DD'),
+ user_type: values.user_type,
+ emp_no: values.emp_no,
+ access_card_no: values.access_card_no,
+ country: values.country,
+ province: values.province,
+ city: values.city,
+ address: values.address,
+ work_addr: values.work_addr,
+ floor: values.floor,
+ inprovince: values.inprovince,
+ // dept_code: values.dept_code,
+ // dept_name: values.dept_name,
+ inner_dept_code: values.inner_dept_code,
+ org_code: values.org_code,
+ org_name: values.org_name,
+ inner_org_code: values.inner_org_code,
+ posts: values.posts ? JSON.parse(values.posts) : [],
+ wx_openid: values.wx_openid,
+ wx_mpopenid: values.wx_mpopenid,
+ wx_miniopenid: values.wx_miniopenid,
+ wx_unionid: values.wx_unionid,
+ mobile_imei: values.mobile_imei,
+ device_num: values.device_num,
+ al_taobao: values.al_taobao,
+ al_alipay: values.al_alipay,
+ al_dingding: values.al_dingding,
+ is_system_user: values.is_system_user,
+ mgr_type: values.mgr_type,
+ pwd_security_level: values.pwd_security_level,
+ pwd_update_date: values.pwd_update_date,
+ last_login_ip: values.last_login_ip,
+ last_login_date: values.last_login_date,
+ freeze_date: values.freeze_date,
+ freeze_cause: values.freeze_cause,
+ zindex: values.zindex,
+ wx_msg: values.wx_msg,
+ email_msg: values.email_msg,
+ system_msg: values.system_msg,
+ remarks: values.remarks,
+ status: values.status,
+ creator: values.creator,
+ create_date: values.create_date,
+ updater: values.updater,
+ update_date: values.update_date
+ })
+ }, [])
+
+ const handleLocalUpdate = () => {
+ form
+ .validateFields()
+ .then(fieldsValue => {
+ const formVals = {...values, ...fieldsValue}
+ formVals.birthday = formatDate(formVals.birthday, 'YYYY-MM-DD')
+ formVals.hiredate = formatDate(formVals.hiredate, 'YYYY-MM-DD')
+ formVals.departure_time = formatDate(formVals.departure_time, 'YYYY-MM-DD')
+ formVals.posts = formVals.posts ? JSON.stringify(formVals.posts) : null
+ formVals.freeze_date = '3' === formVals.status ? formatDate(dayjs().endOf('day'), 'YYYY-MM-DD') : null
+ formVals.freeze_cause = '3' === formVals.status ? formVals.freeze_cause : null
+
+ // if (getDeptTreeBySelectTree) {
+ // formVals.dept_code = getDeptTreeBySelectTree.dept_code
+ // formVals.dept_name = getDeptTreeBySelectTree.title
+ // }
+
+ if (getOrganTreeBySelectTree) {
+ formVals.org_code = getOrganTreeBySelectTree.org_code
+ formVals.org_name = getOrganTreeBySelectTree.title
+ }
+
+ handleUpdate(formVals)
+
+ })
+ .catch(errInfo => {})
+ }
+
+ const afterClose = () =>{
+ form.resetFields();
+ }
+
+ const handleJobStatusChange = (value) => {
+ setJobStatus(value)
+ }
+
+ const handleUserStatusChange = (value) => {
+ setUserStatus(value)
+ }
+
+ return (
+ handleLocalUpdate()}
+ onCancel={() => handleUpdateModalVisible()}
+ afterClose={() => afterClose()}
+ confirmLoading={loading}
+ >
+
+
+ )
+}
+
+export default StaffSheetUpdateForm
diff --git a/src/pages/business_inspection/form/StaffSheetViewForm.js b/src/pages/business_inspection/form/StaffSheetViewForm.js
new file mode 100644
index 0000000..9acb9c4
--- /dev/null
+++ b/src/pages/business_inspection/form/StaffSheetViewForm.js
@@ -0,0 +1,299 @@
+import { useState, useEffect } from 'react'
+import {Col, DatePicker, Form, Input, Modal, Row, Select} from 'antd'
+import datadictionary from '@/utils/dataDictionary'
+import style from "@/global.less";
+import {formatDictOptions, verifyPhone} from "@/utils/globalCommon";
+import {NumberInput} from "@/components/NumberInput";
+import dayjs from "dayjs";
+import SelectOrganTree from "@/components/SelectOrganTree";
+import {formatDateObject} from "@/utils/formatUtils";
+
+const { Item: FormItem } = Form
+const { TextArea } = Input
+const dictData = datadictionary
+
+const StaffSheetViewForm = (props) => {
+ const [form] = Form.useForm()
+ const [jobStatus, setJobStatus] = useState('1')
+ const [userStatus, setUserStatus] = useState('0')
+
+ const { viewModalVisible, handleViewModalVisible, values } = props
+
+ useEffect(() => {
+ setJobStatus(values.job_status)
+ setUserStatus(values.status)
+
+ form.setFieldsValue({
+ user_id: values.user_id,
+ user_name: values.user_name,
+ user_name_cn: values.user_name_cn,
+ user_name_en: values.user_name_en,
+ password: values.password,
+ email: values.email,
+ phone: values.phone,
+ landline: values.landline,
+ sex: values.sex,
+ avatar: values.avatar,
+ sign: values.sign,
+ tags: values.tags,
+ id_card: values.id_card,
+ birthday: formatDateObject(values.birthday, 'YYYY-MM-DD'),
+ job_status: values.job_status,
+ hiredate: formatDateObject(values.hiredate, 'YYYY-MM-DD'),
+ departure_time: formatDateObject(values.departure_time, 'YYYY-MM-DD'),
+ user_type: values.user_type,
+ emp_no: values.emp_no,
+ access_card_no: values.access_card_no,
+ country: values.country,
+ province: values.province,
+ city: values.city,
+ address: values.address,
+ work_addr: values.work_addr,
+ floor: values.floor,
+ inprovince: values.inprovince,
+ // dept_code: values.dept_code,
+ // dept_name: values.dept_name,
+ inner_dept_code: values.inner_dept_code,
+ org_code: values.org_code,
+ org_name: values.org_name,
+ inner_org_code: values.inner_org_code,
+ posts: values.posts ? JSON.parse(values.posts) : [],
+ wx_openid: values.wx_openid,
+ wx_mpopenid: values.wx_mpopenid,
+ wx_miniopenid: values.wx_miniopenid,
+ wx_unionid: values.wx_unionid,
+ mobile_imei: values.mobile_imei,
+ device_num: values.device_num,
+ al_taobao: values.al_taobao,
+ al_alipay: values.al_alipay,
+ al_dingding: values.al_dingding,
+ is_system_user: values.is_system_user,
+ mgr_type: values.mgr_type,
+ pwd_security_level: values.pwd_security_level,
+ pwd_update_date: values.pwd_update_date,
+ last_login_ip: values.last_login_ip,
+ last_login_date: values.last_login_date,
+ freeze_date: values.freeze_date,
+ freeze_cause: values.freeze_cause,
+ zindex: values.zindex,
+ wx_msg: values.wx_msg,
+ email_msg: values.email_msg,
+ system_msg: values.system_msg,
+ remarks: values.remarks,
+ status: values.status,
+ creator: values.creator,
+ create_date: values.create_date,
+ updater: values.updater,
+ update_date: values.update_date
+ })
+ }, [])
+
+ const afterClose = () =>{
+ form.resetFields();
+ }
+
+ const handleJobStatusChange = (value) => {
+ setJobStatus(value)
+ }
+
+ const handleUserStatusChange = (value) => {
+ setUserStatus(value)
+ }
+
+ return (
+ handleViewModalVisible()}
+ onCancel={() => handleViewModalVisible()}
+ afterClose={() => afterClose()}
+ >
+
+
+ )
+}
+
+export default StaffSheetViewForm
diff --git a/src/pages/business_inspection/models/StaffSheet.js b/src/pages/business_inspection/models/StaffSheet.js
new file mode 100644
index 0000000..0b63985
--- /dev/null
+++ b/src/pages/business_inspection/models/StaffSheet.js
@@ -0,0 +1,319 @@
+import { deleteByPrimaryKeyForProUser, selectByPrimaryKeyForProUser, insertForProUser, updateForProUser, deleteByMapForProUser,updateByMapForProUser, getOneForProUser,getAllForProUser,queryPageForProUser, countForProUser, insertBatchForProUser, deleteBatchForProUser,updateBatchForProUser, resetPwdForProUser } from '@/services/system/api_prouser';
+
+export default {
+ namespace: 'safemajo333hazard',
+
+ state: {
+ params: {},
+ data: {
+ list: [],
+ pagination: {},
+ },
+ },
+
+ effects: {
+ *delete_by_primarykey_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(deleteByPrimaryKeyForProUser, payload)
+ yield put({
+ type: 'deleteByPrimaryKeyForProUser',
+ payload: response
+ })
+
+ if (!response.success) {
+ callback && callback(response)
+ return
+ }
+
+ const params = yield select(state => state.prouser.params)
+ const responseData = yield call(queryPageForProUser, params)
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responseData
+ })
+
+ if (callback) callback(response)
+ },
+ *select_by_primarykey_for_prouser({ payload, callback }, { call, put }) {
+ const response = yield call(selectByPrimaryKeyForProUser, payload)
+ yield put({
+ type: 'selectByPrimaryKeyForProUser',
+ payload: response
+ })
+
+ if (callback) callback(response)
+ },
+ *insert_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(insertForProUser, payload)
+ yield put({
+ type: 'insertForProUser',
+ payload: response
+ })
+
+ if (!response.success) {
+ callback && callback(response)
+ return
+ }
+
+ const params = yield select(state => state.prouser.params)
+ const responseData = yield call(queryPageForProUser, params)
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responseData
+ })
+
+ if (callback) callback(response)
+ },
+ *update_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(updateForProUser, payload)
+ yield put({
+ type: 'updateForProUser',
+ payload: response
+ })
+
+ if (!response.success) {
+ callback && callback(response)
+ return
+ }
+
+ const params = yield select(state => state.prouser.params)
+ const responseData = yield call(queryPageForProUser, params)
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responseData
+ })
+
+ if (callback) callback(response)
+ },
+ *delete_by_map_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(deleteByMapForProUser, payload);
+ yield put({
+ type: 'deleteByMapForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *update_by_map_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(updateByMapForProUser, payload);
+ yield put({
+ type: 'updateByMapForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *get_one_for_prouser({ payload, callback }, { call, put }) {
+ const response = yield call(getOneForProUser, payload);
+ yield put({
+ type: 'getOneForProUser',
+ payload: response,
+ });
+
+ if (callback) callback(response);
+ },
+ *get_all_for_prouser({ payload, callback }, { call, put }) {
+ const response = yield call(getAllForProUser, payload);
+ yield put({
+ type: 'getAllForProUser',
+ payload: response,
+ });
+
+ if (callback) callback(response);
+ },
+ *query_page_for_prouser({ payload, callback }, { select, call, put }) {
+ const params = yield select(state => state.prouser.params);
+ const newParams = payload?.resetFlag ? payload : {...params, ...payload};
+ yield put({
+ type: 'setQueryPageByParams',
+ payload: newParams,
+ });
+ const response = yield call(queryPageForProUser, newParams);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: response,
+ });
+
+ if (callback) callback(response);
+ },
+ *count_for_prouser({ payload, callback }, { call, put }) {
+ const response = yield call(countForProUser, payload);
+ yield put({
+ type: 'countForProUser',
+ payload: response,
+ });
+
+ if (callback) callback(response);
+ },
+ *insert_batch_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(insertBatchForProUser, payload);
+ yield put({
+ type: 'insertBatchForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *delete_batch_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(deleteBatchForProUser, payload);
+ yield put({
+ type: 'deleteBatchForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *update_batch_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(updateBatchForProUser, payload);
+ yield put({
+ type: 'updateBatchForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ *resetpwd_for_prouser({ payload, callback }, { select, call, put }) {
+ const response = yield call(resetPwdForProUser, payload);
+ yield put({
+ type: 'resetPwdForProUser',
+ payload: response,
+ });
+
+ const params = yield select(state => state.prouser.params);
+ const responsedata = yield call(queryPageForProUser, params);
+ yield put({
+ type: 'queryPageForProUser',
+ payload: responsedata,
+ });
+
+ if (callback) callback(response);
+ },
+ },
+
+ reducers: {
+ setQueryPageByParams(state, { payload }) {
+ return {
+ ...state,
+ params: {...payload},
+ };
+ },
+ deleteByPrimaryKeyForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ selectByPrimaryKeyForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ insertForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ updateForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ deleteByMapForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ updateByMapForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ getOneForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ getAllForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ queryPageForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ countForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ insertBatchForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ deleteBatchForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ updateBatchForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ resetPwdForProUser(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ },
+};
diff --git a/src/pages/nav_system_content/SystemContentList.js b/src/pages/nav_system_content/SystemContentList.js
index bcd36bc..84b7882 100644
--- a/src/pages/nav_system_content/SystemContentList.js
+++ b/src/pages/nav_system_content/SystemContentList.js
@@ -10,22 +10,13 @@ import { HomeOutlined, LogoutOutlined, AppstoreOutlined, UserOutlined, SettingOu
import { getPageQuery } from '@/utils/utils'
import menuTitle from '@/assets/img/智能管控平台.svg'
import menuTitle1 from '@/assets/img/智能管控平台-1.svg'
+import dataIcon from '@/assets/data_icon.svg'
import fireHydrant from '@/assets/img/fireHydrant.svg'
-import fireHydrant1 from '@/assets/img/fireHydrant1.svg'
-import fireKeynoteArea from '@/assets/img/fire_keynote_area.svg'
-import firewarning from '@/assets/img/icon_firewarning.svg'
-import trouble from '@/assets/img/trouble.svg'
-import book from '@/assets/img/book.svg'
-import danger from '@/assets/img/danger.svg'
import danger1 from '@/assets/img/danger1.svg'
-import license from '@/assets/img/license.svg'
-import people from '@/assets/img/people.svg'
-import risk from '@/assets/img/risk.svg'
-import icon1 from '@/assets/img/icon1.svg'
+import iconfont from "@/assets/basic_data/Iconfont.svg"
import { CustomBreadcrumb } from '@/components/GlobalComponent'
-
// 自定义菜单项渲染组件,支持根据激活状态显示不同图片
const CustomMenuItem = ({ item, selectedKeys }) => {
const isActive = selectedKeys.includes(item.key);
@@ -93,19 +84,33 @@ const SystemContentList = (props) => {
const fixedMenuItems = [
{
- path: '/topnavbar00/business/basic',
+ path: '/topnavbar00/business/data',
icon:
,
- key: "/topnavbar00/business/basic",
- "label": "基础信息管理"
+ key: "/topnavbar00/business/data",
+ "label": "基础数据管理"
},
+ {
+ path: '/topnavbar00/business/dataCollection',
+ icon:
,
+ key: '/topnavbar00/business/dataCollection',
+ "label": "数据采集",
+ }
]
setMenuItems(fixedMenuItems)
// 初始化默认路由
diff --git a/src/pages/nav_system_content/SystemContentList.less b/src/pages/nav_system_content/SystemContentList.less
index 93516c5..9c6431a 100644
--- a/src/pages/nav_system_content/SystemContentList.less
+++ b/src/pages/nav_system_content/SystemContentList.less
@@ -77,11 +77,17 @@
width: 230px;
overflow-y: auto;
overflow-x: hidden;
- background-color: #2E4CD4;
+ background-color: #3900E4;
+ background-image: linear-gradient(180deg, rgba(54, 87, 255, 0.5) 0%, rgba(78, 0, 188, 0.5) 100%),
+ url('@/assets/menuBack.svg');
+ background-repeat: no-repeat, no-repeat;
+ background-position: 0 0, center bottom;
+ background-size: auto, 100% auto;
.ant-menu-inline,
.ant-menu-vertical {
- background: #2E4CD4 !important;
+ background: transparent !important;
+
}
// 默认情况字体样式和右边距
@@ -133,4 +139,4 @@
// height: 100%;
overflow: auto;
}
-}
\ No newline at end of file
+}
diff --git a/src/pages/systemMenu/SystemMenuList.js b/src/pages/systemMenu/SystemMenuList.js
index 57b49e2..dab61f2 100644
--- a/src/pages/systemMenu/SystemMenuList.js
+++ b/src/pages/systemMenu/SystemMenuList.js
@@ -3,25 +3,15 @@ import {
DeleteOutlined,
EditOutlined,
PlusOutlined,
- SearchOutlined,
- RedoOutlined,
- DownOutlined,
ExclamationCircleFilled,
- UpOutlined,
- InfoCircleFilled,
- QuestionCircleFilled,
- DownloadOutlined
} from '@ant-design/icons';
import {connect, history} from '@umijs/max';
import {Button, Card, Divider, Dropdown, message, Modal, Popconfirm, Space, Switch, Tag, Row, Col, Tree} from 'antd';
import StandardTable from '@/components/StandardTable';
-
-import { MyIcon } from "@/components/Icon"
import style from "@/global.less";
import styles from './SystemMenuList.less';
import datadictionary from "@/utils/dataDictionary";
-import {formatDate} from "@/utils/formatUtils";
-import { formatDictText, checkButtonAuthority } from "@/utils/globalCommon";
+import { formatDictText, } from "@/utils/globalCommon";
const { confirm } = Modal;
diff --git a/src/pages/topnavbar/TopNavBar.js b/src/pages/topnavbar/TopNavBar.js
index 82606cd..b77489c 100644
--- a/src/pages/topnavbar/TopNavBar.js
+++ b/src/pages/topnavbar/TopNavBar.js
@@ -9,16 +9,12 @@ import { userInfo } from '@/utils/globalCommon'
const menuItem = [
{
- label: '基础信息管理',
- key: '/topnavbar00/business/basic',
+ label: '基础数据管理',
+ key: '/topnavbar00/business/data',
},
{
- label: '消防重点部位管理',
- key: '/topnavbar00/business/firekeynotearea',
- },
- {
- label: '消防监测报警',
- key: '/topnavbar00/business/fireWarning',
+ label: "数据采集",
+ key: '/topnavbar00/business/dataCollection',
},
]