Files
admin-vben5/apps/web-antd/src/views/property/energyManagement/electricEnergy/elctricitySituation/index.vue

290 lines
6.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { useNotifyStore } from '#/store';
import { useAccessStore } from '@vben/stores';
import FloorTree from '../components/floor-tree.vue';
import { BackTop, message, Spin } from 'ant-design-vue';
import { Page, VbenCountToAnimator } from '@vben/common-ui';
import { ref, onMounted, onBeforeUnmount, reactive, watch } from 'vue';
import { currentReading } from '#/api/property/energyManagement/meterInfo';
const notifyStore = useNotifyStore();
const readingData = ref<any>({});
const readingTime = ref('');
const readingLoading = ref(false);
onMounted(() => {
notifyStore.startListeningMessage();
// 监听sseList的变化
watch(
() => notifyStore.sseList,
(val) => {
const latestMessage = val[val.length - 1];
try {
// 尝试解析消息内容
const parsedMessage = JSON.parse(latestMessage);
console.log('收到sse消息:', parsedMessage);
if (parsedMessage.type === 'meter') {
// 根据消息内容执行相应操作
handleSSEMessage(parsedMessage);
}
} catch (e) {
console.log('收到非JSON消息:', latestMessage);
// 处理非JSON格式消息
}
},
{ deep: true },
);
});
function handleSSEMessage(data: any) {
if (data.data.length === 0) {
message.warn('当前楼层暂无电表!');
}
readingData.value = data.data;
readingTime.value = data.readingTime;
readingLoading.value = false;
}
onBeforeUnmount(() => {
// 关闭页面,发送请求停止心跳
currentReading({ meterType: 0, floorId: 0 });
});
async function handleSelectFloor(selectedKeys, info) {
if (typeof selectedKeys[0] === 'undefined') {
return;
}
readingLoading.value = true;
await currentReading({
meterType: 1,
floorId: selectedKeys[0],
});
}
function targetFn() {
return document.getElementById('right-panel');
}
</script>
<template>
<Page :auto-content-height="true">
<div class="flex h-full gap-[8px]">
<FloorTree
:isMeter="false"
class="w-[260px]"
@select="handleSelectFloor"
></FloorTree>
<div class="flex-1" id="right-panel">
<Spin :spinning="readingLoading" size="large" style="height: 100px">
<div class="cards-container">
<div v-for="item in readingData" class="meterInfo-card">
<h2>
{{ item.meterName }}
</h2>
<div class="meterInfo-reading">
<p>
<VbenCountToAnimator
:end-val="item.initReading"
:decimals="2"
prefix=""
/>
</p>
<div></div>
</div>
<div class="meterInfo-list">
<ul>
<li>
<span>采集时间</span>
<span>{{ readingTime }}</span>
</li>
<li>
<span>设备位置</span>
<span>{{ item.installLocation }}</span>
</li>
</ul>
</div>
<div class="button-get-plan">
<a
v-if="item.communicationState !== 0"
style="background: #6bb1e3"
>
<span>在线</span>
</a>
<a v-else style="background: orange">
<span>离线</span>
</a>
</div>
</div>
</div>
</Spin>
</div>
<BackTop class="back-to-top" :target="targetFn"></BackTop>
</div>
</Page>
</template>
<style scoped>
/* 右侧内容区域样式 */
.flex-1 {
flex: 1;
overflow-y: auto; /* 添加垂直滚动条 */
padding: 10px;
height: 100%; /* 确保高度占满父容器 */
box-sizing: border-box; /* 包括padding在高度计算中 */
}
/* 卡片容器样式 */
.cards-container {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
gap: 20px; /* 使用gap替代margin控制间距 */
}
.meterInfo-card {
background: #fff;
width: 15rem;
padding-left: 2rem;
padding-right: 2rem;
padding-top: 10px;
padding-bottom: 20px;
border-radius: 10px;
border-bottom: 4px solid #87ceeb;
box-shadow: 0 6px 30px rgba(173, 216, 230, 0.3);
font-family: 'Poppins', sans-serif;
height: 270px;
margin: 0 5px 20px 5px;
}
.meterInfo-card h2 {
margin-bottom: 15px;
font-size: 27px;
color: #5faee3;
font-weight: 600;
}
.meterInfo-card h2 span {
display: block;
margin-top: -4px;
color: #7eb8da;
font-size: 12px;
font-weight: 400;
}
.meterInfo-reading {
position: relative;
background: #f0f8ff;
width: 14.46rem;
margin-left: -0.65rem;
padding: 0.2rem 1.2rem;
border-radius: 5px 0 0 5px;
}
.meterInfo-reading p {
margin: 0;
padding-top: 0.4rem;
display: flex;
font-size: 1.9rem;
font-weight: 500;
color: #4a8cbb;
}
.meterInfo-reading p:before {
content: '';
margin-right: 5px;
font-size: 15px;
font-weight: 300;
}
.meterInfo-reading p:after {
content: '/ KW.H';
margin-left: 5px;
font-size: 15px;
font-weight: 300;
}
.meterInfo-reading div {
position: absolute;
bottom: -23px;
right: 0px;
width: 0;
height: 0;
border-top: 13px solid #87ceeb;
border-bottom: 10px solid transparent;
border-right: 13px solid transparent;
z-index: 1;
}
.meterInfo-list {
margin-top: 16px;
}
.meterInfo-list ul {
padding: 0;
font-size: 14px;
}
.meterInfo-list ul li {
color: #5a7d9a;
list-style: none;
margin-bottom: 0.2rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.meterInfo-list ul li svg {
width: 0.9rem;
fill: currentColor;
}
.meterInfo-list ul li span {
font-weight: 300;
white-space: nowrap;
}
.button-get-plan {
display: flex;
justify-content: center;
margin-top: 1.2rem;
}
.button-get-plan a {
display: flex;
justify-content: center;
align-items: center;
color: #fff;
padding: 10px 15px;
border-radius: 5px;
text-decoration: none;
font-size: 0.8rem;
letter-spacing: 0.05rem;
font-weight: 500;
transition: all 0.3s ease;
}
.button-get-plan a:hover {
transform: translateY(-3%);
box-shadow: 0 3px 10px rgba(123, 180, 220, 0.6); /* 浅蓝色阴影 */
background: #5fa0d0; /* 悬停时略深的蓝色 */
}
.button-get-plan .svg-rocket {
margin-right: 10px;
width: 0.9rem;
fill: currentColor;
}
.back-to-top {
width: 50px;
height: 50px;
}
/* 返回顶部按钮 */
.back-to-top:hover {
background-color: #6bb1e3;
transform: translateY(-5px);
}
</style>