|
@@ -0,0 +1,364 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import { onMounted, ref, useTemplateRef, watch } from 'vue';
|
|
|
+
|
|
|
+import LineChart from '@/components/LineChart.vue';
|
|
|
+import SvgIcon from '@/components/SvgIcon.vue';
|
|
|
+
|
|
|
+import monitoringScoring from '@/assets/img/monitoring-scoring.png';
|
|
|
+
|
|
|
+import HumitureCurve from './HumitureCurve.vue';
|
|
|
+import SetTempHumidityModal from './SetTempHumidityModal.vue';
|
|
|
+
|
|
|
+import type { MonitoringPointData, RegionsPointsItem } from '@/types';
|
|
|
+
|
|
|
+interface Props {
|
|
|
+ monitorData: RegionsPointsItem[];
|
|
|
+ monitoringPointData: MonitoringPointData[];
|
|
|
+}
|
|
|
+const humitureCurveRef = useTemplateRef('humitureCurve');
|
|
|
+const props = defineProps<Props>();
|
|
|
+const monitoringId = ref<number>();
|
|
|
+const checkedList = ref<number[]>([3, 2, 1, -1]);
|
|
|
+const monitoringDataOpen = ref<boolean>(false);
|
|
|
+const monitoringIds = ref<number[]>([]);
|
|
|
+const monitoringPointList = ref<MonitoringPointData[]>([]);
|
|
|
+const standards = ref<number>(0);
|
|
|
+const avgTemperature = ref<string>();
|
|
|
+const avgHumidity = ref<string>();
|
|
|
+const outSideTemperature = ref<string>();
|
|
|
+const outSideHumidity = ref<string>();
|
|
|
+const monitorOptions = ref([
|
|
|
+ {
|
|
|
+ label: '超标',
|
|
|
+ value: 3,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '预警',
|
|
|
+ value: 2,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '正常',
|
|
|
+ value: 1,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '离线',
|
|
|
+ value: -1,
|
|
|
+ },
|
|
|
+]);
|
|
|
+const activeMonitoringType = ref<number>(-1);
|
|
|
+const handleTabClick = () => {};
|
|
|
+const historicalDataClick = (data: MonitoringPointData) => {
|
|
|
+ monitoringId.value = data.id;
|
|
|
+ monitoringDataOpen.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+// 仅显示最后一级内容
|
|
|
+const displayLastLabel = ({ labels }: { labels: string[] }) => {
|
|
|
+ return labels[labels.length - 1];
|
|
|
+};
|
|
|
+
|
|
|
+const setClick = () => {
|
|
|
+ humitureCurveRef.value?.getPointTimeSeriesList();
|
|
|
+};
|
|
|
+
|
|
|
+const switchMonitoringList = () => {
|
|
|
+ if (activeMonitoringType.value === -1) {
|
|
|
+ monitoringPointList.value = props.monitoringPointData.filter((item) => checkedList.value.includes(item.status));
|
|
|
+ } else {
|
|
|
+ props.monitorData.forEach((item) => {
|
|
|
+ if (item.id === activeMonitoringType.value) {
|
|
|
+ monitoringPointList.value = item.points.filter((item) => checkedList.value.includes(item.status));
|
|
|
+ avgTemperature.value = item.avgTemperature;
|
|
|
+ avgHumidity.value = item.avgHumidity;
|
|
|
+ outSideTemperature.value = item.outSideTemperature;
|
|
|
+ outSideHumidity.value = item.outSideHumidity;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => activeMonitoringType.value,
|
|
|
+ (count) => {
|
|
|
+ if (count) {
|
|
|
+ switchMonitoringList();
|
|
|
+ }
|
|
|
+ },
|
|
|
+);
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => checkedList.value,
|
|
|
+ (count) => {
|
|
|
+ if (count) {
|
|
|
+ switchMonitoringList();
|
|
|
+ }
|
|
|
+ },
|
|
|
+);
|
|
|
+
|
|
|
+const getMonitoringList = () => {
|
|
|
+ activeMonitoringType.value = -1;
|
|
|
+ standards.value = 0;
|
|
|
+ props.monitoringPointData.forEach((item) => {
|
|
|
+ if (item.status === 3) {
|
|
|
+ standards.value++;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ monitoringPointList.value = props.monitoringPointData;
|
|
|
+};
|
|
|
+
|
|
|
+defineExpose({
|
|
|
+ getMonitoringList,
|
|
|
+});
|
|
|
+onMounted(() => {
|
|
|
+ getMonitoringList();
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <div class="monitoring-header">
|
|
|
+ <AFlex justify="space-between">
|
|
|
+ <AFlex align="center">
|
|
|
+ <img class="scoring-img" :src="monitoringScoring" />
|
|
|
+ <div>
|
|
|
+ <AFlex>
|
|
|
+ <div class="scoring-text">当前环境适宜度</div>
|
|
|
+ <AFlex justify="center" align="center" class="scoring-result">优</AFlex>
|
|
|
+ </AFlex>
|
|
|
+ <div class="scoring-statistics">
|
|
|
+ 共 {{ monitoringPointData.length }} 个监测点,<span class="standards-color">{{ standards }}</span>
|
|
|
+ 个温湿度超标
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </AFlex>
|
|
|
+ <AFlex v-show="activeMonitoringType !== -1" justify="flex-end" align="center" class="monitoring-header-right">
|
|
|
+ <AFlex>
|
|
|
+ <AFlex justify="center" align="center" class="icon-background">
|
|
|
+ <SvgIcon class="icon-size" name="temperature" />
|
|
|
+ </AFlex>
|
|
|
+ <div>
|
|
|
+ <div>
|
|
|
+ <span class="degree-value">{{ avgTemperature }}</span
|
|
|
+ ><span>°C</span>
|
|
|
+ </div>
|
|
|
+ <div class="average-text">室内平均温度</div>
|
|
|
+ </div>
|
|
|
+ </AFlex>
|
|
|
+ <AFlex>
|
|
|
+ <AFlex justify="center" align="center" class="icon-background">
|
|
|
+ <SvgIcon class="icon-size" name="humidity" />
|
|
|
+ </AFlex>
|
|
|
+ <div>
|
|
|
+ <div>
|
|
|
+ <span class="degree-value">{{ avgHumidity }}</span
|
|
|
+ ><span>%</span>
|
|
|
+ </div>
|
|
|
+ <div class="average-text">室内平均湿度</div>
|
|
|
+ </div>
|
|
|
+ </AFlex>
|
|
|
+ <div class="dividing-line"></div>
|
|
|
+ <div>
|
|
|
+ <div>
|
|
|
+ <span class="degree-value">{{ outSideTemperature }}</span
|
|
|
+ ><span>°C</span>
|
|
|
+ </div>
|
|
|
+ <div class="average-text text-center">室外温度</div>
|
|
|
+ </div>
|
|
|
+ <div class="monitoring-margin">
|
|
|
+ <div>
|
|
|
+ <span class="degree-value">{{ outSideHumidity }}</span
|
|
|
+ ><span>°C</span>
|
|
|
+ </div>
|
|
|
+ <div class="average-text text-center">室外湿度</div>
|
|
|
+ </div>
|
|
|
+ </AFlex>
|
|
|
+ </AFlex>
|
|
|
+ </div>
|
|
|
+ <ARow>
|
|
|
+ <ACol :span="16">
|
|
|
+ <ATabs
|
|
|
+ class="button-tabs-card"
|
|
|
+ :tab-bar-gutter="18"
|
|
|
+ v-model:active-key="activeMonitoringType"
|
|
|
+ type="card"
|
|
|
+ @tab-click="handleTabClick"
|
|
|
+ tab-position="top"
|
|
|
+ >
|
|
|
+ <ATabPane :key="-1" tab="总览" />
|
|
|
+ <ATabPane v-for="item in monitorData" :key="item.id" :tab="item.regionName" />
|
|
|
+ </ATabs>
|
|
|
+ </ACol>
|
|
|
+ <ACol :span="8">
|
|
|
+ <AFlex justify="flex-end">
|
|
|
+ <ACheckboxGroup style="margin-top: 5px" v-model:value="checkedList" :options="monitorOptions" />
|
|
|
+ </AFlex>
|
|
|
+ </ACol>
|
|
|
+ </ARow>
|
|
|
+ <div class="monitoring-content">
|
|
|
+ <AFlex wrap="wrap" :gap="14">
|
|
|
+ <div v-for="item in monitoringPointList" :key="item.id">
|
|
|
+ <LineChart :data="item" :icon-show="false" @historicalDataClick="historicalDataClick" />
|
|
|
+ </div>
|
|
|
+ </AFlex>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <AModal v-model:open="monitoringDataOpen" :footer="null" width="920px" :mask-closable="false" :keyboard="false">
|
|
|
+ <template #title>
|
|
|
+ <AFlex>
|
|
|
+ <ACascader
|
|
|
+ class="equipment-group"
|
|
|
+ v-model:value="monitoringIds"
|
|
|
+ :field-names="{ label: 'name', value: 'id', children: 'points' }"
|
|
|
+ :options="monitorData"
|
|
|
+ :placeholder="$t('common.plzSelect')"
|
|
|
+ change-on-select
|
|
|
+ :display-render="displayLastLabel"
|
|
|
+ />
|
|
|
+
|
|
|
+ <SetTempHumidityModal
|
|
|
+ :monitoring-id="monitoringId"
|
|
|
+ :monitoring-data="monitoringPointData"
|
|
|
+ @setClick="setClick"
|
|
|
+ />
|
|
|
+ </AFlex>
|
|
|
+ </template>
|
|
|
+ <HumitureCurve
|
|
|
+ ref="humitureCurve"
|
|
|
+ :monitoring-id="monitoringId"
|
|
|
+ :monitoring-data="monitoringPointData"
|
|
|
+ :set-show="false"
|
|
|
+ :width="'895px'"
|
|
|
+ :height="'650px'"
|
|
|
+ />
|
|
|
+ </AModal>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.standards-color {
|
|
|
+ color: #f56c6c;
|
|
|
+}
|
|
|
+
|
|
|
+.monitoring-header-right .text-center {
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.monitoring-margin {
|
|
|
+ margin: 0 48px 0 56px;
|
|
|
+}
|
|
|
+
|
|
|
+.dividing-line {
|
|
|
+ width: 1px;
|
|
|
+ height: 64px;
|
|
|
+ margin: 0 48px 0 49px;
|
|
|
+ border: 1px dashed #32bac0;
|
|
|
+}
|
|
|
+
|
|
|
+.average-text {
|
|
|
+ font-size: 14px;
|
|
|
+ font-style: normal;
|
|
|
+ font-weight: 400;
|
|
|
+ line-height: 24px;
|
|
|
+ color: #000;
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+
|
|
|
+.degree-value {
|
|
|
+ font-size: 31px;
|
|
|
+ line-height: 36px;
|
|
|
+ color: #000;
|
|
|
+}
|
|
|
+
|
|
|
+.icon-size {
|
|
|
+ font-size: 28px;
|
|
|
+}
|
|
|
+
|
|
|
+.icon-background {
|
|
|
+ width: 64px;
|
|
|
+ height: 64px;
|
|
|
+ margin-right: 16px;
|
|
|
+ margin-left: 48px;
|
|
|
+ color: #32bac0;
|
|
|
+ background: rgb(50 186 192 / 15%);
|
|
|
+ border-radius: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.monitoring-header-right {
|
|
|
+ width: 854px;
|
|
|
+ background: linear-gradient(270deg, rgb(58 194 110 / 14%) 0%, rgb(255 255 255 / 0%) 100%);
|
|
|
+ border-radius: 0 16px 16px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.scoring-statistics {
|
|
|
+ margin-top: 8px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-style: normal;
|
|
|
+ font-weight: 400;
|
|
|
+ line-height: 24px;
|
|
|
+ color: #666;
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+
|
|
|
+.scoring-result {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ margin-left: 5px;
|
|
|
+ color: #67c23a;
|
|
|
+ background: rgb(103 194 58 / 12%);
|
|
|
+ border: 1px solid #67c23a;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.scoring-text {
|
|
|
+ font-size: 14px;
|
|
|
+ font-style: normal;
|
|
|
+ font-weight: 500;
|
|
|
+ line-height: 24px;
|
|
|
+ color: #333;
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+
|
|
|
+.scoring-img {
|
|
|
+ width: 128px;
|
|
|
+ height: 115px;
|
|
|
+ margin: 16px 32px 33px 56px;
|
|
|
+}
|
|
|
+
|
|
|
+.equipment-group {
|
|
|
+ margin-right: 30px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-option {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.status-tag {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 44px;
|
|
|
+ height: 24px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #67c23a;
|
|
|
+ background: rgb(103 194 58 / 12%);
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.monitoring-content {
|
|
|
+ padding: 16px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.monitoring-header {
|
|
|
+ height: 164px;
|
|
|
+ margin: 24px 0 16px;
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid #fff;
|
|
|
+ border-radius: 16px;
|
|
|
+}
|
|
|
+</style>
|