<script setup>
|
import { ref, onMounted, onUnmounted, computed } from 'vue';
|
import request from '@/utils/request';
|
|
const devices = ref([]);
|
const activeTab = ref('line1');
|
|
const getMechanicalStatus = () => {
|
return request({
|
url: '/deviceInteraction/mechanicalMonitor/getMechanicalStatus',
|
method: 'post',
|
headers: {
|
'Content-Type': 'application/json'
|
}
|
});
|
};
|
|
const fetchDeviceStatus = async () => {
|
try {
|
const response = await getMechanicalStatus();
|
if (response.code === 200) {
|
const statusData = response.data.mechanicalStatus;
|
devices.value = statusData.map(device => ({
|
...device,
|
showAlarmInfo: false,
|
alarmTime: device.alarmTime ? new Date(device.alarmTime).toLocaleString() : null,
|
disconnectTime: device.disconnectTime ? new Date(device.disconnectTime).toLocaleString() : null
|
}));
|
}
|
} catch (error) {
|
console.error('获取设备状态失败:', error.message || error);
|
}
|
};
|
|
const deviceIcon = (device) => {
|
if (device.status === 2) { // 故障
|
return 'https://img.ixintu.com/download/jpg/202005/641e5e0d96f770c1306d3628fe55c60b_610_605.jpg!ys';
|
} else if (device.status === 1) { // 正常
|
return 'https://bpic.588ku.com/element_origin_min_pic/19/03/07/e3e263faacbe0454e3a0a2a6679033ed.jpg';
|
}
|
return 'https://img.88icon.com/download/jpg/20200720/56c3ba7ed4a120d9824f589330b82a14_512_512.jpg!bg'; // 未连接
|
};
|
|
const toggleAlarmInfo = (device) => {
|
if (device.status !== 1) { // 非正常状态才显示信息
|
device.showAlarmInfo = !device.showAlarmInfo;
|
}
|
};
|
|
// 获取生产线编号(取id的第一位)
|
const getLineId = (deviceId) => parseInt(deviceId.toString().charAt(0));
|
|
// 按生产线分组的设备
|
const groupedDevices = computed(() => {
|
return {
|
line1: devices.value.filter(device => device.deviceId.toString().startsWith('1')),
|
line2: devices.value.filter(device => device.deviceId.toString().startsWith('2'))
|
};
|
});
|
|
const switchTab = (tab) => {
|
activeTab.value = tab;
|
};
|
|
onMounted(() => {
|
fetchDeviceStatus();
|
const timer = setInterval(fetchDeviceStatus, 30000);
|
|
onUnmounted(() => {
|
clearInterval(timer);
|
});
|
});
|
</script>
|
|
<template>
|
<div class="monitoring-container">
|
<h1>九牧设备连接及故障报警监控</h1>
|
<div class="tab-container">
|
<div
|
class="tab-item"
|
:class="{ active: activeTab === 'line1' }"
|
@click="switchTab('line1')"
|
>
|
一线
|
</div>
|
<div
|
class="tab-item"
|
:class="{ active: activeTab === 'line2' }"
|
@click="switchTab('line2')"
|
>
|
二线
|
</div>
|
</div>
|
|
<!-- 添加调试信息 -->
|
<div v-if="devices.length === 0">暂无设备数据</div>
|
<div v-else>
|
<p>总设备数量: {{ devices.length }}</p>
|
<p>一线设备数量: {{ groupedDevices.line1.length }}</p>
|
<p>二线设备数量: {{ groupedDevices.line2.length }}</p>
|
</div>
|
|
<!-- 一线设备 -->
|
<div v-show="activeTab === 'line1'" class="line-section">
|
<h2 class="line-title">一线</h2>
|
<div class="device-grid">
|
<div v-for="device in groupedDevices.line1"
|
:key="device.deviceId"
|
class="device-panel"
|
@click="toggleAlarmInfo(device)">
|
<div class="device-image">
|
<img :src="deviceIcon(device)" alt="设备图标">
|
<p v-if="device.status === 1" class="status-text normal-status">正常</p>
|
<p v-if="device.status === 0" class="status-text error-status disconnected-status">未连接</p>
|
<p v-if="device.status === 2" class="status-text error-status fault-status">故障</p>
|
</div>
|
<div class="device-details">
|
<h3>{{ device.deviceName }}</h3>
|
<div class="status-line" :class="{ 'connected': device.status === 1, 'disconnected': device.status !== 1 }"></div>
|
<div :class="['alarm-indicator', device.status === 2 ? 'alarm' : 'normal']"></div>
|
</div>
|
<div v-if="device.showAlarmInfo">
|
<div v-if="device.status === 2" class="alarm-message">
|
<div class="alarm-title">故障警告</div>
|
<p>📋 故障类型:{{ device.alarmInfo }}</p>
|
<p>⏰ 发生时间:{{ device.alarmTime }}</p>
|
</div>
|
<div v-if="device.status === 0" class="alarm-message">
|
<div class="alarm-title">连接异常</div>
|
<p>📋 故障类型:机器未连接</p>
|
<p>⏰ 断开时间:{{ device.disconnectTime }}</p>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<!-- 二线设备 -->
|
<div v-show="activeTab === 'line2'" class="line-section">
|
<h2 class="line-title">二线</h2>
|
<div class="device-grid">
|
<div v-for="device in groupedDevices.line2" :key="device.id" class="device-panel" @click="toggleAlarmInfo(device)">
|
<div class="device-image">
|
<img :src="deviceIcon(device)" alt="设备图标">
|
<p v-if="device.status === 1" class="status-text normal-status">正常</p>
|
<p v-if="device.status === 0" class="status-text error-status disconnected-status">未连接</p>
|
<p v-if="device.status === 2" class="status-text error-status fault-status">故障</p>
|
</div>
|
<div class="device-details">
|
<h3>{{ device.deviceName }}</h3>
|
<div class="status-line" :class="{ 'connected': device.status === 1, 'disconnected': device.status !== 1 }"></div>
|
<div :class="['alarm-indicator', device.status === 2 ? 'alarm' : 'normal']"></div>
|
</div>
|
<div v-if="device.showAlarmInfo">
|
<div v-if="device.status === 2" class="alarm-message">
|
<div class="alarm-title">故障警告</div>
|
<p>📋 故障类型:{{ device.alarmInfo }}</p>
|
<p>⏰ 发生时间:{{ device.alarmTime }}</p>
|
</div>
|
<div v-if="device.status === 0" class="alarm-message">
|
<div class="alarm-title">连接异常</div>
|
<p>📋 故障类型:机器未连接</p>
|
<p>⏰ 断开时间:{{ device.disconnectTime }}</p>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<style scoped>
|
|
.monitoring-container {
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
padding: 20px;
|
max-width: 1600px;
|
margin: 0 auto;
|
margin-bottom: 60px;
|
}
|
|
h1 {
|
text-align: center;
|
color: #333;
|
margin-bottom: 30px;
|
font-size: 2.2rem;
|
}
|
|
.line-section {
|
margin-bottom: 40px;
|
}
|
|
.line-title {
|
color: #2c3e50;
|
font-size: 1.5rem;
|
margin: 20px 0;
|
padding-left: 10px;
|
border-left: 4px solid #4CAF50;
|
}
|
|
.device-grid {
|
display: grid;
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
gap: 15px;
|
margin-bottom: 20px;
|
}
|
|
.device-panel {
|
background: #fff;
|
border-radius: 8px;
|
padding: 12px;
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
cursor: pointer;
|
transition: transform 0.2s;
|
margin-bottom: 30px;
|
position: relative;
|
}
|
|
.device-panel:hover {
|
transform: translateY(-5px);
|
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);
|
}
|
|
.device-image {
|
text-align: center;
|
margin-bottom: 10px;
|
}
|
|
.device-image img {
|
width: 60px;
|
height: 60px;
|
object-fit: contain;
|
}
|
|
.device-details h3 {
|
font-size: 0.9rem;
|
margin: 5px 0;
|
color: #333;
|
}
|
|
.status-text {
|
position: absolute;
|
bottom: -25px;
|
left: 50%;
|
transform: translateX(-50%);
|
color: white;
|
padding: 3px 8px;
|
border-radius: 3px;
|
font-size: 0.9rem;
|
white-space: nowrap;
|
z-index: 1;
|
}
|
|
/* 正常状态默认隐藏,hover时显示 */
|
.normal-status {
|
background-color: rgba(0, 0, 0, 0.6);
|
opacity: 0;
|
transition: opacity 0.3s ease;
|
}
|
|
.device-panel:hover .normal-status {
|
opacity: 1;
|
}
|
|
/* 异常状态基础样式 */
|
.error-status {
|
opacity: 1;
|
}
|
|
/* 故障状态使用红色背景 */
|
.fault-status {
|
background-color: rgba(255, 0, 0, 0.8);
|
}
|
|
/* 未连接状态使用灰色背景 */
|
.disconnected-status {
|
background-color: rgba(128, 128, 128, 0.8);
|
}
|
|
.status-line {
|
height: 8px;
|
border-radius: 4px;
|
margin: 10px 0;
|
}
|
|
.connected {
|
background-color: #28a745;
|
}
|
|
.disconnected {
|
background-color: #dc3545;
|
}
|
|
.alarm-indicator {
|
width: 25px;
|
height: 25px;
|
border-radius: 50%;
|
margin: 15px auto 0;
|
}
|
|
.normal {
|
background-color: #ccc;
|
}
|
|
.alarm {
|
background-color: #ff0000;
|
animation: blink 1s infinite;
|
}
|
|
@keyframes blink {
|
0% {
|
opacity: 1;
|
}
|
50% {
|
opacity: 0.3;
|
}
|
100% {
|
opacity: 1;
|
}
|
}
|
|
.alarm-message {
|
background-color: #fff2f2;
|
color: #d32f2f;
|
border-radius: 8px;
|
padding: 15px;
|
margin-top: 20px;
|
text-align: left;
|
font-size: 14px;
|
line-height: 1.8;
|
border: 1px solid #ffcdd2;
|
}
|
|
.alarm-message p {
|
margin: 8px 0;
|
font-weight: 500;
|
}
|
|
.alarm-message .alarm-title {
|
font-size: 16px;
|
font-weight: bold;
|
color: #c62828;
|
margin-bottom: 12px;
|
border-bottom: 1px solid #ffcdd2;
|
padding-bottom: 8px;
|
}
|
|
/* 添加标签样式 */
|
.tab-container {
|
display: flex;
|
justify-content: center;
|
margin-bottom: 30px;
|
gap: 20px;
|
}
|
|
.tab-item {
|
padding: 10px 30px;
|
border-radius: 5px;
|
cursor: pointer;
|
background-color: #f5f5f5;
|
transition: all 0.3s ease;
|
}
|
|
.tab-item:hover {
|
background-color: #e0e0e0;
|
}
|
|
.tab-item.active {
|
background-color: #4CAF50;
|
color: white;
|
}
|
</style>
|