<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="10">
|
<a-card title="设备信息" class="mb-4" :style="{ height: '440px' }">
|
<a-row :gutter="16">
|
<a-col :span="12">
|
<div class="device-image-container">
|
<img :src="deviceInfo.imageUrl" alt="设备图片" class="device-image" />
|
</div>
|
</a-col>
|
<a-col :span="12">
|
<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-col>
|
</a-row>
|
</a-card>
|
</a-col>
|
|
<!-- 设备健康状态与维护建议 -->
|
<a-col :span="14">
|
<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 />
|
|
<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-col :span="24">
|
<a-card title="设备数据" class="mb-4">
|
<a-row :gutter="[16, 16]">
|
<a-col :span="4">
|
<a-statistic title="X轴总移动距离" :value="healthData.xAxisTravel" suffix="km">
|
<template #prefix>
|
<LineChartOutlined />
|
</template>
|
</a-statistic>
|
</a-col>
|
<a-col :span="4">
|
<a-statistic title="Y轴总移动距离" :value="healthData.yAxisTravel" suffix="km">
|
<template #prefix>
|
<LineChartOutlined />
|
</template>
|
</a-statistic>
|
</a-col>
|
<a-col :span="4">
|
<a-statistic title="卡带次数" :value="healthData.tapeJamCount" suffix="次">
|
<template #prefix>
|
<WarningOutlined />
|
</template>
|
</a-statistic>
|
</a-col>
|
<a-col :span="4">
|
<a-statistic title="卡料次数" :value="healthData.materialJamCount" suffix="次">
|
<template #prefix>
|
<WarningOutlined />
|
</template>
|
</a-statistic>
|
</a-col>
|
<a-col :span="4">
|
<a-statistic title="拼板数" :value="healthData.panelCount" suffix="块">
|
<template #prefix>
|
<AppstoreOutlined />
|
</template>
|
</a-statistic>
|
</a-col>
|
<a-col :span="4">
|
<a-statistic title="出错停机时间" :value="healthData.downtime" suffix="秒">
|
<template #prefix>
|
<FieldTimeOutlined />
|
</template>
|
</a-statistic>
|
</a-col>
|
</a-row>
|
</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="nozzleVacuumChart" style="height: 300px;"></div>
|
</a-col>
|
</a-row>
|
|
<!-- 贴装头/吸嘴 -->
|
<a-row :gutter="16" class="mt-4">
|
|
<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-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';
|
import {
|
LineChartOutlined,
|
WarningOutlined,
|
AppstoreOutlined,
|
FieldTimeOutlined
|
} from '@ant-design/icons-vue';
|
|
export default defineComponent({
|
name: 'SmtMachineDetail',
|
setup() {
|
// 模拟数据
|
const deviceInfo = reactive({
|
deviceName: 'SMT贴片机',
|
deviceType: '贴片机',
|
deviceId: 'GPC2012A101',
|
installDate: '2012-06-08',
|
serviceLife: 8,
|
status: '运行中',
|
statusColor: '#52c41a',
|
imageUrl: '/src/assets/images/JUKI.png' // 添加设备图片路径
|
});
|
|
const healthData = reactive({
|
overallHealth: 82,
|
healthColor: '#52c41a',
|
predictedLife: 635,
|
riskLevel: '低风险',
|
riskColor: '#52c41a',
|
xAxisTravel: 300.179,
|
yAxisTravel: 233.392,
|
tapeJamCount: 15,
|
materialJamCount: 15,
|
panelCount: 2480,
|
downtime: 4.5
|
});
|
|
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-04-05',
|
urgency: '中等'
|
},
|
{
|
key: '2',
|
type: '运动系统保养',
|
content: 'X/Y轴伺服电机润滑检查',
|
suggestedTime: '2024-03-20',
|
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
|
};
|
},
|
components: {
|
LineChartOutlined,
|
WarningOutlined,
|
AppstoreOutlined,
|
FieldTimeOutlined
|
},
|
|
mounted() {
|
// 初始化图表
|
const initChart = (chartId: string, title: string, seriesConfig: Array<{ name: string, data: any[], unit: string, baseValue: number, fluctuation: number, color: string }>) => {
|
const chart = echarts.init(document.getElementById(chartId));
|
|
const updateChart = () => {
|
// 生成新的数据点
|
const now = new Date();
|
const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
|
|
seriesConfig.forEach(s => {
|
const newValue = (s.baseValue + (Math.random() * 2 - 1) * s.fluctuation).toFixed(2);
|
s.data.push({
|
time,
|
value: newValue
|
});
|
if (s.data.length > 60) {
|
s.data.shift();
|
}
|
});
|
|
const option = {
|
title: {
|
text: title,
|
left: 'center'
|
},
|
tooltip: {
|
trigger: 'axis',
|
formatter: (params) => {
|
let result = `${params[0].axisValueLabel}<br/>`;
|
params.forEach(param => {
|
result += `${param.marker} ${param.seriesName}: ${param.data}${seriesConfig[param.seriesIndex].unit}<br/>`;
|
});
|
return result;
|
}
|
},
|
grid: {
|
left: '8%', // 增加左侧边距
|
right: '5%',
|
bottom: '10%',
|
containLabel: true
|
},
|
xAxis: {
|
type: 'category',
|
data: seriesConfig[0].data.map(item => item.time)
|
},
|
yAxis: seriesConfig.map((s, index) => ({
|
type: 'value',
|
name: s.name,
|
position: index === 0 ? 'left' : 'right',
|
axisLine: {
|
show: true,
|
},
|
axisLabel: {
|
formatter: (value) => `${value}${s.unit}`
|
}
|
})),
|
series: seriesConfig.map((s, index) => ({
|
name: s.name,
|
data: s.data.map(item => parseFloat(item.value)),
|
type: 'line',
|
smooth: true,
|
yAxisIndex: index,
|
lineStyle: {
|
width: 2,
|
color: s.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);
|
};
|
|
seriesConfig.forEach(s => {
|
s.data = [];
|
// 生成初始数据点(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 = (s.baseValue + (Math.random() * 2 - 1) * s.fluctuation).toFixed(2);
|
s.data.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', '电机温度', [
|
{ name: '温度', data: [], unit: '°C', baseValue: 45, fluctuation: 2, color: '#5470C6' },
|
]);
|
initChart('motorVibrationChart', '电机振动', [
|
{ name: '振动', data: [], unit: 'mm/s', baseValue: 5, fluctuation: 0.5, color: '#5470C6' },
|
], );
|
initChart('nozzleVacuumChart', '吸嘴真空压力', [
|
{ name: '压力', data: [], unit: 'kPa', baseValue: -39, fluctuation: 5, color: '#5470C6' },
|
],);
|
// initChart('beltTensionChart', '皮带张力', [], 'N', 50, 5);
|
|
// 贴装头/吸嘴监测
|
|
initChart('nozzleFlowChart', '吸嘴流量', [
|
{ name: '流量', data: [], unit: 'L/min', baseValue: 5, fluctuation: 0.5, color: '#5470C6' },
|
]);
|
initChart('placementSpeedChart', '贴装速度', [
|
{ name: '速度', data: [], unit: 'mm/s', baseValue: 100, fluctuation: 10, color: '#5470C6' },
|
]);
|
const ambientTemperatureData: any[] = [];
|
const ambientHumidityData: any[] = [];
|
initChart('ambientTemperatureHumidityChart', '环境温湿度', [
|
{ name: '温度', data: ambientTemperatureData, unit: '°C', baseValue: 25, fluctuation: 2, color: '#5470C6' },
|
{ name: '湿度', data: ambientHumidityData, unit: '%', baseValue: 60, fluctuation: 5, color: '#91cc75' }
|
]);
|
// 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);
|
|
}
|
|
});
|
</script>
|
|
<style scoped>
|
.device-detail-container {
|
padding: 16px;
|
background: #f0f2f5;
|
}
|
|
.device-image-container {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
height: 330px; /* 根据需要调整高度 */
|
overflow: hidden;
|
}
|
|
.device-image {
|
max-width: 100%;
|
max-height: 100%;
|
object-fit: contain;
|
}
|
</style>
|