iot-ui-app/pages/tabbar/dashboard.vue

458 lines
9.9 KiB
Vue

<template>
<view class="container">
<!-- 设备统计卡片 -->
<view class="stat-card">
<view class="card-header">
<view class="header-left">
<u-icon name="grid" size="34" color="#666"></u-icon>
<text class="header-title">设备统计</text>
</view>
<view class="header-right" @click="viewDeviceDetails">
<text class="detail-text">查看详情</text>
<u-icon name="arrow-right" size="28" color="#999"></u-icon>
</view>
</view>
<!-- 设备数量统计 -->
<view class="stat-row">
<view class="stat-item">
<text class="stat-value blue">{{deviceInfo.deviceNum || 0}}</text>
<text class="stat-label">设备数量</text>
</view>
<view class="stat-item">
<text class="stat-value blue">{{deviceInfo.deviceOnlineNum || 0}}</text>
<text class="stat-label">在线数</text>
</view>
<view class="stat-item">
<text class="stat-value blue">{{deviceInfo.deviceOfflineNum || 0}}</text>
<text class="stat-label">离线数</text>
</view>
</view>
<!-- 设备消息量统计 -->
<view class="stat-row">
<view class="stat-item">
<text class="stat-value blue">{{deviceInfo.todayMessageNum || 0}}</text>
<text class="stat-label">今日设备消息量</text>
</view>
<view class="stat-item">
<text class="stat-value blue">{{deviceInfo.thisMonthMessageNum || 0}}</text>
<text class="stat-label">当月设备消息量</text>
</view>
</view>
</view>
<!-- 告警统计卡片 -->
<view class="stat-card">
<view class="card-header">
<view class="header-left">
<u-icon name="bell" size="34" color="#666"></u-icon>
<text class="header-title">告警统计</text>
</view>
<view class="header-right" @click="viewAlarmDetails">
<text class="detail-text">查看详情</text>
<u-icon name="arrow-right" size="28" color="#999"></u-icon>
</view>
</view>
<!-- 告警数量统计 -->
<view class="stat-row">
<view class="stat-item">
<text class="stat-value red">{{alarmInfo.todayMessageNum || 0}}</text>
<text class="stat-label">今日告警数</text>
</view>
<view class="stat-item">
<text class="stat-value red">{{alarmInfo.thisMonthMessageNum || 0}}</text>
<text class="stat-label">当月告警数</text>
</view>
</view>
<!-- 最新告警列表 -->
<view class="alarm-list">
<view class="alarm-list-title">最新告警列表</view>
<!-- 告警项 -->
<u-empty v-if="alarmList.length == 0" margin-top="50" text="告警列表为空" mode="list"></u-empty>
<view v-else class="alarm-item" v-for="(item, index) in alarmList" :key="index">
<view class="alarm-info">
<text class="alarm-name">{{ item.alarmName }}</text>
<text class="alarm-status">{{ item.state.text }}</text>
</view>
<view class="alarm-detail">
<view :class="['alarm-level', 'alarm-level-' + item.level]">{{ getAlarmName(item.level) }}</view>
<text class="alarm-time">{{$u.timeFormat(item.time, 'yyyy-mm-dd hh:MM:ss')}}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
deviceInfo:{
deviceNum:0,
deviceOnlineNum:0,
deviceOfflineNum:0,
todayMessageNum:0,
thisMonthMessageNum:0,
},
alarmInfo:{
todayMessageNum:0,
thisMonthMessageNum:0,
},
alarmLevelList:[
{
level: 1,
title: "超紧急"
},
{
level: 2,
title: "紧急"
},
{
level: 3,
title: "严重"
},
{
level: 4,
title: "一般"
},
{
level: 5,
title: "提醒"
}
],
alarmList: []
};
},
onLoad() {
this.getAlarmLevelList();
},
onShow() {
this.getDeviceInfo();
this.getDeviceMessageCount();
this.getAlarmMessageCount();
this.getAlarmList();
},
methods: {
getAlarmName(level) {
const foundItem = this.alarmLevelList.find(item => item.level === level);
return foundItem ? foundItem.title : '';
},
getAlarmLevelList(){
this.$api.iotsApi.getAlarmLevelList().then(res => {
if(res.status == 200){
this.alarmLevelList = res.result.levels || [];
}else{
this.$u.toast(res.message);
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
},
getDeviceInfo(){
this.getDeviceCount('deviceNum',{})
this.getDeviceCount('deviceOnlineNum',{'terms[0].column':'state','terms[0].value':'online'})
this.getDeviceCount('deviceOfflineNum',{'terms[0].column':'state','terms[0].value':'offline'})
},
viewDeviceDetails() {
uni.switchTab({
url: '/pages/tabbar/device'
});
},
viewAlarmDetails() {
uni.navigateTo({
url: '/pages/alarm/statistics-detail'
});
},
getDeviceCount(type,params){
this.$api.iotsApi.getDeviceInstanceCount(params).then(res => {
if(res.status == 200){
this.deviceInfo[type] = res.result;
}else{
this.$u.toast(res.message);
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
},
getDeviceMessageCount(){
this.$api.getDashboardSelect([
{
"dashboard": "device",
"object": "message",
"measurement": "quantity",
"dimension": "agg",
"group": "oneday",
"params": {
"time": "1d",
"format": "yyyy-MM-dd",
"from": "now-1d"
}
},
{
"dashboard": "device",
"object": "message",
"measurement": "quantity",
"dimension": "agg",
"group": "thisMonth",
"params": {
"time": "1M",
"format": "yyyy-MM",
"limit": 1,
"from": "now-1M"
}
}
]).then(res => {
if(res.status == 200){
if(res.result && Array.isArray(res.result)){
res.result.forEach((item)=>{
if(item.group === 'oneday'){
this.deviceInfo.todayMessageNum = item.data.value || 0;
}else if(item.group === 'thisMonth'){
this.deviceInfo.thisMonthMessageNum = item.data.value || 0;
}
})
}
}else{
this.$u.toast(res.message);
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
},
getAlarmMessageCount(){
this.$api.getDashboardSelect([
{
"dashboard": "alarm",
"object": "record",
"measurement": "trend",
"dimension": "agg",
"group": "today",
"params": {
"time": "1d",
"format": "HH:mm:ss",
"from": "2025-04-24 00:00:00",
"to": "now"
}
},
{
"dashboard": "alarm",
"object": "record",
"measurement": "trend",
"dimension": "agg",
"group": "thisMonth",
"params": {
"time": "1M",
"format": "yyyy-MM",
"limit": 1,
"from": "now-1M"
}
}
]).then(res => {
if(res.status == 200){
if(res.result && Array.isArray(res.result)){
res.result.forEach((item)=>{
if(item.group === 'today'){
this.alarmInfo.todayMessageNum = item.data.value || 0;
}else if(item.group === 'thisMonth'){
this.alarmInfo.thisMonthMessageNum = item.data.value || 0;
}
})
}
}else{
this.$u.toast(res.message);
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
},
getAlarmList(){
this.$api.iotsApi.getAlarmList({
"pageIndex": 0,
"pageSize": 5,
"sorts": [
{
"name": "alarmTime",
"order": "desc"
}
],
"terms": [
{
"terms": [
{
"type": "and",
"value": "%warning%",
"termType": "like",
"column": "state"
}
]
}
]
}).then(res => {
if(res.status == 200){
this.alarmList = res.result.data || [];
}else{
this.$u.toast(res.message);
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
},
}
}
</script>
<style lang="scss" scoped>
.container {
background-color: #f5f5f5;
padding: 20rpx;
min-height: 100%;
}
.stat-card {
background-color: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 2px solid #F9F9F9;
.header-left {
display: flex;
align-items: center;
.header-title {
font-size: 32rpx;
font-weight: 500;
margin-left: 10rpx;
color: #333;
}
}
.header-right {
display: flex;
align-items: center;
.detail-text {
font-size: 26rpx;
color: #999;
margin-right: 6rpx;
}
}
}
.stat-row {
display: flex;
justify-content: space-around;
margin-bottom: 20rpx;
padding: 30rpx;
.stat-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
.stat-value {
font-size: 40rpx;
font-weight: bold;
margin-bottom: 10rpx;
&.blue {
color: #2979ff;
}
&.red {
color: #ff5252;
}
}
.stat-label {
font-size: 24rpx;
color: #666;
}
}
}
.alarm-list {
padding: 30rpx;
.alarm-list-title {
font-size: 28rpx;
font-weight: 500;
color: #333;
margin-bottom: 20rpx;
}
.alarm-item {
display: flex;
justify-content: space-between;
padding: 20rpx 0;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.alarm-info {
.alarm-name {
font-size: 28rpx;
color: #333;
margin-bottom: 10rpx;
display: block;
}
.alarm-status {
font-size: 24rpx;
color: #999;
}
}
.alarm-detail {
text-align: right;
.alarm-level {
display: inline-block;
padding: 4rpx 16rpx;
border-radius: 6rpx;
font-size: 22rpx;
margin-bottom: 10rpx;
color: #fff;
&.alarm-level-1 {
background-color: #E50012;
}
&.alarm-level-2 {
background-color: #FF9457;
}
&.alarm-level-3 {
background-color: #FABD47;
}
&.alarm-level-4 {
background-color: #999999;
}
&.alarm-level-5 {
background-color: #BBBBBB;
}
}
.alarm-time {
font-size: 22rpx;
color: #999;
display: block;
}
}
}
}
</style>