You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

667 lines
20 KiB

<template>
<div class="box-ventilationSystem">
<div class="legend-box">
<template v-for="(item, index) in legend" :key="index">
<div class="legend-box-item" @click="selectLegend(item, index)">
<div
class="legend-box-item-img"
:style="{
'background-image': selectIndex === index ? 'url(' + selectImg + ')' : '',
}">
<img :src="item.url" />
</div>
<div class="legend-box-item-name">
{{ item.name }}
</div>
</div>
</template>
</div>
<!-- 温度 -->
<transition name="zep">
<div v-if="selectIndex === 0">
<template v-for="(item, index) in sensorData" :key="index">
<div
style="position: absolute"
:style="{ left: item.styleText.left, bottom: item.styleText.bottom }">
<singleModel :dataSource="item" />
</div>
</template>
</div>
</transition>
<!-- 湿度 -->
<transition name="zep">
<div v-if="selectIndex === 1">
<template v-for="(item, index) in humidityData" :key="index">
<div
style="position: absolute"
:style="{ left: item.styleText.left, bottom: item.styleText.bottom }">
<singleModel :dataSource="item" />
</div>
</template>
</div>
</transition>
<!-- PM2.5 -->
<transition name="zep">
<div v-if="selectIndex === 2">
<template v-for="(item, index) in pmData" :key="index">
<div
style="position: absolute"
:style="{ left: item.styleText.left, bottom: item.styleText.bottom }">
<singleModel :dataSource="item" />
</div>
</template>
</div>
</transition>
<!-- CO2e -->
<transition name="zep">
<div v-if="selectIndex === 3">
<template v-for="(item, index) in CO2Data" :key="index">
<div
style="position: absolute"
:style="{ left: item.styleText.left, bottom: item.styleText.bottom }">
<singleModel :dataSource="item" />
</div>
</template>
</div>
</transition>
<!-- 右侧抽屉的触发按钮 -->
<div
class="drawer-box-in"
v-if="!visible && (selectIndex === 4 || selectIndex === 5 || selectIndex === 6)"
@click="toggleDrawer">
<double-left-outlined class="drawer-icon" style="color: white" />
</div>
<!-- 排风扇 -->
<transition name="zep">
<div v-if="selectIndex === 4">
<template v-for="(item, index) in fanData" :key="index">
<!-- 朝左边 -->
<template v-if="item.lineType === '1'">
<div
style="position: absolute"
:style="{
left: 'calc(' + item.styleText.left + ' - 12.6%)',
bottom: 'calc(' + item.styleText.bottom + ' + 4%)',
}">
<boxModel :dataSource="item" />
</div>
<img
style="width: 50px; height: 75px; position: absolute; z-index: 1"
:style="{
left: 'calc(' + item.styleText.left + ' - 2%)',
bottom: 'calc(' + item.styleText.bottom + ' + 3%)',
transform: 'rotateY(180deg)',
}"
src="../image/liftState/lift/line.png" />
</template>
<!-- 朝右边 -->
<template v-if="item.lineType === '2'">
<div
style="position: absolute"
:style="{
left: 'calc(' + item.styleText.left + ' + 4.3%)',
bottom: 'calc(' + item.styleText.bottom + ' + 4%)',
}">
<boxModel :dataSource="item" />
</div>
<img
style="width: 50px; height: 75px; position: absolute; z-index: 1"
:style="{
left: 'calc(' + item.styleText.left + ' + 1.5%)',
bottom: 'calc(' + item.styleText.bottom + ' + 3%)',
}"
src="../image/liftState/lift/line.png" />
</template>
<img
style="width: 38px; height: 38px; position: absolute; cursor: pointer; z-index: 9"
:style="{ left: item.styleText.left, bottom: item.styleText.bottom }"
src="../image/ventilationSystem/fan.png" />
</template>
</div>
</transition>
<!-- 排风扇 - 弹窗 -->
<a-drawer
v-if="selectIndex === 4 && visible"
:visible="selectIndex === 4"
class="drawer-fan drawer-item"
:width="496"
:forceRender="preload"
placement="right"
:body-style="{ background: 'rgba(0, 0, 0)', opacity: 0.8, color: 'white' }"
:closable="false"
id="drawer"
:maskStyle="{ 'background-color': 'rgba(0, 0, 0, 0)' }">
<!-- 左侧抽屉的关闭按钮 -->
<div class="drawer-box-out" @click="toggleDrawer">
<double-right-outlined class="drawer-icon" style="color: white" />
</div>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="控制面板">
<fanControl
ref="tabs1Ref"
@reset-all="resetDrawer"
:treeData="treeData"
:type="`排风扇`" />
</a-tab-pane>
<a-tab-pane key="2" tab="计划列表" force-render>
<fanPlant ref="tabs2Ref" @reset-all="resetDrawer" :status="stateList" :type="3" />
</a-tab-pane>
<a-tab-pane key="3" tab="日志">
<fanLog ref="tabs3Ref" @reset-all="resetDrawer" :type="3" />
</a-tab-pane>
</a-tabs>
</a-drawer>
<!-- 风幕机 -->
<transition name="zep">
<div v-if="selectIndex === 5">
<template v-for="(item, index) in airCurtainData" :key="index">
<div
style="position: absolute"
:style="{
left: 'calc(' + item.styleText.left + ' - 16.1%)',
bottom: 'calc(' + item.styleText.bottom + ' + 8%)',
}">
<boxModel :dataSource="item" />
</div>
<img
style="width: 50px; height: 75px; position: absolute; z-index: 1"
:style="{
left: 'calc(' + item.styleText.left + ' - 2%)',
bottom: 'calc(' + item.styleText.bottom + ' + 4%)',
transform: 'rotateY(180deg)',
}"
src="../image/liftState/lift/line.png" />
<img
style="width: 38px; height: 38px; position: absolute; z-index: 9"
:style="{ left: item.styleText.left, bottom: item.styleText.bottom }"
src="../image/ventilationSystem/airCurtain.png" />
</template>
</div>
</transition>
<!-- 风幕机 - 弹窗 -->
<a-drawer
v-if="selectIndex === 5 && visible"
:visible="selectIndex === 5"
class="drawer-fan drawer-item"
:width="496"
:forceRender="preload"
placement="right"
:body-style="{ background: 'rgba(0, 0, 0)', opacity: 0.8, color: 'white' }"
:closable="false"
id="drawer"
:maskStyle="{ 'background-color': 'rgba(0, 0, 0, 0)' }"
:mask="false">
<!-- 左侧抽屉的关闭按钮 -->
<div class="drawer-box-out" @click="toggleDrawer">
<double-right-outlined class="drawer-icon" style="color: white" />
</div>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="控制面板">
<fanControl
ref="tabs1Ref"
@reset-all="resetDrawer"
:treeData="treeData"
:type="`风幕机`" />
</a-tab-pane>
<a-tab-pane key="2" tab="计划列表" force-render>
<fanPlant ref="tabs2Ref" @reset-all="resetDrawer" :status="stateList" :type="4" />
</a-tab-pane>
<a-tab-pane key="3" tab="日志">
<fanLog ref="tabs3Ref" @reset-all="resetDrawer" :type="4" />
</a-tab-pane>
</a-tabs>
</a-drawer>
<transition name="zep">
<div v-if="selectIndex === 6">
<template v-for="(item, index) in windowData" :key="index">
<div
style="position: absolute"
:style="{
left: 'calc(' + item.styleText.left + ' - 11%)',
bottom: 'calc(' + item.styleText.bottom + ' + 8%)',
}">
<boxModel :dataSource="item" />
</div>
<img
style="width: 50px; height: 75px; position: absolute; z-index: 1"
:style="{
left: 'calc(' + item.styleText.left + ' - 2%)',
bottom: 'calc(' + item.styleText.bottom + ' + 4%)',
transform: 'rotateY(180deg)',
}"
src="../image/liftState/lift/line.png" />
<img
style="width: 38px; height: 38px; position: absolute; z-index: 9"
:style="{ left: item.styleText.left, bottom: item.styleText.bottom }"
src="../image/ventilationSystem/windowIcon.png" />
</template>
</div>
</transition>
<!-- 电动窗 - 弹窗 -->
<a-drawer
v-if="selectIndex === 6 && visible"
:visible="selectIndex === 6"
class="drawer-fan drawer-item"
:width="496"
:forceRender="preload"
placement="right"
:body-style="{ background: 'rgba(0, 0, 0)', opacity: 0.8, color: 'white' }"
:closable="false"
id="drawer"
:maskStyle="{ 'background-color': 'rgba(0, 0, 0, 0)' }"
:mask="false">
<!-- 左侧抽屉的关闭按钮 -->
<div class="drawer-box-out" @click="toggleDrawer">
<double-right-outlined class="drawer-icon" style="color: white" />
</div>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="控制面板">
<fanControl
ref="tabs1Ref"
@reset-all="resetDrawer"
:treeData="treeData"
:type="`电动窗`" />
</a-tab-pane>
<a-tab-pane key="2" tab="计划列表" force-render>
<fanPlant ref="tabs2Ref" @reset-all="resetDrawer" :status="stateList" :type="5" />
</a-tab-pane>
<a-tab-pane key="3" tab="日志">
<fanLog ref="tabs3Ref" @reset-all="resetDrawer" :type="5" />
</a-tab-pane>
</a-tabs>
</a-drawer>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from 'vue';
//图片
import temperature from '../image/airConditioningSystem/temperature.svg';
import humidity from '../image/ventilationSystem/humidity.svg';
import PM25 from '../image/ventilationSystem/PM25.svg';
import CO2 from '../image/ventilationSystem/CO2.svg';
import ventilatingFan from '../image/ventilationSystem/ventilatingFan.svg';
import window from '../image/ventilationSystem/window.svg';
import airCurtain from '../image/ventilationSystem/fanMachine.svg';
import selectImg from '../image/airConditioningSystem/selectImg.png';
import sunRed from '../image/airConditioningSystem/sunRed.png';
import sunYellow from '../image/airConditioningSystem/sunYellow.png';
import boxModel from './components/boxModel.vue';
import singleModel from '../components/singleModel.vue';
import fanControl from './components/fanControl.vue';
import fanPlant from './components/fanPlant.vue';
import fanLog from './components/fanLog.vue';
import { DoubleLeftOutlined, DoubleRightOutlined } from '@ant-design/icons-vue';
// 请求
import { http } from '/nerv-lib/util/http';
import { getEnum } from '/@/api';
import { ventilating } from '/@/api/ventilatingSystem';
// 全局变量
import { items } from '/@/store/item';
// 定位数据
import { devicePosition1, devicePosition2, devicePosition3 } from './devicePosition';
// 父子组件交互 =======================================================================
// 全局变量
const state = items();
// 状态枚举
const stateList = ref([]);
// 获得状态枚举
const getStateEnum = async () => {
let enumData = await getEnum({ params: { enumType: 'PlanExecuteStatus' } });
stateList.value = enumData.data;
};
// 左侧侧边栏及交互 ====================================================================
// 图例
const legend = ref([
{ url: temperature, name: '温度' },
{ url: humidity, name: '湿度' },
{ url: PM25, name: 'PM2.5' },
{ url: CO2, name: 'CO2浓度' },
{ url: ventilatingFan, name: '排风扇' },
{ url: airCurtain, name: '风幕机' },
{ url: window, name: '电动窗' },
]);
// 选择的图例
const selectIndex = ref(0);
// 图例切换事件
const selectLegend = (item: any, index: any) => {
const name = item.name;
if (selectIndex.value === index) {
return;
} else if (name == '排风扇') {
// 获得树形结构
getTree(1, index);
// 获得设备图例
getDevice(1);
} else if (name == '风幕机') {
getTree(2, index);
getDevice(2);
} else if (name == '电动窗') {
getTree(3, index);
getDevice(3);
// 修改
} else {
selectIndex.value = index;
}
};
// 抽屉相关(排风扇 / 风幕机 / 电动窗) ==================================================
// 选择table
const activeKey = ref('1');
// 抽屉的展示状态
const visible = ref(true);
// 预加载flag,获得分区数据后,预加载抽屉,防止获取ref报错
const preload = ref(true);
// 抽屉 - 开关事件
const toggleDrawer = () => {
visible.value = !visible.value;
};
// 当前设备的请求URL
let url = '';
// 刷新当前的树形结构数据
const reload = () => {
http.get(url, { projectId: state.projectId, siteId: state.siteId }).then((res) => {
const data = res.data;
treeData.value = data[0].childList;
});
};
// 抽屉中tab1 - 控制面板 =================================================================
const treeData = ref([]);
// 获取tab1的树形结构
const getTree = async (type: number, index: number) => {
// 切换时默认选择tab1
activeKey.value = '1';
if (type == 1) {
url = ventilating.getTree1;
} else if (type == 2) {
url = ventilating.getTree2;
} else {
url = ventilating.getTree3;
}
http.get(url, { projectId: state.projectId, siteId: state.siteId }).then((res) => {
const data = res.data;
treeData.value = data[0].childList;
selectIndex.value = index;
});
};
const getDevice = async (type: number) => {
// 切换时默认选择tab1
activeKey.value = '1';
let arr: Array<Object> = [];
let url = '';
let deviceType = '';
if (type == 1) {
// 设备类型
deviceType = 'fan';
// 位置数据
arr = devicePosition1;
// 请求地址
url = ventilating.getDevice1;
} else if (type == 2) {
deviceType = 'airCurtain';
arr = devicePosition2;
url = ventilating.getDevice2;
} else if (type == 3) {
deviceType = 'window';
arr = devicePosition3;
url = ventilating.getDevice3;
}
http.get(url, { projectId: state.projectId, siteId: state.siteId, floor: 1 }).then((res) => {
const data = res.data;
data.forEach((item: any, index: number) => {
let obj = arr[index];
item.styleText = obj.textObject;
item.lineType = obj.lineType;
item.type = deviceType;
});
if (type == 1) {
fanData.value = data;
} else if (type == 2) {
airCurtainData.value = data;
} else if (type == 3) {
windowData.value = data;
}
});
};
// 温度数组
const sensorData = ref([
{
title: '多功能传感器A',
styleText: { left: '48%', bottom: '64%' },
type: '温度',
unit: '℃',
number: 20,
url: sunRed,
},
{
title: '多功能传感器B',
styleText: { left: '48.2%', bottom: '43%' },
type: '温度',
unit: '℃',
number: 20,
url: sunYellow,
},
]);
// 湿度数组
const humidityData = ref([
{
title: '多功能传感器A',
styleText: { left: '48%', bottom: '64%' },
type: '湿度',
unit: '%',
number: 20,
url: humidity,
},
{
title: '多功能传感器B',
styleText: { left: '48.2%', bottom: '43%' },
type: '湿度',
unit: '%',
number: 20,
url: humidity,
},
]);
// PM2.5数组
const pmData = ref([
{
title: '多功能传感器A',
styleText: { left: '48%', bottom: '64%' },
type: 'pm2.5',
unit: '',
number: 20,
url: PM25,
},
{
title: '多功能传感器B',
styleText: { left: '48.2%', bottom: '43%' },
type: 'pm2.5',
unit: '',
number: 20,
url: PM25,
},
]);
// 二氧化碳 浓度
const CO2Data = ref([
{
title: '多功能传感器A',
styleText: { left: '48%', bottom: '64%' },
type: '二氧化碳',
unit: 'CO2e',
number: 20,
url: CO2,
},
{
title: '多功能传感器B',
styleText: { left: '48.2%', bottom: '43%' },
type: '二氧化碳',
unit: 'CO2e',
number: 99,
url: CO2,
},
]);
// 排风扇
const fanData = ref([]);
// 风幕机
const airCurtainData = ref([]);
// 电动窗
const windowData = ref([]);
// 当其中一个tab产生了数据修改,可以调用该方法重置所有tab
const resetDrawer = () => {
// tab1重置
reload();
tabs1Ref.value.refresh();
// tab2 tab3 可能未加载
try {
// tab2重置
tabs2Ref.value.reset();
} catch {}
try {
// tab3重置
tabs3Ref.value.reset();
} catch {}
};
// 抽屉tab1组件的引用
const tabs1Ref = ref();
// 抽屉tab2组件的引用
const tabs2Ref = ref();
// 抽屉tab3组件的引用
const tabs3Ref = ref();
onMounted(() => {
// 获得枚举
getStateEnum();
});
onUnmounted(() => {});
</script>
<style lang="less">
@import url('../style/color.less');
.legend-box {
width: 80px;
height: 100%;
background-color: rgba(33, 40, 54, 0.95);
display: flex;
flex-direction: column;
gap: 10px;
padding: 15px 5px;
.legend-box-item {
display: flex;
flex-direction: column;
align-items: center;
width: 70px;
height: 70px;
.legend-box-item-img {
width: 50px;
height: 60px;
padding-top: 5px;
flex: 1;
cursor: pointer;
background-size: 100% 100%;
text-align: center;
img {
transition: all ease 0.2s;
}
img:hover {
transform: scale(1.1);
}
}
.legend-box-item-name {
transform: translateY(-5px);
text-align: center;
color: white;
font-size: 13px;
}
}
}
.box-ventilationSystem {
width: 100%;
height: 100%;
display: flex;
overflow: hidden;
background-image: url('../image/ventilationSystem/ventilationSystemBg.png');
background-size: 100% 99.9%;
background-repeat: no-repeat;
position: relative;
}
.zep-enter-active,
.zep-leave-active {
animation-duration: 0.6s; /* 增加动画持续时间 */
animation-timing-function: ease-in-out; /* 使用更平滑的动画曲线 */
}
.zep-enter-active {
animation-name: bounce-enter;
}
.zep-leave-active {
animation-name: bounce-leave;
}
/* 进入动画 */
@keyframes bounce-enter {
0% {
opacity: 0; /* 初始时完全透明 */
}
100% {
opacity: 1; /* 结束时完全不透明 */
}
}
/* 离开动画 */
@keyframes bounce-leave {
0% {
opacity: 1; /* 初始时完全不透明 */
}
100% {
opacity: 0; /* 结束时完全透明 */
}
}
.drawer-fan {
width: 496px;
// 抽屉关闭按钮
.drawer-box-out {
width: 30px;
height: 40px;
border-radius: 2px;
position: fixed;
right: 495px;
top: 0;
bottom: 0;
margin: auto;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.ant-tabs-tab-btn {
color: white;
}
.ant-tabs-tabpane {
color: white;
}
}
.drawer-box-in {
width: 30px;
height: 40px;
border-radius: 2px;
position: fixed;
right: 0;
top: 0;
bottom: 0;
margin: auto;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
</style>