新增页面:巡检管理——实时监控

main
yupeng 1 month ago
parent 99443b6d1e
commit d4848ea0b3

@ -18,15 +18,8 @@ import newBgImage from '@/assets/img/a858e701a4fde498b9c3cc56ab2b62693055dee1.pn
import paibanBg from '@/assets/img/paiban.png'
import inspectionBg from '@/assets/img/Rectangle 34624130.svg'
import taskPlanBg from '@/assets/img/image 674 1.svg'
import {
DeleteOutlined,
DownOutlined,
EditOutlined,
ExportOutlined,
EyeOutlined,
PlusOutlined,
RedoOutlined
} from "@ant-design/icons";
import { DeleteOutlined, DownOutlined, EditOutlined, ExportOutlined, EyeOutlined, PlusOutlined, RedoOutlined, ReloadOutlined as IconRefresh, SearchOutlined as IconSearch } from "@ant-design/icons";
import TemperatureHumidityGauges from '../ReusableGauges/ReusableGauges';
const { Search } = Input
export const MenuBg = (props) => {
return (
@ -109,145 +102,6 @@ const Drawers = (props) => {
)
}
// End of removed code
// 员工表格组件
// </a>
// </Space>
// ),
// ]
// // 选择框配置
// const rowSelection = {
// selectedRowKeys,
// onChange: (newSelectedRowKeys) => {
// setSelectedRowKeys(newSelectedRowKeys);
// },
// };
// const fetchTableData = () => {
// try {
// setLoading(true)
// const mockData = [
// {
// key: '1',
// groupId: 'GH001',
// groupName: '输油运行一班',
// groupHeader: '钱佳仪',
// num: '8',
// position: '油罐储存区 A、B 区',
// phone: '189 7731 3118',
// status: true,
// createTime: '2025-09-13',
// remarks: '负责日常输油设备巡检与操作',
// },
// {
// key: '2',
// groupId: 'GH002',
// groupName: '消防应急班组',
// groupHeader: '何颖颀',
// num: '6',
// position: '全厂区消防系统',
// phone: '156 9747 2741',
// status: true,
// createTime: '2025-09-12',
// remarks: '含2 名持证消防设施操作员',
// },
// {
// key: '3',
// groupId: 'GH003',
// groupName: '设备维保班组',
// groupHeader: '周遵武',
// num: '10',
// position: '泵房、工艺设备区',
// phone: '151 4456 8916',
// status: true,
// createTime: '2025-08-16',
// remarks: '擅长油泵、输油管道维护',
// },
// {
// key: '4',
// groupId: 'GH004',
// groupName: '装卸作业班组',
// groupHeader: '钱博西',
// num: '7',
// position: '油品装卸区站台',
// phone: '181 8511 3486',
// status: true,
// createTime: '2025-08-15',
// remarks: '专注装卸作业安全监护',
// },
// {
// key: '5',
// groupId: 'GH005',
// groupName: '工艺调和班组',
// groupHeader: '周缙绅',
// num: '9',
// position: '调和工艺区 1-3 号罐',
// phone: '183 3220 4078',
// status: true,
// createTime: '2025-07-20',
// remarks: '负责油品调和工艺参数管控',
// },
// {
// key: '6',
// groupId: 'GH006',
// groupName: '临时支援班组',
// groupHeader: '周江',
// num: '4',
// position: '全厂区(机动)',
// phone: '187 5703 5618',
// status: false,
// createTime: '2025-07-17',
// remarks: '项目结束,暂停用待复用',
// }
// ]
// setDataSource(mockData)
// setTotal(85)
// } catch (error) {
// console.error(error)
// } finally {
// setLoading(false)
// }
// }
// // 初始加载和分页变化时重新获取数据
// useEffect(() => {
// fetchTableData();
// }, [currentPage, pageSize]);
// // 处理查看详情
// const handleView = (record) => {
// // 预留查看详情逻辑
// console.log('查看详情:', record);
// };
// // 处理编辑
// const handleEdit = (record) => {
// // 预留编辑逻辑
// console.log('编辑:', record);
// };
// // 处理删除
// const handleDelete = (record) => {
// // 预留删除逻辑
// console.log('删除:', record);
// };
// return (
// <Table
// rowSelection={{
// type: 'checkbox',
// ...rowSelection,
// }}
// columns={columns}
// dataSource={dataSource}
// loading={loading}
// pagination={false} // 关闭表格自带分页,使用外部分页组件
// rowKey="key"
// style={{ width: '100%', }}
// />
// )
// }
const TimeTable = () => {
//状态管理
const [dataSource, setDataSource] = useState([]) //表格数据
@ -1491,14 +1345,7 @@ const SmartInspectionContent = () => {
<h3 style={{ margin: '16px', fontSize: 16 }}>实时仪表盘</h3>
{/* 温度仪表盘 - 使用React兼容的ECharts组件 */}
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
<div style={{ marginBottom: 0 }}>
<EChartsGauge id="temperatureGauge" option={temperatureOption} width={450} height={350} />
</div>
{/* 湿度仪表盘 - 使用React兼容的ECharts组件 */}
<div>
<EChartsGauge id="humidityGauge" option={humidityOption} width={450} height={350} />
</div>
<TemperatureHumidityGauges temperature={28} humidity={55} width={450} height={350} />
</div>
</div>
@ -2553,8 +2400,187 @@ const items = [
label: <MenuBg text={'巡检内容'}></MenuBg>,
key: '巡检内容',
},
{
label: <MenuBg text={'巡检管理'}></MenuBg>,
key: '巡检管理',
},
]
const InspectionManagement = () => {
const [activeTab, setActiveTab] = useState('实时监控');
return (
<div style={{ backgroundColor: '#fff', padding: '20px', minHeight: '600px', marginBottom: 10, borderRadius: '15px' }}>
{/* 顶部按钮 */}
<div style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor: '#fff',
padding: '16px 24px',
color: 'black',
fontWeight: '400',
fontSize: 18
}}>
<div>
| 智能巡检内容监控中心
</div>
<div>
<Button className={styles['addBtn']} style={{ backgroundImage: `url(${btnImg1})`, }}>一键生成报告</Button>
<Button className={styles['resetBtn']} style={{ backgroundImage: `url(${btnImg3})`, margin: '0 20px', width: 120 }}>任务调度</Button>
<Button className={styles['delBtn']} icon={<IconRefresh />} style={{ backgroundImage: `url(${btnImg2})`, width: 120 }}>刷新数据</Button>
</div>
</div>
{/* 左侧导航 */}
<div style={{ display: 'flex', height: 'calc(100vh - 200px)' }}>
<div style={{
width: 240,
backgroundColor: '#fff',
// minHeight: 'calc(100vh - 60px)',
padding: 16
}}>
<nav>
<ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>
{['实时监控', '巡检任务', '报告管理'].map((tab) => (
<li key={tab} style={{ marginBottom: 22 }}>
<button
onClick={() => setActiveTab(tab)}
className={`${styles.tabButton} ${activeTab === tab ? styles.active : styles.inactive}`}
style={{
backgroundImage: activeTab === tab ? `url(${activeBgImage})` :
tab === '实时监控' ? `url(${menuInactiveBg1})` :
tab === '巡检任务' ? `url(${menuInactiveBg2})` :
`url(${menuInactiveBg3})`
}}
>
{tab}
</button>
</li>
))}
</ul>
</nav>
</div>
{/* 右侧内容区域 */}
<div style={{ flex: 1 }}>
{activeTab === '实时监控' && (
<div>
{/* 搜索栏 */}
<div style={{ display: 'flex', marginBottom: '20px', alignItems: 'center' }}>
<Input placeholder="请输入名称" style={{ width: '200px', marginRight: '15px' }} />
<Select placeholder="区域" style={{ width: '120px', marginRight: '15px' }}>
<Select.Option value="全部">全部</Select.Option>
</Select>
<Select placeholder="任务" style={{ width: '120px', marginRight: '15px' }}>
<Select.Option value="全部">全部</Select.Option>
</Select>
<Select placeholder="设备" style={{ width: '120px', marginRight: '15px' }}>
<Select.Option value="全部">全部</Select.Option>
</Select>
<Button className={styles['addBtn']} icon={<IconSearch />} style={{ backgroundImage: `url(${btnImg1})`, width: 120 }}>查询</Button>
<Button className={styles['resetBtn']} icon={<IconRefresh />} style={{ backgroundImage: `url(${btnImg3})`, margin: '0 20px', width: 120 }}>重置</Button>
</div>
{/* 内容区域 - 调整高度布局顶部贴近底部只留10px空间 */}
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1.2fr 1fr', gap: '10px', marginTop: 0, marginBottom: '10px', height: '100%', minHeight: '0' }}>
{/* 传感器仪表盘 */}
<div style={{ backgroundColor: '#f5f5f5', borderRadius: '8px', padding: '10px 20px 10px 20px', marginTop: 0, height: '100%', display: 'flex', flexDirection: 'column' }}>
<h3 style={{ marginBottom: '10px', marginTop: 0 }}>传感器仪表盘</h3>
<div style={{ display: 'flex', justifyContent: 'space-around', marginBottom: '10px', alignItems: 'center' }}>
<TemperatureHumidityGauges temperature={28} humidity={55} width={240} height={180} />
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '10px' }}>
<div style={{ backgroundColor: '#fff', padding: '10px', borderRadius: '4px' }}>甲烷: 0.01%</div>
<div style={{ backgroundColor: '#fff', padding: '10px', borderRadius: '4px' }}>一氧化碳: 0.0ppm</div>
<div style={{ backgroundColor: '#fff', padding: '10px', borderRadius: '4px' }}>分贝值: 69.2db</div>
</div>
</div>
{/* 双面监控区 */}
<div style={{ backgroundColor: '#f5f5f5', borderRadius: '8px', padding: '10px 20px 10px 20px', marginTop: 0, height: '100%', display: 'flex', flexDirection: 'column' }}>
<h3 style={{ marginBottom: '10px', marginTop: 0 }}>双面监控区</h3>
<div style={{ display: 'grid', gridTemplateRows: '1fr 1fr', gap: '10px' }}>
<div style={{ backgroundColor: '#000', borderRadius: '4px', height: '150px', display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}>
<img
src={thermalImage}
alt="红外热成像图"
style={{ width: '100%', height: '100%', objectFit: 'cover', borderRadius: 4 }}
/>
</div>
<div style={{ backgroundColor: '#000', borderRadius: '4px', height: '150px', display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}>
<img
src={thermalImage}
alt="视频监控画面"
style={{ width: '100%', height: '100%', objectFit: 'cover', borderRadius: 4 }}
/>
</div>
</div>
</div>
{/* 机器人信息和检测设备状态 */}
<div style={{ height: '100%', display: 'flex', flexDirection: 'column', gap: '10px' }}>
<div style={{ backgroundColor: '#f5f5f5', borderRadius: '8px', padding: '10px 20px 10px 20px', marginTop: 0, marginBottom: 0, flex: 1, display: 'flex', flexDirection: 'column' }}>
<h3 style={{ marginBottom: '10px', marginTop: 0 }}>机器人实时信息</h3>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '10px' }}>
<div style={{ backgroundColor: '#fff', padding: '10px', borderRadius: '4px' }}>机器人名称: AAA</div>
<div style={{ backgroundColor: '#fff', padding: '10px', borderRadius: '4px' }}>当前位置: 中控室</div>
<div style={{ backgroundColor: '#fff', padding: '10px', borderRadius: '4px' }}>速度: 0.07m/s</div>
<div style={{ backgroundColor: '#fff', padding: '10px', borderRadius: '4px' }}>当前模式: 巡回检测</div>
<div style={{ backgroundColor: '#fff', padding: '10px', borderRadius: '4px' }}>电量: 85%</div>
<div style={{ backgroundColor: '#fff', padding: '10px', borderRadius: '4px' }}>累计里程: 96km</div>
</div>
</div>
<div style={{ backgroundColor: '#f5f5f5', borderRadius: '8px', padding: '10px 20px 10px 20px', marginTop: 0, flex: 2, display: 'flex', flexDirection: 'column' }}>
<h3 style={{ marginBottom: '10px', marginTop: 0 }}>检测设备状态</h3>
<Table
dataSource={[
{ key: '1', 序号: 1, 接管设备: '接管设备A', 设备名称: '设备C', 状态: '正常', 检测时间: '2025-10-12 16:40', 检测精度: '已处理' },
{ key: '2', 序号: 2, 接管设备: '接管设备B', 设备名称: '设备C', 状态: '正常', 检测时间: '2025-10-10 09:10', 检测精度: '误报' },
]}
columns={[
{ title: '序号', dataIndex: '序号', key: '序号', width: '40px' },
{ title: '接管设备', dataIndex: '接管设备', key: '接管设备', width: '80px' },
{ title: '设备名称', dataIndex: '设备名称', key: '设备名称', width: '60px' },
{ title: '状态', dataIndex: '状态', key: '状态', width: '60px' },
{ title: '检测时间', dataIndex: '检测时间', key: '检测时间', width: '120px' },
{ title: '检测精度', dataIndex: '检测精度', key: '检测精度', width: '60px' },
]}
pagination={{
total: 85,
pageSize: 10,
current: 8,
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}}
size="small"
/>
</div>
</div>
</div>
</div>
)}
{activeTab === '巡检任务' && (
<div style={{ padding: '20px', textAlign: 'center', color: '#666' }}>
<h3>巡检任务管理</h3>
<p style={{ marginTop: '50px' }}>此处将显示巡检任务相关内容</p>
</div>
)}
{activeTab === '报告管理' && (
<div style={{ padding: '20px', textAlign: 'center', color: '#666' }}>
<h3>巡检报告管理</h3>
<p style={{ marginTop: '50px' }}>此处将显示巡检报告相关内容</p>
</div>
)}
</div>
</div>
</div>
);
};
const list = {
'巡检管理': <InspectionManagement />,
'巡检标准管理': <StandardManagement />,
'设备属性设置': <DeviceAttributeSettings />,
'智能巡检范围监控': <SmartInspectionRange />,

@ -0,0 +1,291 @@
import React, { useRef, useEffect } from 'react';
/**
* ECharts仪表盘组件 - 支持动态大小
*/
export const EChartsGauge = ({ id, option, height, width }) => {
const chartRef = useRef(null);
const chartInstanceRef = useRef(null);
useEffect(() => {
// 确保在浏览器环境中运行
if (typeof window !== 'undefined' && chartRef.current) {
const echarts = require('echarts');
// 初始化图表
if (!chartInstanceRef.current) {
chartInstanceRef.current = echarts.init(chartRef.current);
}
// 设置配置
chartInstanceRef.current.setOption(option);
// 响应窗口大小变化
const handleResize = () => {
if (chartInstanceRef.current) {
chartInstanceRef.current.resize();
}
};
window.addEventListener('resize', handleResize);
// 清理函数
return () => {
window.removeEventListener('resize', handleResize);
if (chartInstanceRef.current) {
chartInstanceRef.current.dispose();
chartInstanceRef.current = null;
}
};
}
}, [option]);
return (
<div
ref={chartRef}
id={id}
style={{ width, height }}
/>
);
};
/**
* 温度仪表盘配置生成函数
* @param {number} value - 温度值
* @returns {object} ECharts配置选项
*/
export const getTemperatureGaugeOption = (value = 28) => {
return {
series: [
{
type: 'gauge',
startAngle: 180,
endAngle: 0,
min: 0,
max: 120,
splitNumber: 6,
itemStyle: {
color: 'rgba(4, 95, 94, 0.5)',
shadowColor: 'rgba(4, 95, 94, 0.7)',
shadowBlur: 10,
shadowOffsetX: 2,
shadowOffsetY: 2
},
progress: {
show: true,
roundCap: true,
width: 18,
itemStyle: {
color: 'rgba(4, 95, 94, 0.5)'
}
},
pointer: {
icon: 'path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999 2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929 C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078 C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014 L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423 2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314 2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028 2089.24407,615.30999 2090.36389,615.30999 Z',
length: '75%',
width: 16,
offsetCenter: [0, '5%'],
itemStyle: {
color: 'rgba(4, 95, 94, 1)'
}
},
axisLine: {
roundCap: true,
lineStyle: {
width: 18,
color: [
[1, 'rgba(4, 95, 94, 0.5)']
]
}
},
axisTick: {
splitNumber: 2,
lineStyle: {
width: 2,
color: '#999'
}
},
splitLine: {
length: 12,
lineStyle: {
width: 3,
color: 'rgba(4, 95, 94, 0.8)'
}
},
axisLabel: {
distance: 30,
color: 'rgba(4, 95, 94, 0.8)',
fontSize: 20
},
title: {
show: true,
offsetCenter: [0, '10%'],
fontSize: 18,
color: 'rgba(4, 95, 94, 0.8)'
},
detail: {
width: '60%',
lineHeight: 40,
height: 40,
borderRadius: 8,
offsetCenter: [0, '35%'],
valueAnimation: true,
formatter: function (value) {
return '{value|温度:' + value.toFixed(0) + '℃}';
},
rich: {
value: {
fontSize: 20,
fontWeight: '400',
color: 'rgba(4, 95, 94, 1)'
},
unit: {
fontSize: 20,
color: 'rgba(4, 95, 94, 0.8)',
padding: [0, 0, -20, 10]
}
}
},
data: [
{
value: value,
name: ''
}
]
}
]
};
};
/**
* 湿度仪表盘配置生成函数
* @param {number} value - 湿度值
* @returns {object} ECharts配置选项
*/
export const getHumidityGaugeOption = (value = 55) => {
return {
series: [
{
type: 'gauge',
startAngle: 180,
endAngle: 0,
min: 0,
max: 120,
splitNumber: 6,
itemStyle: {
color: 'rgba(4, 95, 94, 0.5)',
shadowColor: 'rgba(4, 95, 94, 0.7)',
shadowBlur: 10,
shadowOffsetX: 2,
shadowOffsetY: 2
},
progress: {
show: true,
roundCap: true,
width: 18,
itemStyle: {
color: 'rgba(4, 95, 94, 0.5)'
}
},
pointer: {
icon: 'path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999 2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929 C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078 C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014 L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423 2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314 2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028 2089.24407,615.30999 2090.36389,615.30999 Z',
length: '75%',
width: 16,
offsetCenter: [0, '5%'],
itemStyle: {
color: 'rgba(4, 95, 94, 1)'
}
},
axisLine: {
roundCap: true,
lineStyle: {
width: 18,
color: [
[1, 'rgba(4, 95, 94, 0.5)']
]
}
},
axisTick: {
splitNumber: 2,
lineStyle: {
width: 2,
color: '#999'
}
},
splitLine: {
length: 12,
lineStyle: {
width: 3,
color: 'rgba(4, 95, 94, 0.8)'
}
},
axisLabel: {
distance: 30,
color: 'rgba(4, 95, 94, 0.8)',
fontSize: 20
},
title: {
show: true,
offsetCenter: [0, '10%'],
fontSize: 18,
color: 'rgba(4, 95, 94, 0.8)'
},
detail: {
width: '60%',
lineHeight: 40,
height: 40,
borderRadius: 8,
offsetCenter: [0, '35%'],
valueAnimation: true,
formatter: function (value) {
return '{value|湿度:' + value.toFixed(0) + '%}';
},
rich: {
value: {
fontSize: 20,
fontWeight: '400',
color: 'rgba(4, 95, 94, 1)'
},
unit: {
fontSize: 20,
color: 'rgba(4, 95, 94, 0.8)',
padding: [0, 0, -20, 10]
}
}
},
data: [
{
value: value,
name: ''
}
]
}
]
};
};
/**
* 温湿度仪表盘组合组件
* @param {object} props - 组件属性
* @param {number} props.temperature - 温度值
* @param {number} props.humidity - 湿度值
* @param {number} props.width - 单个仪表盘宽度
* @param {number} props.height - 单个仪表盘高度
*/
const TemperatureHumidityGauges = ({ temperature = 28, humidity = 55, width = 600, height = 600 }) => {
const temperatureOption = getTemperatureGaugeOption(temperature);
const humidityOption = getHumidityGaugeOption(humidity);
return (
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
<div style={{ marginBottom: 0 }}>
<EChartsGauge id="temperatureGauge" option={temperatureOption} width={width} height={height} />
</div>
<div>
<EChartsGauge id="humidityGauge" option={humidityOption} width={width} height={height} />
</div>
</div>
);
};
export default TemperatureHumidityGauges;
Loading…
Cancel
Save