修改ws数据处理

main
suixy 1 month ago
parent e7454f4c88
commit 6f2432466d

@ -10,6 +10,8 @@
</div>
</div>
<div class="title">RFID中间件监控平台</div>
<div class="title1">成功率</div>
<div class="title2">告警统计</div>
<div class="topTitle" style="left: 13%">设备数量:</div>
<div class="topTitle" style="left: 37.5%">在线数量:</div>
<div class="topTitle" style="left: 62%">离线数量:</div>
@ -57,12 +59,12 @@
</div>
</vue3ScrollSeamless>
</div>
<div class="center" ref="scrollNodeRef" @mouseenter="hover = true" @mouseleave="mouseleave">
<div class="center" ref="scrollNodeRef" @mouseenter="mouseenter" @mouseleave="mouseleave">
<div v-masonry style="width: 100%; height: 100%" ref="masonryRef">
<TreeItem v-masonry-tile :data="i" v-for="i in centerData" :key="i.id" :wsData="wsData" />
<TreeItem v-masonry-tile :data="i" v-for="i in centerData" :key="i.id" :wsData="wsData" :copy="false" />
</div>
<div v-masonry style="width: 100%; height: 100%">
<TreeItem v-masonry-tile :data="i" v-for="i in centerData" :key="i.id" :wsData="wsData" />
<TreeItem v-masonry-tile :data="i" v-for="i in centerData" :key="i.id" :wsData="wsData" :copy="true" />
</div>
</div>
</div>
@ -73,9 +75,12 @@ import thbg from '@/assets/chart/thbg.png';
import trbg from '@/assets/chart/trbg.png';
import TreeItem from './treeItem.vue';
import { vue3ScrollSeamless } from 'vue3-scroll-seamless';
import { parseTime } from '@/utils/ruoyi.js';
import { getRealtimeStats, getLocationTree, getSuccessRateTrends } from '@/api/rfid/dashboard';
let timer = null;
function findParentsWithLocationType3(arr) {
const result = [];
@ -122,6 +127,13 @@ const timeFun = () => {
};
};
const mouseenter = () => {
hover.value = true;
if (timer) {
clearTimeout(timer);
}
timer = null;
};
const mouseleave = () => {
setTimeout(() => {
hover.value = false;
@ -172,7 +184,9 @@ const MenuItem = defineComponent({
})}
</ElSubMenu>
) : (
<el-menu-item index={`${data.id}`}>{data.locationAlias}</el-menu-item>
<el-menu-item onClick={() => scrollToId(data.id)} index={`${data.id}`}>
{data.locationAlias}
</el-menu-item>
);
}
});
@ -195,6 +209,31 @@ function scrollToBottom(scrollNode, speed = 1) {
requestAnimationFrame(step);
}
const scrollToId = (id) => {
const container = scrollNodeRef.value;
if (!container) return;
const target = container.querySelector(`#tree${id}`);
if (target) {
const containerTop = container.getBoundingClientRect().top;
const targetTop = target.getBoundingClientRect().top;
const scrollOffset = targetTop - containerTop + container.scrollTop;
container.scrollTo({
top: scrollOffset,
behavior: 'smooth' //
});
hover.value = true;
if (timer) {
clearTimeout(timer);
}
timer = null;
timer = setTimeout(() => {
hover.value = false;
}, 5000);
}
};
const getData = () => {
getSuccessRateTrends().then((res) => {
successRateRef.value.setData({
@ -233,7 +272,14 @@ const getData = () => {
},
xAxis: {
type: 'category',
data: res.data.map((item) => item.timePoint)
data: res.data.map((item) => item.timePoint),
axisLabel: {
show: true,
color: '#7ae7f8'
},
axisLine: {
show: false
}
},
grid: {
top: 30,
@ -242,10 +288,18 @@ const getData = () => {
bottom: 30
},
yAxis: {
name: '%',
nameTextStyle: {
color: '#7ae7f8'
},
splitLine: {
show: false
},
type: 'value'
type: 'value',
axisLabel: {
show: true,
color: '#7ae7f8'
}
},
series: [
{
@ -284,6 +338,7 @@ const getData = () => {
getLocationTree().then((res) => {
treeData.value = res.data;
centerData.value = findParentsWithLocationType3(res.data);
console.log(centerData.value);
nextTick(() => {
scrollToBottom(scrollNodeRef.value, 2);
});
@ -333,11 +388,37 @@ const getSocket = () => {
const socket = new WebSocket('ws://192.168.0.16:7181/ws');
socket.addEventListener('open', () => {
// console.log(' WebSocket ');
console.log('✅ WebSocket 连接成功');
});
socket.addEventListener('message', (event) => {
// console.log(JSON.parse(event.data));
let data = JSON.parse(event.data);
console.log(data);
if (data?.deviceStatus === '1') {
wsData.value[data.deviceId] = data;
}
if (data?.deviceStatus === '2' && data?.alarmFlag === '1') {
tableData.value.push({
alarmTime: parseTime(data.recordTime),
deviceName: wsData.value[data.deviceId]?.epcStr.trimStart() || '',
location: centerData.value.flatMap((item) => item.children || []).find((child) => child.deviceId === targetDeviceId)?.locationAlias || '',
alarmAction: '未获取到标签'
});
if (data.dataType === '2') {
wsData.value[data.deviceId] = data;
}
}
if (data?.deviceStatus === '3' && data?.alarmFlag === '1') {
tableData.value.push({
alarmTime: parseTime(data.recordTime),
deviceName: wsData.value[data.deviceId]?.epcStr.trimStart() || '',
location: centerData.value.flatMap((item) => item.children || []).find((child) => child.deviceId === targetDeviceId)?.locationAlias || '',
alarmAction: '链接断开'
});
if (data.dataType === '2') {
wsData.value[data.deviceId] = data;
}
}
});
socket.addEventListener('close', () => {
@ -353,7 +434,6 @@ const getSocket = () => {
onMounted(() => {
getData();
getSocket();
wsData.value[data.deviceId] = data;
});
</script>
<style scoped lang="less">
@ -434,6 +514,28 @@ onMounted(() => {
color: transparent;
}
.title1 {
position: absolute;
top: 27.9%;
left: 76.5%;
transform: translateY(-50%);
font-size: 1vw;
font-weight: 700;
letter-spacing: 0.2vw;
color: #7ae7f8;
}
.title2 {
position: absolute;
top: 61.5%;
left: 76.5%;
transform: translateY(-50%);
font-size: 1vw;
font-weight: 700;
letter-spacing: 0.2vw;
color: #7ae7f8;
}
.topTitle {
position: absolute;
top: 16.7%;

@ -2,19 +2,25 @@
<div class="node" ref="container">
<!-- 主节点 -->
<div class="node-main" ref="nodeMain">
<div class="node-icon" ref="nodeIcon"></div>
<div class="node-icon" ref="nodeIcon" :id="copy ? '' : `tree${data.id}`"></div>
<div class="node-title">{{ data.locationAlias }}</div>
</div>
<!-- 子节点 -->
<div class="children">
<div v-for="(child, index) in data.children" :key="index" class="child-item" :ref="(el) => (childRefs[index] = el)">
<div class="child-icon"></div>
<div
:id="copy ? '' : `tree${child.id}`"
v-for="(child, index) in data.children"
:key="index"
:class="wsData[data.deviceId]?.epcStr ? 'child-item' : 'child-item1'"
:ref="(el) => (childRefs[index] = el)"
>
<div :class="wsData[data.deviceId]?.epcStr ? 'child-icon' : 'child-icon1'"></div>
<div class="child-info">
<div class="child-name">
工位名称: <span style="font-size: 12px">{{ child.locationAlias }}</span>
</div>
<div class="child-code">编码{{ wsData[data.deviceId]?.epcStr?.trimStart()}}</div>
<div class="child-code">编码{{ wsData[data.deviceId]?.epcStr?.trimStart() }}</div>
<div class="child-time">时间{{ parseTime(wsData[data.deviceId]?.recordTime) }}</div>
</div>
</div>
@ -29,7 +35,7 @@
<script setup>
import { ref, reactive, onMounted, nextTick, watchEffect } from 'vue';
import {parseTime} from '@/utils/ruoyi.js'
import { parseTime } from '@/utils/ruoyi.js';
const props = defineProps({
data: {
@ -40,6 +46,10 @@ const props = defineProps({
type: Object,
required: true
},
copy: {
type: Boolean,
default: false
}
});
const container = ref(null);
@ -152,7 +162,21 @@ watchEffect(() => {
overflow: hidden;
}
.child-item:last-child {
.child-item1 {
background: rgba(0, 255, 180, 0.15);
border-radius: 6px;
margin-bottom: 8px;
position: relative;
height: 75px;
margin-left: 20px;
background-image: url('@/assets/chart/430786e7de542172c80b3882e4ea8dbd.png');
background-size: 100% 100%;
background-repeat: no-repeat;
overflow: hidden;
}
.child-item:last-child,
.child-item1:last-child {
margin-bottom: 0;
}
@ -161,7 +185,21 @@ watchEffect(() => {
height: 50px;
border-radius: 4px;
margin-right: 8px;
background-image: url('@/assets/chart/e06ce08b1a179471f9600f1d53ec3781.png');
background-image: url('@/assets/chart/device1.png');
background-size: 100% 100%;
background-repeat: no-repeat;
position: absolute;
top: 50%;
left: 12px;
transform: translateY(-50%);
}
.child-icon1 {
width: 50px;
height: 50px;
border-radius: 4px;
margin-right: 8px;
background-image: url('@/assets/chart/device2.png');
background-size: 100% 100%;
background-repeat: no-repeat;
position: absolute;

@ -37,7 +37,7 @@
</el-card>
</el-col>
<el-col :xs="12" :sm="12" :md="6">
<el-card shadow="hover" class="shortcut-card" @click="$router.push('/rfid/dashboard')">
<el-card shadow="hover" class="shortcut-card" @click="$router.push('/chart1')">
<div class="shortcut-inner">
<el-icon :size="36" color="#f56c6c"><DataAnalysis /></el-icon>
<span>监控看板</span>
@ -90,7 +90,7 @@
<el-table-column prop="locationAlias" label="位置名称" min-width="120" />
<el-table-column prop="locationType" label="位置类型" width="100" align="center">
<template #default="{ row }">
<dict-tag :options="location_type" :value="row.locationType"/>
<dict-tag :options="location_type" :value="row.locationType" />
</template>
</el-table-column>
<el-table-column prop="childCount" label="子位置数" width="100" align="center" />
@ -124,10 +124,10 @@
<script setup name="Index" lang="ts">
import { onMounted, ref, getCurrentInstance, toRefs, type ComponentInternalInstance, onUnmounted } from 'vue';
import { getHomeStats, type HomeStatsVO } from "@/api/rfid/statistics";
import { getHomeStats, type HomeStatsVO } from '@/api/rfid/statistics';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { location_type } = toRefs<any>(proxy?.useDict("location_type"));
const { location_type } = toRefs<any>(proxy?.useDict('location_type'));
const stats = ref<Partial<HomeStatsVO>>({});
const currentTime = ref('');
@ -136,8 +136,12 @@ let timer: number | null = null;
const updateTime = () => {
const now = new Date();
currentTime.value = now.toLocaleString('zh-CN', {
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit'
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
};
@ -146,7 +150,7 @@ const loadData = async () => {
const res = await getHomeStats();
stats.value = res.data;
} catch (e) {
console.error("获取首页数据失败", e);
console.error('获取首页数据失败', e);
}
};
@ -184,7 +188,7 @@ onUnmounted(() => {
margin: 0 0 8px 0;
}
p {
color: rgba(255,255,255,0.85);
color: rgba(255, 255, 255, 0.85);
font-size: 14px;
margin: 0;
}
@ -197,7 +201,7 @@ onUnmounted(() => {
transition: all 0.3s;
&:hover {
transform: translateY(-4px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
:deep(.el-card__body) {
padding: 24px 16px;
@ -230,9 +234,18 @@ onUnmounted(() => {
font-size: 20px;
font-weight: 600;
color: #303133;
&.text-primary { color: #409eff; }
&.text-success { color: #67c23a; }
&.text-warning { color: #e6a23c; }
&.text-primary {
color: #409eff;
}
&.text-success {
color: #67c23a;
}
&.text-warning {
color: #e6a23c;
}
}
}
:deep(.el-divider) {

Loading…
Cancel
Save