<template>
|
<div class="app-container">
|
<div class="p-5">
|
<!-- 设备健康状态可视化 -->
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
<el-card shadow="hover" class="h-full">
|
<template #header>
|
<div class="card-header">
|
<span>质量健康度评分</span>
|
</div>
|
</template>
|
<!-- 这里将放置健康度分布图表 -->
|
<div ref="chartRef" class="h-400 w-full"></div>
|
</el-card>
|
|
<el-card shadow="hover" class="h-full">
|
<template #header>
|
<div class="card-header">
|
<span>关键指标</span>
|
</div>
|
</template>
|
<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>
|
</el-card>
|
</div>
|
|
<!-- 故障预测与预警 -->
|
<el-card shadow="hover" class="mb-6">
|
<template #header>
|
<div class="card-header">
|
<span>故障预测与预警</span>
|
</div>
|
</template>
|
<div class="grid grid-cols-1 gap-4">
|
<!-- 这里将放置预警表格 -->
|
<el-table
|
:data="warningData"
|
style="width: 100%"
|
:border="true"
|
stripe
|
>
|
<el-table-column prop="name" label="设备名称" />
|
<el-table-column prop="component" label="关键部件" />
|
<el-table-column prop="indicator" label="风险指标" />
|
<el-table-column prop="value" label="当前值" />
|
<el-table-column prop="threshold" label="阈值" />
|
<el-table-column prop="status" label="状态">
|
<template #default="{ row }">
|
<el-tag :type="getStatusTagType(row.status)">
|
{{ row.status }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column prop="maintenanceSuggestion" label="维护建议" />
|
<el-table-column label="操作" width="180">
|
<template #default="{ row }">
|
<el-button link type="primary" @click="handleDetail(row)">详情</el-button>
|
<el-button
|
link
|
type="primary"
|
@click="generateWorkOrder(row)"
|
:disabled="row.maintenanceSuggestion === '暂无建议'"
|
>
|
生成工单
|
</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
</el-card>
|
|
<!-- 备件信息 -->
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
<!-- 设备部件寿命预测 -->
|
<el-card shadow="hover" class="h-500">
|
<template #header>
|
<div class="card-header">
|
<span>设备部件寿命预测</span>
|
</div>
|
</template>
|
<el-table
|
:data="lifePredictionData"
|
style="width: 100%"
|
:border="true"
|
stripe
|
height="410"
|
>
|
<el-table-column prop="deviceName" label="设备名称" />
|
<el-table-column prop="name" label="部件名称" />
|
<el-table-column prop="predictedLife" label="预测寿命 (天)" />
|
<el-table-column prop="remainingDays" label="剩余寿命 (天)" />
|
<el-table-column prop="lifeStatus" label="状态">
|
<template #default="{ row }">
|
<el-tag :type="getLifeStatusTagType(row.remainingDays)">
|
{{ getLifeStatus(row.remainingDays) }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" width="80">
|
<template #default="{ row }">
|
<el-button link type="primary" @click="showLifePredictionDetail(row)">详情</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</el-card>
|
|
<!-- 备件库存与预警 -->
|
<el-card shadow="hover" class="h-500">
|
<template #header>
|
<div class="card-header">
|
<span>备件库存与预警</span>
|
</div>
|
</template>
|
<el-table
|
:data="sparePartData"
|
style="width: 100%"
|
:border="true"
|
stripe
|
height="410"
|
>
|
<el-table-column prop="name" label="备件名称" />
|
<el-table-column prop="currentStock" label="当前库存" />
|
<el-table-column prop="safetyStock" label="安全库存" />
|
<el-table-column prop="predictedDemand" label="预测需求" />
|
<el-table-column prop="stockStatus" label="库存状态">
|
<template #default="{ row }">
|
<el-tag :type="getStockStatusTagType(row.currentStock, row.safetyStock)">
|
{{ getStockStatus(row.currentStock, row.safetyStock) }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" width="80">
|
<template #default="{ row }">
|
<el-button link type="primary" @click="showSparePartDetail(row)">详情</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</el-card>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import { onMounted, ref } from 'vue';
|
import { useRouter } from 'vue-router';
|
import { ElMessage } from 'element-plus';
|
import * as echarts from 'echarts';
|
|
const chartRef = ref<HTMLElement | null>(null);
|
const router = useRouter();
|
|
const healthData = {
|
healthy: 85,
|
warning: 12,
|
critical: 3,
|
maintained: 92,
|
pendingWorkOrders: 5,
|
sparePartWarnings: 2,
|
};
|
|
// 模拟高风险设备数据
|
const warningData = ref([
|
{
|
key: '1',
|
name: 'SMT贴片机',
|
type: 'SMT机器',
|
component: '左3-Head',
|
indicator: '真空压力',
|
value: 32,
|
threshold: 35,
|
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: 28,
|
threshold: 30,
|
status: '低风险',
|
maintenanceSuggestion: '建议检查液压系统密封件',
|
maintenanceType: '检查维护',
|
},
|
]);
|
|
// 模拟备件数据
|
const sparePartData = ref([
|
{
|
key: '1',
|
name: '传送带轴承',
|
currentStock: 10,
|
safetyStock: 15,
|
predictedDemand: 8,
|
},
|
{
|
key: '2',
|
name: '主轴润滑油',
|
currentStock: 2,
|
safetyStock: 3,
|
predictedDemand: 1,
|
},
|
{
|
key: '3',
|
name: '液压系统密封件',
|
currentStock: 20,
|
safetyStock: 25,
|
predictedDemand: 5,
|
},
|
{
|
key: '4',
|
name: '电机碳刷',
|
currentStock: 8,
|
safetyStock: 10,
|
predictedDemand: 2,
|
},
|
{
|
key: '5',
|
name: '喷码机油墨',
|
currentStock: 1,
|
safetyStock: 1,
|
predictedDemand: 1,
|
},
|
{
|
key: '6',
|
name: '钢网清洗液',
|
currentStock: 2,
|
safetyStock: 1,
|
predictedDemand: 1,
|
},
|
{
|
key: '7',
|
name: '十寸精密滤芯',
|
currentStock: 20,
|
safetyStock: 4,
|
predictedDemand: 0,
|
},
|
{
|
key: '8',
|
name: '十寸精密滤芯',
|
currentStock: 20,
|
safetyStock: 4,
|
predictedDemand: 0,
|
},
|
{
|
key: '9',
|
name: '十寸精密滤芯',
|
currentStock: 20,
|
safetyStock: 4,
|
predictedDemand: 0,
|
},
|
{
|
key: '10',
|
name: '十寸精密滤芯',
|
currentStock: 20,
|
safetyStock: 4,
|
predictedDemand: 0,
|
},
|
]);
|
|
const lifePredictionData = ref([
|
{ key: '1', deviceName: 'SMT贴片机', componentName: '传送带', name: '真空发生器', predictedLife: 700, remainingDays: 83 },
|
{ key: '2', deviceName: '包装机', componentName: '传送带', name: '发热丝', predictedLife: 260, remainingDays: 61 },
|
{ key: '3', deviceName: '激光打标机', componentName: '传送带', name: '冷却水', predictedLife: 180, remainingDays: 43 },
|
{ key: '4', deviceName: '钢网清洗机', componentName: '传送带', name: '清洗液', predictedLife: 180, remainingDays: 95 },
|
{ key: '5', deviceName: '钢网清洗机', componentName: '传送带', name: '滤芯', predictedLife: 180, remainingDays: 95 },
|
{ key: '6', deviceName: '端子机', componentName: '传送带', name: '刀片', predictedLife: 180, remainingDays: 112 },
|
{ key: '7', deviceName: '电脑剥线机', componentName: '传送带', name: '刀片', predictedLife: 180, remainingDays: 107 },
|
{ key: '8', deviceName: 'CNC加工中心', componentName: '主轴', name: '刀筒夹', predictedLife: 1100, remainingDays: 130 },
|
{ key: '9', deviceName: '空压机', componentName: '安全阀', name: '安全阀', predictedLife: 365, remainingDays: 130 },
|
{ key: '10', deviceName: '喷码机', componentName: '传送带', name: '墨水', predictedLife: 365, remainingDays: 184 },
|
{ key: '11', deviceName: '注塑机', componentName: '液压系统', name: '液压油', predictedLife: 1100, remainingDays: 395 },
|
{ key: '12', deviceName: '焊接机器人', componentName: '焊枪', name: '烙铁芯', predictedLife: 1000, remainingDays: 512 }
|
]);
|
|
const getStatusTagType = (status) => {
|
switch (status) {
|
case '高风险': return 'danger';
|
case '中风险': return 'warning';
|
case '低风险': return 'primary';
|
default: return 'success';
|
}
|
};
|
|
const getLifeStatus = (remainingDays) => {
|
if (remainingDays <= 90) {
|
return '即将到期';
|
} else if (remainingDays <= 150) {
|
return '中期预警';
|
} else {
|
return '寿命充足';
|
}
|
};
|
|
const getLifeStatusTagType = (remainingDays) => {
|
if (remainingDays <= 90) {
|
return 'warning';
|
} else if (remainingDays <= 150) {
|
return 'primary';
|
} else {
|
return 'success';
|
}
|
};
|
|
const showLifePredictionDetail = (record) => {
|
ElMessage.info(`备件名称: ${record.name}, 预测寿命: ${record.predictedLife}天, 剩余寿命: ${record.remainingDays}天`);
|
};
|
|
const getStockStatus = (currentStock, safetyStock) => {
|
if (currentStock < safetyStock) {
|
return '库存预警';
|
} else {
|
return '库存充足';
|
}
|
};
|
|
const getStockStatusTagType = (currentStock, safetyStock) => {
|
if (currentStock < safetyStock) {
|
return 'warning';
|
} else {
|
return 'success';
|
}
|
};
|
|
const showSparePartDetail = (record) => {
|
ElMessage.info(`备件名称: ${record.name}, 当前库存: ${record.currentStock}, 安全库存: ${record.safetyStock}, 预测需求: ${record.predictedDemand}`);
|
};
|
|
const generateWorkOrder = (record) => {
|
// 工单生成逻辑
|
ElMessage.success(`已为 ${record.name} 生成工单`);
|
};
|
|
const handleDetail = (record) => {
|
router.push({ path: '/ai/detail', query: { deviceId: 15 } });
|
};
|
|
onMounted(() => {
|
if (chartRef.value) {
|
const myChart = echarts.init(chartRef.value);
|
const option = {
|
tooltip: {
|
trigger: 'axis',
|
axisPointer: {
|
type: 'shadow'
|
}
|
},
|
xAxis: {
|
type: 'category',
|
data: ['10分', '9分', '8分', '7分', '6分', '5分', '4分', '3分', '2分', '1分'],
|
},
|
yAxis: {
|
type: 'value',
|
name: '设备数量',
|
minInterval: 1
|
},
|
series: [
|
{
|
name: '设备数量',
|
type: 'bar',
|
barWidth: '60%',
|
data: [
|
{ value: 48, itemStyle: { color: '#52c41a' } },
|
{ value: 53, itemStyle: { color: '#52c41a' } },
|
{ value: 37, itemStyle: { color: '#52c41a' } },
|
{ value: 29, itemStyle: { color: '#52c41a' } },
|
{ value: 21, itemStyle: { color: '#52c41a' } },
|
{ value: 8, itemStyle: { color: '#faad14' } },
|
{ value: 5, itemStyle: { color: '#faad14' } },
|
],
|
label: {
|
show: true,
|
position: 'top',
|
formatter: '{c}台'
|
}
|
}
|
]
|
};
|
myChart.setOption(option);
|
|
window.addEventListener('resize', () => {
|
myChart.resize();
|
});
|
}
|
});
|
</script>
|
|
<style scoped>
|
.app-container {
|
padding: 0;
|
}
|
|
.h-500 {
|
height: 500px;
|
}
|
|
.card-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
}
|
|
.grid {
|
display: grid;
|
}
|
|
.grid-cols-1 {
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
}
|
|
.grid-cols-2 {
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
}
|
|
.gap-4 {
|
gap: 1rem;
|
}
|
|
.mb-6 {
|
margin-bottom: 1.5rem;
|
}
|
|
.p-5 {
|
padding: 1.25rem;
|
}
|
|
.w-full {
|
width: 100%;
|
}
|
|
.h-400 {
|
height: 400px;
|
}
|
|
.bg-blue-50 {
|
background-color: #eff6ff;
|
}
|
|
.bg-yellow-50 {
|
background-color: #fffbeb;
|
}
|
|
.bg-red-50 {
|
background-color: #fef2f2;
|
}
|
|
.bg-green-50 {
|
background-color: #f0fdf4;
|
}
|
|
.rounded {
|
border-radius: 0.25rem;
|
}
|
|
.text-sm {
|
font-size: 0.875rem;
|
}
|
|
.text-xl {
|
font-size: 1.25rem;
|
}
|
|
.font-bold {
|
font-weight: 700;
|
}
|
|
.text-gray-600 {
|
color: #4b5563;
|
}
|
|
@media (min-width: 768px) {
|
.md\:grid-cols-2 {
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
}
|
}
|
</style>
|