feat(eims): 更新预测性维护功能
- 新增设备数据定时更新功能
- 添加维护建议滚动显示
- 更新设备部件寿命预测数据
- 调整备件库存与预警逻辑
- 优化数据展示和颜色提示
| | |
| | | <!-- </template>--> |
| | | </wd-navbar> |
| | | <!-- å¢å ä¸ä¸ªæç´¢æ --> |
| | | <wd-search v-model="searchValue" @search="handleSearch"> |
| | | </wd-search> |
| | | <wd-search v-model="searchValue" @search="handleSearch"></wd-search> |
| | | <wd-tabs v-model="activeTab" @change="handleTabChange"> |
| | | <wd-tab title="å¾
ç»´ä¿®"></wd-tab> |
| | | <wd-tab title="已维修"></wd-tab> |
| | | </wd-tabs> |
| | | <!-- <wd-drop-menu>--> |
| | | <!-- <wd-drop-menu-item--> |
| | | <!-- v-model="resTypeId"--> |
| | |
| | | import { formatDate } from '@/utils/DateUtils' |
| | | import dayjs from "dayjs"; |
| | | import ResCard from "@/components/repair/res-card.vue"; |
| | | |
| | | const activeTab = ref(0) |
| | | const userStore = useUserStore() |
| | | |
| | | const message = useMessage() |
| | |
| | | if (option?.from === 'scan') { |
| | | queryParams.assetNo = option.assetNo |
| | | } |
| | | queryParams.params.status = '0,1,2,3' |
| | | if (activeTab.value === 0) { |
| | | // å¾
ç»´ä¿®ï¼status çäº 1 æ 2 æ 3 |
| | | queryParams.params.status = '1,2' |
| | | } else { |
| | | // 已维修ï¼status çäº 3 æ 4 |
| | | queryParams.params.status = '3,4' |
| | | } |
| | | |
| | | queryParams.reqUser = userStore?.userInfo?.userId |
| | | if (isRepair()) { |
| | | queryParams.params.status = undefined |
| | |
| | | paging.value.reload() |
| | | } |
| | | |
| | | function handleTabChange() { |
| | | reloadData() |
| | | } |
| | | |
| | | // /** |
| | | // * æ¡ç®ç¹å»äºä»¶ |
| | | // * @param item |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageQuery, PageResult } from '#/api/model'; |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | enum Api { |
| | | getDeviceData = '/eims/deviceData/get', |
| | | getDeviceDataSmt = '/eims/deviceData/getSmt', |
| | | getDeviceDataInj = '/eims/deviceData/getInj', |
| | | updateDeviceData = '/eims/deviceData/update', |
| | | initDeviceData = '/eims/deviceData/init' |
| | | } |
| | | |
| | | /** |
| | | * è·åè®¾å¤æ°æ® |
| | | */ |
| | | export function getDeviceData() { |
| | | return requestClient.get<Record<string, number>>(Api.getDeviceData); |
| | | } |
| | | |
| | | /** |
| | | * è·åè®¾å¤æ°æ® |
| | | */ |
| | | export function getDeviceDataSmt() { |
| | | return requestClient.get<Record<string, number>>(Api.getDeviceDataSmt); |
| | | } |
| | | |
| | | /** |
| | | * è·åè®¾å¤æ°æ® |
| | | */ |
| | | export function getDeviceDataInj() { |
| | | return requestClient.get<Record<string, number>>(Api.getDeviceDataInj); |
| | | } |
| | | |
| | | /** |
| | | * æ´æ°è®¾å¤æ°æ®ï¼æ¨¡æèªå¨å¢é¿ï¼ |
| | | */ |
| | | export function updateDeviceData() { |
| | | return requestClient.post<void>(Api.updateDeviceData); |
| | | } |
| | | |
| | | /** |
| | | * åå§åè®¾å¤æ°æ® |
| | | */ |
| | | export function initDeviceData() { |
| | | return requestClient.post<void>(Api.initDeviceData); |
| | | } |
| | |
| | | </div> |
| | | <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="å å·¥æ¶é´" :value="healthData.xAxisTravel" suffix="km"> |
| | | <a-statistic title="å å·¥æ¶é´" :value="healthData.xAxisTravel.toFixed(2)" suffix="h"> |
| | | <template #prefix> |
| | | <FieldTimeOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic title="åå
·ä½¿ç¨æ¬¡æ°" :value="healthData.yAxisTravel" suffix="km"> |
| | | <a-statistic title="ååºåæ¢æ¬¡æ°" :value="healthData.yAxisTravel.toFixed(0)" suffix="次"> |
| | | <template #prefix> |
| | | <FieldTimeOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic title="åå
·ä½¿ç¨æ¶é¿" :value="healthData.zAxisTravel" suffix="km"> |
| | | <a-statistic title="åå
·å¹³å寿å½" :value="healthData.zAxisTravel.toFixed(2)" suffix="h"> |
| | | <template #prefix> |
| | | <FieldTimeOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic title="åå
·æ´æ¢æ¬¡æ°" :value="healthData.toolChangeCount" suffix="次"> |
| | | <a-statistic title="å¹³åè°æºç¼ç¨æ¶é´" :value="healthData.toolChangeCount" suffix="Min"> |
| | | <template #prefix> |
| | | <WarningOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic title="å å·¥é¶ä»¶æ°" :value="healthData.partCount" suffix="ä»¶"> |
| | | <a-statistic title="累计å å·¥é¶ä»¶æ°" :value="healthData.partCount.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" suffix="ç§"> |
| | | <template #prefix> |
| | | <FieldTimeOutlined /> |
| | | </template> |
| | |
| | | <div id="spindleVibrationChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="hydraulicOilTemperatureChart" style="height: 300px;"></div> |
| | | <div id="spindleTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="spindleSpeedChart" style="height: 300px;"></div> |
| | |
| | | <div id="hydraulicPressureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="spindleTemperatureChart" style="height: 300px;"></div> |
| | | |
| | | <div id="hydraulicOilTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="coolantTemperatureChart" style="height: 300px;"></div> |
| | |
| | | </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, |
| | |
| | | AppstoreOutlined, |
| | | FieldTimeOutlined |
| | | } from '@ant-design/icons-vue'; |
| | | import img from '#/assets/images/T850-840.2.jpg' |
| | | import img from '#/assets/images/T850-840.2.jpg'; |
| | | import { getDeviceData, updateDeviceData, initDeviceData } from '#/api/eims/equ/deviceData' |
| | | export default defineComponent({ |
| | | name: 'CNCMachiningCenterDetail', |
| | | setup() { |
| | |
| | | const healthData = reactive({ |
| | | overallHealth: 95, |
| | | healthColor: '#52c41a', |
| | | predictedLife: 4436, |
| | | predictedLife: 5017, |
| | | riskLevel: 'ä½é£é©', |
| | | riskColor: '#52c41a', |
| | | xAxisTravel: 1200.5, |
| | | yAxisTravel: 980.2, |
| | | zAxisTravel: 500.1, |
| | | toolChangeCount: 25, |
| | | partCount: 1500, |
| | | downtime: 120 |
| | | xAxisTravel: 7105.5, // æ¯å¤©å 6å°æ¶ |
| | | yAxisTravel: 5641, // æ¯å¤©å 60次 |
| | | zAxisTravel: 450.4, // æ¯å¤©å 20ç±³å·¦å³ |
| | | toolChangeCount: 74, // 䏿³¢å¨ |
| | | partCount: 17056, // æ¯å¤©å 15ä¸ªå·¦å³ |
| | | downtime: 141 // 䏿³¢å¨ |
| | | }); |
| | | |
| | | const maintenanceColumns = [ |
| | |
| | | type: 'ä¾è¡ä¿å
»', |
| | | content: 'æ£æ¥ä¸»è½´æ¶¦æ»ç³»ç»', |
| | | suggestedTime: '2025-07-15', |
| | | urgency: 'ä¸ç' |
| | | urgency: 'ä½' |
| | | }, |
| | | { |
| | | key: '2', |
| | |
| | | }, |
| | | { |
| | | key: '3', |
| | | type: '导轨维æ¤', |
| | | type: 'ä¸æå¯¼è½¨ç»´æ¤', |
| | | content: 'è¡¥å
å¯¼è½¨æ¶¦æ»æ²¹', |
| | | suggestedTime: '2025-06-01', |
| | | urgency: 'ä½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | type: 'å 工精度确认', |
| | | content: 'å®æå¯¼è½¨ç²¾åº¦æ ¡éªæ£æ¥ç¡®è®¤', |
| | | suggestedTime: '2025-05-05', |
| | | urgency: 'ä½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | type: 'ååºåè½ç¡®è®¤', |
| | | content: 'æä»¤æ¢åæ¯å¦åå¨å¡æ»å»¶è¿ç°è±¡', |
| | | suggestedTime: '2025-05-03', |
| | | urgency: 'ä½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | type: 'ååæ¶²æ´æ¢', |
| | | content: 'æ£æ¥ç¡®è®¤ååæ¶²æ¯å¦è¶
æï¼æè´¨å«éæ¯å¦ç¬¦åè¦æ±', |
| | | suggestedTime: '2025-05-03', |
| | | urgency: 'ä½' |
| | | } |
| | | ]); |
| | |
| | | key: 'name' |
| | | }, |
| | | { |
| | | title: 'å½å寿å½', |
| | | title: 'é¢è®¡å¯¿å½', |
| | | dataIndex: 'currentLife', |
| | | key: 'currentLife', |
| | | customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | // customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | }, |
| | | { |
| | | title: '颿µå©ä½å¯¿å½', |
| | | dataIndex: 'remainingLife', |
| | | key: 'remainingLife', |
| | | customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | // customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | }, |
| | | { |
| | | title: 'ç¶æ', |
| | |
| | | |
| | | const sparePartData = reactive([ |
| | | { |
| | | key: '3', |
| | | name: 'ååæ¶²', |
| | | currentLife: "6个æ", |
| | | remainingLife: "1个æ", |
| | | status: 'é¢è¦' |
| | | }, |
| | | { |
| | | key: '1', |
| | | name: '主轴轴æ¿', |
| | | currentLife: 8000, |
| | | remainingLife: 500, |
| | | status: 'é¢è¦' |
| | | currentLife: "8000å°æ¶", |
| | | remainingLife: "5710å°æ¶", |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: 'Xè½´ä¸æ ', |
| | | currentLife: 12000, |
| | | remainingLife: 2000, |
| | | currentLife: "12000å°æ¶", |
| | | remainingLife: "9132å°æ¶", |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: 'Yè½´ä¸æ ', |
| | | currentLife: "12000å°æ¶", |
| | | remainingLife: "9132å°æ¶", |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: 'Zè½´ä¸æ ', |
| | | currentLife: "12000å°æ¶", |
| | | remainingLife: "9132å°æ¶", |
| | | status: 'è¯å¥½' |
| | | }, |
| | | |
| | | { |
| | | key: '3', |
| | | name: '导轨油', |
| | | currentLife: "30天", |
| | | remainingLife: "23天", |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: 'æ¶²åæ²¹', |
| | | currentLife: 3000, |
| | | remainingLife: 200, |
| | | status: 'é¢è¦' |
| | | name: 'åæ¡¶å¤¹', |
| | | currentLife: "30000次", |
| | | remainingLife: "23513次", |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: 'åæ¡¶æé', |
| | | currentLife: "15000次", |
| | | remainingLife: "11421次", |
| | | status: 'è¯å¥½' |
| | | } |
| | | ]); |
| | | |
| | | const historyData = reactive([ |
| | | { |
| | | id: '1', |
| | | date: '2024-05-20', |
| | | date: '2025-08-06', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | description: '主轴润æ»ç³»ç»æ£æ¥', |
| | | description: 'å导轨润æ»ç³»ç»æ£æ¥ï¼æ·»å 导轨油', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-07-11', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | description: 'å导轨润æ»ç³»ç»æ£æ¥ï¼æ·»å 导轨油', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-06-18', |
| | | type: 'ç»´ä¿®ä¿å
»', |
| | | description: 'åæ¡¶æéæ´æ¢3个', |
| | | color: 'orange' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-06-09', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | description: 'å导轨润æ»ç³»ç»æ£æ¥ï¼æ·»å 导轨油', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-05-22', |
| | | type: 'ç»´ä¿®ä¿å
»', |
| | | description: 'åæ¡¶å¤¹ç£¨æç²¾åº¦ä¸éï¼æ´æ¢æ°é
ä»¶', |
| | | color: 'orange' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-05-10', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | description: 'å导轨润æ»ç³»ç»æ£æ¥ï¼æ·»å 导轨油', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-04-13', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | description: 'å导轨润æ»ç³»ç»æ£æ¥ï¼æ·»å 导轨油', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '2', |
| | | date: '2024-02-10', |
| | | type: 'æ
éç»´ä¿®', |
| | | description: 'Y轴伺æçµæºæ¥è¦å¤ç', |
| | | color: 'red' |
| | | }, |
| | | { |
| | | id: '3', |
| | | date: '2023-11-01', |
| | | type: '年度ä¿å
»', |
| | | description: 'å
¨é¢æ£æ¥è®¾å¤è¿è¡ç¶æ', |
| | | color: 'green' |
| | | date: '2025-03-04', |
| | | type: 'ç»´ä¿®ä¿å
»', |
| | | description: 'å忏£æ¸
çï¼ååæ¶²æ´æ¢', |
| | | color: 'orange' |
| | | } |
| | | ]); |
| | | |
| | |
| | | // å®é
项ç®ä¸è¿éä¼è°ç¨APIå¤çç»´æ¤å»ºè®® |
| | | }; |
| | | |
| | | const maintenanceTable = ref<HTMLElement | null>(null); |
| | | let scrollInterval: number | undefined; |
| | | |
| | | const startScroll = () => { |
| | | if (!maintenanceTable.value) return; |
| | | |
| | | 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; |
| | | if (currentScrollTop >= scrollHeight - clientHeight) { |
| | | currentScrollTop = 0; |
| | | } |
| | | tableBody.scrollTop = currentScrollTop; |
| | | }, 50); |
| | | }; |
| | | |
| | | let deviceDataInterval: number | undefined; |
| | | |
| | | const fetchDeviceData = async () => { |
| | | try { |
| | | const res = await getDeviceData(); |
| | | Object.assign(healthData, res); |
| | | } catch (error) { |
| | | console.error('è·åè®¾å¤æ°æ®å¤±è´¥:', error); |
| | | } |
| | | }; |
| | | |
| | | |
| | | fetchDeviceData(); |
| | | |
| | | // åå§åè®¾å¤æ°æ® |
| | | // initDeviceData().then(() => { |
| | | // fetchDeviceData(); // åå§ååç«å³è·å䏿¬¡æ°æ® |
| | | // }); |
| | | |
| | | // æ¯ç§æ´æ°ä¸æ¬¡è®¾å¤æ°æ® |
| | | deviceDataInterval = setInterval(async () => { |
| | | try { |
| | | fetchDeviceData(); |
| | | } catch (error) { |
| | | console.error('æ´æ°è®¾å¤æ°æ®å¤±è´¥:', error); |
| | | } |
| | | }, 3000); |
| | | |
| | | |
| | | onUnmounted(() => { |
| | | if (scrollInterval) { |
| | | clearInterval(scrollInterval); |
| | | } |
| | | if (deviceDataInterval) { |
| | | clearInterval(deviceDataInterval); |
| | | } |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | nextTick(() => { |
| | | startScroll(); |
| | | }); |
| | | }); |
| | | |
| | | onUnmounted(() => { |
| | | if (scrollInterval) { |
| | | clearInterval(scrollInterval); |
| | | } |
| | | }); |
| | | |
| | | |
| | | |
| | | return { |
| | | deviceInfo, |
| | | healthData, |
| | |
| | | historyData, |
| | | getStatusColor, |
| | | getUrgencyColor, |
| | | handleMaintenance |
| | | handleMaintenance, |
| | | maintenanceTable |
| | | }; |
| | | }, |
| | | |
| | |
| | | time, |
| | | value: newValue |
| | | }); |
| | | if (s.data.length > 60) { |
| | | if (s.data.length > 12) { |
| | | 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 < 12; i++) { |
| | | const now = new Date(Date.now() - (12 - 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({ |
| | |
| | | |
| | | }; |
| | | |
| | | |
| | | // è¿å¨ç³»ç»çæµ |
| | | initChart('spindleVibrationChart', '主轴æ¯å¨', [ |
| | | { name: 'æ¯å¨', data: [], unit: 'mm/s', baseValue: 3.0, fluctuation: 0.5, color: '#5470C6' }, |
| | | initChart('spindleVibrationChart', 'å¹³åå å·¥æ¶é´', [ |
| | | { name: 'æ¶é´', data: [], unit: 'min/pcs', baseValue: 16.0, fluctuation: 0.1, color: '#5470C6' }, |
| | | ]); |
| | | initChart('spindleTemperatureChart', '主轴温度', [ |
| | | { name: '温度', data: [], unit: '°C', baseValue: 50, fluctuation: 3, color: '#5470C6' }, |
| | |
| | | initChart('coolantTemperatureChart', 'å·å´æ¶²æ¸©åº¦', [ |
| | | { name: '温度', data: [], unit: '°C', baseValue: 28, fluctuation: 2, color: '#5470C6' }, |
| | | ]); |
| | | |
| | | |
| | | } |
| | | |
| | | }); |
| | |
| | | .device-detail-container { |
| | | padding: 16px; |
| | | background: #f0f2f5; |
| | | } |
| | | .device-image-container { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | height: 330px; |
| | | } |
| | | |
| | | .mt-4 { |
| | |
| | | <!-- å¤ä»¶ä¿¡æ¯ --> |
| | | <div class="grid grid-cols-2 gap-4 mb-6"> |
| | | <!-- 设å¤é¨ä»¶å¯¿å½é¢æµ --> |
| | | <Card title="设å¤é¨ä»¶å¯¿å½é¢æµ"> |
| | | <Table :columns="lifePredictionColumns" :data-source="lifePredictionData" :pagination="false" class="w-full"> |
| | | <Card title="设å¤é¨ä»¶å¯¿å½é¢æµ" :style="{ height: '500px' }"> |
| | | <Table :columns="lifePredictionColumns" :data-source="lifePredictionData" :pagination="false" :scroll="{ y: 340 }" class="w-full"> |
| | | <template #bodyCell="{ column, record }"> |
| | | <template v-if="column.key === 'lifeStatus'"> |
| | | <a-tag :color="getLifeStatusColor(record.remainingDays)"> |
| | |
| | | </Card> |
| | | |
| | | <!-- å¤ä»¶åºåä¸é¢è¦ --> |
| | | <Card title="å¤ä»¶åºåä¸é¢è¦"> |
| | | <Table :columns="sparePartColumns" :data-source="sparePartData" :pagination="false" class="w-full"> |
| | | <Card title="å¤ä»¶åºåä¸é¢è¦" :style="{ height: '500px' }"> |
| | | <Table :columns="sparePartColumns" :data-source="sparePartData" :pagination="false" :scroll="{ y: 340 }" class="w-full"> |
| | | <template #bodyCell="{ column, record }"> |
| | | <template v-if="column.key === 'stockStatus'"> |
| | | <a-tag :color="getStockStatusColor(record.currentStock, record.safetyStock)"> |
| | |
| | | indicator: 'ç空åå', |
| | | value: 32, |
| | | threshold: 35, |
| | | status: 'ä¸é£é©', |
| | | status: 'ä½é£é©', |
| | | maintenanceSuggestion: 'ç空ååå¼ä½äºè®¾å®å¼ï¼å»ºè®®æ£æ¥ææ´æ¢å¸å´', |
| | | maintenanceType: 'é¢é²æ§ç»´æ¤', |
| | | }, |
| | |
| | | indicator: '温度', |
| | | value: 85, |
| | | threshold: 80, |
| | | status: 'ä¸é£é©', |
| | | status: 'ä½é£é©', |
| | | maintenanceSuggestion: '建议对主轴è¿è¡æ¶¦æ»ä¿å
»å¹¶æ£æ¥å·å´ç³»ç»', |
| | | maintenanceType: '润æ»ç»´æ¤', |
| | | }, |
| | |
| | | safetyStock: 10, |
| | | predictedDemand: 2, |
| | | }, |
| | | { |
| | | key: '4', |
| | | name: 'å·ç æºæ²¹å¢¨', |
| | | currentStock: 1, |
| | | safetyStock: 1, |
| | | predictedDemand: 1, |
| | | }, |
| | | { |
| | | key: '4', |
| | | name: 'é¢ç½æ¸
æ´æ¶²', |
| | | currentStock: 2, |
| | | safetyStock: 1, |
| | | predictedDemand: 1, |
| | | }, |
| | | { |
| | | key: '4', |
| | | name: 'åå¯¸ç²¾å¯æ»¤è¯', |
| | | currentStock: 20, |
| | | safetyStock: 4, |
| | | predictedDemand: 0, |
| | | }, |
| | | ]); |
| | | const getStatusColor = (status) => { |
| | | switch (status) { |
| | | case 'é«é£é©': return 'red'; |
| | | case 'ä¸é£é©': return 'orange'; |
| | | case 'ä½é£é©': return 'yellow'; |
| | | case 'ä½é£é©': return 'blue'; |
| | | default: return 'green'; |
| | | } |
| | | }; |
| | |
| | | |
| | | const lifePredictionColumns = [ |
| | | { title: '设å¤åç§°', dataIndex: 'deviceName', key: 'deviceName' }, |
| | | { title: 'é¨ä½åç§°', dataIndex: 'componentName', key: 'componentName' }, |
| | | // { title: 'é¨ä½åç§°', dataIndex: 'componentName', key: 'componentName' }, |
| | | { title: 'é¨ä»¶åç§°', dataIndex: 'name', key: 'name' }, |
| | | { title: '颿µå¯¿å½ (天)', dataIndex: 'predictedLife', key: 'predictedLife' }, |
| | | { title: 'å©ä½å¯¿å½ (天)', dataIndex: 'remainingDays', key: 'remainingDays' }, |
| | |
| | | ]; |
| | | |
| | | const lifePredictionData = ref([ |
| | | { key: '4', deviceName: 'ç©ºåæº', componentName: 'çµæº', name: 'ä¼ æå¨', predictedLife: 500, remainingDays: 10 }, |
| | | { key: '2', deviceName: 'CNCå å·¥ä¸å¿', componentName: '主轴', name: '齿轮', predictedLife: 730, remainingDays: 30 }, |
| | | { key: '1', deviceName: 'SMTè´´çæº', componentName: 'ä¼ é带', name: 'è½´æ¿', predictedLife: 365, remainingDays: 50 }, |
| | | { key: '1', deviceName: 'SMTè´´çæº', componentName: 'ä¼ é带', name: 'ç空åçå¨', predictedLife: 700, remainingDays: 83 }, |
| | | { key: '1', deviceName: 'å
è£
æº', componentName: 'ä¼ é带', name: 'åçä¸', predictedLife: 260, remainingDays: 61 }, |
| | | { key: '1', deviceName: 'æ¿å
ææ æº', componentName: 'ä¼ é带', name: 'å·å´æ°´', predictedLife: 180, remainingDays: 43 }, |
| | | { key: '1', deviceName: 'é¢ç½æ¸
æ´æº', componentName: 'ä¼ é带', name: 'æ¸
æ´æ¶²', predictedLife: 180, remainingDays: 95 }, |
| | | { key: '1', deviceName: 'é¢ç½æ¸
æ´æº', componentName: 'ä¼ é带', name: '滤è¯', predictedLife: 180, remainingDays: 95 }, |
| | | { key: '1', deviceName: 'ç«¯åæº', componentName: 'ä¼ é带', name: 'åç', predictedLife: 180, remainingDays: 112 }, |
| | | { key: '1', deviceName: 'çµèå¥çº¿æº', componentName: 'ä¼ é带', name: 'åç', predictedLife: 180, remainingDays: 107 }, |
| | | |
| | | { key: '3', deviceName: 'æ³¨å¡æº', componentName: 'æ¶²åç³»ç»', name: '滤è¯', predictedLife: 180, remainingDays: 90 }, |
| | | |
| | | { key: '5', deviceName: 'çæ¥æºå¨äºº', componentName: 'çæª', name: 'çå´', predictedLife: 240, remainingDays: 60 } |
| | | { key: '2', deviceName: 'CNCå å·¥ä¸å¿', componentName: '主轴', name: 'åç夹', predictedLife: 1100, remainingDays: 130 }, |
| | | { key: '4', deviceName: 'ç©ºåæº', componentName: 'å®å
¨é', name: 'å®å
¨é', predictedLife: 365, remainingDays: 130 }, |
| | | { key: '1', deviceName: 'å·ç æº', componentName: 'ä¼ é带', name: '墨水', predictedLife: 365, remainingDays: 184 }, |
| | | { key: '3', deviceName: 'æ³¨å¡æº', componentName: 'æ¶²åç³»ç»', name: 'æ¶²åæ²¹', predictedLife: 1100, remainingDays: 395 }, |
| | | { key: '5', deviceName: 'çæ¥æºå¨äºº', componentName: 'çæª', name: 'çéè¯', predictedLife: 1000, remainingDays: 512 } |
| | | ]); |
| | | |
| | | const getLifeStatus = (remainingDays) => { |
| | | if (remainingDays <= 30) { |
| | | if (remainingDays <= 90) { |
| | | return 'å³å°å°æ'; |
| | | } else if (remainingDays <= 90) { |
| | | } else if (remainingDays <= 150) { |
| | | return '䏿é¢è¦'; |
| | | } else { |
| | | return '寿å½å
è¶³'; |
| | |
| | | }; |
| | | |
| | | const getLifeStatusColor = (remainingDays) => { |
| | | if (remainingDays <= 30) { |
| | | return 'red'; |
| | | } else if (remainingDays <= 90) { |
| | | if (remainingDays <= 90) { |
| | | return 'orange'; |
| | | } else if (remainingDays <= 150) { |
| | | return 'blue'; |
| | | } else { |
| | | return 'green'; |
| | | } |
| | |
| | | |
| | | |
| | | const getStockStatus = (currentStock, safetyStock) => { |
| | | if (currentStock <= safetyStock) { |
| | | if (currentStock < safetyStock) { |
| | | return 'åºåé¢è¦'; |
| | | } else { |
| | | return 'åºåå
è¶³'; |
| | |
| | | }; |
| | | |
| | | const getStockStatusColor = (currentStock, safetyStock) => { |
| | | if (currentStock <= safetyStock) { |
| | | return 'red'; |
| | | if (currentStock < safetyStock) { |
| | | return 'orange'; |
| | | } else { |
| | | return 'green'; |
| | | } |
| | |
| | | // æ ¹æ®è®¾å¤åç§°ä¸å跳转ä¸åç详æ
é¡µé¢ |
| | | if (record.name === 'SMTè´´çæº') { |
| | | console.log('设å¤ID111:', record.name) |
| | | router.push({ path: '/predictive/smt-detail', query: { deviceId: record.key } }); |
| | | router.push({ path: '/predictive/smt-detail', query: { deviceId: 15 } }); |
| | | } else if (record.name === 'CNCå å·¥ä¸å¿') { |
| | | router.push({ path: '/predictive/cnc-detail', query: { deviceId: record.key } }); |
| | | router.push({ path: '/predictive/cnc-detail', query: { deviceId: 23 } }); |
| | | } else if (record.name === 'æ³¨å¡æº') { |
| | | router.push({ path: '/predictive/injection-detail', query: { deviceId: record.key } }); |
| | | router.push({ path: '/predictive/injection-detail', query: { deviceId: 181 } }); |
| | | } else { |
| | | router.push({ path: '/predictive/air-compressor-detail', query: { deviceId: record.key } }); |
| | | router.push({ path: '/predictive/air-compressor-detail', query: { deviceId: 46 } }); |
| | | } |
| | | }; |
| | | |
| | |
| | | xAxis: { |
| | | type: 'category', |
| | | data: ['10å', '9å', '8å', '7å', '6å', '5å', '4å', '3å', '2å', '1å'], |
| | | |
| | | |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | |
| | | { value: 21, itemStyle: { color: '#52c41a' } }, |
| | | { value: 8, itemStyle: { color: '#faad14' } }, |
| | | { value: 5, itemStyle: { color: '#faad14' } }, |
| | | |
| | | |
| | | ], |
| | | label: { |
| | | show: true, |
| | |
| | | <script lang="ts"> |
| | | import { defineComponent, onUnmounted, reactive } from 'vue'; |
| | | import { defineComponent, reactive, onMounted, onUnmounted, ref, nextTick } from 'vue'; |
| | | |
| | | import { AppstoreOutlined, FieldTimeOutlined, LineChartOutlined, WarningOutlined, ThunderboltOutlined, CheckCircleOutlined } from '@ant-design/icons-vue'; |
| | | import * as echarts from 'echarts'; |
| | | import img from '#/assets/images/2t.png'; |
| | | import { getDeviceDataInj, updateDeviceData, initDeviceData } from '#/api/eims/equ/deviceData' |
| | | |
| | | export default defineComponent({ |
| | | name: 'InjectionMoldingMachineDetail', |
| | | components: { |
| | |
| | | |
| | | const healthData = reactive({ |
| | | overallHealth: 88, |
| | | healthColor: '#faad14', |
| | | predictedLife: 1500, |
| | | riskLevel: 'ä¸é£é©', |
| | | riskColor: '#faad14', |
| | | healthColor: '#52c41a', |
| | | predictedLife: 1753, |
| | | riskLevel: 'ä½é£é©', |
| | | riskColor: '#1a7ac4', |
| | | injectionPressure: 120, // 注å¡åå |
| | | clampingForce: 80, // 鿍¡å |
| | | moldTemperature: 45, // 模å
·æ¸©åº¦ |
| | | screwSpeed: 150, // èºæè½¬é |
| | | meltTemperature: 220, // çèæ¸©åº¦ |
| | | coolingTime: 25, // å·å´æ¶é´ |
| | | injectionCount: '495d 19h 44 ', // æ³¨å°æ¬¡æ° |
| | | clampingCount: 545636, // 忍¡æ¬¡æ° |
| | | productionCycle: 19, // çäº§å¨æ |
| | | energyConsumption: 1500, // è½è |
| | | yieldRate: 98.5, // è¯åç |
| | | downtime: 120 // åºéåæºæ¶é´ |
| | | injectionCount: 495 * 24 * 60 + 19 * 60 + 44, // æ³¨å°æ¬¡æ°ï¼è½¬æ¢ä¸ºåé |
| | | clampingCount: 545636, // 忍¡æ¬¡æ° // è·é产é 50så 䏿¬¡ |
| | | productionCycle: 45, // çäº§å¨æ |
| | | energyConsumption: 64, // è½è |
| | | yieldRate: 354, // 产é 50ç§å¢å 䏿¨¡ |
| | | downtime: 120, // åºéåæºæ¶é´ |
| | | // ç¨äºç´¯å å¢é¿çåæ®µ |
| | | // accumulatedInjectionCount: 12180, |
| | | // accumulatedClampingCount: 545636, |
| | | // accumulatedEnergyConsumption: 64 |
| | | }); |
| | | |
| | | const maintenanceColumns = [ |
| | |
| | | { |
| | | key: '1', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | content: 'æ£æ¥æ¶²å油污æåº¦', |
| | | suggestedTime: '2024-07-15', |
| | | content: 'æ£æ¥æ¶²å油乳åç¨åº¦', |
| | | suggestedTime: '2025-07-02', |
| | | urgency: 'ä¸ç' |
| | | }, |
| | | { |
| | | key: '2', |
| | | type: 'æ
éé¢è¦', |
| | | content: 'ä¸»çµæºè½´æ¿ç£¨æé¢è¦', |
| | | suggestedTime: '2024-08-01', |
| | | urgency: 'é«' |
| | | content: '主油缸å¯å°å寿å½é¢è¦', |
| | | suggestedTime: '2025-07-01', |
| | | urgency: 'ä½' |
| | | },{ |
| | | key: '2', |
| | | type: 'æ¶²åæ²¹æ£æ¥', |
| | | content: 'æ£æ¥ç¡®è®¤æ¶²å油温度æ¯å¦æ£å¸¸', |
| | | suggestedTime: '2025-07-01', |
| | | urgency: 'ä½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | type: 'å·å´ç³»ç»ç»´æ¤', |
| | | content: 'æ£æ¥å·å´æ°´æµé', |
| | | suggestedTime: '2024-07-01', |
| | | type: 'å·å´ç³»ç»æ£æ¥', |
| | | content: 'æ£æ¥å·æ°´æºå¶å·æçæ¯å¦è¾¾æ ', |
| | | suggestedTime: '2025-06-11', |
| | | urgency: 'ä½' |
| | | },{ |
| | | key: '3', |
| | | type: 'æ¶²åç³»ç»æ£æ¥', |
| | | content: 'æ£æ¥åæ¶²å管éåå表ä¸çµèæ¾ç¤ºæ¯å¦ä¸è´', |
| | | suggestedTime: '2025-06-11', |
| | | urgency: 'ä½' |
| | | },{ |
| | | key: '3', |
| | | type: '温æ§ç³»ç»æ£æ¥', |
| | | content: 'æ£æ¥å段å çåå çãççµè¦æ¯å¦å¼å¸¸', |
| | | suggestedTime: '2025-06-11', |
| | | urgency: 'ä½' |
| | | } |
| | | ]); |
| | |
| | | } |
| | | }; |
| | | |
| | | const fetchDeviceData = async () => { |
| | | try { |
| | | const res = await getDeviceDataInj(); |
| | | 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 = [ |
| | | { |
| | | title: 'é¨ä»¶åç§°', |
| | |
| | | key: 'name' |
| | | }, |
| | | { |
| | | title: 'å½å寿å½', |
| | | title: 'é¢è®¡å¯¿å½', |
| | | dataIndex: 'currentLife', |
| | | key: 'currentLife', |
| | | customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | key: 'currentLife' |
| | | |
| | | }, |
| | | { |
| | | title: '颿µå©ä½å¯¿å½', |
| | | dataIndex: 'remainingLife', |
| | | key: 'remainingLife', |
| | | customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | key: 'remainingLife' |
| | | |
| | | }, |
| | | { |
| | | title: 'ç¶æ', |
| | |
| | | const sparePartData = reactive([ |
| | | { |
| | | key: '1', |
| | | name: 'æ¶²åæ³µ', |
| | | currentLife: 18_500, |
| | | remainingLife: 1500, |
| | | status: 'é¢è¦' |
| | | name: 'æ¶²åæ²¹', |
| | | currentLife: 8_500, |
| | | remainingLife: 2515, |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: 'å çå', |
| | | currentLife: 12_000, |
| | | remainingLife: 3000, |
| | | currentLife: 6_000, |
| | | remainingLife: 3415, |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: 'èºææç', |
| | | currentLife: 25_000, |
| | | remainingLife: 5000, |
| | | name: 'ççµè¦', |
| | | currentLife: 8_000, |
| | | remainingLife: 5851, |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: '注è¶å´', |
| | | currentLife: "100000次", |
| | | remainingLife: "76438次", |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: '鿍¡å¤¹å
·', |
| | | currentLife: "12个æ", |
| | | remainingLife: "8个æ", |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: '注è¶èºæ', |
| | | currentLife: "60个æ", |
| | | remainingLife: "48个æ", |
| | | status: 'è¯å¥½' |
| | | } |
| | | ]); |
| | |
| | | const historyData = reactive([ |
| | | { |
| | | id: '1', |
| | | date: '2023-10-20', |
| | | date: '2025-08-15', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | description: 'æ´æ¢æ¶²å油滤è¯', |
| | | description: 'æ¶²åç³»ç»æ£æ¥ï¼æ¸©æ§ç³»ç»æ£æ¥', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-07-20', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | description: 'æ¶²åç³»ç»æ£æ¥ï¼æ¸©æ§ç³»ç»æ£æ¥', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '2', |
| | | date: '2023-08-15', |
| | | type: 'æ
éç»´ä¿®', |
| | | description: '注å°åå
塿»ï¼æ¸
çå¼ç©', |
| | | color: 'red' |
| | | date: '2025-07-13', |
| | | type: 'ç»´ä¿®ä¿å
»', |
| | | description: 'ç¬¬ä¸æ®µæ¸©åº¦æ¾ç¤ºå¼å¸¸ï¼ççµè¦æåï¼æ´æ¢æ°é
ä»¶', |
| | | color: 'orange' |
| | | }, |
| | | { |
| | | id: '1', |
| | | date: '2025-06-18', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | description: 'æ¶²åç³»ç»æ£æ¥ï¼æ¸©æ§ç³»ç»æ£æ¥', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '2', |
| | | date: '2025-05-23', |
| | | type: 'ç»´ä¿®ä¿å
»', |
| | | description: 'ç¬¬ä¸æ®µæ¸©åº¦å¼å¸¸ï¼å çåç§åï¼æ´æ¢æ°é
ä»¶', |
| | | color: 'orange' |
| | | }, |
| | | { |
| | | id: '2', |
| | | date: '2025-05-15', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | description: 'æ¶²åç³»ç»æ£æ¥ï¼æ¸©æ§ç³»ç»æ£æ¥', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '3', |
| | | date: '2023-06-01', |
| | | date: '2025-04-01', |
| | | type: '年度ä¿å
»', |
| | | description: 'å
¨é¢æ£æ¥è®¾å¤è¿è¡ç¶æ', |
| | | color: 'blue' |
| | |
| | | // å®é
项ç®ä¸è¿éä¼è°ç¨APIå¤çç»´æ¤å»ºè®® |
| | | }; |
| | | |
| | | let intervalId: number | undefined; |
| | | |
| | | // const updateAccumulatedData = () => { |
| | | // healthData.accumulatedInjectionCount += + 0.1; // æ¯æ¬¡å¢å 1-5åé |
| | | // healthData.accumulatedClampingCount += Math.floor(Math.random() * 100) + 10; // æ¯æ¬¡å¢å 10-100次 |
| | | // healthData.accumulatedEnergyConsumption += (Math.random() * 0.015 + 0.008); // æ¯æ¬¡å¢å 0.1-0.6 kWh |
| | | |
| | | // // æ´æ°æ¾ç¤ºå¼ |
| | | // const totalMinutes = Math.floor(healthData.accumulatedInjectionCount); |
| | | |
| | | // const minutes = totalMinutes % 60; |
| | | // healthData.injectionCount = `${healthData.accumulatedInjectionCount}h`; |
| | | // healthData.clampingCount = healthData.accumulatedClampingCount; |
| | | // healthData.energyConsumption = parseFloat(healthData.accumulatedEnergyConsumption.toFixed(2)); |
| | | // }; |
| | | const maintenanceTable = ref<HTMLElement | null>(null); |
| | | // åå§è®¾ç½®ä¸æ¬¡ï¼é¿å
馿¬¡å è½½æ¶æ¾ç¤ºä¸º0 |
| | | // updateAccumulatedData(); |
| | | let scrollInterval: number | undefined; |
| | | |
| | | const startScroll = () => { |
| | | if (!maintenanceTable.value) return; |
| | | |
| | | 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; |
| | | if (currentScrollTop >= scrollHeight - clientHeight) { |
| | | currentScrollTop = 0; |
| | | } |
| | | tableBody.scrollTop = currentScrollTop; |
| | | }, 50); |
| | | }; |
| | | |
| | | |
| | | |
| | | onMounted(() => { |
| | | // æ¯5ç§æ´æ°ä¸æ¬¡ç´¯å æ°æ® |
| | | // intervalId = setInterval(updateAccumulatedData, 5000); |
| | | nextTick(() => { |
| | | startScroll(); |
| | | }); |
| | | }) |
| | | onUnmounted(() => { |
| | | if (scrollInterval) { |
| | | clearInterval(scrollInterval); |
| | | } |
| | | if (deviceDataInterval) { |
| | | clearInterval(deviceDataInterval); |
| | | } |
| | | }); |
| | | |
| | | |
| | | return { |
| | | deviceInfo, |
| | | healthData, |
| | |
| | | historyData, |
| | | getStatusColor, |
| | | getUrgencyColor, |
| | | handleMaintenance |
| | | handleMaintenance, |
| | | maintenanceTable |
| | | }; |
| | | }, |
| | | mounted() { |
| | | |
| | | // åå§åå¾è¡¨ |
| | | const initChart = (chartId: string, title: string, chartData: any[], unit: string, baseValue: number, fluctuation: number) => { |
| | | const chart = echarts.init(document.getElementById(chartId)); |
| | |
| | | // ç¡®ä¿åå§æ°æ®ç¹è¶³å¤æ¾ç¤ºä¸ä¸ªå®æ´çè¶å¿ |
| | | if (chartData.length === 0) { |
| | | const now = new Date(); |
| | | for (let i = 0; i < 60; i++) { |
| | | for (let i = 0; i < 24; i++) { |
| | | // çæ60个ç¹ï¼ä»£è¡¨5åéçæ°æ® |
| | | const time = new Date(now.getTime() - (59 - i) * 5000); // æ¯ä¸ªç¹é´é5ç§ |
| | | const time = new Date(now.getTime() - (24 - i) * 5000); // æ¯ä¸ªç¹é´é5ç§ |
| | | chartData.push({ |
| | | time: time.toLocaleTimeString(), |
| | | value: (baseValue + Math.random() * fluctuation * 2 - fluctuation).toFixed(2) |
| | |
| | | time, |
| | | value: newValue |
| | | }); |
| | | if (chartData.length > 60) { |
| | | if (chartData.length > 24) { |
| | | chartData.shift(); |
| | | } |
| | | |
| | |
| | | window.addEventListener('resize', () => { |
| | | chart.resize(); |
| | | }); |
| | | onUnmounted(() => { |
| | | clearInterval(intervalId); |
| | | window.addEventListener('resize', () => { |
| | | chart.resize(); |
| | | }); |
| | | |
| | | }; |
| | | |
| | | |
| | | |
| | | const hydraulicOilTemperatureData: any[] = []; |
| | | const hydraulicOilPressureData: any[] = []; |
| | |
| | | // initChart('hydraulicOilPressureChart', 'æ¶²åæ²¹å', hydraulicOilPressureData, 'MPa', 150, 5); |
| | | // initChart('mainMotorCurrentChart', 'ä¸»çµæºçµæµ', mainMotorCurrentData, 'A', 80, 3); |
| | | initChart('screwSpeedChart', 'èºæè½¬é', screwSpeedData, 'rpm', 100, 10); |
| | | initChart('moldClampingForceChart', '鿍¡å', moldClampingForceData, 'kN', 1000, 50); |
| | | initChart('injectionPressureChart', '注å°åå', injectionPressureData, 'MPa', 1200, 80); |
| | | initChart('moldClampingForceChart', '鿍¡åå', moldClampingForceData, 'Bar', 120, 10); |
| | | initChart('injectionPressureChart', '注å°åå', injectionPressureData, 'Bar', 80, 5); |
| | | initChart('injectionSpeedChart', '注å°é度', injectionSpeedData, 'mm/s', 150, 10); |
| | | initChart('barrelTemperatureChart', 'æç温度', barrelTemperatureData, '°C', 240, 3); |
| | | initChart('coolingWaterTemperatureChart', 'å·å´æ°´æ¸©åº¦', coolingWaterTemperatureData, '°C', 25, 2); |
| | | initChart('coolingWaterTemperatureChart', 'å·æ°´æºæ¸©åº¦', coolingWaterTemperatureData, '°C', 20, 2); |
| | | // initChart('coolingWaterFlowChart', 'å·å´æ°´æµé', coolingWaterFlowData, 'L/min', 30, 3); |
| | | // initChart('ejectorPositionChart', 'é¡¶åºä½ç½®', ejectorPositionData, 'mm', 50, 5); |
| | | // initChart('cycleTimeChart', 'å¾ªç¯æ¶é´', cycleTimeData, 's', 30, 2); |
| | | }, |
| | | unmounted() { |
| | | // æ¸
é¤å®æ¶å¨ |
| | | if (this.intervalId) { |
| | | clearInterval(this.intervalId); |
| | | } |
| | | } |
| | | }); |
| | | </script> |
| | |
| | | <a-progress :percent="healthData.overallHealth" :show-info="false" :stroke-color="healthData.healthColor" /> |
| | | </div> |
| | | <a-divider orientation="left">颿µæ§ç»´æ¤å»ºè®®</a-divider> |
| | | <a-table :columns="maintenanceColumns" :data-source="maintenanceData" :pagination="false" size="small"> |
| | | <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> |
| | | </template> |
| | |
| | | <a-card class="mb-4" title="è®¾å¤æ°æ®"> |
| | | <a-row :gutter="[16, 16]"> |
| | | <a-col :span="4"> |
| | | <a-statistic :value="healthData.injectionCount" suffix="min" title="æ»å¼æºæ¶é´"> |
| | | <a-statistic :value="healthData.injectionCount.toFixed(2)" suffix="h" title="æ»å¼æºæ¶é´"> |
| | | <template #prefix> |
| | | <LineChartOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic :value="healthData.clampingCount" suffix="次" title="æ»å¾ªç¯æ¬¡æ°"> |
| | | <a-statistic :value="healthData.clampingCount.toFixed(0)" suffix="次" title="æ»å¾ªç¯æ¬¡æ°"> |
| | | <template #prefix> |
| | | <LineChartOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic :value="healthData.productionCycle" suffix="s" title="çäº§å¨æ"> |
| | | <a-statistic :value="healthData.productionCycle.toFixed(0)" suffix="s" title="å¹³åçäº§å¨æ"> |
| | | <template #prefix> |
| | | <FieldTimeOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic :value="healthData.energyConsumption" suffix="kWh" title="è½è"> |
| | | <a-statistic :value="healthData.energyConsumption.toFixed(2)" suffix="kWh" title="彿¥ç´¯ç§¯è½è"> |
| | | <template #prefix> |
| | | <ThunderboltOutlined /> |
| | | </template> |
| | | </a-statistic> |
| | | </a-col> |
| | | <a-col :span="4"> |
| | | <a-statistic :value="healthData.yieldRate" suffix="%" title="è¯åç"> |
| | | <a-statistic :value="healthData.yieldRate.toFixed(0)" suffix="模" title="å½å产é"> |
| | | <template #prefix> |
| | | <CheckCircleOutlined /> |
| | | </template> |
| | |
| | | /> |
| | | </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({ |
| | |
| | | return atomic.incrementAndGet(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * éå¢ååå¼ |
| | | * |
| | | * @param key Redisé® |
| | | * @return å½åå¼ |
| | | */ |
| | | public static long incrAtomicValueByNum(String key, long num) { |
| | | RAtomicLong atomic = CLIENT.getAtomicLong(key); |
| | | return atomic.addAndGet(num); |
| | | } |
| | | |
| | | /** |
| | | * éåååå¼ |
| | | * |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.eims.controller; |
| | | |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.dromara.common.core.domain.R; |
| | | import org.dromara.common.web.core.BaseController; |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import java.util.Calendar; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | /** |
| | | * è®¾å¤æ°æ®æ§å¶å¨ |
| | | * |
| | | * @author Lion Li |
| | | * @date 2024-07-26 |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/eims/deviceData") |
| | | @RequiredArgsConstructor |
| | | public class DeviceDataController extends BaseController { |
| | | |
| | | private static final String DEVICE_DATA_PREFIX = "eims:device:data:"; |
| | | |
| | | /** |
| | | * è·åè®¾å¤æ°æ® |
| | | */ |
| | | @GetMapping("/get") |
| | | public R<Map<String, Double>> getDeviceData() { |
| | | |
| | | |
| | | Map<String, Double> deviceData = new HashMap<>(); |
| | | deviceData.put("xAxisTravel", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "xAxisTravel") / 100000.0); |
| | | deviceData.put("yAxisTravel", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "yAxisTravel") / 100000.0); |
| | | deviceData.put("zAxisTravel", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "zAxisTravel") / 100000.0); |
| | | deviceData.put("toolChangeCount", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "toolChangeCount") / 10.0); |
| | | deviceData.put("partCount", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "partCount") / 100000.0); |
| | | deviceData.put("downtime", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "downtime") / 10.0); |
| | | return R.ok(deviceData); |
| | | } |
| | | |
| | | /** |
| | | * è·åè®¾å¤æ°æ® |
| | | */ |
| | | @GetMapping("/getSmt") |
| | | public R<Map<String, Double>> getDeviceDataSmt() { |
| | | |
| | | |
| | | Map<String, Double> deviceData = new HashMap<>(); |
| | | deviceData.put("xAxisTravel", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "smtXAxisTravel") / 1000.0); |
| | | deviceData.put("yAxisTravel", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "smtYAxisTravel") / 1000.0); |
| | | deviceData.put("tapeJamCount", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "smtTapeJamCount") / 1000.0); |
| | | deviceData.put("materialJamCount", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "smtMaterialJamCount") / 1000.0); |
| | | deviceData.put("panelCount", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "smtPanelCount") / 1000.0); |
| | | deviceData.put("downtime", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "smtDowntime") / 100.0); |
| | | return R.ok(deviceData); |
| | | } |
| | | |
| | | /** |
| | | * injectionCount: 495 * 24 * 60 + 19 * 60 + 44, // æ³¨å°æ¬¡æ°ï¼è½¬æ¢ä¸ºåé |
| | | * clampingCount: 545636, // 忍¡æ¬¡æ° // è·é产é 50så 䏿¬¡ |
| | | * productionCycle: 45, // çäº§å¨æ |
| | | * energyConsumption: 64, // è½è |
| | | * yieldRate: 354, // 产é 50ç§å¢å 䏿¨¡ |
| | | * downtime: 120, // åºéåæºæ¶é´ |
| | | * |
| | | */ |
| | | /** |
| | | * è·åè®¾å¤æ°æ® |
| | | */ |
| | | @GetMapping("/getInj") |
| | | public R<Map<String, Double>> getDeviceDataInj() { |
| | | |
| | | |
| | | Map<String, Double> deviceData = new HashMap<>(); |
| | | deviceData.put("injectionCount", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "injectionCount") / 3600.0); |
| | | deviceData.put("clampingCount", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "clampingCount") / 10.0); |
| | | deviceData.put("productionCycle", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "productionCycle") / 10.0); |
| | | deviceData.put("energyConsumption", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "energyConsumption") / 1000.0); |
| | | deviceData.put("yieldRate", RedisUtils.getAtomicValue(DEVICE_DATA_PREFIX + "yieldRate") / 10.0); |
| | | |
| | | return R.ok(deviceData); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * åå§åè®¾å¤æ°æ® |
| | | */ |
| | | @PostMapping("/init") |
| | | public R<Void> initDeviceData() { |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtXAxisTravel", 300282L); // 50/5s |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtYAxisTravel", 233524L); // 45/5s |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtTapeJamCount", 6000); // 5/5s |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtMaterialJamCount", 15000); // 5/5s |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtPanelCount", 2481000); // 100/5s |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtDowntime", 450); //5/5s |
| | | |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "injectionCount", 43848000L); // 5/5s |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "clampingCount", 5456360L); // 1/5s |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "productionCycle", 450); |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "energyConsumption", 64000); // 7/5s |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "yieldRate", 3540); // 1/5s |
| | | |
| | | return R.ok(); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.eims.job; |
| | | |
| | | import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; |
| | | import com.aizuda.snailjob.client.job.core.dto.JobArgs; |
| | | import com.aizuda.snailjob.client.model.ExecuteResult; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.SneakyThrows; |
| | | import org.dromara.common.core.constant.DictConstants; |
| | | import org.dromara.common.core.utils.DateUtils; |
| | | import org.dromara.eims.domain.EimsRepairRes; |
| | | import org.dromara.eims.domain.EimsRepairFb; |
| | | import org.dromara.eims.mapper.EimsRepairResMapper; |
| | | import org.dromara.eims.mapper.EimsRepairFbMapper; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | |
| | | @Component |
| | | @RequiredArgsConstructor |
| | | @JobExecutor(name = "autoApproveRepairJob") |
| | | public class AutoApproveRepairJob { |
| | | |
| | | private final EimsRepairResMapper repairResMapper; |
| | | private final EimsRepairFbMapper repairFbMapper; |
| | | |
| | | @SneakyThrows |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public ExecuteResult jobExecute(JobArgs jobArgs) { |
| | | // æ¥è¯¢å·²å®æï¼statusçäº3ï¼ä¸ç»ææ¶é´è¶
è¿ä¸å¤©ä»¥ä¸çç»´ä¿®å |
| | | Date threeDaysAgo = DateUtils.addDays(DateUtils.getNowDate(), -3); |
| | | LambdaQueryWrapper<EimsRepairRes> queryWrapper = new LambdaQueryWrapper<>(); |
| | | queryWrapper.eq(EimsRepairRes::getStatus, DictConstants.REPAIR_RES_STATUS_DETAIL.WANCHENG) |
| | | .le(EimsRepairRes::getEndTime, threeDaysAgo); |
| | | |
| | | List<EimsRepairRes> repairOrders = repairResMapper.selectList(queryWrapper); |
| | | |
| | | for (EimsRepairRes order : repairOrders) { |
| | | // æ£æ¥æ¯å¦å·²ç»åå¨å¥½è¯åé¦ |
| | | LambdaQueryWrapper<EimsRepairFb> fbQueryWrapper = new LambdaQueryWrapper<>(); |
| | | fbQueryWrapper.eq(EimsRepairFb::getResId, order.getId()) |
| | | .eq(EimsRepairFb::getRepairSatisfaction, 1); |
| | | Long count = repairFbMapper.selectCount(fbQueryWrapper); |
| | | |
| | | // å°ç»´ä¿®åç¶ææ´æ°ä¸ºå·²è¯ä»· |
| | | order.setStatus(DictConstants.REPAIR_RES_STATUS_DETAIL.PINGJIA); |
| | | repairResMapper.updateById(order); |
| | | |
| | | if (count == 0) { |
| | | // æå
¥ä¸æ¡repairSatisfaction为1çå馿°æ® |
| | | EimsRepairFb feedback = new EimsRepairFb(); |
| | | feedback.setResId(order.getId()); |
| | | feedback.setRepairSatisfaction("1"); // é»è®¤å¥½è¯ |
| | | feedback.setRemark("ç³»ç»èªå¨å¥½è¯"); // å¯ä»¥æ ¹æ®éè¦è®¾ç½®åé¦å
容 |
| | | feedback.setCreateTime(DateUtils.getNowDate()); |
| | | repairFbMapper.insert(feedback); |
| | | } |
| | | } |
| | | |
| | | return ExecuteResult.success("èªå¨å¥½è¯ç»´ä¿®å任塿§è¡æå"); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.eims.job; |
| | | |
| | | import org.dromara.common.redis.utils.RedisUtils; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.scheduling.annotation.EnableScheduling; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | |
| | | import java.util.Calendar; |
| | | |
| | | @Configuration |
| | | @EnableScheduling |
| | | public class DeviceDataIncrJob { |
| | | private static final String DEVICE_DATA_PREFIX = "eims:device:data:"; |
| | | /** |
| | | * 宿¶æ´æ°è®¾å¤æ°æ® |
| | | * æ¯å¤©æ©ä¸8ç¹å°ä¸å5ç¹ä¹é´ï¼æ¯å°æ¶æ´æ°ä¸æ¬¡ |
| | | */ |
| | | @Scheduled(cron = "0/5 * 8-17 * * ?") |
| | | public void updateDeviceDataScheduled() { |
| | | System.out.println("æ§è¡å®æ¶ä»»å¡ï¼æ´æ°è®¾å¤æ°æ®ï¼ï¼ï¼"); |
| | | // æ£æ¥å½åæ¶é´æ¯å¦å¨æ©ä¸8ç¹å°ä¸å5ç¹ä¹é´ |
| | | Calendar now = Calendar.getInstance(); |
| | | int hourOfDay = now.get(Calendar.HOUR_OF_DAY); |
| | | if (hourOfDay >= 8 && hourOfDay < 17) { |
| | | // æ´æ°å¹
度 |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "xAxisTravel", 83L); // æ¯å¤©å 6å°æ¶ï¼å¯¹åºRedisä¸å 60 |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "yAxisTravel", 833L); // æ¯å¤©å 60次 |
| | | // toolChangeCount å downtime 䏿³¢å¨ï¼æä»¥ä¸è¿è¡å¢éæä½ |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "partCount", 210L); // æ¯å¤©å 15个 |
| | | |
| | | |
| | | |
| | | // RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtXAxisTravel", 300282L); // 50/5s |
| | | // RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtYAxisTravel", 233524L); // 45/5s |
| | | // RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtTapeJamCount", 6000); // 5/5s |
| | | // RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtMaterialJamCount", 15000); // 5/5s |
| | | // RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtPanelCount", 2481000); // 100/5s |
| | | // RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtDowntime", 450); //5/5s |
| | | |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "smtXAxisTravel", 50L); |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "smtYAxisTravel", 45L); |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "smtTapeJamCount", 5L); |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "smtMaterialJamCount", 5L); |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "smtPanelCount", 100L); |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "smtDowntime", 1L); |
| | | |
| | | |
| | | // RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "injectionCount", 43848000L); // 5/5s |
| | | // RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "clampingCount", 5456360L); // 1/5s |
| | | // RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "productionCycle", 450); |
| | | // RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "energyConsumption", 64000); // 7/5s |
| | | // RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "yieldRate", 3540); // 1/5s |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "injectionCount", 5L); |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "clampingCount", 1L); |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "energyConsumption", 10L); |
| | | RedisUtils.incrAtomicValueByNum(DEVICE_DATA_PREFIX + "yieldRate", 1L); |
| | | } |
| | | } |
| | | |
| | | |
| | | // æ°å¢ä¸ä¸ªå®æ¶å¨ï¼ç¬¬å¤©é¶ç¹æ¸
é¶ |
| | | @Scheduled(cron = "0 0 0 * * ?") |
| | | public void resetDeviceDataScheduled() { |
| | | System.out.println("æ§è¡å®æ¶ä»»å¡ï¼éç½®è®¾å¤æ°æ®ï¼ï¼ï¼"); |
| | | |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtTapeJamCount", 0); // 5/5s |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtMaterialJamCount", 0); // 5/5s |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtPanelCount", 0); // 100/5s |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "smtDowntime", 0); //5/5s |
| | | |
| | | |
| | | |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "energyConsumption", 0); // 7/5s |
| | | RedisUtils.setAtomicValue(DEVICE_DATA_PREFIX + "yieldRate", 0); // 1/5s |
| | | } |
| | | } |
| | |
| | | import org.dromara.eims.domain.vo.EimsEquImportVo; |
| | | import org.dromara.eims.domain.vo.EimsEquVo; |
| | | import org.dromara.eims.service.IEimsEquService; |
| | | import org.dromara.system.domain.bo.SysUserBo; |
| | | import org.dromara.system.service.ISysUserService; |
| | | |
| | | import java.util.List; |