You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

483 lines
16 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { useState } from "react";
import styles from './InspectionTaskPlan.less';
import { Button, Card, Col, Row, Table, Tabs, Input, Space, Modal, Tag, Tree } from "antd";
import { SearchOutlined, DownloadOutlined, PlusOutlined, DownOutlined, RightOutlined, ReloadOutlined } from "@ant-design/icons";
// 自定义树节点图标
const TreeNode = Tree.TreeNode;
// 设备树数据
const deviceTreeData = [
{
title: "407输送机",
key: "407",
expanded: true,
children: [
{
title: "托辊组 (600)",
key: "407_rollers",
children: [
{ title: "1#托辊组", key: "407_roller_1" },
{ title: "2#托辊组", key: "407_roller_2" },
{ title: "3#托辊组", key: "407_roller_3" },
{ title: "4#托辊组", key: "407_roller_4" }
]
},
{
title: "电机 (2)",
key: "407_motors",
children: [
{ title: "1#电机", key: "407_motor_1" },
{ title: "2#电机", key: "407_motor_2" }
]
},
{
title: "减速器 (2)",
key: "407_reducers",
children: [
{ title: "1#减速器", key: "407_reducer_1" },
{ title: "2#减速器", key: "407_reducer_2" }
]
},
{ title: "滚筒 (2)", key: "407_drums" },
{ title: "输送带", key: "407_belt" },
{ title: "物料溜槽", key: "407_chute" }
]
},
{
title: "MA501输送机",
key: "MA501",
expanded: false
},
{
title: "PM105输送机",
key: "PM105",
expanded: false
}
];
const { TabPane } = Tabs;
const { Search } = Input;
// 数据分析巡检管理组件
const DataAnalysisInspectionManagement = () => {
const [activeKey, setActiveKey] = useState('1');
const [query, setQuery] = useState('');
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [detailVisible, setDetailVisible] = useState(false);
const [currentRecord, setCurrentRecord] = useState(null);
const [expandedKeys, setExpandedKeys] = useState(['407', '407_rollers', '407_motors', '407_reducers']);
const [selectedKeys, setSelectedKeys] = useState(['407_roller_1']);
// 处理树节点展开/折叠
const onExpand = (expandedKeysValue) => {
setExpandedKeys(expandedKeysValue);
};
// 处理树节点选择
const onSelect = (selectedKeysValue) => {
setSelectedKeys(selectedKeysValue);
};
// 渲染设备树
const renderDeviceTree = () => {
const renderTreeNodes = (data) => {
return data.map((item) => {
if (item.children) {
return (
<TreeNode title={item.title} key={item.key} dataRef={item}>
{renderTreeNodes(item.children)}
</TreeNode>
);
}
return <TreeNode title={item.title} key={item.key} dataRef={item} />;
});
};
return (
<div className={styles.deviceTreeContainer}>
<h3>设备层级导航</h3>
<Tree
expandedKeys={expandedKeys}
selectedKeys={selectedKeys}
onExpand={onExpand}
onSelect={onSelect}
showIcon={false}
>
{renderTreeNodes(deviceTreeData)}
</Tree>
</div>
);
};
// 表格列配置
const columns = [
{
title: '序号',
dataIndex: 'id',
key: 'id',
width: 80,
align: 'center',
},
{
title: '设备/部件',
dataIndex: 'device',
key: 'device',
width: 150,
render: (text) => <span style={{ color: '#006665' }}>{text}</span>,
},
{
title: '运行时长',
dataIndex: 'duration',
key: 'duration',
width: 120,
align: 'center',
},
{
title: '异常类型',
dataIndex: 'type',
key: 'type',
width: 120,
align: 'center',
render: (t) => {
let color = 'green';
if (t === '温度预警') color = 'orange';
if (t === '异常') color = 'red';
return <Tag color={color}>{t}</Tag>;
},
},
{
title: '环境温度',
dataIndex: 'temperature',
key: 'temperature',
width: 120,
align: 'center',
},
{
title: '处理状态',
dataIndex: 'status',
key: 'status',
width: 120,
align: 'center',
render: (status) => {
let color = '#006665';
if (status === '待检修') color = '#ff6600';
return <span style={{ color, fontWeight: 'bold' }}>{status}</span>;
},
},
];
// 表格数据(示例)
const initialData = [
{
key: 1,
id: 1,
device: '407输送机1#托辊组',
duration: '300小时',
type: '无异常',
temperature: '25.5℃',
status: '正常',
},
{
key: 2,
id: 2,
device: '407输送机1#电机',
duration: '280小时',
type: '温度预警',
temperature: '48℃',
status: '待检修',
},
{
key: 3,
id: 3,
device: '407输送机2#托辊组',
duration: '290小时',
type: '无异常',
temperature: '26.2℃',
status: '正常',
},
{
key: 4,
id: 4,
device: '407输送机2#电机',
duration: '275小时',
type: '无异常',
temperature: '45℃',
status: '正常',
},
{
key: 5,
id: 5,
device: '407输送机3#托辊组',
duration: '285小时',
type: '无异常',
temperature: '25.8℃',
status: '正常',
},
{
key: 6,
id: 6,
device: '407输送机1#减速器',
duration: '310小时',
type: '无异常',
temperature: '32℃',
status: '正常',
},
{
key: 7,
id: 7,
device: '407输送机2#减速器',
duration: '305小时',
type: '无异常',
temperature: '33℃',
status: '正常',
},
{
key: 8,
id: 8,
device: '407输送机滚筒',
duration: '315小时',
type: '无异常',
temperature: '28℃',
status: '正常',
},
{
key: 9,
id: 9,
device: '407输送机输送带',
duration: '320小时',
type: '无异常',
temperature: '27℃',
status: '正常',
},
{
key: 10,
id: 10,
device: '407输送物料溜槽',
duration: '300小时',
type: '无异常',
temperature: '26℃',
status: '正常',
},
];
const [data, setData] = useState(initialData);
function openDetail(record) {
setCurrentRecord(record);
setDetailVisible(true);
}
function closeDetail() {
setDetailVisible(false);
setCurrentRecord(null);
}
function handleSearch(value) {
setQuery(value);
// 简单本地过滤示例 — 实际请接后端
const filtered = initialData.filter((r) => r.device.includes(value) || String(r.id) === value);
setData(filtered);
setPage(1);
}
function handleExport() {
// 简单 CSV 导出示例
const headers = ['id', 'device', 'duration', 'type', 'temperature', 'status'];
const rows = data.map((r) => headers.map((h) => (r[h] ?? '')).join(','));
const csv = [headers.join(','), ...rows].join('\n');
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'data_analysis_export.csv';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
return (
<div className={styles['data-analysis-container']}>
<Row gutter={16}>
{/* 左侧设备导航树 */}
<Col xs={24} sm={24} md={6} lg={6} xl={5}>
<Card className={styles.deviceTreeCard}>
{renderDeviceTree()}
</Card>
</Col>
{/* 右侧主要内容区域 */}
<Col xs={24} sm={24} md={18} lg={18} xl={19}>
{/* 设备拓扑和环境监测区域 */}
<Row gutter={16} style={{ marginBottom: 16 }}>
{/* 设备拓扑可视化 */}
<Col xs={24} sm={24} md={12} lg={12} xl={12}>
<Card className={styles.topologyContainer} title="设备拓扑可视化">
<div className={styles.topologyContent}>
<div className={styles.topologyInfo}>
<div className={styles.statusIndicators}>
<div className={styles.statusItem}>
<div className={styles.statusDot} style={{ backgroundColor: '#00ff00' }}></div>
<span>正常</span>
</div>
<div className={styles.statusItem}>
<div className={styles.statusDot} style={{ backgroundColor: '#ffff00' }}></div>
<span>预警</span>
</div>
<div className={styles.statusItem}>
<div className={styles.statusDot} style={{ backgroundColor: '#ff0000' }}></div>
<span>异常</span>
</div>
</div>
<div className={styles.deviceInfo}>
<p>407/输送机</p>
<p>长度 1900mm宽度 2500mm</p>
</div>
</div>
<div className={styles.topologyImage}>
{/* 设备拓扑图占位 */}
<div className={styles.conveyorBelt}></div>
</div>
<div className={styles.topologyControls}>
<Button size="small" className={styles.controlBtn}>+</Button>
<Button size="small" className={styles.controlBtn}>-</Button>
<Button size="small" className={styles.controlBtn}></Button>
</div>
</div>
</Card>
</Col>
{/* 巡检区域环境监测 */}
<Col xs={24} sm={24} md={12} lg={12} xl={12}>
<Card className={styles.environmentContainer} title="巡检区域环境">
<div className={styles.environmentContent}>
<div className={styles.dashboardMetrics}>
<div className={styles.metricItem}>
<div className={styles.metricLabel}>温度</div>
<div className={styles.metricValue}>26°C</div>
</div>
<div className={styles.metricItem}>
<div className={styles.metricLabel}>湿度</div>
<div className={styles.metricValue}>55%RH</div>
</div>
<div className={styles.metricItem}>
<div className={styles.metricLabel}>甲烷</div>
<div className={styles.metricValue}>0.0%</div>
</div>
<div className={styles.metricItem}>
<div className={styles.metricLabel}>一氧化碳</div>
<div className={styles.metricValue}>4.0ppm</div>
</div>
<div className={styles.metricItem}>
<div className={styles.metricLabel}>粉尘(PM2.5)</div>
<div className={styles.metricValue}>16μg/</div>
</div>
</div>
<div className={styles.thermalImageContainer}>
{/* 热成像图占位 */}
<div className={styles.thermalImage}></div>
<div className={styles.thermalControls}>
<Button size="small" className={styles.controlBtn}>+</Button>
<Button size="small" className={styles.controlBtn}>-</Button>
</div>
</div>
</div>
</Card>
</Col>
</Row>
<Card className={styles.dashboardContainer} style={{ marginBottom: 16 }}>
<Row gutter={16} align="middle">
<Col flex="320px">
<Space>
<Search
placeholder="请输入设备名称或编号"
onSearch={handleSearch}
enterButton={<SearchOutlined />}
allowClear
style={{ width: 320 }}
className={styles.searchInput}
/>
<Button type="primary" icon={<PlusOutlined />} className={styles.addBtn} disabled>新增</Button>
<Button type="link" icon={<ReloadOutlined />} onClick={() => { }} className={styles.refreshBtn}>重置</Button>
</Space>
</Col>
<Col flex="auto" style={{ textAlign: 'right' }}>
<div className={styles.dataUpdateTime}>数据更新时间2025-12-15 10:00</div>
</Col>
</Row>
</Card>
<Tabs activeKey={activeKey} onChange={setActiveKey}>
<TabPane tab="历史数据" key="1">
<Card className={styles.thresholdConfigContainer} bordered={false}>
<Table
columns={columns}
dataSource={data}
rowKey="key"
pagination={{
current: page,
pageSize,
total: 85,
showSizeChanger: true,
showTotal: (total) => `${total}`,
pageSizeOptions: ['10', '20', '50'],
onChange: (p, ps) => {
setPage(p);
setPageSize(ps);
},
// 确保分页样式与界面一致
className: styles.tablePagination
}}
bordered
// 添加表格样式
className={styles.historyTable}
// 行悬停效果
onRow={(record) => ({
onClick: () => openDetail(record),
style: {
cursor: 'pointer',
'&:hover': {
backgroundColor: 'rgba(0, 102, 101, 0.05)'
}
}
})}
/>
</Card>
</TabPane>
<TabPane tab="实时监控" key="2">
<Card className={styles.chartContainer} bordered={false} style={{ minHeight: 240 }}>
<h3>实时数据监控</h3>
<p>显示关键指标趋势图和告警列表此处为占位</p>
<div style={{ display: 'flex', gap: 16, marginTop: 12 }}>
<div style={{ flex: 1, minHeight: 120, background: '#fff', borderRadius: 6, padding: 12 }}>图表占位</div>
<div style={{ width: 320, minHeight: 120, background: '#fff', borderRadius: 6, padding: 12 }}>告警列表占位</div>
</div>
</Card>
</TabPane>
</Tabs>
</Col>
</Row>
<Modal visible={detailVisible} title="巡检详情" onCancel={closeDetail} footer={null} width={720}>
{currentRecord ? (
<div>
<p><strong>设备</strong>{currentRecord.device}</p>
<p><strong>运行时长</strong>{currentRecord.duration}</p>
<p><strong>异常类型</strong>{currentRecord.type}</p>
<p><strong>环境温度</strong>{currentRecord.temperature}</p>
<p><strong>处理状态</strong>{currentRecord.status}</p>
<div style={{ marginTop: 12, padding: 12, background: '#fafafa', borderRadius: 4 }}>趋势图/更多信息占位</div>
</div>
) : null}
</Modal>
</div>
);
};
export default DataAnalysisInspectionManagement;