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

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;