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 ( + + {/* 主要内容区域 - 地图、历史轨迹和人员警告在同一行 */} + + {/* 左侧:地图显示(占一半宽度) */} + + +
+ {/* 由于缺少实际地图组件,这里使用模拟的地图容器 */} +
+
+
+
+ 正常 (45) +
+
+
+ 预警 (32) +
+
+
+ 告警 (12) +
+
+
+ GIS地图 + {/* 地图上的标记点 */} +
+ 张三 - A区安控室 +
+
+ 李四 - A区发电室 +
+
+ 王五 - A区发电室 +
+
+ 赵六 - A区发电室 +
+
+ 孙七 - A区发电室 +
+
+
+
+ {/* 筛选栏 - 移至地图卡片内部 */} + +
+ + + + + 安全区域 + + 人员类型 + + + + + + + + + + +
+
+ + + {/* 中间:历史轨迹(占四分之一宽度) */} + + +
+ {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',