| | |
| | | <!-- </wd-cell>--> |
| | | <view class="w-full h-[1px] bg-base"></view> |
| | | <wd-input |
| | | v-if="inspSt.status !== '0'" |
| | | label="è¿è¡æ¶é´" |
| | | label-width="200rpx" |
| | | clearable |
| | |
| | | size="large" |
| | | /> |
| | | <wd-input |
| | | v-if="inspSt.status !== '0'" |
| | | label="æ
éæ¶é´" |
| | | label-width="200rpx" |
| | | clearable |
| | |
| | | message.alert('请填åè¿è¡æ¬¡æ°åæ
鿬¡æ°!') |
| | | return false |
| | | } |
| | | // 妿å½åæ¶é´è·ä¸æ¬¡æ°æ¶é´ä¸¤å°æ¶ä»¥å
åä¸å
许确认 |
| | | console.log('inspSt.updateTime', inspSt.updateTime) |
| | | console.log('new Date().getTime()', new Date().getTime()) |
| | | console.log('inspSt.updateTime', new Date(inspSt.updateTime).getTime()) |
| | | console.log('new Date().getTime() - new Date(inspSt.updateTime).getTime()', new Date().getTime() - new Date(inspSt.updateTime).getTime()) |
| | | console.log("2 * 60 * 60 * 1000", 2 * 60 * 60 * 1000) |
| | | console.log('new Date().getTime() - new Date(inspSt.updateTime).getTime() < 2 * 60 * 60 * 1000', new Date().getTime() - new Date(inspSt.updateTime).getTime() < 2 * 60 * 60 * 1000) |
| | | if ( |
| | | new Date().getTime() - new Date(inspSt.updateTime).getTime() < 2 * 60 * 60 * 1000 |
| | | ) { |
| | | console.log("new Date().getTime() - new Date(inspSt.updateTime).getTime() < 2 * 60 * 60 * 1000",new Date().getTime() - new Date(inspSt.updateTime).getTime() < 2 * 60 * 60 * 1000) |
| | | message.alert('ç¹æ£ä¸¤å°æ¶ä»¥å
ä¸å
许确认!') |
| | | return false |
| | | } |
| | | const now = new Date(); |
| | | const data: any = Object.assign( |
| | | {}, |
| | |
| | | </view> |
| | | </wd-card> |
| | | </view> |
| | | |
| | | <wd-fab |
| | | v-if="status === '1' && isLeader()" |
| | | :draggable="true" |
| | | type="success" |
| | | position="left-bottom" |
| | | :expandable="false" |
| | | inactiveIcon="check" |
| | | @click="handleBatchComplete" |
| | | direction="top" |
| | | /> |
| | | </z-paging> |
| | | </template> |
| | | |
| | |
| | | import { ref, computed } from 'vue' |
| | | import { getMaintStList } from '@/service/maint' |
| | | import dayjs from 'dayjs' |
| | | import { updateMaintSt } from '@/service/maint' |
| | | import { useUserStore } from "@/store"; |
| | | import { isLeader } from '@/utils/RoleUtils' |
| | | import { useToast } from 'wot-design-uni' |
| | | |
| | | const searchValue = ref<string>('') |
| | | /** |
| | | * å
¶ä»é¡µé¢ä¼ è¿æ¥çæ°æ® |
| | |
| | | paging.value.reload() |
| | | } |
| | | |
| | | const userStore = useUserStore() |
| | | const toast = useToast() |
| | | |
| | | async function handleBatchComplete() { |
| | | console.log('handleBatchComplete', dataList.value.length) |
| | | if (!isLeader()) { |
| | | toast.info('æ æéæä½') |
| | | return |
| | | } |
| | | // 妿å¾
确认工åå表为空ï¼åæç¤ºç¨æ·æ å¾
确认工å |
| | | if (dataList.value.length < 1) { |
| | | toast.info('æ å¾
确认工å') |
| | | return |
| | | } |
| | | const now = new Date() |
| | | const verifyTime = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}` |
| | | |
| | | // å设 dataList æ¯å½åå¾
确认çå·¥åå表 |
| | | const promises = dataList.value.map(item => { |
| | | return updateMaintSt({ |
| | | id: item.id, |
| | | status: '2', |
| | | verifyUser: userStore?.userInfo?.userId, |
| | | verifyTime |
| | | }) |
| | | }) |
| | | |
| | | try { |
| | | await Promise.all(promises) |
| | | toast.success('ä¸é®ç¡®è®¤å®æ') |
| | | reloadData() // å·æ°å表 |
| | | } catch (e) { |
| | | toast.error('é¨åå·¥å确认失败ï¼è¯·éè¯') |
| | | } |
| | | } |
| | | |
| | | onLoad((options) => { |
| | | Object.assign(option, options) |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="device-detail-container"> |
| | | <a-page-header |
| | | title="ç©ºåæºé¢æµæ§ç»´æ¤è¯¦æ
" |
| | | :sub-title="deviceInfo.deviceName" |
| | | @back="() => $router.go(-1)" |
| | | /> |
| | | |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <!-- 设å¤åºæ¬ä¿¡æ¯ --> |
| | | <a-col :span="8"> |
| | | <a-card title="设å¤åºæ¬ä¿¡æ¯" class="mb-4" :style="{ height: '440px' }"> |
| | | <a-descriptions bordered :column="1"> |
| | | <a-descriptions-item label="设å¤åç§°">{{ deviceInfo.deviceName }}</a-descriptions-item> |
| | | <a-descriptions-item label="设å¤ç±»å">{{ deviceInfo.deviceType }}</a-descriptions-item> |
| | | <a-descriptions-item label="设å¤ç¼å·">{{ deviceInfo.deviceId }}</a-descriptions-item> |
| | | <a-descriptions-item label="å®è£
æ¥æ">{{ deviceInfo.installDate }}</a-descriptions-item> |
| | | <a-descriptions-item label="使ç¨å¹´é">{{ deviceInfo.serviceLife }}å¹´</a-descriptions-item> |
| | | <a-descriptions-item label="å½åç¶æ"> |
| | | <a-tag :color="deviceInfo.statusColor">{{ deviceInfo.status }}</a-tag> |
| | | </a-descriptions-item> |
| | | </a-descriptions> |
| | | </a-card> |
| | | </a-col> |
| | | |
| | | <!-- 设å¤å¥åº·ç¶æä¸ç»´æ¤å»ºè®® --> |
| | | <a-col :span="16"> |
| | | <a-card title="设å¤å¥åº·ç¶æä¸ç»´æ¤å»ºè®®" class="mb-4" :style="{ height: '440px' }"> |
| | | <a-row :gutter="16"> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | title="æ´ä½å¥åº·åº¦" |
| | | :value="healthData.overallHealth" |
| | | :precision="0" |
| | | suffix="%" |
| | | :value-style="{ color: healthData.healthColor }" |
| | | /> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | title="颿µå©ä½å¯¿å½" |
| | | :value="healthData.predictedLife" |
| | | suffix="天" |
| | | /> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | title="æ
éé£é©ç级" |
| | | :value="healthData.riskLevel" |
| | | :value-style="{ color: healthData.riskColor }" |
| | | /> |
| | | </a-col> |
| | | </a-row> |
| | | <div class="mt-4"> |
| | | <a-progress |
| | | :percent="healthData.overallHealth" |
| | | :stroke-color="healthData.healthColor" |
| | | :show-info="false" |
| | | /> |
| | | </div> |
| | | <a-divider orientation="left">颿µæ§ç»´æ¤å»ºè®®</a-divider> |
| | | <a-table |
| | | :columns="maintenanceColumns" |
| | | :data-source="maintenanceData" |
| | | :pagination="false" |
| | | size="small" |
| | | > |
| | | <template #urgency="{ text }"> |
| | | <a-tag :color="getUrgencyColor(text)">{{ text }}</a-tag> |
| | | </template> |
| | | <template #action="{ record }"> |
| | | <a-button type="link" size="small" @click="handleMaintenance(record)">å¤ç</a-button> |
| | | </template> |
| | | </a-table> |
| | | </a-card> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | <!-- 宿¶æ°æ®è¶å¿å¾ --> |
| | | <a-card title="宿¶æ°æ®è¶å¿å¾" class="mb-4"> |
| | | <a-row :gutter="16"> |
| | | <a-col :span="8"> |
| | | <div id="exhaustPressureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="exhaustTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="hostVibrationChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="mainBearingTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="mainMotorCurrentChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="oilTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="oilPressureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="oilLevelChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="inletPressureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="inletTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="airFlowChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="dryerDewPointChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="coolingWaterTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="coolingWaterFlowChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="ambientTemperatureHumidityChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | </a-card> |
| | | <a-row :gutter="16"> |
| | | <!-- å¤ä»¶å¯¿å½é¢æµ --> |
| | | <a-col :span="12"> |
| | | <a-card title="å¤ä»¶å¯¿å½é¢æµ" class="mb-4"> |
| | | <a-table |
| | | :columns="sparePartColumns" |
| | | :data-source="sparePartData" |
| | | :pagination="false" |
| | | size="small" |
| | | > |
| | | <template #status="{ text }"> |
| | | <a-tag :color="getStatusColor(text)">{{ text }}</a-tag> |
| | | </template> |
| | | </a-table> |
| | | </a-card> |
| | | </a-col> |
| | | |
| | | <!-- åå²ç»´æ¤è®°å½ --> |
| | | <a-col :span="12"> |
| | | <a-card title="åå²ç»´æ¤è®°å½" class="mb-4"> |
| | | <a-timeline> |
| | | <a-timeline-item v-for="item in historyData" :key="item.id" :color="item.color"> |
| | | {{ item.date }} - {{ item.type }}: {{ item.description }} |
| | | </a-timeline-item> |
| | | </a-timeline> |
| | | </a-card> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { defineComponent, reactive, onMounted, onUnmounted } from 'vue'; |
| | | import * as echarts from 'echarts'; |
| | | |
| | | export default defineComponent({ |
| | | name: 'AirCompressorDetail', |
| | | setup() { |
| | | // æ¨¡ææ°æ® |
| | | const deviceInfo = reactive({ |
| | | deviceName: 'ç©ºåæº #AC-001', |
| | | deviceType: 'ç©ºåæº', |
| | | deviceId: 'AC-2024-001', |
| | | installDate: '2023-05-10', |
| | | serviceLife: 10, |
| | | status: 'è¿è¡ä¸', |
| | | statusColor: '#52c41a' |
| | | }); |
| | | |
| | | const healthData = reactive({ |
| | | overallHealth: 92, |
| | | healthColor: '#52c41a', |
| | | predictedLife: 3000, |
| | | riskLevel: 'ä½é£é©', |
| | | riskColor: '#52c41a' |
| | | }); |
| | | |
| | | const maintenanceColumns = [ |
| | | { |
| | | title: 'ç»´æ¤ç±»å', |
| | | dataIndex: 'type', |
| | | key: 'type' |
| | | }, |
| | | { |
| | | title: 'ç»´æ¤å
容', |
| | | dataIndex: 'content', |
| | | key: 'content' |
| | | }, |
| | | { |
| | | title: '建议æ¶é´', |
| | | dataIndex: 'suggestedTime', |
| | | key: 'suggestedTime' |
| | | }, |
| | | { |
| | | title: 'ç´§æ¥ç¨åº¦', |
| | | dataIndex: 'urgency', |
| | | key: 'urgency', |
| | | slots: { customRender: 'urgency' } |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | key: 'action', |
| | | slots: { customRender: 'action' } |
| | | } |
| | | ]; |
| | | |
| | | const maintenanceData = reactive([ |
| | | { |
| | | key: '1', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | content: 'æ£æ¥ä¸»æºç´§åºä»¶', |
| | | suggestedTime: '2024-07-01', |
| | | urgency: 'ä¸ç' |
| | | }, |
| | | { |
| | | key: '2', |
| | | type: '润æ»ç³»ç»ç»´æ¤', |
| | | content: 'æ´æ¢æ¶¦æ»æ²¹', |
| | | suggestedTime: '2024-09-01', |
| | | urgency: 'é«' |
| | | }, |
| | | { |
| | | key: '3', |
| | | type: '空æ°ç³»ç»ç»´æ¤', |
| | | content: 'æ´æ¢ç©ºæ»¤è¯', |
| | | suggestedTime: '2024-08-15', |
| | | urgency: 'ä½' |
| | | } |
| | | ]); |
| | | |
| | | const getUrgencyColor = (urgency: string) => { |
| | | switch (urgency) { |
| | | case 'é«': |
| | | return 'red'; |
| | | case 'ä¸ç': |
| | | return 'orange'; |
| | | case 'ä½': |
| | | return 'green'; |
| | | default: |
| | | return 'default'; |
| | | } |
| | | }; |
| | | |
| | | const sparePartColumns = [ |
| | | { |
| | | title: 'å¤ä»¶åç§°', |
| | | dataIndex: 'name', |
| | | key: 'name' |
| | | }, |
| | | { |
| | | title: 'å½å寿å½', |
| | | dataIndex: 'currentLife', |
| | | key: 'currentLife', |
| | | customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | }, |
| | | { |
| | | title: '颿µå©ä½å¯¿å½', |
| | | dataIndex: 'remainingLife', |
| | | key: 'remainingLife', |
| | | customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | }, |
| | | { |
| | | title: 'ç¶æ', |
| | | dataIndex: 'status', |
| | | key: 'status', |
| | | slots: { customRender: 'status' } |
| | | } |
| | | ]; |
| | | |
| | | const sparePartData = reactive([ |
| | | { |
| | | key: '1', |
| | | name: '空滤è¯', |
| | | currentLife: 1000, |
| | | remainingLife: 200, |
| | | status: 'é¢è¦' |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: '油滤è¯', |
| | | currentLife: 1500, |
| | | remainingLife: 500, |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: 'æ²¹æ°å离å¨', |
| | | currentLife: 2000, |
| | | remainingLife: 300, |
| | | status: 'é¢è¦' |
| | | } |
| | | ]); |
| | | |
| | | const historyData = reactive([ |
| | | { |
| | | id: '1', |
| | | date: '2024-06-10', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | description: 'æ´æ¢ç©ºæ»¤è¯ã油滤è¯', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '2', |
| | | date: '2024-03-05', |
| | | type: 'æ
éç»´ä¿®', |
| | | description: '主æºè½´æ¿æ¶¦æ»èè¡¥å
', |
| | | color: 'red' |
| | | }, |
| | | { |
| | | id: '3', |
| | | date: '2023-12-01', |
| | | type: '年度ä¿å
»', |
| | | description: 'å
¨é¢æ£æ¥è®¾å¤è¿è¡ç¶æ', |
| | | color: 'green' |
| | | } |
| | | ]); |
| | | |
| | | const getStatusColor = (status: string) => { |
| | | switch (status) { |
| | | case 'è¯å¥½': |
| | | return '#52c41a'; |
| | | case 'é¢è¦': |
| | | return '#faad14'; |
| | | case 'å±é©': |
| | | return '#f5222d'; |
| | | default: |
| | | return '#d9d9d9'; |
| | | } |
| | | }; |
| | | |
| | | const handleMaintenance = (record: any) => { |
| | | console.log('å¤çç»´æ¤å»ºè®®:', record); |
| | | // å®é
项ç®ä¸è¿éä¼è°ç¨APIå¤çç»´æ¤å»ºè®® |
| | | }; |
| | | |
| | | return { |
| | | deviceInfo, |
| | | healthData, |
| | | maintenanceColumns, |
| | | maintenanceData, |
| | | sparePartColumns, |
| | | sparePartData, |
| | | historyData, |
| | | getStatusColor, |
| | | getUrgencyColor, |
| | | handleMaintenance |
| | | }; |
| | | }, |
| | | |
| | | mounted() { |
| | | // åå§åå¾è¡¨ |
| | | const initChart = (chartId: string, title: string, chartData: any[], unit: string, baseValue: number, fluctuation: number) => { |
| | | const chart = echarts.init(document.getElementById(chartId)); |
| | | |
| | | // é¢å
çæ60ä¸ªæ°æ®ç¹ |
| | | for (let i = 0; i < 60; i++) { |
| | | const now = new Date(Date.now() - (60 - 1 - i) * 5000); // 忍æ¶é´ |
| | | const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`; |
| | | const newValue = (baseValue + (Math.random() * fluctuation * 2 - fluctuation)).toFixed(2); |
| | | chartData.push({ |
| | | time, |
| | | value: newValue |
| | | }); |
| | | } |
| | | |
| | | const updateChart = () => { |
| | | // çææ°çæ°æ®ç¹ |
| | | const now = new Date(); |
| | | const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`; |
| | | const newValue = (baseValue + (Math.random() * fluctuation * 2 - fluctuation)).toFixed(2); |
| | | |
| | | // æ·»å æ°æ°æ®ç¹ï¼æå¤ä¿ç60个ç¹ï¼5åéæ°æ®ï¼ |
| | | chartData.push({ |
| | | time, |
| | | value: newValue |
| | | }); |
| | | if (chartData.length > 60) { |
| | | chartData.shift(); |
| | | } |
| | | |
| | | const option = { |
| | | title: { |
| | | text: title, |
| | | left: 'center' |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | formatter: (params) => { |
| | | return `${params[0].axisValueLabel}<br/>${params[0].marker} ${params[0].seriesName}: ${params[0].data}${unit}`; |
| | | } |
| | | }, |
| | | grid: { |
| | | left: '8%', // å¢å å·¦ä¾§è¾¹è· |
| | | right: '5%', |
| | | bottom: '10%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: chartData.map(item => item.time) |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | axisLabel: { |
| | | formatter: (value) => `${value}${unit}` |
| | | } |
| | | }, |
| | | series: [ |
| | | { |
| | | data: chartData.map(item => parseFloat(item.value)), |
| | | type: 'line', |
| | | smooth: true, |
| | | lineStyle: { |
| | | width: 2, |
| | | color: '#5470C6' // Default color |
| | | }, |
| | | areaStyle: { |
| | | opacity: 0.8, |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: 'rgba(84,112,198,0.3)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: 'rgba(84,112,198,0)' |
| | | } |
| | | ]) |
| | | }, |
| | | } |
| | | ] |
| | | }; |
| | | chart.setOption(option); |
| | | }; |
| | | |
| | | // åå§æ¸²æ |
| | | updateChart(); |
| | | |
| | | // æ¯5ç§æ´æ°ä¸æ¬¡æ°æ® |
| | | const intervalId = setInterval(updateChart, 5000); |
| | | |
| | | window.addEventListener('resize', () => { |
| | | chart.resize(); |
| | | }); |
| | | onUnmounted(() => { |
| | | clearInterval(intervalId); |
| | | }); |
| | | |
| | | }; |
| | | |
| | | |
| | | initChart('exhaustPressureChart', 'ææ°åå', [], 'bar', 7.5, 0.2); |
| | | initChart('exhaustTemperatureChart', 'ææ°æ¸©åº¦', [], '°C', 85, 2); |
| | | initChart('hostVibrationChart', 'ä¸»æºæ¯å¨', [], 'mm/s', 3.5, 0.5); |
| | | initChart('mainBearingTemperatureChart', 'ä¸»è½´æ¿æ¸©åº¦', [], '°C', 70, 3); |
| | | initChart('mainMotorCurrentChart', 'ä¸»çµæºçµæµ', [], 'A', 120, 5); |
| | | initChart('oilTemperatureChart', '油温', [], '°C', 60, 2); |
| | | initChart('oilPressureChart', 'æ²¹å', [], 'bar', 4.0, 0.1); |
| | | initChart('oilLevelChart', 'æ²¹ä½', [], '%', 80, 5); |
| | | initChart('inletPressureChart', 'è¿æ°åå', [], 'bar', 1.0, 0.05); |
| | | initChart('inletTemperatureChart', 'è¿æ°æ¸©åº¦', [], '°C', 25, 2); |
| | | initChart('airFlowChart', 'ç©ºæ°æµé', [], 'm³/min', 15, 1); |
| | | initChart('dryerDewPointChart', 'å¹²ç¥å¨é²ç¹', [], '°C', 3, 1); |
| | | initChart('coolingWaterTemperatureChart', 'å·å´æ°´æ¸©åº¦', [], '°C', 30, 2); |
| | | initChart('coolingWaterFlowChart', 'å·å´æ°´æµé', [], 'L/min', 10, 0.5); |
| | | initChart('ambientTemperatureHumidityChart', 'ç¯å¢æ¸©æ¹¿åº¦', [], '°C', 28, 2); |
| | | } |
| | | |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .device-detail-container { |
| | | padding: 16px; |
| | | background: #f0f2f5; |
| | | } |
| | | |
| | | .mt-4 { |
| | | margin-top: 16px; |
| | | } |
| | | |
| | | .mb-4 { |
| | | margin-bottom: 16px; |
| | | } |
| | | </style> |
| | | |
| | | |
| | | <style scoped> |
| | | .air-compressor-detail { |
| | | padding: 16px; |
| | | background-color: #f0f2f5; |
| | | } |
| | | .header-card { |
| | | margin-bottom: 16px; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="device-detail-container"> |
| | | <a-page-header |
| | | title="CNCå å·¥ä¸å¿é¢æµæ§ç»´æ¤è¯¦æ
" |
| | | :sub-title="deviceInfo.deviceName" |
| | | @back="() => $router.go(-1)" |
| | | /> |
| | | |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <!-- 设å¤åºæ¬ä¿¡æ¯ --> |
| | | <a-col :span="8"> |
| | | <a-card title="设å¤åºæ¬ä¿¡æ¯" class="mb-4" :style="{ height: '440px' }"> |
| | | <a-descriptions bordered :column="1"> |
| | | <a-descriptions-item label="设å¤åç§°">{{ deviceInfo.deviceName }}</a-descriptions-item> |
| | | <a-descriptions-item label="设å¤ç±»å">{{ deviceInfo.deviceType }}</a-descriptions-item> |
| | | <a-descriptions-item label="设å¤ç¼å·">{{ deviceInfo.deviceId }}</a-descriptions-item> |
| | | <a-descriptions-item label="å®è£
æ¥æ">{{ deviceInfo.installDate }}</a-descriptions-item> |
| | | <a-descriptions-item label="使ç¨å¹´é">{{ deviceInfo.serviceLife }}å¹´</a-descriptions-item> |
| | | <a-descriptions-item label="å½åç¶æ"> |
| | | <a-tag :color="deviceInfo.statusColor">{{ deviceInfo.status }}</a-tag> |
| | | </a-descriptions-item> |
| | | </a-descriptions> |
| | | </a-card> |
| | | </a-col> |
| | | |
| | | <!-- 设å¤å¥åº·ç¶æä¸ç»´æ¤å»ºè®® --> |
| | | <a-col :span="16"> |
| | | <a-card title="设å¤å¥åº·ç¶æä¸ç»´æ¤å»ºè®®" class="mb-4" :style="{ height: '440px' }"> |
| | | <a-row :gutter="16"> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | title="æ´ä½å¥åº·åº¦" |
| | | :value="healthData.overallHealth" |
| | | :precision="0" |
| | | suffix="%" |
| | | :value-style="{ color: healthData.healthColor }" |
| | | /> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | title="颿µå©ä½å¯¿å½" |
| | | :value="healthData.predictedLife" |
| | | suffix="天" |
| | | /> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | title="æ
éé£é©ç级" |
| | | :value="healthData.riskLevel" |
| | | :value-style="{ color: healthData.riskColor }" |
| | | /> |
| | | </a-col> |
| | | </a-row> |
| | | <div class="mt-4"> |
| | | <a-progress |
| | | :percent="healthData.overallHealth" |
| | | :stroke-color="healthData.healthColor" |
| | | :show-info="false" |
| | | /> |
| | | </div> |
| | | <a-divider orientation="left">颿µæ§ç»´æ¤å»ºè®®</a-divider> |
| | | <a-table |
| | | :columns="maintenanceColumns" |
| | | :data-source="maintenanceData" |
| | | :pagination="false" |
| | | size="small" |
| | | > |
| | | <template #urgency="{ text }"> |
| | | <a-tag :color="getUrgencyColor(text)">{{ text }}</a-tag> |
| | | </template> |
| | | <template #action="{ record }"> |
| | | <a-button type="link" size="small" @click="handleMaintenance(record)">å¤ç</a-button> |
| | | </template> |
| | | </a-table> |
| | | </a-card> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | <!-- 宿¶æ°æ®è¶å¿å¾ --> |
| | | <a-card title="宿¶æ°æ®è¶å¿å¾" class="mb-4"> |
| | | <a-row :gutter="16"> |
| | | <a-col :span="8"> |
| | | <div id="spindleVibrationChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="spindleTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="spindleCurrentChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="spindleSpeedChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="servoMotorCurrentChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="servoMotorTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="axisMotionSmoothnessChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="guideRailTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="guideRailResistanceNoiseChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="hydraulicPressureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="hydraulicFlowChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="hydraulicOilTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="airSourcePressureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="coolantFlowChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="coolantTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | </a-card> |
| | | <a-row :gutter="16"> |
| | | <!-- å¤ä»¶å¯¿å½é¢æµ --> |
| | | <a-col :span="12"> |
| | | <a-card title="å¤ä»¶å¯¿å½é¢æµ" class="mb-4"> |
| | | <a-table |
| | | :columns="sparePartColumns" |
| | | :data-source="sparePartData" |
| | | :pagination="false" |
| | | size="small" |
| | | > |
| | | <template #status="{ text }"> |
| | | <a-tag :color="getStatusColor(text)">{{ text }}</a-tag> |
| | | </template> |
| | | </a-table> |
| | | </a-card> |
| | | </a-col> |
| | | |
| | | <!-- åå²ç»´æ¤è®°å½ --> |
| | | <a-col :span="12"> |
| | | <a-card title="åå²ç»´æ¤è®°å½" class="mb-4"> |
| | | <a-timeline> |
| | | <a-timeline-item v-for="item in historyData" :key="item.id" :color="item.color"> |
| | | {{ item.date }} - {{ item.type }}: {{ item.description }} |
| | | </a-timeline-item> |
| | | </a-timeline> |
| | | </a-card> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { defineComponent, reactive, onMounted, onUnmounted } from 'vue'; |
| | | import * as echarts from 'echarts'; |
| | | |
| | | export default defineComponent({ |
| | | name: 'CNCMachiningCenterDetail', |
| | | setup() { |
| | | // æ¨¡ææ°æ® |
| | | const deviceInfo = reactive({ |
| | | deviceName: 'CNCå å·¥ä¸å¿ #CNC-001', |
| | | deviceType: 'CNCå å·¥ä¸å¿', |
| | | deviceId: 'CNC-2024-001', |
| | | installDate: '2023-08-20', |
| | | serviceLife: 15, |
| | | status: 'è¿è¡ä¸', |
| | | statusColor: '#52c41a' |
| | | }); |
| | | |
| | | const healthData = reactive({ |
| | | overallHealth: 95, |
| | | healthColor: '#52c41a', |
| | | predictedLife: 4500, |
| | | riskLevel: 'ä½é£é©', |
| | | riskColor: '#52c41a' |
| | | }); |
| | | |
| | | const maintenanceColumns = [ |
| | | { |
| | | title: 'ç»´æ¤ç±»å', |
| | | dataIndex: 'type', |
| | | key: 'type' |
| | | }, |
| | | { |
| | | title: 'ç»´æ¤å
容', |
| | | dataIndex: 'content', |
| | | key: 'content' |
| | | }, |
| | | { |
| | | title: '建议æ¶é´', |
| | | dataIndex: 'suggestedTime', |
| | | key: 'suggestedTime' |
| | | }, |
| | | { |
| | | title: 'ç´§æ¥ç¨åº¦', |
| | | dataIndex: 'urgency', |
| | | key: 'urgency', |
| | | slots: { customRender: 'urgency' } |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | key: 'action', |
| | | slots: { customRender: 'action' } |
| | | } |
| | | ]; |
| | | |
| | | const maintenanceData = reactive([ |
| | | { |
| | | key: '1', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | content: 'æ£æ¥ä¸»è½´æ¶¦æ»ç³»ç»', |
| | | suggestedTime: '2024-07-15', |
| | | urgency: 'ä¸ç' |
| | | }, |
| | | { |
| | | key: '2', |
| | | type: '伺æç³»ç»ç»´æ¤', |
| | | content: 'æ£æ¥X轴伺æçµæº', |
| | | suggestedTime: '2024-09-01', |
| | | urgency: 'ä½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | type: '导轨维æ¤', |
| | | content: 'è¡¥å
å¯¼è½¨æ¶¦æ»æ²¹', |
| | | suggestedTime: '2024-08-01', |
| | | urgency: 'é«' |
| | | } |
| | | ]); |
| | | |
| | | const getUrgencyColor = (urgency: string) => { |
| | | switch (urgency) { |
| | | case 'é«': |
| | | return 'red'; |
| | | case 'ä¸ç': |
| | | return 'orange'; |
| | | case 'ä½': |
| | | return 'green'; |
| | | default: |
| | | return 'default'; |
| | | } |
| | | }; |
| | | |
| | | const sparePartColumns = [ |
| | | { |
| | | title: 'å¤ä»¶åç§°', |
| | | dataIndex: 'name', |
| | | key: 'name' |
| | | }, |
| | | { |
| | | title: 'å½å寿å½', |
| | | dataIndex: 'currentLife', |
| | | key: 'currentLife', |
| | | customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | }, |
| | | { |
| | | title: '颿µå©ä½å¯¿å½', |
| | | dataIndex: 'remainingLife', |
| | | key: 'remainingLife', |
| | | customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | }, |
| | | { |
| | | title: 'ç¶æ', |
| | | dataIndex: 'status', |
| | | key: 'status', |
| | | slots: { customRender: 'status' } |
| | | } |
| | | ]; |
| | | |
| | | const sparePartData = reactive([ |
| | | { |
| | | key: '1', |
| | | name: '主轴轴æ¿', |
| | | currentLife: 8000, |
| | | remainingLife: 500, |
| | | status: 'é¢è¦' |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: 'Xè½´ä¸æ ', |
| | | currentLife: 12000, |
| | | remainingLife: 2000, |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: 'æ¶²åæ²¹', |
| | | currentLife: 3000, |
| | | remainingLife: 200, |
| | | status: 'é¢è¦' |
| | | } |
| | | ]); |
| | | |
| | | const historyData = reactive([ |
| | | { |
| | | id: '1', |
| | | date: '2024-05-20', |
| | | 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' |
| | | } |
| | | ]); |
| | | |
| | | const getStatusColor = (status: string) => { |
| | | switch (status) { |
| | | case 'è¯å¥½': |
| | | return '#52c41a'; |
| | | case 'é¢è¦': |
| | | return '#faad14'; |
| | | case 'å±é©': |
| | | return '#f5222d'; |
| | | default: |
| | | return '#d9d9d9'; |
| | | } |
| | | }; |
| | | |
| | | const handleMaintenance = (record: any) => { |
| | | console.log('å¤çç»´æ¤å»ºè®®:', record); |
| | | // å®é
项ç®ä¸è¿éä¼è°ç¨APIå¤çç»´æ¤å»ºè®® |
| | | }; |
| | | |
| | | return { |
| | | deviceInfo, |
| | | healthData, |
| | | maintenanceColumns, |
| | | maintenanceData, |
| | | sparePartColumns, |
| | | sparePartData, |
| | | historyData, |
| | | getStatusColor, |
| | | getUrgencyColor, |
| | | handleMaintenance |
| | | }; |
| | | }, |
| | | |
| | | mounted() { |
| | | // åå§åå¾è¡¨ |
| | | const initChart = (chartId: string, title: string, chartData: any[], unit: string, baseValue: number, fluctuation: number) => { |
| | | const chart = echarts.init(document.getElementById(chartId)); |
| | | |
| | | const updateChart = () => { |
| | | // çææ°çæ°æ®ç¹ |
| | | const now = new Date(); |
| | | const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`; |
| | | const newValue = (baseValue + (Math.random() * 2 - 1) * fluctuation).toFixed(2); |
| | | |
| | | // æ·»å æ°æ°æ®ç¹ï¼æå¤ä¿ç60个ç¹ï¼5åéæ°æ®ï¼ |
| | | chartData.push({ |
| | | time, |
| | | value: newValue |
| | | }); |
| | | if (chartData.length > 60) { |
| | | chartData.shift(); |
| | | } |
| | | |
| | | const option = { |
| | | title: { |
| | | text: title, |
| | | left: 'center' |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | formatter: (params) => { |
| | | return `${params[0].axisValueLabel}<br/>${params[0].marker} ${params[0].seriesName}: ${params[0].data}${unit}`; |
| | | } |
| | | }, |
| | | grid: { |
| | | left: '8%', // å¢å å·¦ä¾§è¾¹è· |
| | | right: '5%', |
| | | bottom: '10%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: chartData.map(item => item.time) |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | axisLabel: { |
| | | formatter: (value) => `${value}${unit}` |
| | | } |
| | | }, |
| | | series: [ |
| | | { |
| | | data: chartData.map(item => parseFloat(item.value)), |
| | | type: 'line', |
| | | smooth: true, |
| | | lineStyle: { |
| | | width: 2, |
| | | color: '#5470C6' // Default color |
| | | }, |
| | | areaStyle: { |
| | | opacity: 0.8, |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: 'rgba(84,112,198,0.3)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: 'rgba(84,112,198,0)' |
| | | } |
| | | ]) |
| | | }, |
| | | } |
| | | ] |
| | | }; |
| | | chart.setOption(option); |
| | | }; |
| | | |
| | | // çæåå§æ°æ®ç¹ï¼60个ç¹ï¼5åéæ°æ®ï¼ |
| | | for (let i = 0; i < 60; i++) { |
| | | const now = new Date(Date.now() - (60 - i) * 5000); // çæè¿å»5åéçæ°æ® |
| | | const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`; |
| | | const newValue = (baseValue + (Math.random() * 2 - 1) * fluctuation).toFixed(2); |
| | | chartData.push({ |
| | | time, |
| | | value: newValue |
| | | }); |
| | | } |
| | | |
| | | // åå§æ¸²æ |
| | | updateChart(); |
| | | |
| | | // æ¯5ç§æ´æ°ä¸æ¬¡æ°æ® |
| | | const intervalId = setInterval(updateChart, 5000); |
| | | |
| | | window.addEventListener('resize', () => { |
| | | chart.resize(); |
| | | }); |
| | | onUnmounted(() => { |
| | | clearInterval(intervalId); |
| | | }); |
| | | |
| | | }; |
| | | |
| | | |
| | | |
| | | |
| | | initChart('spindleVibrationChart', '主轴æ¯å¨', [], 'mm/s', 3.0, 0.5); |
| | | initChart('spindleTemperatureChart', '主轴温度', [], '°C', 50, 3); |
| | | initChart('spindleCurrentChart', 'ä¸»è½´çµæµ', [], 'A', 150, 10); |
| | | initChart('spindleSpeedChart', '主轴转é', [], 'RPM', 8000, 100); |
| | | initChart('servoMotorCurrentChart', '伺æçµæºçµæµ', [], 'A', 50, 5); |
| | | initChart('servoMotorTemperatureChart', '伺æçµæºæ¸©åº¦', [], '°C', 45, 3); |
| | | initChart('axisMotionSmoothnessChart', 'è½´è¿å¨å¹³ç¨³æ§', [], '', 0.8, 0.1); |
| | | initChart('guideRailTemperatureChart', '导轨温度', [], '°C', 35, 2); |
| | | initChart('guideRailResistanceNoiseChart', '导轨è¿å¨é»å/åªé³', [], 'dB', 10, 2); |
| | | initChart('hydraulicPressureChart', 'æ¶²åç³»ç»åå', [], 'bar', 150, 5); |
| | | initChart('hydraulicFlowChart', 'æ¶²åç³»ç»æµé', [], 'L/min', 20, 2); |
| | | initChart('hydraulicOilTemperatureChart', 'æ¶²åæ²¹æ¸©åº¦', [], '°C', 55, 3); |
| | | initChart('airSourcePressureChart', 'æ°æºåå', [], 'bar', 0.7, 0.05); |
| | | initChart('coolantFlowChart', 'å·å´æ¶²æµé', [], 'L/min', 30, 3); |
| | | initChart('coolantTemperatureChart', 'å·å´æ¶²æ¸©åº¦', [], '°C', 28, 2); |
| | | } |
| | | |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .device-detail-container { |
| | | padding: 16px; |
| | | background: #f0f2f5; |
| | | } |
| | | |
| | | .mt-4 { |
| | | margin-top: 16px; |
| | | } |
| | | |
| | | .mb-4 { |
| | | margin-bottom: 16px; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="device-detail-container"> |
| | | <a-page-header |
| | | title="设å¤é¢æµæ§ç»´æ¤è¯¦æ
" |
| | | :sub-title="deviceInfo.deviceName" |
| | | @back="() => $router.go(-1)" |
| | | /> |
| | | |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <!-- 设å¤åºæ¬ä¿¡æ¯ --> |
| | | <a-col :span="8"> |
| | | <a-card title="设å¤åºæ¬ä¿¡æ¯" class="mb-4" :style="{ height: '440px' }"> |
| | | <a-descriptions bordered :column="1"> |
| | | <a-descriptions-item label="设å¤åç§°">{{ deviceInfo.deviceName }}</a-descriptions-item> |
| | | <a-descriptions-item label="设å¤ç±»å">{{ deviceInfo.deviceType }}</a-descriptions-item> |
| | | <a-descriptions-item label="设å¤ç¼å·">{{ deviceInfo.deviceId }}</a-descriptions-item> |
| | | <a-descriptions-item label="å®è£
æ¥æ">{{ deviceInfo.installDate }}</a-descriptions-item> |
| | | <a-descriptions-item label="使ç¨å¹´é">{{ deviceInfo.serviceLife }}å¹´</a-descriptions-item> |
| | | <a-descriptions-item label="å½åç¶æ"> |
| | | <a-tag :color="deviceInfo.statusColor">{{ deviceInfo.status }}</a-tag> |
| | | </a-descriptions-item> |
| | | </a-descriptions> |
| | | </a-card> |
| | | </a-col> |
| | | |
| | | <!-- 设å¤å¥åº·ç¶æä¸ç»´æ¤å»ºè®® --> |
| | | <a-col :span="16"> |
| | | <a-card title="设å¤å¥åº·ç¶æä¸ç»´æ¤å»ºè®®" class="mb-4" :style="{ height: '440px' }"> |
| | | <a-row :gutter="16"> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | title="æ´ä½å¥åº·åº¦" |
| | | :value="healthData.overallHealth" |
| | | :precision="0" |
| | | suffix="%" |
| | | :value-style="{ color: healthData.healthColor }" |
| | | /> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | title="颿µå©ä½å¯¿å½" |
| | | :value="healthData.predictedLife" |
| | | suffix="天" |
| | | /> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | title="æ
éé£é©ç级" |
| | | :value="healthData.riskLevel" |
| | | :value-style="{ color: healthData.riskColor }" |
| | | /> |
| | | </a-col> |
| | | </a-row> |
| | | <div class="mt-4"> |
| | | <a-progress |
| | | :percent="healthData.overallHealth" |
| | | :stroke-color="healthData.healthColor" |
| | | :show-info="false" |
| | | /> |
| | | </div> |
| | | <a-divider orientation="left">颿µæ§ç»´æ¤å»ºè®®</a-divider> |
| | | <a-table |
| | | :columns="maintenanceColumns" |
| | | :data-source="maintenanceData" |
| | | :pagination="false" |
| | | size="small" |
| | | > |
| | | <template #urgency="{ text }"> |
| | | <a-tag :color="getUrgencyColor(text)">{{ text }}</a-tag> |
| | | </template> |
| | | <template #action="{ record }"> |
| | | <a-button type="link" size="small" @click="handleMaintenance(record)">å¤ç</a-button> |
| | | </template> |
| | | </a-table> |
| | | </a-card> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | <!-- 宿¶æ°æ®è¶å¿å¾ --> |
| | | <a-card title="宿¶æ°æ®è¶å¿å¾" class="mb-4"> |
| | | <a-row :gutter="16"> |
| | | <a-col :span="8"> |
| | | <div id="temperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="vibrationChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="currentChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | </a-card> |
| | | <a-row :gutter="16"> |
| | | <!-- å¤ä»¶å¯¿å½é¢æµ --> |
| | | <a-col :span="12"> |
| | | <a-card title="å¤ä»¶å¯¿å½é¢æµ" class="mb-4"> |
| | | <a-table |
| | | :columns="sparePartColumns" |
| | | :data-source="sparePartData" |
| | | :pagination="false" |
| | | size="small" |
| | | > |
| | | <template #status="{ text }"> |
| | | <a-tag :color="getStatusColor(text)">{{ text }}</a-tag> |
| | | </template> |
| | | </a-table> |
| | | </a-card> |
| | | </a-col> |
| | | |
| | | <!-- åå²ç»´æ¤è®°å½ --> |
| | | <a-col :span="12"> |
| | | <a-card title="åå²ç»´æ¤è®°å½" class="mb-4"> |
| | | <a-timeline> |
| | | <a-timeline-item v-for="item in historyData" :key="item.id" :color="item.color"> |
| | | {{ item.date }} - {{ item.type }}: {{ item.description }} |
| | | </a-timeline-item> |
| | | </a-timeline> |
| | | </a-card> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { defineComponent, reactive, onMounted, onUnmounted } from 'vue'; |
| | | import * as echarts from 'echarts'; |
| | | |
| | | export default defineComponent({ |
| | | name: 'DeviceDetail', |
| | | setup() { |
| | | // æ¨¡ææ°æ® |
| | | const deviceInfo = reactive({ |
| | | deviceName: 'CNCå å·¥ä¸å¿', |
| | | deviceType: 'æ°æ§æºåº', |
| | | deviceId: 'CNC-2023-001', |
| | | installDate: '2023-01-15', |
| | | serviceLife: 10, |
| | | status: 'è¿è¡ä¸', |
| | | statusColor: '#52c41a' |
| | | }); |
| | | |
| | | const healthData = reactive({ |
| | | overallHealth: 85, |
| | | healthColor: '#52c41a', |
| | | predictedLife: 1825, |
| | | riskLevel: 'ä¸é£é©', |
| | | riskColor: '#faad14' |
| | | }); |
| | | |
| | | const maintenanceColumns = [ |
| | | { |
| | | title: 'ç»´æ¤ç±»å', |
| | | dataIndex: 'type', |
| | | key: 'type' |
| | | }, |
| | | { |
| | | title: 'ç»´æ¤å
容', |
| | | dataIndex: 'content', |
| | | key: 'content' |
| | | }, |
| | | { |
| | | title: '建议æ¶é´', |
| | | dataIndex: 'suggestedTime', |
| | | key: 'suggestedTime' |
| | | }, |
| | | { |
| | | title: 'ç´§æ¥ç¨åº¦', |
| | | dataIndex: 'urgency', |
| | | key: 'urgency' |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | key: 'action', |
| | | slots: { customRender: 'action' } |
| | | }, |
| | | { |
| | | title: 'ç´§æ¥ç¨åº¦', |
| | | dataIndex: 'urgency', |
| | | key: 'urgency', |
| | | slots: { customRender: 'urgency' } |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | key: 'action', |
| | | slots: { customRender: 'action' } |
| | | } |
| | | ]; |
| | | |
| | | const maintenanceData = reactive([ |
| | | { |
| | | key: '1', |
| | | type: '润æ»ä¿å
»', |
| | | content: '主轴润æ»ç³»ç»éè¦æ´æ¢æ¶¦æ»æ²¹', |
| | | suggestedTime: '2024-03-15', |
| | | urgency: 'ä¸ç' |
| | | }, |
| | | { |
| | | key: '2', |
| | | type: 'æ ¡åæ£æ¥', |
| | | content: 'X轴导轨éè¦éæ°æ ¡å', |
| | | suggestedTime: '2024-04-01', |
| | | urgency: 'é«' |
| | | } |
| | | ]); |
| | | |
| | | const getUrgencyColor = (urgency: string) => { |
| | | switch (urgency) { |
| | | case 'é«': |
| | | return 'red'; |
| | | case 'ä¸ç': |
| | | return 'orange'; |
| | | case 'ä½': |
| | | return 'green'; |
| | | default: |
| | | return 'default'; |
| | | } |
| | | }; |
| | | |
| | | const sparePartColumns = [ |
| | | { |
| | | title: 'å¤ä»¶åç§°', |
| | | dataIndex: 'name', |
| | | key: 'name' |
| | | }, |
| | | { |
| | | title: 'å½å寿å½', |
| | | dataIndex: 'currentLife', |
| | | key: 'currentLife', |
| | | customRender: ({ text }: { text: number }) => `${text}天` |
| | | }, |
| | | { |
| | | title: '颿µå©ä½å¯¿å½', |
| | | dataIndex: 'remainingLife', |
| | | key: 'remainingLife', |
| | | customRender: ({ text }: { text: number }) => `${text}天` |
| | | }, |
| | | { |
| | | title: 'ç¶æ', |
| | | dataIndex: 'status', |
| | | key: 'status', |
| | | slots: { customRender: 'status' } |
| | | } |
| | | ]; |
| | | |
| | | const sparePartData = reactive([ |
| | | { |
| | | key: '1', |
| | | name: '主轴轴æ¿', |
| | | currentLife: 365, |
| | | remainingLife: 120, |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: 'X轴导轨', |
| | | currentLife: 730, |
| | | remainingLife: 30, |
| | | status: 'é¢è¦' |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: 'åå
·å¤¹å¤´', |
| | | currentLife: 180, |
| | | remainingLife: 90, |
| | | status: 'è¯å¥½' |
| | | } |
| | | ]); |
| | | |
| | | const historyData = reactive([ |
| | | { |
| | | id: '1', |
| | | date: '2024-01-10', |
| | | type: '宿ä¿å
»', |
| | | description: '宿å£åº¦ä¿å
»ï¼æ´æ¢æ¶¦æ»æ²¹åè¿æ»¤å¨', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '2', |
| | | date: '2023-10-15', |
| | | type: 'æ
éç»´ä¿®', |
| | | description: 'ä¿®å¤ä¸»è½´çµæºè¿çé®é¢', |
| | | color: 'red' |
| | | }, |
| | | { |
| | | id: '3', |
| | | date: '2023-07-20', |
| | | type: '宿ä¿å
»', |
| | | description: '宿åå¹´ä¿å
»ï¼æ ¡åå轴精度', |
| | | color: 'green' |
| | | } |
| | | ]); |
| | | |
| | | const getStatusColor = (status: string) => { |
| | | switch (status) { |
| | | case 'è¯å¥½': |
| | | return '#52c41a'; |
| | | case 'é¢è¦': |
| | | return '#faad14'; |
| | | case 'å±é©': |
| | | return '#f5222d'; |
| | | default: |
| | | return '#d9d9d9'; |
| | | } |
| | | }; |
| | | |
| | | const handleMaintenance = (record: any) => { |
| | | console.log('å¤çç»´æ¤å»ºè®®:', record); |
| | | // å®é
项ç®ä¸è¿éä¼è°ç¨APIå¤çç»´æ¤å»ºè®® |
| | | }; |
| | | |
| | | return { |
| | | deviceInfo, |
| | | healthData, |
| | | maintenanceColumns, |
| | | maintenanceData, |
| | | sparePartColumns, |
| | | sparePartData, |
| | | historyData, |
| | | getStatusColor, |
| | | getUrgencyColor, |
| | | handleMaintenance |
| | | }; |
| | | }, |
| | | |
| | | mounted() { |
| | | // åå§åå¾è¡¨ |
| | | const initChart = (chartId: string, title: string, chartData: any[], unit: string, baseValue: number, fluctuation: number) => { |
| | | const chart = echarts.init(document.getElementById(chartId)); |
| | | |
| | | // é¢çæ60ä¸ªæ°æ®ç¹ |
| | | for (let i = 0; i < 60; i++) { |
| | | const now = new Date(Date.now() - (60 - 1 - i) * 5000); // 5ç§é´é |
| | | const value = +(Math.random() * fluctuation + baseValue - fluctuation / 2).toFixed(2); |
| | | chartData.push({ |
| | | time: `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`, |
| | | value: value |
| | | }); |
| | | } |
| | | |
| | | const updateChart = () => { |
| | | // çææ°çæ°æ®ç¹ |
| | | const now = new Date(); |
| | | const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`; |
| | | const newValue = +(Math.random() * fluctuation + baseValue - fluctuation / 2).toFixed(2); |
| | | |
| | | // æ·»å æ°æ°æ®ç¹ï¼æå¤ä¿ç60个ç¹ï¼5åéæ°æ®ï¼ |
| | | chartData.push({ |
| | | time, |
| | | value: newValue |
| | | }); |
| | | if (chartData.length > 60) { |
| | | chartData.shift(); |
| | | } |
| | | |
| | | const option = { |
| | | title: { |
| | | text: title, |
| | | left: 'center' |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | formatter: (params: any) => { |
| | | return `${params[0].axisValueLabel}<br/>${params[0].marker} ${params[0].seriesName}: ${params[0].data}${unit}`; |
| | | } |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: chartData.map(item => item.time) |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | axisLabel: { |
| | | formatter: (value: number) => { |
| | | return `${value}${unit}`; |
| | | } |
| | | } |
| | | }, |
| | | series: [ |
| | | { |
| | | data: chartData.map(item => parseFloat(item.value)), |
| | | type: 'line', |
| | | smooth: true, |
| | | lineStyle: { |
| | | width: 2, |
| | | color: chartId === 'temperatureChart' ? '#5470C6' : chartId === 'vibrationChart' ? '#91CC75' : '#FAC858' // æ ¹æ®å¾è¡¨ID设置é¢è² |
| | | }, |
| | | areaStyle: { |
| | | opacity: 0.8, |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: chartId === 'temperatureChart' ? 'rgba(84,112,198,0.3)' : chartId === 'vibrationChart' ? 'rgba(145,204,117,0.3)' : 'rgba(250,200,88,0.3)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: chartId === 'temperatureChart' ? 'rgba(84,112,198,0)' : chartId === 'vibrationChart' ? 'rgba(145,204,117,0)' : 'rgba(250,200,88,0)' |
| | | } |
| | | ]) |
| | | }, |
| | | } |
| | | ] |
| | | }; |
| | | chart.setOption(option); |
| | | }; |
| | | |
| | | // åå§æ¸²æ |
| | | updateChart(); |
| | | |
| | | // æ¯5ç§æ´æ°ä¸æ¬¡æ°æ® |
| | | const intervalId = setInterval(updateChart, 5000); |
| | | |
| | | window.addEventListener('resize', () => { |
| | | chart.resize(); |
| | | }); |
| | | onUnmounted(() => { |
| | | clearInterval(intervalId); |
| | | }); |
| | | |
| | | }; |
| | | |
| | | const temperatureData: any[] = reactive([]); |
| | | const vibrationData: any[] = reactive([]); |
| | | const currentData: any[] = reactive([]); |
| | | |
| | | initChart('temperatureChart', '温度è¶å¿', temperatureData, '°C', 60, 5); |
| | | initChart('vibrationChart', 'æ¯å¨è¶å¿', vibrationData, 'mm/s', 10, 2); |
| | | initChart('currentChart', 'çµæµè¶å¿', currentData, 'A', 50, 10); |
| | | } |
| | | |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .device-detail-container { |
| | | padding: 16px; |
| | | background: #f0f2f5; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <Page :auto-content-height="true" :padding="false" class="p-0" content-class="flex flex-col w-full gap-4"> |
| | | <div class="p-5"> |
| | | |
| | | <!-- 设å¤å¥åº·ç¶æå¯è§å --> |
| | | <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> |
| | | <Card title="设å¤å¥åº·åº¦åå¸" > |
| | | <!-- è¿éå°æ¾ç½®å¥åº·åº¦åå¸å¾è¡¨ --> |
| | | <div ref="chartRef" class="h-64 w-full"></div> |
| | | </Card> |
| | | <Card title="å
³é®ææ " > |
| | | <div class="grid grid-cols-2 gap-2"> |
| | | <div class="p-2 bg-blue-50 rounded"> |
| | | <p class="text-sm text-gray-600">å¥åº·è®¾å¤</p> |
| | | <p class="text-xl font-bold">85%</p> |
| | | </div> |
| | | <div class="p-2 bg-yellow-50 rounded"> |
| | | <p class="text-sm text-gray-600">é¢è¦è®¾å¤</p> |
| | | <p class="text-xl font-bold">12%</p> |
| | | </div> |
| | | <div class="p-2 bg-red-50 rounded"> |
| | | <p class="text-sm text-gray-600">æ
é设å¤</p> |
| | | <p class="text-xl font-bold">3%</p> |
| | | </div> |
| | | <div class="p-2 bg-green-50 rounded"> |
| | | <p class="text-sm text-gray-600">ç»´æ¤å®æ</p> |
| | | <p class="text-xl font-bold">92%</p> |
| | | </div> |
| | | <div class="p-2 bg-blue-50 rounded"> |
| | | <p class="text-sm text-gray-600">å¾
å¤çå·¥å</p> |
| | | <p class="text-xl font-bold">{{ healthData.pendingWorkOrders }}</p> |
| | | </div> |
| | | <div class="p-2 bg-yellow-50 rounded"> |
| | | <p class="text-sm text-gray-600">å¤ä»¶åºåé¢è¦</p> |
| | | <p class="text-xl font-bold">{{ healthData.sparePartWarnings }}</p> |
| | | </div> |
| | | </div> |
| | | </Card> |
| | | </div> |
| | | |
| | | <!-- æ
é颿µä¸é¢è¦ --> |
| | | <Card title="æ
é颿µä¸é¢è¦" class="mb-6"> |
| | | <div class="grid grid-cols-1 gap-4"> |
| | | |
| | | <!-- è¿éå°æ¾ç½®é¢è¦è¡¨æ ¼ --> |
| | | <a-table :columns="warningColumns" :data-source="warningData" :pagination="false" class="w-full"> |
| | | <template #bodyCell="{ column, record }"> |
| | | <template v-if="column.key === 'status'"> |
| | | <a-tag :color="getStatusColor(record.status)"> |
| | | {{ record.status }} |
| | | </a-tag> |
| | | </template> |
| | | <template v-else-if="column.key === 'action'"> |
| | | <a-button type="link" @click="handleDetail(record)">详æ
</a-button> |
| | | <a-button type="link" @click="generateWorkOrder(record)" :disabled="record.maintenanceSuggestion === 'ææ å»ºè®®'">çæå·¥å</a-button> |
| | | </template> |
| | | </template> |
| | | </a-table> |
| | | </div> |
| | | |
| | | </Card> |
| | | |
| | | <!-- å¤ä»¶ä¿¡æ¯ --> |
| | | <div class="grid grid-cols-2 gap-4 mb-6"> |
| | | <!-- å¤ä»¶å¯¿å½é¢æµ --> |
| | | <Card title="å¤ä»¶å¯¿å½é¢æµ"> |
| | | <a-table :columns="lifePredictionColumns" :data-source="lifePredictionData" :pagination="false" class="w-full"> |
| | | <template #bodyCell="{ column, record }"> |
| | | <template v-if="column.key === 'lifeStatus'"> |
| | | <a-tag :color="getLifeStatusColor(record.remainingDays)"> |
| | | {{ getLifeStatus(record.remainingDays) }} |
| | | </a-tag> |
| | | </template> |
| | | <template v-else-if="column.key === 'action'"> |
| | | <a-button type="link" @click="showLifePredictionDetail(record)">详æ
</a-button> |
| | | </template> |
| | | </template> |
| | | </a-table> |
| | | </Card> |
| | | |
| | | <!-- å¤ä»¶åºåä¸é¢è¦ --> |
| | | <Card title="å¤ä»¶åºåä¸é¢è¦"> |
| | | <a-table :columns="sparePartColumns" :data-source="sparePartData" :pagination="false" class="w-full"> |
| | | <template #bodyCell="{ column, record }"> |
| | | <template v-if="column.key === 'stockStatus'"> |
| | | <a-tag :color="getStockStatusColor(record.currentStock, record.safetyStock)"> |
| | | {{ getStockStatus(record.currentStock, record.safetyStock) }} |
| | | </a-tag> |
| | | </template> |
| | | <template v-else-if="column.key === 'action'"> |
| | | <a-button type="link" @click="showSparePartDetail(record)">详æ
</a-button> |
| | | </template> |
| | | </template> |
| | | </a-table> |
| | | </Card> |
| | | </div> |
| | | |
| | | |
| | | </div> |
| | | </Page> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { onMounted, ref } from 'vue'; |
| | | import { Page } from '@vben/common-ui'; |
| | | import { Card, Table, Tag, Button, Form, Input, Textarea, Select, message } from 'ant-design-vue'; |
| | | import * as echarts from 'echarts'; |
| | | |
| | | const chartRef = ref<HTMLElement | null>(null); |
| | | |
| | | const healthData = { |
| | | healthy: 85, |
| | | warning: 12, |
| | | critical: 3, |
| | | maintained: 92, |
| | | pendingWorkOrders: 5, // 模æå¾
å¤ç工忰 |
| | | sparePartWarnings: 2, // 模æå¤ä»¶åºåé¢è¦æ° |
| | | }; |
| | | |
| | | // é«é£é©è®¾å¤é¢è¦æ°æ® |
| | | const warningColumns = [ |
| | | { title: '设å¤åç§°', dataIndex: 'name', key: 'name' }, |
| | | |
| | | { title: 'å
³é®é¨ä»¶', dataIndex: 'component', key: 'component' }, |
| | | { title: 'é£é©ææ ', dataIndex: 'indicator', key: 'indicator' }, |
| | | { title: 'å½åå¼', dataIndex: 'value', key: 'value' }, |
| | | { title: 'éå¼', dataIndex: 'threshold', key: 'threshold' }, |
| | | { title: 'ç¶æ', dataIndex: 'status', key: 'status' }, |
| | | { title: 'ç»´æ¤å»ºè®®', dataIndex: 'maintenanceSuggestion', key: 'maintenanceSuggestion' }, |
| | | { title: 'æä½', key: 'action' }, |
| | | ]; |
| | | |
| | | // 模æé«é£é©è®¾å¤æ°æ® |
| | | const warningData = ref([ |
| | | { |
| | | key: '1', |
| | | name: 'SMTè´´çæº', |
| | | type: 'SMTæºå¨', |
| | | component: 'ä¼ é带', |
| | | indicator: 'æ¯å¨å¹
度', |
| | | value: 0.8, |
| | | threshold: 0.5, |
| | | status: 'é«é£é©', |
| | | maintenanceSuggestion: 'å»ºè®®æ´æ¢ä¼ é带轴æ¿', |
| | | maintenanceType: 'é¢é²æ§ç»´æ¤', |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: 'CNCå å·¥ä¸å¿', |
| | | type: 'CNC', |
| | | component: '主轴', |
| | | indicator: '温度', |
| | | value: 85, |
| | | threshold: 80, |
| | | status: 'ä¸é£é©', |
| | | maintenanceSuggestion: '建议对主轴è¿è¡æ¶¦æ»ä¿å
»', |
| | | maintenanceType: '润æ»ç»´æ¤', |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: 'æ³¨å¡æº', |
| | | type: '注å¡è®¾å¤', |
| | | component: 'æ¶²åç³»ç»', |
| | | indicator: 'åå', |
| | | value: 120, |
| | | threshold: 150, |
| | | status: 'ä½é£é©', |
| | | maintenanceSuggestion: 'å»ºè®®æ£æ¥æ¶²åç³»ç»å¯å°ä»¶', |
| | | maintenanceType: 'æ£æ¥ç»´æ¤', |
| | | }, |
| | | { |
| | | key: '4', |
| | | name: 'ç©ºåæº', |
| | | type: '空æ°å缩æº', |
| | | component: 'çµæº', |
| | | indicator: 'çµæµ', |
| | | value: 49, |
| | | threshold: 50, |
| | | status: 'ä½é£é©', |
| | | maintenanceSuggestion: 'ææ å»ºè®®', |
| | | maintenanceType: 'æ ', |
| | | }, |
| | | ]); |
| | | |
| | | // å¤ä»¶åºåæ°æ® |
| | | const sparePartColumns = [ |
| | | { title: 'å¤ä»¶åç§°', dataIndex: 'name', key: 'name' }, |
| | | { title: 'å½ååºå', dataIndex: 'currentStock', key: 'currentStock' }, |
| | | { title: 'å®å
¨åºå', dataIndex: 'safetyStock', key: 'safetyStock' }, |
| | | { title: '颿µéæ±', dataIndex: 'predictedDemand', key: 'predictedDemand' }, |
| | | { title: 'åºåç¶æ', dataIndex: 'stockStatus', key: 'stockStatus' }, |
| | | ]; |
| | | |
| | | // 模æå¤ä»¶æ°æ® |
| | | const sparePartData = ref([ |
| | | { |
| | | key: '1', |
| | | name: 'ä¼ é带轴æ¿', |
| | | currentStock: 10, |
| | | safetyStock: 5, |
| | | predictedDemand: 3, |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: 'ä¸»è½´æ¶¦æ»æ²¹', |
| | | currentStock: 2, |
| | | safetyStock: 3, |
| | | predictedDemand: 1, |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: 'æ¶²åç³»ç»å¯å°ä»¶', |
| | | currentStock: 20, |
| | | safetyStock: 10, |
| | | predictedDemand: 5, |
| | | }, |
| | | { |
| | | key: '4', |
| | | name: 'çµæºç¢³å·', |
| | | currentStock: 8, |
| | | safetyStock: 10, |
| | | predictedDemand: 2, |
| | | }, |
| | | ]); |
| | | const getStatusColor = (status) => { |
| | | switch (status) { |
| | | case 'é«é£é©': return 'red'; |
| | | case 'ä¸é£é©': return 'orange'; |
| | | case 'ä½é£é©': return 'yellow'; |
| | | default: return 'green'; |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | // å·¥åè¡¨åæ°æ® |
| | | const workOrderForm = ref({ |
| | | type: '', |
| | | equipment: '', |
| | | content: '', |
| | | priority: 'medium', |
| | | }); |
| | | |
| | | const selectedMaintenance = ref(null); |
| | | |
| | | const lifePredictionColumns = [ |
| | | { title: '设å¤åç§°', dataIndex: 'deviceName', key: 'deviceName' }, |
| | | { title: 'é¨ä»¶åç§°', dataIndex: 'componentName', key: 'componentName' }, |
| | | { title: 'å¤ä»¶åç§°', dataIndex: 'name', key: 'name' }, |
| | | { title: '颿µå¯¿å½ (天)', dataIndex: 'predictedLife', key: 'predictedLife' }, |
| | | { title: 'å©ä½å¯¿å½ (天)', dataIndex: 'remainingDays', key: 'remainingDays' }, |
| | | { title: 'ç¶æ', dataIndex: 'lifeStatus', key: 'lifeStatus' }, |
| | | { title: 'æä½', dataIndex: 'action', key: 'action' }, |
| | | ]; |
| | | |
| | | const lifePredictionData = ref([ |
| | | { key: '1', deviceName: 'SMTè´´çæº', componentName: 'ä¼ é带', name: 'è½´æ¿A', predictedLife: 365, remainingDays: 120 }, |
| | | { key: '2', deviceName: 'CNCå å·¥ä¸å¿', componentName: '主轴', name: '齿轮B', predictedLife: 730, remainingDays: 30 }, |
| | | { key: '3', deviceName: 'æ³¨å¡æº', componentName: 'æ¶²åç³»ç»', name: '滤è¯C', predictedLife: 180, remainingDays: 90 }, |
| | | { key: '4', deviceName: 'ç©ºåæº', componentName: 'çµæº', name: 'ä¼ æå¨D', predictedLife: 500, remainingDays: 10 }, |
| | | { key: '5', deviceName: 'çæ¥æºå¨äºº', componentName: 'çæª', name: 'çå´E', predictedLife: 240, remainingDays: 60 } |
| | | ]); |
| | | |
| | | const getLifeStatus = (remainingDays) => { |
| | | if (remainingDays <= 30) { |
| | | return 'å³å°å°æ'; |
| | | } else if (remainingDays <= 90) { |
| | | return '䏿é¢è¦'; |
| | | } else { |
| | | return '寿å½å
è¶³'; |
| | | } |
| | | }; |
| | | |
| | | const getLifeStatusColor = (remainingDays) => { |
| | | if (remainingDays <= 30) { |
| | | return 'red'; |
| | | } else if (remainingDays <= 90) { |
| | | return 'orange'; |
| | | } else { |
| | | return 'green'; |
| | | } |
| | | }; |
| | | |
| | | const showLifePredictionDetail = (record) => { |
| | | message.info(`å¤ä»¶åç§°: ${record.name}, 颿µå¯¿å½: ${record.predictedLife}天, å©ä½å¯¿å½: ${record.remainingDays}天`); |
| | | }; |
| | | |
| | | |
| | | |
| | | const getStockStatus = (currentStock, safetyStock) => { |
| | | if (currentStock <= safetyStock) { |
| | | return 'åºåé¢è¦'; |
| | | } else { |
| | | return 'åºåå
è¶³'; |
| | | } |
| | | }; |
| | | |
| | | const getStockStatusColor = (currentStock, safetyStock) => { |
| | | if (currentStock <= safetyStock) { |
| | | return 'red'; |
| | | } else { |
| | | return 'green'; |
| | | } |
| | | }; |
| | | |
| | | const showSparePartDetail = (record) => { |
| | | message.info(`å¤ä»¶åç§°: ${record.name}, å½ååºå: ${record.currentStock}, å®å
¨åºå: ${record.safetyStock}, 颿µéæ±: ${record.predictedDemand}`); |
| | | }; |
| | | |
| | | const generateWorkOrder = (record) => { |
| | | selectedMaintenance.value = record; |
| | | workOrderForm.value = { |
| | | type: record.maintenanceType, |
| | | equipment: record.name, |
| | | content: record.maintenanceSuggestion, |
| | | priority: 'medium', |
| | | }; |
| | | }; |
| | | |
| | | const submitWorkOrder = () => { |
| | | console.log('æäº¤å·¥å:', workOrderForm.value); |
| | | // è¿éå¯ä»¥æ·»å å·¥åæäº¤é»è¾ |
| | | message.success('å·¥åæäº¤æå'); |
| | | selectedMaintenance.value = null; |
| | | workOrderForm.value = { |
| | | type: '', |
| | | equipment: '', |
| | | content: '', |
| | | priority: 'medium', |
| | | }; |
| | | }; |
| | | |
| | | import { useRouter } from 'vue-router'; |
| | | |
| | | const router = useRouter(); |
| | | |
| | | const handleDetail = (record) => { |
| | | // æ ¹æ®è®¾å¤åç§°ä¸å跳转ä¸åç详æ
é¡µé¢ |
| | | if (record.name === 'SMTè´´çæº') { |
| | | console.log('设å¤ID111:', record.name) |
| | | router.push({ path: '/predictive/smt-detail', query: { deviceId: record.key } }); |
| | | } else if (record.name === 'CNCå å·¥ä¸å¿') { |
| | | router.push({ path: '/predictive/predictive-detail', query: { deviceId: record.key } }); |
| | | } else if (record.name === 'æ³¨å¡æº') { |
| | | router.push({ path: '/predictive/injection-detail', query: { deviceId: record.key } }); |
| | | } else { |
| | | router.push({ path: '/predictive/air-compressor-detail', query: { deviceId: record.key } }); |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | if (chartRef.value) { |
| | | const myChart = echarts.init(chartRef.value); |
| | | const option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'shadow' |
| | | } |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: ['90%-100%', '80%-90%', '70%-80%', '60%-70%', '50%-60%', '40%-50%', '30%-40%', '20%-30%', '10%-20%', '0%-10%'], |
| | | axisLabel: { |
| | | rotate: 45 |
| | | } |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | name: 'è®¾å¤æ°é', |
| | | minInterval: 1 |
| | | }, |
| | | series: [ |
| | | { |
| | | name: 'è®¾å¤æ°é', |
| | | type: 'bar', |
| | | barWidth: '60%', |
| | | data: [ |
| | | { value: 15, itemStyle: { color: '#52c41a' } }, |
| | | { value: 20, itemStyle: { color: '#52c41a' } }, |
| | | { value: 25, itemStyle: { color: '#faad14' } }, |
| | | { value: 15, itemStyle: { color: '#faad14' } }, |
| | | { value: 10, itemStyle: { color: '#faad14' } }, |
| | | { value: 5, itemStyle: { color: '#ff4d4f' } }, |
| | | { value: 5, itemStyle: { color: '#ff4d4f' } }, |
| | | { value: 3, itemStyle: { color: '#ff4d4f' } }, |
| | | { value: 1, itemStyle: { color: '#ff4d4f' } }, |
| | | { value: 1, itemStyle: { color: '#ff4d4f' } } |
| | | ], |
| | | label: { |
| | | show: true, |
| | | position: 'top' |
| | | } |
| | | } |
| | | ] |
| | | }; |
| | | myChart.setOption(option); |
| | | |
| | | // ååºå¼è°æ´å¾è¡¨å¤§å° |
| | | window.addEventListener('resize', () => { |
| | | myChart.resize(); |
| | | }); |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | /* å¯ä»¥å¨è¿éæ·»å ç»ä»¶æ ·å¼ */ |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts"> |
| | | import { defineComponent, onUnmounted, reactive } from 'vue'; |
| | | |
| | | import * as echarts from 'echarts'; |
| | | |
| | | export default defineComponent({ |
| | | name: 'InjectionMoldingMachineDetail', |
| | | setup() { |
| | | // æ¨¡ææ°æ® |
| | | const deviceInfo = reactive({ |
| | | deviceName: 'æ³¨å¡æº #IM-001', |
| | | deviceType: 'æ³¨å¡æº', |
| | | deviceId: 'IM-2024-001', |
| | | installDate: '2023-08-20', |
| | | serviceLife: 15, |
| | | status: 'è¿è¡ä¸', |
| | | statusColor: '#52c41a' |
| | | }); |
| | | |
| | | const healthData = reactive({ |
| | | overallHealth: 88, |
| | | healthColor: '#faad14', |
| | | predictedLife: 1500, |
| | | riskLevel: 'ä¸é£é©', |
| | | riskColor: '#faad14' |
| | | }); |
| | | |
| | | const maintenanceColumns = [ |
| | | { |
| | | title: 'ç»´æ¤ç±»å', |
| | | dataIndex: 'type', |
| | | key: 'type' |
| | | }, |
| | | { |
| | | title: 'ç»´æ¤å
容', |
| | | dataIndex: 'content', |
| | | key: 'content' |
| | | }, |
| | | { |
| | | title: '建议æ¶é´', |
| | | dataIndex: 'suggestedTime', |
| | | key: 'suggestedTime' |
| | | }, |
| | | { |
| | | title: 'ç´§æ¥ç¨åº¦', |
| | | dataIndex: 'urgency', |
| | | key: 'urgency', |
| | | slots: { customRender: 'urgency' } |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | key: 'action', |
| | | slots: { customRender: 'action' } |
| | | } |
| | | ]; |
| | | |
| | | const maintenanceData = reactive([ |
| | | { |
| | | key: '1', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | content: 'æ£æ¥æ¶²å油污æåº¦', |
| | | suggestedTime: '2024-07-15', |
| | | urgency: 'ä¸ç' |
| | | }, |
| | | { |
| | | key: '2', |
| | | type: 'æ
éé¢è¦', |
| | | content: 'ä¸»çµæºè½´æ¿ç£¨æé¢è¦', |
| | | suggestedTime: '2024-08-01', |
| | | urgency: 'é«' |
| | | }, |
| | | { |
| | | key: '3', |
| | | type: 'å·å´ç³»ç»ç»´æ¤', |
| | | content: 'æ£æ¥å·å´æ°´æµé', |
| | | suggestedTime: '2024-07-01', |
| | | urgency: 'ä½' |
| | | } |
| | | ]); |
| | | |
| | | const getUrgencyColor = (urgency: string) => { |
| | | switch (urgency) { |
| | | case 'ä¸ç': { |
| | | return 'orange'; |
| | | } |
| | | case 'ä½': { |
| | | return 'green'; |
| | | } |
| | | case 'é«': { |
| | | return 'red'; |
| | | } |
| | | default: { |
| | | return 'default'; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const sparePartColumns = [ |
| | | { |
| | | title: 'å¤ä»¶åç§°', |
| | | dataIndex: 'name', |
| | | key: 'name' |
| | | }, |
| | | { |
| | | title: 'å½å寿å½', |
| | | dataIndex: 'currentLife', |
| | | key: 'currentLife', |
| | | customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | }, |
| | | { |
| | | title: '颿µå©ä½å¯¿å½', |
| | | dataIndex: 'remainingLife', |
| | | key: 'remainingLife', |
| | | customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | }, |
| | | { |
| | | title: 'ç¶æ', |
| | | dataIndex: 'status', |
| | | key: 'status', |
| | | slots: { customRender: 'status' } |
| | | } |
| | | ]; |
| | | |
| | | const sparePartData = reactive([ |
| | | { |
| | | key: '1', |
| | | name: 'æ¶²åæ³µ', |
| | | currentLife: 18_500, |
| | | remainingLife: 1500, |
| | | status: 'é¢è¦' |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: 'å çå', |
| | | currentLife: 12_000, |
| | | remainingLife: 3000, |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: 'èºææç', |
| | | currentLife: 25_000, |
| | | remainingLife: 5000, |
| | | status: 'è¯å¥½' |
| | | } |
| | | ]); |
| | | |
| | | const historyData = reactive([ |
| | | { |
| | | id: '1', |
| | | date: '2023-10-20', |
| | | type: 'ä¾è¡ä¿å
»', |
| | | description: 'æ´æ¢æ¶²å油滤è¯', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '2', |
| | | date: '2023-08-15', |
| | | type: 'æ
éç»´ä¿®', |
| | | description: '注å°åå
塿»ï¼æ¸
çå¼ç©', |
| | | color: 'red' |
| | | }, |
| | | { |
| | | id: '3', |
| | | date: '2023-06-01', |
| | | type: '年度ä¿å
»', |
| | | description: 'å
¨é¢æ£æ¥è®¾å¤è¿è¡ç¶æ', |
| | | color: 'blue' |
| | | } |
| | | ]); |
| | | |
| | | const getStatusColor = (status: string) => { |
| | | switch (status) { |
| | | case 'å±é©': { |
| | | return '#f5222d'; |
| | | } |
| | | case 'è¯å¥½': { |
| | | return '#52c41a'; |
| | | } |
| | | case 'é¢è¦': { |
| | | return '#faad14'; |
| | | } |
| | | default: { |
| | | return '#d9d9d9'; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const handleMaintenance = (record: any) => { |
| | | console.log('å¤çç»´æ¤å»ºè®®:', record); |
| | | // å®é
项ç®ä¸è¿éä¼è°ç¨APIå¤çç»´æ¤å»ºè®® |
| | | }; |
| | | |
| | | return { |
| | | deviceInfo, |
| | | healthData, |
| | | maintenanceColumns, |
| | | maintenanceData, |
| | | sparePartColumns, |
| | | sparePartData, |
| | | historyData, |
| | | getStatusColor, |
| | | getUrgencyColor, |
| | | handleMaintenance |
| | | }; |
| | | }, |
| | | |
| | | 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++) { // çæ60个ç¹ï¼ä»£è¡¨5åéçæ°æ® |
| | | const time = new Date(now.getTime() - (59 - i) * 5000); // æ¯ä¸ªç¹é´é5ç§ |
| | | chartData.push({ |
| | | time: time.toLocaleTimeString(), |
| | | value: (baseValue + Math.random() * fluctuation * 2 - fluctuation).toFixed(2), |
| | | }); |
| | | } |
| | | } |
| | | |
| | | const updateChart = () => { |
| | | // çææ°çæ°æ®ç¹ |
| | | const now = new Date(); |
| | | const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`; |
| | | const newValue = (baseValue + Math.random() * fluctuation * 2 - fluctuation).toFixed(2); |
| | | |
| | | // æ·»å æ°æ°æ®ç¹ï¼æå¤ä¿ç60个ç¹ï¼5åéæ°æ®ï¼ |
| | | chartData.push({ |
| | | time, |
| | | value: newValue |
| | | }); |
| | | if (chartData.length > 60) { |
| | | chartData.shift(); |
| | | } |
| | | |
| | | const option = { |
| | | title: { |
| | | text: title, |
| | | left: 'center' |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | formatter: (params) => { |
| | | return `${params[0].axisValueLabel}<br/>${params[0].marker} ${params[0].seriesName}: ${params[0].data}${unit}`; |
| | | } |
| | | }, |
| | | grid: { |
| | | left: '8%', // å¢å å·¦ä¾§è¾¹è· |
| | | right: '5%', |
| | | bottom: '10%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: chartData.map(item => item.time) |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | axisLabel: { |
| | | formatter: (value) => `${value}${unit}` |
| | | } |
| | | }, |
| | | series: [ |
| | | { |
| | | data: chartData.map(item => Number.parseFloat(item.value)), |
| | | type: 'line', |
| | | smooth: true, |
| | | lineStyle: { |
| | | width: 2, |
| | | color: '#5470C6' // Default color |
| | | }, |
| | | areaStyle: { |
| | | opacity: 0.8, |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: 'rgba(84,112,198,0.3)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: 'rgba(84,112,198,0)' |
| | | } |
| | | ]) |
| | | }, |
| | | } |
| | | ] |
| | | }; |
| | | chart.setOption(option); |
| | | }; |
| | | |
| | | // åå§æ¸²æ |
| | | updateChart(); |
| | | |
| | | // æ¯5ç§æ´æ°ä¸æ¬¡æ°æ® |
| | | const intervalId = setInterval(updateChart, 5000); |
| | | |
| | | window.addEventListener('resize', () => { |
| | | chart.resize(); |
| | | }); |
| | | onUnmounted(() => { |
| | | clearInterval(intervalId); |
| | | }); |
| | | |
| | | }; |
| | | |
| | | |
| | | const hydraulicOilTemperatureData: any[] = []; |
| | | const hydraulicOilPressureData: any[] = []; |
| | | const mainMotorCurrentData: any[] = []; |
| | | const screwSpeedData: any[] = []; |
| | | const moldClampingForceData: any[] = []; |
| | | const injectionPressureData: any[] = []; |
| | | const injectionSpeedData: any[] = []; |
| | | const barrelTemperatureData: any[] = []; |
| | | const coolingWaterTemperatureData: any[] = []; |
| | | const coolingWaterFlowData: any[] = []; |
| | | const ejectorPositionData: any[] = []; |
| | | const cycleTimeData: any[] = []; |
| | | |
| | | initChart('hydraulicOilTemperatureChart', 'æ¶²åæ²¹æ¸©', hydraulicOilTemperatureData, '°C', 50, 2); |
| | | 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('injectionSpeedChart', '注å°é度', injectionSpeedData, 'mm/s', 150, 10); |
| | | initChart('barrelTemperatureChart', 'æç温度', barrelTemperatureData, '°C', 200, 5); |
| | | initChart('coolingWaterTemperatureChart', 'å·å´æ°´æ¸©åº¦', coolingWaterTemperatureData, '°C', 25, 2); |
| | | initChart('coolingWaterFlowChart', 'å·å´æ°´æµé', coolingWaterFlowData, 'L/min', 30, 3); |
| | | initChart('ejectorPositionChart', 'é¡¶åºä½ç½®', ejectorPositionData, 'mm', 50, 5); |
| | | initChart('cycleTimeChart', 'å¾ªç¯æ¶é´', cycleTimeData, 's', 30, 2); |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <div class="device-detail-container"> |
| | | <a-page-header |
| | | :sub-title="deviceInfo.deviceName" |
| | | title="æ³¨å¡æºé¢æµæ§ç»´æ¤è¯¦æ
" |
| | | @back="() => $router.go(-1)" |
| | | /> |
| | | |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <!-- 设å¤åºæ¬ä¿¡æ¯ --> |
| | | <a-col :span="8"> |
| | | <a-card :style="{ height: '440px' }" class="mb-4" title="设å¤åºæ¬ä¿¡æ¯"> |
| | | <a-descriptions :column="1" bordered> |
| | | <a-descriptions-item label="设å¤åç§°">{{ deviceInfo.deviceName }}</a-descriptions-item> |
| | | <a-descriptions-item label="设å¤ç±»å">{{ deviceInfo.deviceType }}</a-descriptions-item> |
| | | <a-descriptions-item label="设å¤ç¼å·">{{ deviceInfo.deviceId }}</a-descriptions-item> |
| | | <a-descriptions-item label="å®è£
æ¥æ">{{ deviceInfo.installDate }}</a-descriptions-item> |
| | | <a-descriptions-item label="使ç¨å¹´é">{{ deviceInfo.serviceLife }}å¹´</a-descriptions-item> |
| | | <a-descriptions-item label="å½åç¶æ"> |
| | | <a-tag :color="deviceInfo.statusColor">{{ deviceInfo.status }}</a-tag> |
| | | </a-descriptions-item> |
| | | </a-descriptions> |
| | | </a-card> |
| | | </a-col> |
| | | |
| | | <!-- 设å¤å¥åº·ç¶æä¸ç»´æ¤å»ºè®® --> |
| | | <a-col :span="16"> |
| | | <a-card :style="{ height: '440px' }" class="mb-4" title="设å¤å¥åº·ç¶æä¸ç»´æ¤å»ºè®®"> |
| | | <a-row :gutter="16"> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | :precision="0" |
| | | :value="healthData.overallHealth" |
| | | :value-style="{ color: healthData.healthColor }" |
| | | suffix="%" |
| | | title="æ´ä½å¥åº·åº¦" |
| | | /> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | :value="healthData.predictedLife" |
| | | suffix="天" |
| | | title="颿µå©ä½å¯¿å½" |
| | | /> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | :value="healthData.riskLevel" |
| | | :value-style="{ color: healthData.riskColor }" |
| | | title="æ
éé£é©ç级" |
| | | /> |
| | | </a-col> |
| | | </a-row> |
| | | <div class="mt-4"> |
| | | <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" |
| | | > |
| | | <template #urgency="{ text }"> |
| | | <a-tag :color="getUrgencyColor(text)">{{ text }}</a-tag> |
| | | </template> |
| | | <template #action="{ record }"> |
| | | <a-button size="small" type="link" @click="handleMaintenance(record)">å¤ç</a-button> |
| | | </template> |
| | | </a-table> |
| | | </a-card> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | <!-- 宿¶æ°æ®è¶å¿å¾ --> |
| | | <a-card class="mb-4" title="宿¶æ°æ®è¶å¿å¾"> |
| | | <a-row :gutter="16"> |
| | | <a-col :span="8"> |
| | | <div id="hydraulicOilTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="hydraulicOilPressureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="mainMotorCurrentChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="screwSpeedChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="moldClampingForceChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="injectionPressureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="injectionSpeedChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="barrelTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="coolingWaterTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="coolingWaterFlowChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="ejectorPositionChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="cycleTimeChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | </a-card> |
| | | |
| | | <a-row :gutter="16"> |
| | | <!-- å¤ä»¶å¯¿å½é¢æµ --> |
| | | <a-col :span="12"> |
| | | <a-card class="mb-4" title="å¤ä»¶å¯¿å½é¢æµ"> |
| | | <a-table |
| | | :columns="sparePartColumns" |
| | | :data-source="sparePartData" |
| | | :pagination="false" |
| | | size="small" |
| | | > |
| | | <template #status="{ text }"> |
| | | <a-tag :color="getStatusColor(text)">{{ text }}</a-tag> |
| | | </template> |
| | | </a-table> |
| | | </a-card> |
| | | </a-col> |
| | | |
| | | <!-- åå²ç»´æ¤è®°å½ --> |
| | | <a-col :span="12"> |
| | | <a-card class="mb-4" title="åå²ç»´æ¤è®°å½"> |
| | | <a-timeline> |
| | | <a-timeline-item v-for="item in historyData" :key="item.id" :color="item.color"> |
| | | {{ item.date }} - {{ item.type }}: {{ item.description }} |
| | | </a-timeline-item> |
| | | </a-timeline> |
| | | </a-card> |
| | | </a-col> |
| | | </a-row> |
| | | </div> |
| | | </template> |
| | | |
| | | <style scoped> |
| | | .device-detail-container { |
| | | padding: 16px; |
| | | background: #f0f2f5; |
| | | } |
| | | |
| | | .mt-4 { |
| | | margin-top: 16px; |
| | | } |
| | | |
| | | .mb-4 { |
| | | margin-bottom: 16px; |
| | | } |
| | | </style> |
| | | |
| | | |
| | | <style scoped> |
| | | .injection-molding-machine-detail { |
| | | padding: 16px; |
| | | background-color: #f0f2f5; |
| | | } |
| | | |
| | | .header-card { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .device-info h2 { |
| | | font-size: 24px; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .device-info p { |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .health-status h3 { |
| | | font-size: 20px; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .ant-statistic-content { |
| | | font-size: 20px !important; |
| | | } |
| | | |
| | | .ant-list-item-meta-title { |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .ant-list-item-meta-description { |
| | | font-size: 14px; |
| | | color: rgba(0, 0, 0, 0.65); |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="device-detail-container"> |
| | | <a-page-header |
| | | title="SMTè´´çæºé¢æµæ§ç»´æ¤è¯¦æ
" |
| | | :sub-title="deviceInfo.deviceName" |
| | | @back="() => $router.go(-1)" |
| | | /> |
| | | |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <!-- 设å¤åºæ¬ä¿¡æ¯ --> |
| | | <a-col :span="8"> |
| | | <a-card title="设å¤åºæ¬ä¿¡æ¯" class="mb-4" :style="{ height: '440px' }"> |
| | | <a-descriptions bordered :column="1"> |
| | | <a-descriptions-item label="设å¤åç§°">{{ deviceInfo.deviceName }}</a-descriptions-item> |
| | | <a-descriptions-item label="设å¤ç±»å">{{ deviceInfo.deviceType }}</a-descriptions-item> |
| | | <a-descriptions-item label="设å¤ç¼å·">{{ deviceInfo.deviceId }}</a-descriptions-item> |
| | | <a-descriptions-item label="å®è£
æ¥æ">{{ deviceInfo.installDate }}</a-descriptions-item> |
| | | <a-descriptions-item label="使ç¨å¹´é">{{ deviceInfo.serviceLife }}å¹´</a-descriptions-item> |
| | | <a-descriptions-item label="å½åç¶æ"> |
| | | <a-tag :color="deviceInfo.statusColor">{{ deviceInfo.status }}</a-tag> |
| | | </a-descriptions-item> |
| | | </a-descriptions> |
| | | </a-card> |
| | | </a-col> |
| | | |
| | | <!-- 设å¤å¥åº·ç¶æä¸ç»´æ¤å»ºè®® --> |
| | | <a-col :span="16"> |
| | | <a-card title="设å¤å¥åº·ç¶æä¸ç»´æ¤å»ºè®®" class="mb-4" :style="{ height: '440px' }"> |
| | | <a-row :gutter="16"> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | title="æ´ä½å¥åº·åº¦" |
| | | :value="healthData.overallHealth" |
| | | :precision="0" |
| | | suffix="%" |
| | | :value-style="{ color: healthData.healthColor }" |
| | | /> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | title="颿µå©ä½å¯¿å½" |
| | | :value="healthData.predictedLife" |
| | | suffix="天" |
| | | /> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <a-statistic |
| | | title="æ
éé£é©ç级" |
| | | :value="healthData.riskLevel" |
| | | :value-style="{ color: healthData.riskColor }" |
| | | /> |
| | | </a-col> |
| | | </a-row> |
| | | <div class="mt-4"> |
| | | <a-progress |
| | | :percent="healthData.overallHealth" |
| | | :stroke-color="healthData.healthColor" |
| | | :show-info="false" |
| | | /> |
| | | </div> |
| | | <a-divider orientation="left">颿µæ§ç»´æ¤å»ºè®®</a-divider> |
| | | <a-table |
| | | :columns="maintenanceColumns" |
| | | :data-source="maintenanceData" |
| | | :pagination="false" |
| | | size="small" |
| | | > |
| | | <template #urgency="{ text }"> |
| | | <a-tag :color="getUrgencyColor(text)">{{ text }}</a-tag> |
| | | </template> |
| | | <template #action="{ record }"> |
| | | <a-button type="link" size="small" @click="handleMaintenance(record)">å¤ç</a-button> |
| | | </template> |
| | | </a-table> |
| | | </a-card> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | <!-- 宿¶æ°æ®è¶å¿å¾ --> |
| | | <a-card title="宿¶æ°æ®è¶å¿å¾" class="mb-4"> |
| | | <!-- è¿å¨ç³»ç» --> |
| | | <a-row :gutter="16"> |
| | | <a-col :span="8"> |
| | | <div id="xAxisMotorCurrentChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="yAxisMotorCurrentChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="zAxisMotorCurrentChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="motorTemperatureChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="motorVibrationChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="beltTensionChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | <!-- è´´è£
头/å¸å´ --> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="nozzleVacuumChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="nozzleFlowChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="placementSpeedChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | <!-- è§è§ç³»ç» --> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="placementAccuracyChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="visionAlignmentChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="lightIntensityChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | <!-- ç¯å¢åæ° --> |
| | | <a-row :gutter="16" class="mt-4"> |
| | | <a-col :span="8"> |
| | | <div id="feederMotorCurrentChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="esdChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | <a-col :span="8"> |
| | | <div id="ambientTemperatureHumidityChart" style="height: 300px;"></div> |
| | | </a-col> |
| | | </a-row> |
| | | </a-card> |
| | | <a-row :gutter="16"> |
| | | <!-- å¤ä»¶å¯¿å½é¢æµ --> |
| | | <a-col :span="12"> |
| | | <a-card title="å¤ä»¶å¯¿å½é¢æµ" class="mb-4"> |
| | | <a-table |
| | | :columns="sparePartColumns" |
| | | :data-source="sparePartData" |
| | | :pagination="false" |
| | | size="small" |
| | | > |
| | | <template #status="{ text }"> |
| | | <a-tag :color="getStatusColor(text)">{{ text }}</a-tag> |
| | | </template> |
| | | </a-table> |
| | | </a-card> |
| | | </a-col> |
| | | |
| | | <!-- åå²ç»´æ¤è®°å½ --> |
| | | <a-col :span="12"> |
| | | <a-card title="åå²ç»´æ¤è®°å½" class="mb-4"> |
| | | <a-timeline> |
| | | <a-timeline-item v-for="item in historyData" :key="item.id" :color="item.color"> |
| | | {{ item.date }} - {{ item.type }}: {{ item.description }} |
| | | </a-timeline-item> |
| | | </a-timeline> |
| | | </a-card> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { defineComponent, reactive, onMounted, onUnmounted } from 'vue'; |
| | | import * as echarts from 'echarts'; |
| | | |
| | | export default defineComponent({ |
| | | name: 'SmtMachineDetail', |
| | | setup() { |
| | | // æ¨¡ææ°æ® |
| | | const deviceInfo = reactive({ |
| | | deviceName: 'SMTè´´çæº-001', |
| | | deviceType: 'è´´çæº', |
| | | deviceId: 'SMT-2024-001', |
| | | installDate: '2024-01-01', |
| | | serviceLife: 8, |
| | | status: 'è¿è¡ä¸', |
| | | statusColor: '#52c41a' |
| | | }); |
| | | |
| | | const healthData = reactive({ |
| | | overallHealth: 92, |
| | | healthColor: '#52c41a', |
| | | predictedLife: 2500, |
| | | riskLevel: 'ä½é£é©', |
| | | riskColor: '#52c41a' |
| | | }); |
| | | |
| | | const maintenanceColumns = [ |
| | | { |
| | | title: 'ç»´æ¤ç±»å', |
| | | dataIndex: 'type', |
| | | key: 'type' |
| | | }, |
| | | { |
| | | title: 'ç»´æ¤å
容', |
| | | dataIndex: 'content', |
| | | key: 'content' |
| | | }, |
| | | { |
| | | title: '建议æ¶é´', |
| | | dataIndex: 'suggestedTime', |
| | | key: 'suggestedTime' |
| | | }, |
| | | { |
| | | title: 'ç´§æ¥ç¨åº¦', |
| | | dataIndex: 'urgency', |
| | | key: 'urgency', |
| | | slots: { customRender: 'urgency' } |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | key: 'action', |
| | | slots: { customRender: 'action' } |
| | | } |
| | | ]; |
| | | |
| | | const maintenanceData = reactive([ |
| | | { |
| | | key: '1', |
| | | type: 'è¿å¨ç³»ç»ä¿å
»', |
| | | content: 'X/Y轴伺æçµæºæ¶¦æ»æ£æ¥', |
| | | suggestedTime: '2024-03-20', |
| | | urgency: 'ä¸ç' |
| | | }, |
| | | { |
| | | key: '2', |
| | | type: 'è´´è£
头维æ¤', |
| | | content: 'å¸å´ç空ååæ ¡å', |
| | | suggestedTime: '2024-04-05', |
| | | urgency: 'é«' |
| | | }, |
| | | { |
| | | key: '3', |
| | | type: 'ä¾æç³»ç»æ£æ¥', |
| | | content: 'é£è¾¾å¡å¸¦/å¡ææ¬¡æ°æ¸
é¶', |
| | | suggestedTime: '2024-03-10', |
| | | urgency: 'ä½' |
| | | } |
| | | ]); |
| | | |
| | | const getUrgencyColor = (urgency: string) => { |
| | | switch (urgency) { |
| | | case 'é«': |
| | | return 'red'; |
| | | case 'ä¸ç': |
| | | return 'orange'; |
| | | case 'ä½': |
| | | return 'green'; |
| | | default: |
| | | return 'default'; |
| | | } |
| | | }; |
| | | |
| | | const sparePartColumns = [ |
| | | { |
| | | title: 'å¤ä»¶åç§°', |
| | | dataIndex: 'name', |
| | | key: 'name' |
| | | }, |
| | | { |
| | | title: 'å½å寿å½', |
| | | dataIndex: 'currentLife', |
| | | key: 'currentLife', |
| | | customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | }, |
| | | { |
| | | title: '颿µå©ä½å¯¿å½', |
| | | dataIndex: 'remainingLife', |
| | | key: 'remainingLife', |
| | | customRender: ({ text }: { text: number }) => `${text}å°æ¶` |
| | | }, |
| | | { |
| | | title: 'ç¶æ', |
| | | dataIndex: 'status', |
| | | key: 'status', |
| | | slots: { customRender: 'status' } |
| | | } |
| | | ]; |
| | | |
| | | const sparePartData = reactive([ |
| | | { |
| | | key: '1', |
| | | name: 'X轴伺æçµæº', |
| | | currentLife: 5000, |
| | | remainingLife: 1500, |
| | | status: 'è¯å¥½' |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: 'å¸å´', |
| | | currentLife: 1000, |
| | | remainingLife: 50, |
| | | status: 'é¢è¦' |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: 'é£è¾¾', |
| | | currentLife: 8000, |
| | | remainingLife: 2000, |
| | | status: 'è¯å¥½' |
| | | } |
| | | ]); |
| | | |
| | | const historyData = reactive([ |
| | | { |
| | | id: '1', |
| | | date: '2024-02-15', |
| | | type: '宿ä¿å
»', |
| | | description: '宿å£åº¦ä¿å
»ï¼æ£æ¥è¿å¨ç³»ç»æ¶¦æ»', |
| | | color: 'green' |
| | | }, |
| | | { |
| | | id: '2', |
| | | date: '2024-01-20', |
| | | type: 'æ
éç»´ä¿®', |
| | | description: 'ä¿®å¤å¸å´å µå¡é®é¢', |
| | | color: 'red' |
| | | }, |
| | | { |
| | | id: '3', |
| | | date: '2023-12-01', |
| | | type: '宿ä¿å
»', |
| | | description: 'å®æå¹´åº¦ä¿å
»ï¼æ ¡åè§è§ç³»ç»', |
| | | color: 'green' |
| | | } |
| | | ]); |
| | | |
| | | const getStatusColor = (status: string) => { |
| | | switch (status) { |
| | | case 'è¯å¥½': |
| | | return '#52c41a'; |
| | | case 'é¢è¦': |
| | | return '#faad14'; |
| | | case 'å±é©': |
| | | return '#f5222d'; |
| | | default: |
| | | return '#d9d9d9'; |
| | | } |
| | | }; |
| | | |
| | | const handleMaintenance = (record: any) => { |
| | | console.log('å¤çç»´æ¤å»ºè®®:', record); |
| | | // å®é
项ç®ä¸è¿éä¼è°ç¨APIå¤çç»´æ¤å»ºè®® |
| | | }; |
| | | |
| | | return { |
| | | deviceInfo, |
| | | healthData, |
| | | maintenanceColumns, |
| | | maintenanceData, |
| | | sparePartColumns, |
| | | sparePartData, |
| | | historyData, |
| | | getStatusColor, |
| | | getUrgencyColor, |
| | | handleMaintenance |
| | | }; |
| | | }, |
| | | |
| | | mounted() { |
| | | // åå§åå¾è¡¨ |
| | | const initChart = (chartId: string, title: string, chartData: any[], unit: string, baseValue: number, fluctuation: number) => { |
| | | const chart = echarts.init(document.getElementById(chartId)); |
| | | |
| | | const updateChart = () => { |
| | | // çææ°çæ°æ®ç¹ |
| | | const now = new Date(); |
| | | const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`; |
| | | const newValue = (baseValue + (Math.random() * 2 - 1) * fluctuation).toFixed(2); |
| | | |
| | | // æ·»å æ°æ°æ®ç¹ï¼æå¤ä¿ç60个ç¹ï¼5åéæ°æ®ï¼ |
| | | chartData.push({ |
| | | time, |
| | | value: newValue |
| | | }); |
| | | if (chartData.length > 60) { |
| | | chartData.shift(); |
| | | } |
| | | |
| | | const option = { |
| | | title: { |
| | | text: title, |
| | | left: 'center' |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | formatter: (params) => { |
| | | return `${params[0].axisValueLabel}<br/>${params[0].marker} ${params[0].seriesName}: ${params[0].data}${unit}`; |
| | | } |
| | | }, |
| | | grid: { |
| | | left: '8%', // å¢å å·¦ä¾§è¾¹è· |
| | | right: '5%', |
| | | bottom: '10%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: chartData.map(item => item.time) |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | axisLabel: { |
| | | formatter: (value) => `${value}${unit}` |
| | | } |
| | | }, |
| | | series: [ |
| | | { |
| | | data: chartData.map(item => parseFloat(item.value)), |
| | | type: 'line', |
| | | smooth: true, |
| | | lineStyle: { |
| | | width: 2, |
| | | color: chartId === 'motorCurrentChart' ? '#5470C6' : chartId === 'motorTemperatureChart' ? '#91CC75' : '#FAC858' // æ ¹æ®å¾è¡¨ID设置é¢è² |
| | | }, |
| | | areaStyle: { |
| | | opacity: 0.8, |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: chartId === 'motorCurrentChart' ? 'rgba(84,112,198,0.3)' : chartId === 'motorTemperatureChart' ? 'rgba(145,204,117,0.3)' : 'rgba(250,200,88,0.3)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: chartId === 'motorCurrentChart' ? 'rgba(84,112,198,0)' : chartId === 'motorTemperatureChart' ? 'rgba(145,204,117,0)' : 'rgba(250,200,88,0)' |
| | | } |
| | | ]) |
| | | }, |
| | | } |
| | | ] |
| | | }; |
| | | chart.setOption(option); |
| | | }; |
| | | |
| | | // çæåå§æ°æ®ç¹ï¼60个ç¹ï¼5åéæ°æ®ï¼ |
| | | for (let i = 0; i < 60; i++) { |
| | | const now = new Date(Date.now() - (60 - i) * 5000); // çæè¿å»5åéçæ°æ® |
| | | const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`; |
| | | const newValue = (baseValue + (Math.random() * 2 - 1) * fluctuation).toFixed(2); |
| | | chartData.push({ |
| | | time, |
| | | value: newValue |
| | | }); |
| | | } |
| | | |
| | | // åå§æ¸²æ |
| | | updateChart(); |
| | | |
| | | // æ¯5ç§æ´æ°ä¸æ¬¡æ°æ® |
| | | const intervalId = setInterval(updateChart, 5000); |
| | | |
| | | window.addEventListener('resize', () => { |
| | | chart.resize(); |
| | | }); |
| | | onUnmounted(() => { |
| | | clearInterval(intervalId); |
| | | }); |
| | | |
| | | }; |
| | | |
| | | // è¿å¨ç³»ç»çæµ |
| | | initChart('xAxisMotorCurrentChart', 'Xè½´çµæºçµæµ', [], 'A', 10, 1); |
| | | initChart('yAxisMotorCurrentChart', 'Yè½´çµæºçµæµ', [], 'A', 10, 1); |
| | | initChart('zAxisMotorCurrentChart', 'Zè½´çµæºçµæµ', [], 'A', 8, 0.8); |
| | | initChart('motorTemperatureChart', 'çµæºæ¸©åº¦', [], '°C', 45, 2); |
| | | initChart('motorVibrationChart', 'çµæºæ¯å¨', [], 'mm/s', 5, 0.5); |
| | | initChart('beltTensionChart', 'ç®å¸¦å¼ å', [], 'N', 50, 5); |
| | | |
| | | // è´´è£
头/å¸å´çæµ |
| | | initChart('nozzleVacuumChart', 'å¸å´ç空åå', [], 'kPa', 80, 5); |
| | | initChart('nozzleFlowChart', 'å¸å´æµé', [], 'L/min', 5, 0.5); |
| | | initChart('placementSpeedChart', 'è´´è£
é度', [], 'mm/s', 100, 10); |
| | | initChart('placementAccuracyChart', 'è´´è£
精度', [], 'μm', 50, 5); |
| | | |
| | | // è§è§ç³»ç»çæµ |
| | | initChart('visionAlignmentChart', 'è§è§å¯¹ä½ç²¾åº¦', [], 'μm', 30, 3); |
| | | initChart('lightIntensityChart', 'å
æºäº®åº¦', [], 'lux', 5000, 500); |
| | | |
| | | // ä¾æç³»ç»çæµ |
| | | initChart('feederMotorCurrentChart', 'ä¾æçµæºçµæµ', [], 'A', 5, 0.5); |
| | | |
| | | // ç¯å¢çæµ |
| | | initChart('esdChart', 'éçµçæµ', [], 'kV', 0.1, 0.05); |
| | | initChart('ambientTemperatureHumidityChart', 'ç¯å¢æ¸©æ¹¿åº¦', [], '°C', 25, 2); |
| | | } |
| | | |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .device-detail-container { |
| | | padding: 16px; |
| | | background: #f0f2f5; |
| | | } |
| | | </style> |