From 7b4cd6ef04b358e0805846d49e3acf02d7eae5cb Mon Sep 17 00:00:00 2001 From: baoshiwei <baoshiwei@shlanbao.cn> Date: 星期三, 30 七月 2025 11:08:33 +0800 Subject: [PATCH] feat(eims): 更新预测性维护功能 - 新增设备数据定时更新功能 - 添加维护建议滚动显示 - 更新设备部件寿命预测数据 - 调整备件库存与预警逻辑 - 优化数据展示和颜色提示 --- eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/injection-molding-machine-detail.vue | 277 ++++++++++-- eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/index.vue | 83 ++- eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/job/AutoApproveRepairJob.java | 64 +++ eims-ui/apps/web-antd/src/api/eims/equ/deviceData.ts | 45 ++ eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/cnc-machining-center-detail.vue | 284 ++++++++++-- eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/smt-machine-detail.vue | 279 ++++++++++-- eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java | 12 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/DeviceDataController.java | 109 +++++ eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/job/DeviceDataIncrJob.java | 76 +++ eims-ui-mobile/src/pages/repair/res-list.vue | 22 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/listener/EimsEquImportListener.java | 1 11 files changed, 1,058 insertions(+), 194 deletions(-) diff --git a/eims-ui-mobile/src/pages/repair/res-list.vue b/eims-ui-mobile/src/pages/repair/res-list.vue index 3ca5864..c572112 100644 --- a/eims-ui-mobile/src/pages/repair/res-list.vue +++ b/eims-ui-mobile/src/pages/repair/res-list.vue @@ -20,8 +20,11 @@ <!-- </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"--> @@ -61,6 +64,8 @@ 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() @@ -148,7 +153,14 @@ 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 @@ -167,6 +179,10 @@ paging.value.reload() } +function handleTabChange() { + reloadData() +} + // /** // * 鏉$洰鐐瑰嚮浜嬩欢 // * @param item diff --git a/eims-ui/apps/web-antd/src/api/eims/equ/deviceData.ts b/eims-ui/apps/web-antd/src/api/eims/equ/deviceData.ts new file mode 100644 index 0000000..2b9f0df --- /dev/null +++ b/eims-ui/apps/web-antd/src/api/eims/equ/deviceData.ts @@ -0,0 +1,45 @@ +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); +} \ No newline at end of file diff --git a/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/cnc-machining-center-detail.vue b/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/cnc-machining-center-detail.vue index 4c2ea27..044774b 100644 --- a/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/cnc-machining-center-detail.vue +++ b/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/cnc-machining-center-detail.vue @@ -69,10 +69,12 @@ </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> @@ -90,42 +92,42 @@ <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> @@ -142,7 +144,7 @@ <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> @@ -155,8 +157,7 @@ <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> @@ -197,7 +198,7 @@ </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, @@ -205,7 +206,8 @@ 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() { @@ -224,15 +226,15 @@ 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 = [ @@ -270,7 +272,7 @@ type: '渚嬭淇濆吇', content: '妫�鏌ヤ富杞存鼎婊戠郴缁�', suggestedTime: '2025-07-15', - urgency: '涓瓑' + urgency: '浣�' }, { key: '2', @@ -281,9 +283,30 @@ }, { 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: '浣�' } ]); @@ -308,16 +331,16 @@ 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: '鐘舵��', @@ -329,49 +352,120 @@ 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: '鍒囧墛娓f竻鐞嗭紝鍒囧墛娑叉洿鎹�', + color: 'orange' } ]); @@ -393,6 +487,84 @@ // 瀹為檯椤圭洰涓繖閲屼細璋冪敤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, @@ -403,7 +575,8 @@ historyData, getStatusColor, getUrgencyColor, - handleMaintenance + handleMaintenance, + maintenanceTable }; }, @@ -430,7 +603,7 @@ time, value: newValue }); - if (s.data.length > 60) { + if (s.data.length > 12) { s.data.shift(); } }); @@ -503,8 +676,8 @@ 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({ @@ -530,9 +703,10 @@ }; + // 杩愬姩绯荤粺鐩戞祴 - 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' }, @@ -576,6 +750,8 @@ initChart('coolantTemperatureChart', '鍐峰嵈娑叉俯搴�', [ { name: '娓╁害', data: [], unit: '掳C', baseValue: 28, fluctuation: 2, color: '#5470C6' }, ]); + + } }); @@ -585,12 +761,6 @@ .device-detail-container { padding: 16px; background: #f0f2f5; -} -.device-image-container { - display: flex; - justify-content: center; - align-items: center; - height: 330px; } .mt-4 { diff --git a/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/index.vue b/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/index.vue index 7b629cb..026b8c2 100644 --- a/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/index.vue +++ b/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/index.vue @@ -63,8 +63,8 @@ <!-- 澶囦欢淇℃伅 --> <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)"> @@ -79,8 +79,8 @@ </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)"> @@ -140,7 +140,7 @@ indicator: '鐪熺┖鍘嬪姏', value: 32, threshold: 35, - status: '涓闄�', + status: '浣庨闄�', maintenanceSuggestion: '鐪熺┖鍘嬪姏鍊间綆浜庤瀹氬�硷紝寤鸿妫�鏌ユ垨鏇存崲鍚稿槾', maintenanceType: '棰勯槻鎬х淮鎶�', }, @@ -152,7 +152,7 @@ indicator: '娓╁害', value: 85, threshold: 80, - status: '涓闄�', + status: '浣庨闄�', maintenanceSuggestion: '寤鸿瀵逛富杞磋繘琛屾鼎婊戜繚鍏诲苟妫�鏌ュ喎鍗寸郴缁�', maintenanceType: '娑︽粦缁存姢', }, @@ -221,12 +221,33 @@ 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'; } }; @@ -245,7 +266,7 @@ 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' }, @@ -254,19 +275,25 @@ ]; 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 '瀵垮懡鍏呰冻'; @@ -274,10 +301,10 @@ }; 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'; } @@ -290,7 +317,7 @@ const getStockStatus = (currentStock, safetyStock) => { - if (currentStock <= safetyStock) { + if (currentStock < safetyStock) { return '搴撳瓨棰勮'; } else { return '搴撳瓨鍏呰冻'; @@ -298,8 +325,8 @@ }; const getStockStatusColor = (currentStock, safetyStock) => { - if (currentStock <= safetyStock) { - return 'red'; + if (currentStock < safetyStock) { + return 'orange'; } else { return 'green'; } @@ -340,13 +367,13 @@ // 鏍规嵁璁惧鍚嶇О涓嶅悓璺宠浆涓嶅悓鐨勮鎯呴〉闈� 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 } }); } }; @@ -363,7 +390,7 @@ xAxis: { type: 'category', data: ['10鍒�', '9鍒�', '8鍒�', '7鍒�', '6鍒�', '5鍒�', '4鍒�', '3鍒�', '2鍒�', '1鍒�'], - + }, yAxis: { type: 'value', @@ -383,7 +410,7 @@ { value: 21, itemStyle: { color: '#52c41a' } }, { value: 8, itemStyle: { color: '#faad14' } }, { value: 5, itemStyle: { color: '#faad14' } }, - + ], label: { show: true, diff --git a/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/injection-molding-machine-detail.vue b/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/injection-molding-machine-detail.vue index 5ec94fc..46237fd 100644 --- a/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/injection-molding-machine-detail.vue +++ b/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/injection-molding-machine-detail.vue @@ -1,9 +1,11 @@ <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: { @@ -29,22 +31,26 @@ 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 = [ @@ -80,22 +86,40 @@ { 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: '妫�鏌ョ‘璁ゆ恫鍘嬫补娓╁害鏄惁姝e父', + 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: '浣�' } ]); @@ -117,6 +141,27 @@ } }; + 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: '閮ㄤ欢鍚嶇О', @@ -124,16 +169,16 @@ 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: '鐘舵��', @@ -146,23 +191,44 @@ 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: '鑹ソ' } ]); @@ -170,21 +236,49 @@ 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' @@ -213,6 +307,68 @@ // 瀹為檯椤圭洰涓繖閲屼細璋冪敤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, @@ -223,10 +379,12 @@ 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)); @@ -234,9 +392,9 @@ // 纭繚鍒濆鏁版嵁鐐硅冻澶熸樉绀轰竴涓畬鏁寸殑瓒嬪娍 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) @@ -255,7 +413,7 @@ time, value: newValue }); - if (chartData.length > 60) { + if (chartData.length > 24) { chartData.shift(); } @@ -323,10 +481,13 @@ window.addEventListener('resize', () => { chart.resize(); }); - onUnmounted(() => { - clearInterval(intervalId); + window.addEventListener('resize', () => { + chart.resize(); }); + }; + + const hydraulicOilTemperatureData: any[] = []; const hydraulicOilPressureData: any[] = []; @@ -345,14 +506,20 @@ // 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> @@ -411,7 +578,7 @@ <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> @@ -426,35 +593,35 @@ <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> diff --git a/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/smt-machine-detail.vue b/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/smt-machine-detail.vue index afb4146..b274799 100644 --- a/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/smt-machine-detail.vue +++ b/eims-ui/apps/web-antd/src/views/eims/predictive-maintenance/smt-machine-detail.vue @@ -68,13 +68,15 @@ /> </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> @@ -89,42 +91,42 @@ <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> @@ -214,7 +216,7 @@ </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, @@ -223,6 +225,7 @@ 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', @@ -244,20 +247,20 @@ 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 = [ @@ -293,25 +296,65 @@ { 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) => { @@ -326,6 +369,27 @@ 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 = [ { @@ -356,33 +420,111 @@ const sparePartData = reactive([ { key: '1', - name: 'X杞翠己鏈嶇數鏈�', + name: '1鍙疯创瑁呯郴缁烼杞翠己鏈嶇數鏈�', currentLife: '15000灏忔椂', - remainingLife: '4354灏忔椂', + remainingLife: '1451灏忔椂', + status: '棰勮' + }, + { + key: '5', + name: '1鍙疯创瑁呯郴缁焃杞翠己鏈嶇數鏈�', + 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鍙疯创瑁呯郴缁烼杞翠己鏈嶇數鏈�', + currentLife: '15000灏忔椂', + remainingLife: '7540灏忔椂', + status: '鑹ソ' + }, + { + key: '7', + name: '2鍙疯创瑁呯郴缁焃杞翠己鏈嶇數鏈�', + 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: '瀹屾垚瀛e害淇濆吇锛屾鏌ヨ繍鍔ㄧ郴缁熸鼎婊�', + 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' }, { @@ -394,9 +536,9 @@ }, { id: '3', - date: '2024-12-01', + date: '2025-01-15', type: '瀹氭湡淇濆吇', - description: '瀹屾垚骞村害淇濆吇锛屾牎鍑嗚瑙夌郴缁�', + description: '瀹屾垚骞村害淇濆吇锛岃创瑁呯郴缁熸牎鍑嗭紝鏄撴崯浠舵洿鎹紝鏍″噯瑙嗚绯荤粺', color: 'green' } ]); @@ -420,34 +562,70 @@ }; 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); } }); @@ -461,7 +639,8 @@ historyData, getStatusColor, getUrgencyColor, - handleMaintenance + handleMaintenance, + maintenanceTable }; }, components: { @@ -487,7 +666,7 @@ time, value: newValue }); - if (s.data.length > 60) { + if (s.data.length > 24) { s.data.shift(); } }); @@ -560,8 +739,8 @@ 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({ diff --git a/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java index 67be2fb..4a44042 100644 --- a/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java +++ b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java @@ -505,6 +505,18 @@ return atomic.incrementAndGet(); } + + /** + * 閫掑鍘熷瓙鍊� + * + * @param key Redis閿� + * @return 褰撳墠鍊� + */ + public static long incrAtomicValueByNum(String key, long num) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + return atomic.addAndGet(num); + } + /** * 閫掑噺鍘熷瓙鍊� * diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/DeviceDataController.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/DeviceDataController.java new file mode 100644 index 0000000..c431bd8 --- /dev/null +++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/DeviceDataController.java @@ -0,0 +1,109 @@ +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(); + } +} diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/job/AutoApproveRepairJob.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/job/AutoApproveRepairJob.java new file mode 100644 index 0000000..eaa444a --- /dev/null +++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/job/AutoApproveRepairJob.java @@ -0,0 +1,64 @@ +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) { + // 鎻掑叆涓�鏉epairSatisfaction涓�1鐨勫弽棣堟暟鎹� + EimsRepairFb feedback = new EimsRepairFb(); + feedback.setResId(order.getId()); + feedback.setRepairSatisfaction("1"); // 榛樿濂借瘎 + feedback.setRemark("绯荤粺鑷姩濂借瘎"); // 鍙互鏍规嵁闇�瑕佽缃弽棣堝唴瀹� + feedback.setCreateTime(DateUtils.getNowDate()); + repairFbMapper.insert(feedback); + } + } + + return ExecuteResult.success("鑷姩濂借瘎缁翠慨鍗曚换鍔℃墽琛屾垚鍔�"); + } +} \ No newline at end of file diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/job/DeviceDataIncrJob.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/job/DeviceDataIncrJob.java new file mode 100644 index 0000000..5b2e888 --- /dev/null +++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/job/DeviceDataIncrJob.java @@ -0,0 +1,76 @@ +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灏忔椂锛屽搴擱edis涓姞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 + } +} diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/listener/EimsEquImportListener.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/listener/EimsEquImportListener.java index bf9b051..23d1e31 100644 --- a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/listener/EimsEquImportListener.java +++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/listener/EimsEquImportListener.java @@ -21,7 +21,6 @@ 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; -- Gitblit v1.9.3