diff --git a/config/routes.js b/config/routes.js
index ce3fc6c..8f63b3d 100644
--- a/config/routes.js
+++ b/config/routes.js
@@ -103,10 +103,22 @@ export default [
component: './hrefficiency_hiddentrouble/HiddenTrouble',
},
// 安全教育培训
- {
+ {
path:'/topnavbar00/hrefficiency/safetraining',
name: 'safetraining',
component: './safe_training/SafeTrainingList',
+ },
+ // 人员定位
+ {
+ path:'/topnavbar00/hrefficiency/personnellocation',
+ name: 'personnellocation',
+ component: './personnel_location/PersonnelLocation',
+ },
+ // 特殊作业许可
+ {
+ path:'/topnavbar00/hrefficiency/specialoperationpermit',
+ name: 'specialoperationpermit',
+ component: './special_operation_permit/SpecialOperationPermit',
}
],
},
diff --git a/src/assets/img/bookDark.svg b/src/assets/img/bookDark.svg
new file mode 100644
index 0000000..86b68e3
--- /dev/null
+++ b/src/assets/img/bookDark.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/img/bookLight.svg b/src/assets/img/bookLight.svg
new file mode 100644
index 0000000..a9e31d3
--- /dev/null
+++ b/src/assets/img/bookLight.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/img/gisTemp.svg b/src/assets/img/gisTemp.svg
new file mode 100644
index 0000000..7a90aae
--- /dev/null
+++ b/src/assets/img/gisTemp.svg
@@ -0,0 +1,32 @@
+
diff --git a/src/assets/img/licenseLight.svg b/src/assets/img/licenseLight.svg
new file mode 100644
index 0000000..6805ba4
--- /dev/null
+++ b/src/assets/img/licenseLight.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/img/personnelPosition1.svg b/src/assets/img/personnelPosition1.svg
new file mode 100644
index 0000000..6a45b20
--- /dev/null
+++ b/src/assets/img/personnelPosition1.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/img/personnelPosition2.svg b/src/assets/img/personnelPosition2.svg
new file mode 100644
index 0000000..bd928a5
--- /dev/null
+++ b/src/assets/img/personnelPosition2.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/locales/zh-CN/menu.js b/src/locales/zh-CN/menu.js
index 770da9b..1d5ab36 100644
--- a/src/locales/zh-CN/menu.js
+++ b/src/locales/zh-CN/menu.js
@@ -10,12 +10,15 @@ export default {
'menu.topnavbar00.hrefficiency.deptuph': '部门效率监控',
'menu.topnavbar00.hrefficiency.allstaffuph': '全员效率监控',
'menu.topnavbar00.hrefficiency.workreport': '工作报表',
- 'menu.topnavbar00.hrefficiency.system': '系统管理',
'menu.topnavbar00.hrefficiency.system.organization': '组织管理',
'menu.topnavbar00.hrefficiency.system.role': '角色配置',
'menu.topnavbar00.hrefficiency.system.menu': '菜单配置',
- 'menu.topnavbar00': '业务导航',
+ // 其他安全相关菜单
+ 'menu.topnavbar00.hrefficiency.hiddentrouble': '隐患排查',
+ 'menu.topnavbar00.hrefficiency.safetraining': '安全教育培训',
+ 'menu.topnavbar00.hrefficiency.personnellocation': '人员定位',
+ 'menu.topnavbar00.hrefficiency.specialoperationpermit': '特殊作业许可',
'menu.topnavbar00.sysmenu': '系统配置',
'menu.topnavbar00.sysmenu.system': '系统管理',
diff --git a/src/pages/nav_system_content/SystemContentList.js b/src/pages/nav_system_content/SystemContentList.js
index 243e774..a63afc7 100644
--- a/src/pages/nav_system_content/SystemContentList.js
+++ b/src/pages/nav_system_content/SystemContentList.js
@@ -17,9 +17,13 @@ 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 licenseLight from '@/assets/img/licenseLight.svg'
import people from '@/assets/img/people.svg'
import risk from '@/assets/img/risk.svg'
import safeEducationLight from '@/assets/img/safeEducationLight.svg'
+import bookDark from '@/assets/img/bookDark.svg'
+import bookLight from '@/assets/img/bookLight.svg'
+import personnelPosition2 from '@/assets/img/personnelPosition2.svg'
import { CustomBreadcrumb } from '@/components/GlobalComponent'
@@ -118,18 +122,30 @@ const SystemContentList = (props) => {
"key": "/topnavbar00/hrefficiency/allstaffuph",
"label": "全员效率监控"
},
- {
+ {
"path": "/topnavbar00/hrefficiency/hiddentrouble",
icon:
,
"key": "/topnavbar00/hrefficiency/hiddentrouble",
"label": "隐患排查"
},
- {
+ {
"path": "/topnavbar00/hrefficiency/safetraining",
- icon:
,
+ icon:
,
"key": "/topnavbar00/hrefficiency/safetraining",
"label": "安全教育培训"
},
+ {
+ "path": "/topnavbar00/hrefficiency/personnellocation",
+ icon:
,
+ "key": "/topnavbar00/hrefficiency/personnellocation",
+ "label": "人员定位"
+ },
+ {
+ "path": "/topnavbar00/hrefficiency/specialoperationpermit",
+ icon:
,
+ "key": "/topnavbar00/hrefficiency/specialoperationpermit",
+ "label": "特殊作业许可"
+ },
{
"path": "/topnavbar00/hrefficiency/system",
icon:
,
@@ -375,9 +391,17 @@ const SystemContentList = (props) => {
else if (item.key === '/topnavbar00/hrefficiency/staffsheet' && typeof danger1 !== 'undefined') {
iconSrc = danger1;
}
- // 安全教育培训激活态使用safeEducationLight
- else if (item.key === '/topnavbar00/hrefficiency/safetraining' && typeof safeEducationLight !== 'undefined') {
- iconSrc = safeEducationLight;
+ // 安全教育培训激活态使用bookLight
+ else if (item.key === '/topnavbar00/hrefficiency/safetraining' && typeof bookLight !== 'undefined') {
+ iconSrc = bookLight;
+ }
+ // 人员定位激活态使用personnelPosition2
+ else if (item.key === '/topnavbar00/hrefficiency/personnellocation' && typeof personnelPosition2 !== 'undefined') {
+ iconSrc = personnelPosition2;
+ }
+ // 特殊作业许可激活态使用licenseLight
+ else if (item.key === '/topnavbar00/hrefficiency/specialoperationpermit' && typeof licenseLight !== 'undefined') {
+ iconSrc = licenseLight;
}
}
diff --git a/src/pages/personnel_location/PersonnelLocation.js b/src/pages/personnel_location/PersonnelLocation.js
new file mode 100644
index 0000000..1409b34
--- /dev/null
+++ b/src/pages/personnel_location/PersonnelLocation.js
@@ -0,0 +1,486 @@
+import React, { PureComponent } from 'react';
+import { Button, Card, Row, Col, Input, Select, Space, Tag, Divider } from 'antd';
+import { SearchOutlined, FilterOutlined, ExportOutlined, LocateOutlined, UserOutlined, ClockCircleOutlined, EnvironmentOutlined }
+ from '@ant-design/icons';
+import StandardTable from '@/components/StandardTable';
+import styles from './PersonnelLocation.less';
+import datadictionary from "@/utils/dataDictionary";
+import gisTemp from '@/assets/img/gisTemp.svg';
+
+const { Option } = Select;
+const { Search } = Input;
+
+// 模拟数据
+const mockLocationData = {
+ list: [
+ {
+ id: '001',
+ name: '张三',
+ empId: '10001',
+ position: '管理人员',
+ department: '安全部',
+ location: 'A区安控室',
+ time: '2025-09-03 21:32',
+ status: '正常'
+ },
+ {
+ id: '002',
+ name: '李四',
+ empId: '10002',
+ position: '管理人员',
+ department: '设备部',
+ location: 'A区发电室',
+ time: '2025-09-03 21:30',
+ status: '预警'
+ },
+ {
+ id: '003',
+ name: '王五',
+ empId: '10003',
+ position: '管理人员',
+ department: '设备部',
+ location: 'A区发电室',
+ time: '2025-09-03 21:29',
+ status: '预警'
+ },
+ {
+ id: '004',
+ name: '赵六',
+ empId: '10004',
+ position: '管理人员',
+ department: '设备部',
+ location: 'A区发电室',
+ time: '2025-09-03 21:28',
+ status: '告警'
+ },
+ {
+ id: '005',
+ name: '孙七',
+ empId: '10005',
+ position: '管理人员',
+ department: '设备部',
+ location: 'A区发电室',
+ time: '2025-09-03 21:27',
+ status: '正常'
+ },
+ ],
+ pagination: {
+ total: 120,
+ current: 1,
+ pageSize: 5,
+ },
+};
+
+// 历史轨迹数据
+const historyTrailData = [
+ {
+ title: '进入危险区域管理',
+ time: '2025-09-03 20:30',
+ location: 'A区发电室'
+ },
+ {
+ title: '长时间停留',
+ time: '2025-09-03 20:15',
+ location: 'A区发电室'
+ },
+ {
+ title: '异常行为',
+ time: '2025-09-03 19:45',
+ location: 'A区发电室'
+ },
+ {
+ title: '工作开始',
+ time: '2025-09-03 08:00',
+ location: 'A区发电室'
+ },
+];
+
+// 人员警告信息数据
+const personnelWarningData = [
+ {
+ title: '电池低电量',
+ time: '2025-09-03 21:35',
+ location: 'A区发电室',
+ level: 'warning'
+ },
+ {
+ title: '信号丢失',
+ time: '2025-09-03 21:30',
+ location: 'B区地下室',
+ level: 'error'
+ },
+ {
+ title: '超过活动范围',
+ time: '2025-09-03 21:25',
+ location: 'C区仓库',
+ level: 'warning'
+ },
+ {
+ title: '静止时间过长',
+ time: '2025-09-03 21:20',
+ location: 'D区会议室',
+ level: 'warning'
+ },
+];
+
+class PersonnelLocation extends PureComponent {
+ state = {
+ selectedRows: [],
+ formValues: {},
+ selectedPerson: null,
+ };
+
+ // 表格列定义
+ columns = [
+ {
+ title: '姓名',
+ dataIndex: 'name',
+ key: 'name',
+ width: 100,
+ render: (text) => (
+ {text}
+ ),
+ },
+ {
+ title: '工号',
+ dataIndex: 'empId',
+ key: 'empId',
+ width: 100,
+ render: (text) => (
+ {text}
+ ),
+ },
+ {
+ title: '岗位',
+ dataIndex: 'position',
+ key: 'position',
+ width: 120,
+ render: (text) => (
+ {text}
+ ),
+ },
+ {
+ title: '所属部门',
+ dataIndex: 'department',
+ key: 'department',
+ width: 120,
+ render: (text) => (
+ {text}
+ ),
+ },
+ {
+ title: '当前位置',
+ dataIndex: 'location',
+ key: 'location',
+ width: 150,
+ render: (text) => (
+ {text}
+ ),
+ },
+ {
+ title: '时间',
+ dataIndex: 'time',
+ key: 'time',
+ width: 150,
+ render: (text) => (
+ {text}
+ ),
+ },
+ {
+ title: '状态',
+ dataIndex: 'status',
+ key: 'status',
+ width: 80,
+ render: (text) => {
+ if (text === '正常') {
+ return {text};
+ } else if (text === '预警') {
+ return {text};
+ } else {
+ return {text};
+ }
+ },
+ },
+ {
+ title: '操作',
+ key: 'action',
+ width: 80,
+ fixed: 'right',
+ render: (_, record) => (
+ this.handleLocate(record)}
+ >
+ 定位
+
+ ),
+ },
+ ];
+
+ // 获取地图配置选项
+ getMapChartOption = () => {
+ return {
+ tooltip: {
+ trigger: 'item',
+ formatter: '{b}'
+ },
+ series: [
+ {
+ name: '人员分布',
+ type: 'scatter',
+ coordinateSystem: 'geo',
+ symbolSize: 20,
+ data: [
+ { name: '张三', value: [116.404, 39.915], itemStyle: { color: '#52C41A' } },
+ { name: '李四', value: [116.414, 39.925], itemStyle: { color: '#FAAD14' } },
+ { name: '王五', value: [116.424, 39.935], itemStyle: { color: '#FAAD14' } },
+ { name: '赵六', value: [116.434, 39.945], itemStyle: { color: '#FF4D4F' } },
+ { name: '孙七', value: [116.444, 39.955], itemStyle: { color: '#52C41A' } },
+ ],
+ emphasis: {
+ focus: 'series',
+ itemStyle: {
+ borderColor: '#fff',
+ borderWidth: 2
+ }
+ }
+ }
+ ],
+ geo: {
+ map: 'beijing',
+ label: {
+ show: true
+ },
+ roam: true,
+ itemStyle: {
+ areaColor: '#f0f2f5',
+ borderColor: '#999'
+ },
+ emphasis: {
+ itemStyle: {
+ areaColor: '#e6f7ff'
+ }
+ }
+ }
+ };
+ };
+
+ // 处理表格变化
+ handleTableChange = (pagination, sorter) => {
+ const { dispatch } = this.props;
+ const { formValues } = this.state;
+
+ const params = {
+ currentPage: pagination.current,
+ pageSize: pagination.pageSize,
+ ...formValues
+ };
+
+ sorter.field && (params.sorter = `${sorter.field}_${sorter.order}`);
+ };
+
+ // 处理行选择
+ handleSelectRows = rows => {
+ this.setState({
+ selectedRows: rows
+ });
+ };
+
+ // 处理搜索
+ handleSearch = values => {
+ this.setState({
+ formValues: values
+ });
+ };
+
+ // 处理定位
+ handleLocate = (record) => {
+ this.setState({
+ selectedPerson: record
+ });
+ // 这里可以添加地图定位的逻辑
+ console.log('定位人员:', record);
+ };
+
+ render() {
+ const {
+ selectedRows,
+ selectedPerson
+ } = this.state;
+
+ return (
+
+ {/* 主要内容区域 - 地图、历史轨迹和人员警告在同一行 */}
+
+ {/* 左侧:地图显示(占一半宽度) */}
+
+
+
+ {/* 由于缺少实际地图组件,这里使用模拟的地图容器 */}
+
+
+
+

+ {/* 地图上的标记点 */}
+
+ 张三 - A区安控室
+
+
+ 李四 - A区发电室
+
+
+ 王五 - A区发电室
+
+
+ 赵六 - A区发电室
+
+
+ 孙七 - A区发电室
+
+
+
+
+ {/* 筛选栏 - 移至地图卡片内部 */}
+
+
+
+
+
+
+ 安全区域
+
+ 人员类型
+
+
+
+
+
+ }
+ className={styles['button-style']}
+ >
+ 筛选
+
+ }
+ className={styles['button-style']}
+ >
+ 导出
+
+
+
+
+
+
+
+
+ {/* 中间:历史轨迹(占四分之一宽度) */}
+
+
+
+ {historyTrailData.map((item, index) => (
+
+
+
+
+
+
{item.title}
+
+ {item.time}
+ {item.location}
+
+
+
+ ))}
+
+
+
+
+ {/* 右侧:人员警告信息(占四分之一宽度) */}
+
+
+
+ {personnelWarningData.map((item, index) => (
+
+
+ {item.level === 'error' ? 严重 : 警告}
+
+
+
{item.title}
+
+ {item.time}
+ {item.location}
+
+
+
+ ))}
+
+
+
+
+
+ {/* 底部表格区域 */}
+
+
+ `共 ${total} 条`}
+ />
+
+
+
+ );
+ }
+}
+
+export default PersonnelLocation;
\ No newline at end of file
diff --git a/src/pages/personnel_location/PersonnelLocation.less b/src/pages/personnel_location/PersonnelLocation.less
new file mode 100644
index 0000000..d33d5a3
--- /dev/null
+++ b/src/pages/personnel_location/PersonnelLocation.less
@@ -0,0 +1,452 @@
+// Ant Design 5.x不再需要导入less主题文件
+// 直接定义我们需要的主题变量
+@primary-color: rgba(36, 114, 214, 1); // 与全局样式保持一致
+@success-color: #52c41a;
+@warning-color: #faad14;
+@error-color: #ff4d4f;
+@bg-color: #f7f8fa;
+@card-bg: #ffffff;
+@border-color: #e8e8e8;
+@text-primary: #333333;
+@text-secondary: #666666;
+@text-tertiary: #999999;
+
+// 阴影效果
+@shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
+@shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
+@shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);
+
+// 动画效果
+@transition-base: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+@transition-hover: all 0.2s ease-in-out;
+
+.card-container {
+ padding: 16px;
+ background-color: @bg-color;
+ min-height: 100vh;
+}
+
+// 顶部工具栏样式
+.table-toolbar-container {
+ padding: 12px 16px;
+ background-color: @card-bg;
+ border-radius: 8px;
+ box-shadow: @shadow-sm;
+}
+
+// 搜索和筛选控件样式
+.search-input {
+ width: 240px;
+ height: 36px;
+ border-radius: 6px;
+ font-size: 14px;
+ transition: @transition-hover;
+ &:focus {
+ box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+ }
+}
+
+.filter-select {
+ width: 140px;
+ height: 36px;
+ border-radius: 6px;
+ font-size: 14px;
+ transition: @transition-hover;
+}
+
+// 按钮样式
+.button-style {
+ margin-left: 12px;
+ height: 36px;
+ padding: 0 16px;
+ border-radius: 6px;
+ font-size: 14px;
+ transition: @transition-hover;
+ &:hover {
+ transform: translateY(-1px);
+ box-shadow: @shadow-md;
+ }
+}
+
+// 地图卡片样式
+.map-card {
+ width: 100%;
+ min-height: 400px;
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: @shadow-md;
+ transition: @transition-hover;
+ display: flex;
+ flex-direction: column;
+ &:hover {
+ box-shadow: @shadow-lg;
+ }
+}
+
+.map-container {
+ height: calc(100% - 120px);
+}
+
+.mock-map {
+ width: 100%;
+ height: 100%;
+ position: relative;
+ background: linear-gradient(135deg, #f0f2f5 0%, #e6f7ff 100%);
+ border-radius: 0 0 8px 8px;
+ overflow: hidden;
+}
+
+// 地图图例样式
+.map-legend {
+ position: absolute;
+ top: 16px;
+ right: 16px;
+ background: rgba(255, 255, 255, 0.95);
+ padding: 12px 16px;
+ border-radius: 8px;
+ box-shadow: @shadow-md;
+ z-index: 10;
+ backdrop-filter: blur(4px);
+}
+
+.legend-item {
+ display: flex;
+ align-items: center;
+ margin-bottom: 6px;
+ font-size: 13px;
+ color: @text-secondary;
+ &:last-child {
+ margin-bottom: 0;
+ }
+}
+
+.legend-dot {
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ margin-right: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+// 地图内容样式
+.map-content {
+ width: 100%;
+ height: 100%;
+ position: relative;
+}
+
+.map-image {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ border-radius: 0 0 8px 8px;
+}
+
+// 地图标记点样式
+.map-marker {
+ position: absolute;
+ width: 18px;
+ height: 18px;
+ border-radius: 50%;
+ cursor: pointer;
+ transform: translate(-50%, -50%);
+ box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.9);
+ transition: @transition-hover;
+ &:hover {
+ transform: translate(-50%, -50%) scale(1.2);
+ box-shadow: 0 0 0 6px rgba(255, 255, 255, 0.95);
+ z-index: 20;
+ }
+}
+
+// 标记点提示样式
+.marker-tooltip {
+ position: absolute;
+ top: -32px;
+ left: 50%;
+ transform: translateX(-50%);
+ background: rgba(0, 0, 0, 0.8);
+ color: white;
+ padding: 6px 12px;
+ border-radius: 6px;
+ font-size: 13px;
+ white-space: nowrap;
+ display: none;
+ animation: fadeIn 0.2s ease-in-out;
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateX(-50%) translateY(5px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(-50%) translateY(0);
+ }
+}
+
+.map-marker:hover .marker-tooltip {
+ display: block;
+}
+
+// 统计卡片样式
+.stats-card {
+ margin-bottom: 16px;
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: @shadow-md;
+ transition: @transition-hover;
+ &:hover {
+ box-shadow: @shadow-lg;
+ }
+}
+
+// 历史轨迹卡片样式
+.trail-card {
+ height: 100%;
+ min-height: 240px;
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: @shadow-md;
+ transition: @transition-hover;
+ display: flex;
+ flex-direction: column;
+ &:hover {
+ box-shadow: @shadow-lg;
+ }
+}
+
+// 人员警告卡片样式
+.warning-card {
+ height: 100%;
+ min-height: 240px;
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: @shadow-md;
+ transition: @transition-hover;
+ display: flex;
+ flex-direction: column;
+ &:hover {
+ box-shadow: @shadow-lg;
+ }
+}
+
+.trail-list {
+ flex: 1;
+ overflow-y: auto;
+ padding-right: 8px;
+}
+
+// 轨迹项样式
+.trail-item {
+ display: flex;
+ padding: 12px 0;
+ border-bottom: 1px solid #f0f0f0;
+ transition: @transition-hover;
+ &:hover {
+ background-color: #fafafa;
+ padding-left: 8px;
+ border-left: 3px solid @primary-color;
+ }
+ &:last-child {
+ border-bottom: none;
+ }
+}
+
+.trail-icon {
+ margin-right: 12px;
+ color: @primary-color;
+ font-size: 16px;
+ flex-shrink: 0;
+}
+
+.trail-content {
+ flex: 1;
+}
+
+.trail-title {
+ font-size: 14px;
+ color: @text-primary;
+ margin-bottom: 6px;
+ font-weight: 500;
+}
+
+.trail-info {
+ font-size: 12px;
+ color: @text-tertiary;
+}
+
+.trail-info span {
+ margin-right: 12px;
+}
+
+// 表格容器样式
+.table-container {
+ margin-top: 16px;
+}
+
+// 位置表格卡片样式
+.location-table-card {
+ min-height: 400px;
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: @shadow-md;
+ transition: @transition-hover;
+ &:hover {
+ box-shadow: @shadow-lg;
+ }
+}
+
+// 滚动条样式优化
+.trail-list::-webkit-scrollbar,
+.warning-list::-webkit-scrollbar {
+ width: 6px;
+}
+
+.trail-list::-webkit-scrollbar-track,
+.warning-list::-webkit-scrollbar-track {
+ background: #f5f5f5;
+ border-radius: 3px;
+}
+
+.trail-list::-webkit-scrollbar-thumb,
+.warning-list::-webkit-scrollbar-thumb {
+ background: #d9d9d9;
+ border-radius: 3px;
+ transition: @transition-hover;
+ &:hover {
+ background: #bfbfbf;
+ }
+}
+
+// Ant Design 表格样式覆盖
+.ant-table {
+ .ant-table-thead > tr > th {
+ background-color: #fafafa;
+ font-weight: 500;
+ border-bottom: 1px solid #e8e8e8;
+ }
+ .ant-table-tbody > tr:hover > td {
+ background-color: #f5f8ff !important;
+ }
+ .ant-table-pagination {
+ margin-top: 16px;
+ }
+}
+
+// 状态标签样式
+.status-tag {
+ display: inline-block;
+ padding: 2px 8px;
+ border-radius: 10px;
+ font-size: 12px;
+ font-weight: 500;
+ &.status-normal {
+ background-color: #f6ffed;
+ color: @success-color;
+ border: 1px solid #b7eb8f;
+ }
+ &.status-warning {
+ background-color: #fff7e6;
+ color: @warning-color;
+ border: 1px solid #ffd591;
+ }
+ &.status-error {
+ background-color: #fff1f0;
+ color: @error-color;
+ border: 1px solid #ffccc7;
+ }
+}
+
+// 人员警告列表样式
+.warning-list {
+ flex: 1;
+ overflow-y: auto;
+ padding-right: 8px;
+}
+
+// 警告项样式
+.warning-item {
+ display: flex;
+ padding: 12px 0;
+ border-bottom: 1px solid #f0f0f0;
+ transition: @transition-hover;
+ &:hover {
+ background-color: #fafafa;
+ padding-left: 8px;
+ border-left: 3px solid @primary-color;
+ }
+ &:last-child {
+ border-bottom: none;
+ }
+ &.warning-warning {
+ border-left: 3px solid @warning-color;
+ }
+ &.warning-error {
+ border-left: 3px solid @error-color;
+ }
+}
+
+.warning-icon {
+ margin-right: 12px;
+ flex-shrink: 0;
+}
+
+.warning-content {
+ flex: 1;
+}
+
+.warning-title {
+ font-size: 14px;
+ color: @text-primary;
+ margin-bottom: 6px;
+ font-weight: 500;
+}
+
+.warning-info {
+ font-size: 12px;
+ color: @text-tertiary;
+}
+
+.warning-info span {
+ margin-right: 12px;
+}
+
+// 响应式布局适配
+@media (max-width: 1200px) {
+ .search-input {
+ width: 200px;
+ }
+ .filter-select {
+ width: 120px;
+ }
+}
+
+@media (max-width: 768px) {
+ .card-container {
+ padding: 8px;
+ }
+ .table-toolbar-container {
+ padding: 12px 8px;
+ }
+ .search-input {
+ width: 100%;
+ margin-bottom: 12px;
+ }
+ .filter-select {
+ width: 100%;
+ margin-bottom: 12px;
+ }
+ .button-style {
+ margin-left: 0;
+ margin-right: 8px;
+ }
+ .map-card {
+ min-height: 300px;
+ }
+ .trail-card {
+ height: auto;
+ min-height: 200px;
+ }
+}
\ No newline at end of file
diff --git a/src/pages/special_operation_permit/SpecialOperationPermit.js b/src/pages/special_operation_permit/SpecialOperationPermit.js
new file mode 100644
index 0000000..2d0994d
--- /dev/null
+++ b/src/pages/special_operation_permit/SpecialOperationPermit.js
@@ -0,0 +1,501 @@
+import React, { useState, useEffect } from 'react';
+import { Table, Card, Row, Col, Tag, Button, Statistic, Select, Input, Space } from 'antd';
+import { SearchOutlined, CheckOutlined, ExclamationCircleOutlined, FileTextOutlined, BarChartOutlined, BellOutlined, AlertOutlined } from '@ant-design/icons';
+import ReactECharts from 'echarts-for-react';
+import styles from './SpecialOperationPermit.less';
+
+const { Option } = Select;
+const { Column } = Table;
+
+// 模拟数据 - 统计卡片数据
+const statsData = [
+ {
+ title: '作业总数',
+ count: 126,
+ icon: ,
+ status: '正常',
+ color: '#52c41a'
+ },
+ {
+ title: '技能合格率',
+ count: '23%',
+ icon: ,
+ status: '待提升',
+ color: '#ff7875'
+ },
+ {
+ title: '作业完成率',
+ count: '67%',
+ icon: ,
+ status: '正常',
+ color: '#52c41a'
+ },
+ {
+ title: '风险防控数',
+ count: 16,
+ icon: ,
+ status: '较上月持平',
+ color: '#1890ff'
+ }
+];
+
+// 模拟数据 - 趋势分析图表
+const trendAnalysisData = {
+ title: {
+ text: '趋势分析',
+ left: 'center',
+ },
+ tooltip: {
+ trigger: 'axis',
+ },
+ legend: {
+ data: ['技能合格率', '作业完成率', '风险防控数'],
+ bottom: 0,
+ },
+ grid: {
+ left: '3%',
+ right: '4%',
+ bottom: '15%',
+ containLabel: true,
+ },
+ xAxis: {
+ type: 'category',
+ boundaryGap: false,
+ data: ['10-01', '10-02', '10-03', '10-04', '10-05', '10-06', '10-07'],
+ },
+ yAxis: {
+ type: 'value',
+ max: 100,
+ },
+ series: [
+ {
+ name: '技能合格率',
+ type: 'line',
+ smooth: true,
+ showSymbol: false,
+ data: [25, 23, 28, 26, 30, 23, 25],
+ itemStyle: { color: '#ff7a75' },
+ areaStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [{
+ offset: 0, color: 'rgba(255, 122, 117, 0.8)'
+ }, {
+ offset: 1, color: 'rgba(255, 122, 117, 0.1)'
+ }]
+ }
+ }
+ },
+ {
+ name: '作业完成率',
+ type: 'line',
+ smooth: true,
+ showSymbol: false,
+ data: [65, 68, 70, 65, 62, 67, 69],
+ itemStyle: { color: '#9254de' },
+ areaStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [{
+ offset: 0, color: 'rgba(146, 84, 222, 0.8)'
+ }, {
+ offset: 1, color: 'rgba(146, 84, 222, 0.1)'
+ }]
+ }
+ }
+ },
+ {
+ name: '风险防控数',
+ type: 'line',
+ smooth: true,
+ showSymbol: false,
+ data: [15, 18, 16, 14, 17, 16, 19],
+ itemStyle: { color: '#40a9ff' },
+ areaStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [{
+ offset: 0, color: 'rgba(64, 169, 255, 0.8)'
+ }, {
+ offset: 1, color: 'rgba(64, 169, 255, 0.1)'
+ }]
+ }
+ }
+ }
+ ],
+};
+
+// 模拟数据 - 作业类型分布图表
+const operationTypeData = {
+ title: {
+ text: '作业类型分布',
+ left: 'center',
+ },
+ tooltip: {
+ trigger: 'item',
+ },
+ legend: {
+ orient: 'vertical',
+ left: 'left',
+ data: ['动火作业', '高处作业', '有限空间作业', '临时用电', '断路作业'],
+ },
+ series: [
+ {
+ name: '作业类型',
+ type: 'pie',
+ radius: '60%',
+ data: [
+ {
+ value: 35,
+ name: '动火作业',
+ itemStyle: { color: '#1890ff' }
+ },
+ {
+ value: 25,
+ name: '高处作业',
+ itemStyle: { color: '#52c41a' }
+ },
+ {
+ value: 20,
+ name: '有限空间作业',
+ itemStyle: { color: '#faad14' }
+ },
+ {
+ value: 15,
+ name: '临时用电',
+ itemStyle: { color: '#f5222d' }
+ },
+ {
+ value: 5,
+ name: '断路作业',
+ itemStyle: { color: '#722ed1' }
+ }
+ ],
+ emphasis: {
+ itemStyle: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: 'rgba(0, 0, 0, 0.5)',
+ },
+ },
+ },
+ ],
+};
+
+// 模拟数据 - 作业列表数据
+const operationListData = [
+ {
+ key: '1',
+ operationType: '动火作业',
+ operationNo: 'DH-20230906-002',
+ applicant: '张小龙',
+ location: '2号车间',
+ startTime: '2025-09-03 03:23:12',
+ warningDept: '生产一部',
+ warningType: '气体浓度超标',
+ riskLevel: '高风险',
+ status: '进行中',
+ },
+ {
+ key: '2',
+ operationType: '高处作业',
+ operationNo: 'GC-20230906-002',
+ applicant: '李小龙',
+ location: '2号车间',
+ startTime: '2025-09-03 03:23:12',
+ warningDept: '生产一部',
+ warningType: '气体浓度超标',
+ riskLevel: '较高风险',
+ status: '未开始',
+ },
+ {
+ key: '3',
+ operationType: '有限空间作业',
+ operationNo: 'YX-20230906-002',
+ applicant: '张小虎',
+ location: '2号车间',
+ startTime: '2025-09-03 03:23:12',
+ warningDept: '生产一部',
+ warningType: '气体浓度超标',
+ riskLevel: '中风险',
+ status: '未开始',
+ },
+ {
+ key: '4',
+ operationType: '临时用电',
+ operationNo: 'LS-20230906-002',
+ applicant: '张小龙',
+ location: '2号车间',
+ startTime: '2025-09-03 03:23:12',
+ warningDept: '生产一部',
+ warningType: '气体浓度超标',
+ riskLevel: '低风险',
+ status: '进行中',
+ },
+ {
+ key: '5',
+ operationType: '动火作业',
+ operationNo: 'DH-20230906-002',
+ applicant: '张小龙',
+ location: '2号车间',
+ startTime: '2025-09-03 03:23:12',
+ warningDept: '生产一部',
+ warningType: '气体浓度超标',
+ riskLevel: '高风险',
+ status: '进行中',
+ },
+];
+
+// 状态标签渲染
+const renderStatusTag = (status) => {
+ switch (status) {
+ case '进行中':
+ return {status};
+ case '未开始':
+ return {status};
+ case '已完成':
+ return {status};
+ case '已暂停':
+ return {status};
+ default:
+ return {status};
+ }
+};
+
+// 风险等级标签渲染
+const renderRiskLevelTag = (level) => {
+ switch (level) {
+ case '高风险':
+ return {level};
+ case '较高风险':
+ return {level};
+ case '中风险':
+ return {level};
+ case '低风险':
+ return {level};
+ default:
+ return {level};
+ }
+};
+
+const SpecialOperationPermit = () => {
+ const [currentPage, setCurrentPage] = useState(1);
+ const [pageSize, setPageSize] = useState(10);
+ const [searchText, setSearchText] = useState('');
+ const [filteredData, setFilteredData] = useState(operationListData);
+
+ // 搜索处理
+ const handleSearch = (value) => {
+ setSearchText(value);
+ const filtered = operationListData.filter(item =>
+ item.operationNo.includes(value) ||
+ item.applicant.includes(value) ||
+ item.location.includes(value)
+ );
+ setFilteredData(filtered);
+ setCurrentPage(1);
+ };
+
+ // 处理操作按钮
+ const handleViewDetails = (record) => {
+ // 查看详情逻辑
+ console.log('查看详情:', record);
+ };
+
+ const handleApprove = (record) => {
+ // 审批逻辑
+ console.log('审批:', record);
+ };
+
+ return (
+
+ {/* 顶部统计卡片 */}
+
+ {statsData.map((stat, index) => (
+
+
+
+
+ {React.cloneElement(stat.icon, { style: { color: stat.color } })}
+
+
+
{stat.title}
+
{stat.count}
+
{stat.status}
+
+
+
+
+ ))}
+
+
+ {/* 中间图表区域 */}
+
+ {/* 监控预警 */}
+
+
+
+
+
+
+
高风险气体超标
+
测试气体浓度超出安全标准值25.0%
+
5分钟前
+
+
+
+
+
+
+
高温作业防护缺失
+
作业人员未按规定佩戴防护装备
+
30分钟前
+
+
+
+
+
+
+
受限空间超时
+
作业人员在受限空间内停留超过规定时间
+
60分钟前
+
+
+
+
+
+
+
受限空间作业超时
+
受限空间作业已超规定时间30分钟
+
90分钟前
+
+
+
+
+
+
+ {/* 趋势分析图表 */}
+
+
+
+
+
+ {/* 作业类型分布图表 */}
+
+
+
+
+
+
+
+ {/* 作业列表区域 */}
+
+ {/* 搜索和筛选 */}
+
+
+ }
+ allowClear
+ style={{ width: 300 }}
+ onChange={(e) => handleSearch(e.target.value)}
+ />
+
+
+
+
+
+
+ {/* 作业列表表格 */}
+ `共 ${total} 条 ${range[0]}-${range[1]}`
+ }}
+ rowKey="key"
+ size="small"
+ className={styles.operationTable}
+ >
+
+
+
+
+
+
+
+ renderRiskLevelTag(text)}
+ />
+ renderStatusTag(text)}
+ />
+ (
+
+
+
+
+ )}
+ />
+
+
+
+ );
+};
+
+export default SpecialOperationPermit;
\ No newline at end of file
diff --git a/src/pages/special_operation_permit/SpecialOperationPermit.less b/src/pages/special_operation_permit/SpecialOperationPermit.less
new file mode 100644
index 0000000..bba7f2c
--- /dev/null
+++ b/src/pages/special_operation_permit/SpecialOperationPermit.less
@@ -0,0 +1,207 @@
+/* 主容器样式 */
+.container {
+ padding: 16px;
+ background-color: #f0f2f5;
+}
+
+/* 统计卡片样式 */
+.statsRow {
+ margin-bottom: 16px;
+}
+
+.statCard {
+ background-color: #fff;
+ border-radius: 4px;
+ border: 1px solid #e8e8e8;
+ overflow: hidden;
+ transition: all 0.3s;
+ height: 100%;
+
+ &:hover {
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ transform: translateY(-2px);
+ }
+}
+
+.statContent {
+ display: flex;
+ align-items: center;
+ padding: 16px;
+}
+
+.statIcon {
+ width: 48px;
+ height: 48px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: #e6f7ff;
+ border-radius: 4px;
+ font-size: 24px;
+ margin-right: 16px;
+}
+
+.statInfo {
+ flex: 1;
+}
+
+.statTitle {
+ font-size: 14px;
+ color: #666;
+ margin-bottom: 4px;
+}
+
+.statCount {
+ font-size: 24px;
+ font-weight: 500;
+ color: #333;
+ margin-bottom: 4px;
+}
+
+.statStatus {
+ font-size: 12px;
+ font-weight: 500;
+}
+
+/* 图表区域样式 */
+.chartRow {
+ margin-bottom: 16px;
+}
+
+.chartCard {
+ margin-bottom: 16px;
+ height: 360px;
+ overflow: hidden;
+}
+
+/* 监控预警样式 */
+.alarmList {
+ height: 100%;
+ overflow-y: auto;
+ padding: 8px 0;
+
+ &::-webkit-scrollbar {
+ width: 4px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: #d9d9d9;
+ border-radius: 2px;
+ }
+
+ &::-webkit-scrollbar-track {
+ background: #f5f5f5;
+ }
+}
+
+.alarmItem {
+ display: flex;
+ align-items: flex-start;
+ padding: 12px 16px;
+ margin-bottom: 8px;
+ background: #fafafa;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: all 0.3s;
+
+ &:hover {
+ background: #f0f0f0;
+ transform: translateX(4px);
+ }
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+}
+
+.alarmIcon {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 12px;
+ flex-shrink: 0;
+}
+
+.alarmInfo {
+ flex: 1;
+ min-width: 0;
+}
+
+.alarmTitle {
+ font-size: 14px;
+ font-weight: 500;
+ color: #333;
+ margin-bottom: 4px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.alarmDesc {
+ font-size: 12px;
+ color: #666;
+ margin-bottom: 4px;
+ line-height: 1.4;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+}
+
+.alarmTime {
+ font-size: 11px;
+ color: #999;
+}
+
+.chart {
+ height: 300px;
+}
+
+/* 表格区域样式 */
+.tableCard {
+ background-color: #fff;
+ border-radius: 4px;
+}
+
+.searchFilter {
+ margin-bottom: 16px;
+ padding-top: 16px;
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+}
+
+.operationTable {
+ .ant-table-thead > tr > th {
+ background-color: #fafafa;
+ border-bottom: 1px solid #f0f0f0;
+ }
+
+ .ant-table-tbody > tr > td {
+ border-bottom: 1px solid #f0f0f0;
+ }
+}
+
+/* 响应式调整 */
+@media (max-width: 768px) {
+ .container {
+ padding: 8px;
+ }
+
+ .searchFilter {
+ flex-direction: column;
+ align-items: stretch;
+ }
+
+ .searchFilter > * {
+ margin-bottom: 8px !important;
+ }
+
+ .chart {
+ height: 250px;
+ }
+}
\ No newline at end of file
diff --git a/src/pages/topnavbar/TopNavBar.js b/src/pages/topnavbar/TopNavBar.js
index 23bad47..008ed3c 100644
--- a/src/pages/topnavbar/TopNavBar.js
+++ b/src/pages/topnavbar/TopNavBar.js
@@ -43,7 +43,7 @@ const menuItem = [
key: '/topnavbar00/hrefficiency/basicinformation',
// icon: ,
},
- {
+ {
label: '重大危险源管理',
key: '/topnavbar00/hrefficiency/safeMajorHazard',
// icon: ,
@@ -53,6 +53,21 @@ const menuItem = [
key: '/topnavbar00/hrefficiency/hiddentrouble',
// icon: ,
},
+ {
+ label: '人员定位',
+ key: '/topnavbar00/hrefficiency/personnellocation',
+ // icon: ,
+ },
+ {
+ label: '安全教育培训',
+ key: '/topnavbar00/hrefficiency/safetraining',
+ // icon: ,
+ },
+ {
+ label: '特殊作业许可',
+ key: '/topnavbar00/hrefficiency/specialoperationpermit',
+ // icon: ,
+ },
{
label: '系统管理',
key: '/topnavbar00/hrefficiency/system',