| | |
| | | /> |
| | | </div> |
| | | |
| | | <a-divider /> |
| | | <a-divider orientation="left">预测性维护建议</a-divider> |
| | | |
| | | <a-table |
| | | ref="maintenanceTable" |
| | | :columns="maintenanceColumns" |
| | | :data-source="maintenanceData" |
| | | :pagination="false" |
| | | size="small" |
| | | :scroll="{ y: 150 }" |
| | | > |
| | | <template #urgency="{ text }"> |
| | | <a-tag :color="getUrgencyColor(text)">{{ text }}</a-tag> |
| | |
| | | <a-card title="设备数据" class="mb-4"> |
| | | <a-row :gutter="[16, 16]"> |
| | | <a-col :span="4"> |
| | | <a-statistic title="X轴总移动距离" :value="healthData.xAxisTravel" suffix="km"> |
| | | <a-statistic title="X轴总移动距离" :value="healthData.xAxisTravel.toFixed(2)" suffix="km"> |
| | | <template #prefix> |
| | | <LineChartOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic title="Y轴总移动距离" :value="healthData.yAxisTravel" suffix="km"> |
| | | <a-statistic title="Y轴总移动距离" :value="healthData.yAxisTravel.toFixed(2)" suffix="km"> |
| | | <template #prefix> |
| | | <LineChartOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic title="卡带次数" :value="healthData.tapeJamCount" suffix="次"> |
| | | <a-statistic title="卡带次数" :value="healthData.tapeJamCount.toFixed(0)" suffix="次"> |
| | | <template #prefix> |
| | | <WarningOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic title="卡料次数" :value="healthData.materialJamCount" suffix="次"> |
| | | <a-statistic title="卡料次数" :value="healthData.materialJamCount.toFixed(0)" suffix="次"> |
| | | <template #prefix> |
| | | <WarningOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic title="拼板数" :value="healthData.panelCount" suffix="块"> |
| | | <a-statistic title="拼板数" :value="healthData.panelCount.toFixed(0)" suffix="块"> |
| | | <template #prefix> |
| | | <AppstoreOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic title="出错停机时间" :value="healthData.downtime" suffix="秒"> |
| | | <a-statistic title="出错停机时间" :value="healthData.downtime.toFixed(1)" suffix="秒"> |
| | | <template #prefix> |
| | | <FieldTimeOutlined /> |
| | | </template> |
| | |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { defineComponent, reactive, onMounted, onUnmounted } from 'vue'; |
| | | import { defineComponent, reactive, onMounted, onUnmounted, ref, nextTick } from 'vue'; |
| | | import * as echarts from 'echarts'; |
| | | import { |
| | | LineChartOutlined, |
| | |
| | | FieldTimeOutlined |
| | | } from '@ant-design/icons-vue'; |
| | | import img from '#/assets/images/JUKI.png' |
| | | import { getDeviceDataSmt, updateDeviceData, initDeviceData } from '#/api/eims/equ/deviceData' |
| | | |
| | | export default defineComponent({ |
| | | name: 'SmtMachineDetail', |
| | |
| | | healthColor: '#52c41a', |
| | | predictedLife: 635, |
| | | riskLevel: '低风险', |
| | | riskColor: '#52c41a', |
| | | riskColor: '#1a7ac4', |
| | | xAxisTravel: 300.179, |
| | | yAxisTravel: 233.392, |
| | | tapeJamCount: 6, |
| | | materialJamCount: 15, |
| | | panelCount: 2480, |
| | | downtime: 4.5, |
| | | // 用于累加的数据 |
| | | accumulatedXAxisTravel: 300.179, |
| | | accumulatedYAxisTravel: 233.392, |
| | | accumulatedTapeJamCount: 6, |
| | | accumulatedMaterialJamCount: 15, |
| | | accumulatedPanelCount: 2480, |
| | | accumulatedDowntime: 4.5 |
| | | // // 用于累加的数据 |
| | | // accumulatedXAxisTravel: 300.179, |
| | | // accumulatedYAxisTravel: 233.392, |
| | | // accumulatedTapeJamCount: 6, |
| | | // accumulatedMaterialJamCount: 15, |
| | | // accumulatedPanelCount: 2480, |
| | | // accumulatedDowntime: 4.5 |
| | | }); |
| | | |
| | | const maintenanceColumns = [ |
| | |
| | | { |
| | | key: '1', |
| | | |
| | | type: '贴装头维护', |
| | | content: '吸嘴真空压力校准', |
| | | suggestedTime: '2024-04-05', |
| | | type: '1号贴装系统维护', |
| | | content: '吸嘴真空压力偏低', |
| | | suggestedTime: '2025-07-05', |
| | | urgency: '中等' |
| | | }, |
| | | { |
| | | key: '6', |
| | | |
| | | type: '4号贴装系统维护', |
| | | content: 'T轴马达寿命告急', |
| | | suggestedTime: '2025-07-05', |
| | | urgency: '中等' |
| | | }, |
| | | { |
| | | key: '2', |
| | | type: '运动系统保养', |
| | | content: 'X/Y轴伺服电机润滑检查', |
| | | suggestedTime: '2024-03-20', |
| | | suggestedTime: '2025-06-20', |
| | | urgency: '低' |
| | | }, |
| | | { |
| | | key: '3', |
| | | type: '供料系统检查', |
| | | content: '飞达卡带/卡料次数清零', |
| | | suggestedTime: '2024-03-10', |
| | | suggestedTime: '2025-06-10', |
| | | urgency: '低' |
| | | } |
| | | }, |
| | | { |
| | | key: '4', |
| | | |
| | | type: '2号贴装系统维护', |
| | | content: '真空压力不稳定', |
| | | suggestedTime: '2025-07-05', |
| | | urgency: '低' |
| | | }, |
| | | { |
| | | key: '5', |
| | | type: '3号贴装系统维护', |
| | | content: 'Z轴马达电流异常', |
| | | suggestedTime: '2025-07-05', |
| | | urgency: '低' |
| | | }, |
| | | |
| | | { |
| | | key: '7', |
| | | |
| | | type: '5号贴装头维护', |
| | | content: '真空压力不稳定', |
| | | suggestedTime: '2025-07-05', |
| | | urgency: '低' |
| | | }, |
| | | { |
| | | key: '8', |
| | | |
| | | type: '6号贴装头维护', |
| | | content: '真空压力不稳定', |
| | | suggestedTime: '2025-07-05', |
| | | urgency: '低' |
| | | }, |
| | | ]); |
| | | |
| | | const getUrgencyColor = (urgency: string) => { |
| | |
| | | return 'default'; |
| | | } |
| | | }; |
| | | |
| | | |
| | | const fetchDeviceData = async () => { |
| | | try { |
| | | const res = await getDeviceDataSmt(); |
| | | Object.assign(healthData, res); |
| | | } catch (error) { |
| | | console.error('获取设备数据失败:', error); |
| | | } |
| | | }; |
| | | |
| | | let deviceDataInterval: number | undefined; |
| | | fetchDeviceData(); |
| | | |
| | | deviceDataInterval = setInterval(async () => { |
| | | try { |
| | | fetchDeviceData(); |
| | | } catch (error) { |
| | | console.error('更新设备数据失败:', error); |
| | | } |
| | | }, 3000); |
| | | |
| | | const sparePartColumns = [ |
| | | { |
| | |
| | | const sparePartData = reactive([ |
| | | { |
| | | key: '1', |
| | | name: 'X轴伺服电机', |
| | | name: '1号贴装系统T轴伺服电机', |
| | | currentLife: '15000小时', |
| | | remainingLife: '4354小时', |
| | | remainingLife: '1451小时', |
| | | status: '预警' |
| | | }, |
| | | { |
| | | key: '5', |
| | | name: '1号贴装系统Z轴伺服电机', |
| | | currentLife: '15000小时', |
| | | remainingLife: '7521小时', |
| | | status: '良好' |
| | | }, |
| | | { |
| | | key: '9', |
| | | name: '1号贴装系统真空电磁阀', |
| | | currentLife: '10000小时', |
| | | remainingLife: '2154小时', |
| | | status: '良好' |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: '吸嘴', |
| | | name: '1号贴装头', |
| | | currentLife: '1000000次', |
| | | remainingLife: '425000次', |
| | | remainingLife: '425542次', |
| | | status: '良好' |
| | | }, |
| | | { |
| | | key: '6', |
| | | name: '2号贴装系统T轴伺服电机', |
| | | currentLife: '15000小时', |
| | | remainingLife: '7540小时', |
| | | status: '良好' |
| | | }, |
| | | { |
| | | key: '7', |
| | | name: '2号贴装系统Z轴伺服电机', |
| | | currentLife: '15000小时', |
| | | remainingLife: '7521小时', |
| | | status: '良好' |
| | | }, |
| | | { |
| | | key: '9', |
| | | name: '2号贴装系统真空电磁阀', |
| | | currentLife: '10000小时', |
| | | remainingLife: '2154小时', |
| | | status: '良好' |
| | | }, |
| | | { |
| | | key: '8', |
| | | name: '2号贴装头', |
| | | currentLife: '1000000次', |
| | | remainingLife: '751251次', |
| | | status: '良好' |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: '飞达', |
| | | currentLife: '96个月', |
| | | remainingLife: '48个月', |
| | | remainingLife: '43个月', |
| | | status: '良好' |
| | | } |
| | | }, |
| | | |
| | | ]); |
| | | |
| | | const historyData = reactive([ |
| | | { |
| | | id: '1', |
| | | date: '2025-07-22', |
| | | type: '定期保养', |
| | | description: '完成月度保养,丝杆导轨注油,抛料清理', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-06-18', |
| | | type: '定期保养', |
| | | description: '完成月度保养,易损件更换', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-05-15', |
| | | type: '定期保养', |
| | | description: '完成季度保养,检查运动系统润滑', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-04-20', |
| | | type: '定期保养', |
| | | description: '完成月度保养,防尘过滤网清理,导轨注油', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-03-16', |
| | | type: '定期保养', |
| | | description: '完成月度保养,真空值校准', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-02-13', |
| | | type: '定期保养', |
| | | description: '完成月度保养,吸嘴检查更换,抛料清理,相机参数校准', |
| | | color: 'green' |
| | | }, |
| | | { |
| | |
| | | }, |
| | | { |
| | | id: '3', |
| | | date: '2024-12-01', |
| | | date: '2025-01-15', |
| | | type: '定期保养', |
| | | description: '完成年度保养,校准视觉系统', |
| | | description: '完成年度保养,贴装系统校准,易损件更换,校准视觉系统', |
| | | color: 'green' |
| | | } |
| | | ]); |
| | |
| | | }; |
| | | |
| | | let healthDataInterval: number | undefined; |
| | | let scrollInterval: number | undefined; |
| | | const maintenanceTable = ref<HTMLElement | null>(null); |
| | | |
| | | const updateHealthData = () => { |
| | | healthData.accumulatedXAxisTravel = parseFloat((healthData.accumulatedXAxisTravel + Math.random() * 0.01).toFixed(3)); |
| | | healthData.accumulatedYAxisTravel = parseFloat((healthData.accumulatedYAxisTravel + Math.random() * 0.01).toFixed(3)); |
| | | healthData.accumulatedTapeJamCount = healthData.accumulatedTapeJamCount + Math.random() * 0.005; |
| | | healthData.accumulatedMaterialJamCount = healthData.accumulatedMaterialJamCount + Math.random() * 0.005; |
| | | healthData.accumulatedPanelCount =healthData.accumulatedPanelCount + Math.random() * 0.1; |
| | | healthData.accumulatedDowntime = parseFloat((healthData.accumulatedDowntime + Math.random() * 0.01).toFixed(1)); |
| | | const startScroll = () => { |
| | | if (!maintenanceTable.value) return; |
| | | |
| | | // 更新显示的数据 |
| | | healthData.xAxisTravel = healthData.accumulatedXAxisTravel; |
| | | healthData.yAxisTravel = healthData.accumulatedYAxisTravel; |
| | | healthData.tapeJamCount = Math.round(healthData.accumulatedTapeJamCount); |
| | | healthData.materialJamCount = Math.round(healthData.accumulatedMaterialJamCount); |
| | | healthData.panelCount = Math.round( healthData.accumulatedPanelCount); |
| | | healthData.downtime = healthData.accumulatedDowntime; |
| | | const tableBody = maintenanceTable.value.$el.querySelector('.ant-table-body'); |
| | | if (!tableBody) return; |
| | | |
| | | const scrollHeight = tableBody.scrollHeight; |
| | | const clientHeight = tableBody.clientHeight; |
| | | |
| | | if (scrollHeight <= clientHeight) { |
| | | // 内容未溢出,无需滚动 |
| | | return; |
| | | } |
| | | |
| | | let currentScrollTop = 0; |
| | | scrollInterval = setInterval(() => { |
| | | currentScrollTop += 1; // 每次滚动1px |
| | | if (currentScrollTop >= scrollHeight - clientHeight) { |
| | | currentScrollTop = 0; // 滚动到底部后回到顶部 |
| | | } |
| | | tableBody.scrollTop = currentScrollTop; |
| | | }, 50); // 每50毫秒滚动一次 |
| | | }; |
| | | |
| | | // const updateHealthData = () => { |
| | | // healthData.accumulatedXAxisTravel = parseFloat((healthData.accumulatedXAxisTravel + Math.random() * 0.01).toFixed(3)); |
| | | // healthData.accumulatedYAxisTravel = parseFloat((healthData.accumulatedYAxisTravel + Math.random() * 0.01).toFixed(3)); |
| | | // healthData.accumulatedTapeJamCount = healthData.accumulatedTapeJamCount + Math.random() * 0.005; |
| | | // healthData.accumulatedMaterialJamCount = healthData.accumulatedMaterialJamCount + Math.random() * 0.005; |
| | | // healthData.accumulatedPanelCount =healthData.accumulatedPanelCount + Math.random() * 0.1; |
| | | // healthData.accumulatedDowntime = parseFloat((healthData.accumulatedDowntime + Math.random() * 0.01).toFixed(1)); |
| | | |
| | | // // 更新显示的数据 |
| | | // healthData.xAxisTravel = healthData.accumulatedXAxisTravel; |
| | | // healthData.yAxisTravel = healthData.accumulatedYAxisTravel; |
| | | // healthData.tapeJamCount = Math.round(healthData.accumulatedTapeJamCount); |
| | | // healthData.materialJamCount = Math.round(healthData.accumulatedMaterialJamCount); |
| | | // healthData.panelCount = Math.round( healthData.accumulatedPanelCount); |
| | | // healthData.downtime = healthData.accumulatedDowntime; |
| | | // }; |
| | | |
| | | onMounted(() => { |
| | | // 初始更新一次数据 |
| | | updateHealthData(); |
| | | // updateHealthData(); |
| | | // 每5秒更新一次设备数据 |
| | | healthDataInterval = setInterval(updateHealthData, 5000); |
| | | // healthDataInterval = setInterval(updateHealthData, 5000); |
| | | |
| | | nextTick(() => { |
| | | startScroll(); |
| | | }); |
| | | }); |
| | | |
| | | onUnmounted(() => { |
| | | if (healthDataInterval) { |
| | | clearInterval(healthDataInterval); |
| | | } |
| | | if (scrollInterval) { |
| | | clearInterval(scrollInterval); |
| | | } |
| | | if (deviceDataInterval) { |
| | | clearInterval(deviceDataInterval); |
| | | } |
| | | }); |
| | | |
| | |
| | | historyData, |
| | | getStatusColor, |
| | | getUrgencyColor, |
| | | handleMaintenance |
| | | handleMaintenance, |
| | | maintenanceTable |
| | | }; |
| | | }, |
| | | components: { |
| | |
| | | time, |
| | | value: newValue |
| | | }); |
| | | if (s.data.length > 60) { |
| | | if (s.data.length > 24) { |
| | | s.data.shift(); |
| | | } |
| | | }); |
| | |
| | | seriesConfig.forEach(s => { |
| | | s.data = []; |
| | | // 生成初始数据点(60个点,5分钟数据) |
| | | for (let i = 0; i < 60; i++) { |
| | | const now = new Date(Date.now() - (60 - i) * 5000); // 生成过去5分钟的数据 |
| | | for (let i = 0; i < 24; i++) { |
| | | const now = new Date(Date.now() - (24 - i) * 5000); // 生成过去5分钟的数据 |
| | | const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`; |
| | | const newValue = (s.baseValue + (Math.random() * 2 - 1) * s.fluctuation).toFixed(2); |
| | | s.data.push({ |