<template> <div class="iot-data-left"> <div class="left-box"> <titleBgBox class="left-title-bg-box" title="基础情况"> <div class="base-data"> <div class="base-box base-data-device" :class="{ 'base-data-active': deviceStatus == 'all' }" @click="deviceStatusSelect('all')" > <span class="name">物联设备</span> <span class="num">{{ basicsInfo.totalDevices }}</span> </div> <div class="base-box base-data-online" :class="{ 'base-data-active': deviceStatus == 'online' }" @click="deviceStatusSelect('online')" > <span class="name">在线数</span> <span class="num">{{ basicsInfo.onlineDevices }}</span> </div> <div class="base-box base-data-unline" :class="{ 'base-data-active': deviceStatus == 'unline' }" @click="deviceStatusSelect('unline')" > <span class="name">离线数</span> <span class="num">{{ basicsInfo.offlineDevices }}</span> </div> <div class="base-box base-data-ratio"> <span class="name">在线率</span> <span class="num">{{ basicsInfo.onlineRate }}</span> </div> </div> </titleBgBox> <titleBgBox class="left-title-bg-box" title="设备类型"> <!-- 头部色彩比例块 --> <colorDiv class="color-box" :data="deviceTypeArr" :colorData="equipmentColor" ></colorDiv> <div class="device-type"> <div class="device-type-item" v-for="(item, index) in deviceTypeArr" :key="index" @click="selectCurrentKey(item)" > <div class="icon-label" :style="{ backgroundColor: equipmentColor[index % deviceTypeArr.length], }" ></div> <span class="name" :style="{ color: selectDeviceType.includes(item.monitorScene) ? '#FFD041' : '', }" >{{ item.monitorScene }}</span > <span class="num" :style="{ color: selectDeviceType.includes(item.monitorScene) ? '#FFC85A' : '', }" >{{ item.numRatio + '%' }}</span > </div> </div> </titleBgBox> <titleBgBox class="left-title-bg-box" title="设备分布"> <div class="device-distribute"> <div class="device-distribute-item" v-for="(item, index) in deviceDistrubuteArr" :key="index" > <span class="name">{{ item.name }}</span> <span class="num">{{ item.num }}</span ><span class="num1">个</span> <el-progress :percentage="getCount(deviceDistrubuteArr, item.num)" :show-text="false" /> </div> </div> </titleBgBox> </div> </div> </template> <script setup> import { onMounted, reactive, ref, computed } from "vue"; import titleBgBox from "./titleBgBox.vue"; import colorDiv from "@/components/ColorDiv.vue"; import { QueryBasicsInfo, QueryListEquipment, QueryTrendsOnline, } from "../../../service/iotService"; //设备类型统计数据 const equipmentData = ref([]); const equipmentColor = ref([ "#549bf1", "#67d470", "#bcbf5c", "#0daee3", "#3182ea", "#aa8a6e", "#5a70bc", " #b2dfff", "#5cabbf", "#2cecbc", ]); //基本情况obj const basicsInfo = reactive({ totalDevices: "", onlineDevices: "", offlineDevices: "", unregisterDevices: "", onlineRate: "", }); //设备分类当前项选中 const selectDeviceType = ref([]); //设备在线状态选中 const deviceStatus = ref(null); const getCount = (totalArr, num) => { const total = totalArr .map((item) => item.num) .reduce(function (prev, curr) { return prev + curr; }); console.log(total); return (num / total) * 100; }; const getBasicsInfo = () => { QueryBasicsInfo().then((res) => { if (res.data.code == "200") { basicsInfo.totalDevices = res.data.data.totalDevices; basicsInfo.onlineDevices = res.data.data.onlineDevices; basicsInfo.offlineDevices = res.data.data.offlineDevices; basicsInfo.onlineRate = res.data.data.onlineRate; } }); }; //设备类型/设备分布数据 const getListEquipment = () => { QueryListEquipment().then((res) => { if (res.data.code == "200") { const data = res.data.data; const typeObj = {}; data.list.forEach((item) => { if (typeObj[item.monitorScene]) { typeObj[item.monitorScene].num++; //onlineState: 设备状态 0:未激活;1:在线;2:离线 } else { typeObj[item.monitorScene] = { monitorScene: item.monitorScene, //监管场景 serialNumber: item.serialNumber, district: item.district, //分布区域 num: 1, onlineNum: 0, unlineNum: 0, total: data.total, }; } item.onlineState === 1 && typeObj[item.monitorScene].onlineNum++; item.onlineState === 2 && typeObj[item.monitorScene].unlineNum++; }); equipmentData.value = Object.values(typeObj); } }); }; //获取设备分布数据 const deviceDistrubuteArr = computed(() => { const deviceDistruibute = {}; //选择需要获取的字段 const numName = deviceStatus.value == "online" ? "onlineNum" : deviceStatus.value == "unline" ? "unlineNum" : "num"; equipmentData.value.forEach((item) => { if ( selectDeviceType.value.length > 0 && !selectDeviceType.value.includes(item.monitorScene) ) { return; } //统计数量 if (deviceDistruibute[item.district]) { deviceDistruibute[item.district][numName] += item[numName]; } else { deviceDistruibute[item.district] = { name: item.district, num: item[numName], }; } }); return Object.values(deviceDistruibute); }); //获取设备类型数据 const deviceTypeArr = computed(() => { const numName = deviceStatus.value == "online" ? "onlineNum" : deviceStatus.value == "unline" ? "unlineNum" : "num"; const result = equipmentData.value.map((item) => { return { ...item, numRatio: ((item[numName] * 100) / item.total).toFixed(0), }; }); return result; }); //设备类型选中 const selectCurrentKey = (params) => { if (selectDeviceType.value.includes(params.monitorScene)) { selectDeviceType.value = selectDeviceType.value.filter( (item) => item != params.monitorScene ); return; } //暂时只支持单选,如果后续可以多选,将下行代码注释 selectDeviceType.value = []; selectDeviceType.value.push(params.monitorScene); }; //基本情况设备状态选择 const deviceStatusSelect = (status) => { if(deviceStatus.value == status){ deviceStatus.value = null return } deviceStatus.value = status; }; const init = () => { getBasicsInfo(); getListEquipment(); }; onMounted(() => { init(); }); </script> <style scoped lang="scss"> .iot-data-left { box-sizing: border-box; position: fixed; top: 0; left: 0; width: 450px; height: 100vh; font-size: 18px; z-index: 99; padding: 58px 0 44px 25px; background: linear-gradient( 90deg, rgba(0, 17, 50, 0.75), rgba(0, 17, 50, 0.5), rgba(0, 17, 51, 0) ); .left-box { box-sizing: border-box; width: 100%; height: 100%; padding: 15px 25px 15px 25px; background-image: url("@/assets/imgs/IOTImage/left-bg.png"); background-repeat: no-repeat; background-size: 100% 100%; // background-position-x: -220px; .color-box { width: calc(100% - 30px); padding-left: 3px; margin-top: 5px; } .base-data { position: relative; width: 100%; height: 151px; background-image: url("@/assets/imgs/IOTImage/1.png"); background-size: 100% 100%; .base-box { display: flex; flex-direction: column; color: #ffffff; text-align: right; width: 60px; .name { font-size: 14px; color: #cce6ff; } .num { font-size: 18px; font-family: "heitao"; padding-top: 2px; color: #dfecfb; } } .base-data-device { position: absolute; left: 30px; top: 22px; } .base-data-online { position: absolute; left: 30px; bottom: 22px; .num { // color: #ffd041; } } .base-data-active { .num, .name { color: #ffd041; } } .base-data-unline { position: absolute; right: 25px; top: 22px; text-align: left; } .base-data-ratio { position: absolute; right: 25px; bottom: 22px; text-align: left; } } .device-type { display: flex; justify-content: flex-start; flex-wrap: wrap; gap: 0px 19px; padding-bottom: 15px; .device-type-item { display: flex; flex-direction: column; text-align: left; position: relative; color: #ffffff; padding-top: 10px; padding-left: 20px; .icon-label { position: absolute; width: 8px; height: 8px; border-radius: 1px; top: 30%; left: 5px; } .name { font-size: 14px; color: #9bb9dd; min-width: 80px; } .num { color: #dfecfb; font-size: 18px; font-family: "heitao"; } } } .device-distribute { padding-left: 8px; .device-distribute-item { display: flex; align-items: center; margin-bottom: 4px; .name { font-size: 14px; color: #bfd5e0; width: 50px; } .num { font-size: 18px; font-family: "heitao"; padding-left: 15px; color: #c6daeb; width: 30px; } .num1 { font-size: 14px; padding-top: 2px; color: #c6daeb; } :deep(.el-progress) { width: calc(100% - 160px); margin-left: 13px; .el-progress-bar__outer { background-color: rgba(35, 64, 95, 0.51); height: 6px !important; } .el-progress-bar__inner { // background-color: rgba(60, 139, 219, 1); height: 6px; background: linear-gradient( to right, rgba(60, 139, 219, 1), rgba(60, 139, 219, 0.5) ); } } } } .left-title-bg-box { :deep(.title-box) { width: calc(100% - 25px); } } } } </style>