Files
SaaS-lib/hx-ai-intelligent/src/view/equipmentControl/waterSystem/index.vue
2024-09-03 17:02:13 +08:00

668 lines
20 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.

<template>
<div class="main">
<!-- 左上角设备信息面板 -->
<deviceInfo :state="deviceState" />
<!-- 示意图 -->
<div class="map">
<!-- 污水池图标 -->
<deviceItem v-for="(item, index) in device1" :key="index" :info="item" />
<!-- 阀门图标 -->
<deviceItem v-for="(item, index) in device2" :key="index" :info="item" />
<!-- 集水池图标 -->
<deviceItem v-for="(item, index) in device3" :key="index" :info="item" />
<!-- 排水泵图标 -->
<deviceItem v-for="(item, index) in device4" :key="index" :info="item" />
<!-- 市政管道图标 -->
<div class="pipe">
<div>市政管道</div>
<img src="./images/pipe.png" alt="" />
</div>
<!-- 设备图标底部连线 -->
<deviceLine v-for="(item, index) in linePosition" :key="index" :position="item" />
</div>
<!-- 右下角按钮 -->
<div class="buttons">
<a-button type="primary" @click="openDrawer">执行</a-button>
<a-button type="primary" @click="resetAll">全部撤销</a-button>
</div>
<!-- 页面右侧抽屉开关 -->
<div class="right-button">
<div>计划与日志</div>
<img @click="visible = true" src="./images/open.png" alt="" />
</div>
<!-- 右侧 计划日志抽屉 -->
<a-drawer
v-model:visible="visible"
class="drawer-item"
width="496"
placement="right"
:body-style="{ background: 'rgba(0, 0, 0)', opacity: 0.8 }"
:closable="false"
id="drawer"
:maskStyle="{ 'background-color': 'rgba(0, 0, 0, 0)' }">
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="计划列表" force-render>
<planTab ref="tabs1Ref" @reset-all="resetDrawer" />
</a-tab-pane>
<a-tab-pane key="2" tab="日志">
<logTab ref="tabs2Ref" @reset-all="resetDrawer" />
</a-tab-pane>
</a-tabs>
</a-drawer>
<!-- 右侧 操作队列 -->
<a-drawer
v-model:visible="visible1"
class="drawer-item"
width="496"
placement="right"
style="opacity: 0.8"
:body-style="{ background: 'black' }"
:closable="false"
id="drawer"
:maskStyle="{ 'background-color': 'rgba(0, 0, 0, 0)' }">
<a-tabs v-model:activeKey="activeKey1">
<a-tab-pane key="1" tab="操作队列" force-render>
<div>
<a-badge :offset="[-5, 12]" :count="valveList.length">
<button :class="{ btn: true, selected: activeButton == 1 }" @click="changeBtn(1)"
>阀门</button
>
</a-badge>
<a-badge :offset="[-5, 12]" :count="pumpList.length">
<button :class="{ btn: true, selected: activeButton == 2 }" @click="changeBtn(2)"
>水泵</button
>
</a-badge>
</div>
<div class="device-list" v-if="activeButton == 1">
<div class="device-list-item" v-for="(item, index) in valveList" :key="index">
<div class="list-item-title">
<div class="item-title">
<img src="./images/device1.png" alt="" />
<span>{{ item.name }}</span>
</div>
<div class="revoke" @click="revoke(item.id, index, 1)">撤销</div>
</div>
<div class="list-item-main">
<div>
<div class="info">开度</div>
<div class="text">
<span>{{ item.oldVal + item.unit }}</span>
<img src="/asset/image/bulbLogo/22406.png" alt="" />
<span>{{ item.value + item.unit }}</span>
</div>
</div>
</div>
</div>
<a-empty style="margin-top: 100px" v-if="valveList.length == 0">
<template #description> <span style="color: white">暂无数据</span></template>
</a-empty>
</div>
<div class="device-list" v-if="activeButton == 2">
<div class="device-list-item" v-for="(item, index) in pumpList" :key="index">
<div class="list-item-title">
<div class="item-title">
<img src="./images/device2.png" alt="" />
<span>{{ item.name }}</span>
</div>
<div class="revoke" @click="revoke(item.id, index, 2)">撤销</div>
</div>
<div class="list-item-main">
<div>
<div class="info">频率</div>
<div class="text">
<span>{{ item.oldVal + item.unit }}</span>
<img src="/asset/image/bulbLogo/22406.png" alt="" />
<span>{{ item.value + item.unit }}</span>
</div>
</div>
<div>
<div class="info">开关</div>
<div class="text">
<span>{{ item.opened ? '开' : '关' }}</span>
<img src="/asset/image/bulbLogo/22406.png" alt="" />
<span>{{ item.open == 1 ? '开' : '关' }}</span>
</div>
</div>
</div>
</div>
<a-empty style="margin-top: 100px" v-if="pumpList.length == 0">
<template #description> <span style="color: white">暂无数据</span></template>
</a-empty>
</div>
<div style="width: 100%; height: 100px"></div>
<div class="button-box">
<button class="cancel" @click="visible1 = false">取消</button>
<a-popconfirm
title="此操作将提交以上修改内容"
ok-text="确定"
cancel-text="取消"
placement="bottomRight"
@confirm="submitChange">
<button class="execute">执行</button>
</a-popconfirm>
</div>
</a-tab-pane>
</a-tabs>
</a-drawer>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { Modal, message } from 'ant-design-vue';
import deviceInfo from './deviceInfo.vue';
import deviceLine from './deviceLine.vue';
import deviceItem from './deviceItem.vue';
import planTab from './component/planTab.vue';
import logTab from './component/logTab.vue';
import { linePosition, device1, device2, device3, device4 } from './device';
// 网络请求
import { http } from '/nerv-lib/util/http';
import { waterSys } from '/@/api/waterSystem';
// 全局变量
import { items } from '/@/store/item';
// 初始化 ===========================================================================================
const state = items();
onMounted(() => {
// 获得所有设备状态
getAllDevice();
});
const deviceState = 1;
// 计划与日志 抽屉业务 =========================================================================================
// 计划与日志
const visible = ref(false);
// 当前选中的tab
const activeKey = ref('1');
// 执行 抽屉业务 =========================================================================================
// 执行
const visible1 = ref(false);
// 当前选中的tab
const activeKey1 = '1';
// 当前选中的设备类型 阀门=1/水泵=2
const activeButton = ref(1);
// 切换设备类型
const changeBtn = (key: number) => {
activeButton.value = key;
};
// 当前修改的水泵数据
const pumpList = ref<any>([]);
// 当前修改的水阀数据
const valveList = ref<any>([]);
// 打开右侧抽屉
const openDrawer = () => {
valveList.value = device2.value.filter((item: any) => {
return item.edited;
});
pumpList.value = device4.value.filter((item: any) => {
return item.edited;
});
if (valveList.value.length || pumpList.value.length) {
visible1.value = true;
} else {
message.info('未产生任何修改');
}
};
// 右侧抽屉 - 撤回
const revoke = (id: any, index: number, type: number) => {
if (type == 1) {
valveList.value.splice(index, 1);
device2.value.forEach((item: any) => {
if (item.id == id) {
item.value = item.oldVal;
item.edited = false;
}
});
} else if (type == 2) {
pumpList.value.splice(index, 1);
device4.value.forEach((item: any) => {
if (item.id == id) {
item.value = item.oldVal;
item.open = item.opened;
item.edited = false;
}
});
}
};
const submitChange = () => {
let valveList = [];
device2.value.forEach((item: any) => {
if (item.edited) {
valveList.push({
deviceGroup: item.id,
openPercent: item.value,
});
}
});
let pumpList = [];
device4.value.forEach((item: any) => {
if (item.edited) {
pumpList.push({
deviceGroup: item.id,
frequency: item.value,
switchStatus: +item.open,
});
}
});
state.setLoading(true);
http
.post(waterSys.submitList, {
projectId: state.projectId,
siteId: state.siteId,
valveList,
pumpList,
})
.then((res) => {
let data = res.data;
state.setLoading(false);
// 修改请求发送了,但操作时产生了失败结果
if (res.retcode != 0) {
// 直接提示并跳出
return message.warning(res.msg);
}
// 所有修改均生效
if (data.allSucceed) {
message.success('修改完成');
// allSucceed不为true则至少有一条数据修改失败
} else {
message.info(`${data.successList.length}条修改成功,${data.failList.length}条修改失败`);
}
// 将所有已修改状态的数据还原
resetEdit();
visible1.value = false;
getAllDevice();
});
};
const resetEdit = () => {
device2.value.forEach((item) => {
item.edited = false;
});
device4.value.forEach((item) => {
item.edited = false;
});
};
// 设备数据业务 ==========================================================================================
// 当其中一个tab产生了数据修改可以调用该方法重置所有tab
const resetDrawer = () => {
try {
// tab1重置
tabs1Ref.value.reset();
} catch {}
try {
// tab2重置
tabs2Ref.value.reset();
} catch {}
};
// 抽屉tab1组件的引用
const tabs1Ref = ref();
// 抽屉tab2组件的引用
const tabs2Ref = ref();
// 撤销所有修改
const resetAll = () => {
Modal.confirm({
title: '提示信息',
content: '该操作将还原已编辑内容',
onOk() {
// 水阀
device2.value.forEach((item: any) => {
if (item.edited) {
item.value = item.oldVal;
item.edited = false;
}
});
// 水泵 水泵包含
device4.value.forEach((item: any) => {
if (item.edited) {
item.value = item.oldVal;
item.open = item.opened;
item.edited = false;
}
});
},
onCancel() {},
});
};
// 获得所有设备状态
const getAllDevice = () => {
getDevice(1);
getDevice(2);
getDevice(3);
getDevice(4);
};
/**
* 获取一个设备类型的数据
* @param type 污水池=1/阀门=2/集水池=3/水泵=4
*/
const getDevice = (type: number) => {
// 请求地址
let url = '';
if (type == 1) {
url = waterSys.getPool1;
} else if (type == 2) {
url = waterSys.getValve;
} else if (type == 3) {
url = waterSys.getPool2;
} else if (type == 4) {
url = waterSys.getPump;
}
http
.get(url, {
projectId: state.projectId,
siteId: state.siteId,
})
.then((res) => {
let data = res.data;
// 污水池数据
if (type == 1) {
device1.value.forEach((item: any, index: number) => {
let result = data[index];
// 污水池名称
item.name = result.deviceInfoName;
// 污水池容量
item.value = result.record.capacity ? result.record.capacity : '--';
// 单位
item.unit = result.record.capacityUnit ? result.record.capacityUnit : '';
});
}
// 阀门数据
if (type == 2) {
device2.value.forEach((item: any, index: number) => {
let result = data[index];
// 阀门名称
item.name = result.deviceGroupName;
// 阀门ID
item.id = result.deviceGroup;
// 编辑状态重置
item.edited = false;
// 设备状态(是否正常)
item.state = result.record.runStatus.value != null ? result.record.runStatus.value : -1;
// 开度-新值
item.value = result.record.openPercent ? result.record.openPercent : 0;
// 开度-旧值(用于判断旧值是否被修改)
item.oldVal = result.record.openPercent ? result.record.openPercent : null;
// 单位
item.unit = result.record.openPercentUnit ? result.record.openPercentUnit : '';
});
}
// 集水池数据
if (type == 3) {
device3.value.forEach((item: any, index: number) => {
let result = data[index];
// 集水池名称
item.name = result.deviceInfoName;
// 集水池容量
item.value = result.record.capacity ? result.record.capacity : '--';
// 单位
item.unit = result.record.capacityUnit ? result.record.capacityUnit : '';
});
}
// 水泵数据
if (type == 4) {
device4.value.forEach((item: any, index: number) => {
let result = data[index];
// 水泵名称
item.name = result.deviceGroupName;
// 水泵ID
item.id = result.deviceGroup;
// 编辑状态重置
item.edited = false;
// 水泵的开启状态-新值
item.open = result.record.switchStatus.value == 1 ? true : false;
// 水泵的开启状态-旧值(用于判断是否被修改)
item.opened = result.record.switchStatus.value == 1 ? true : false;
// 设备状态(是否正常)
item.state = result.record.runStatus.value != null ? result.record.runStatus.value : -1;
// 频率-新值
item.value = result.record.frequency ? result.record.frequency : 0;
// 频率-旧值(用于判断是否被修改)
item.oldVal = result.record.frequency ? result.record.frequency : null;
// 单位
item.unit = result.record.frequencyUnit ? result.record.frequencyUnit : '';
});
}
});
};
</script>
<style lang="less" scoped>
.main {
width: 100%;
height: 100%;
position: relative;
background: linear-gradient(to bottom, rgb(35, 102, 165), rgb(1, 19, 81));
// 图例区域
.map {
width: 85vw;
height: 38vw;
position: relative;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
// 右侧 市政管道
.pipe {
width: 120px;
height: 120px;
position: absolute;
text-align: center;
left: 92%;
top: 40%;
z-index: 3;
transform: translateY(-60px);
img {
height: 100%;
user-select: none;
}
div {
width: inherit;
color: white;
position: absolute;
top: -1.5em;
font-size: 16px;
}
}
}
// 右下角按钮
.buttons {
position: absolute;
right: 15px;
bottom: 15px;
display: flex;
gap: 15px;
height: 40px;
> button {
height: 40px;
}
}
.right-button {
height: 25px;
position: absolute;
top: 0;
bottom: 0;
right: 10px;
margin: auto;
display: flex;
z-index: 99;
gap: 10px;
color: #0dffff;
> img {
width: 25px;
height: 25px;
border-radius: 2px;
vertical-align: middle;
cursor: pointer;
user-select: none;
}
}
.drawer-item {
width: 100px;
height: 100px;
border: 2px solid red;
}
}
// 抽屉顶部tab按钮样式
:deep(.ant-tabs-tab-btn) {
color: white;
}
.btn {
width: 92px;
height: 40px;
border-radius: 4px;
opacity: 1;
margin-top: 10px;
margin-left: 15px;
font-size: 14px;
font-weight: 400;
opacity: 1;
// border: 1px solid rgba(207, 212, 219, 1);
border: none;
line-height: 20.27px;
color: white;
text-align: center;
vertical-align: top;
background-color: rgba(255, 255, 255, 0.1);
}
.selected {
background: linear-gradient(180deg, rgba(201, 245, 255, 1) 0%, rgba(138, 215, 255, 1) 100%);
color: rgba(0, 61, 90, 1);
border: none;
}
.btn:hover {
background-color: rgba(207, 212, 219, 1);
}
.btn:active {
background-color: rgba(102, 102, 102, 1);
color: white;
}
.device-list {
margin-left: 15px;
margin-top: 15px;
width: 100%;
height: auto;
display: flex;
gap: 15px;
flex-direction: column;
.device-list-item {
width: calc(100% - 15px);
box-sizing: border-box;
padding: 10px;
border: 2px solid #03407e;
border-radius: 4px;
background: rgba(0, 177, 255, 0.2);
display: flex;
gap: 10px;
flex-direction: column;
.list-item-title {
color: white;
display: flex;
justify-content: space-between;
.item-title {
img {
width: 25px;
}
span {
margin-left: 10px;
font-size: 16px;
}
}
.revoke {
text-align: center;
border: none;
border-radius: 4px;
padding: 5px 15px;
background: linear-gradient(
180deg,
rgba(255, 187, 0, 1) 0%,
rgba(255, 112, 3, 1) 91.21%,
rgba(255, 129, 3, 1) 100%
);
cursor: pointer;
}
}
.list-item-main {
display: flex;
font-size: 13px;
flex-direction: column;
gap: 15px;
> div {
flex: 1;
display: flex;
gap: 8px;
> .info {
text-align: center;
width: 6em;
height: 2.5em;
line-height: 2.5em;
border-radius: 4px;
color: white;
background: linear-gradient(
180deg,
rgba(86, 221, 253, 1) 0%,
rgba(25, 176, 255, 1) 100%
);
}
> .text {
:first-child {
color: white;
line-height: 2.5em;
}
img {
padding: 0 5px;
}
:last-child {
line-height: 2.5em;
color: red;
}
}
}
}
}
}
.button-box {
width: 100%;
box-sizing: border-box;
padding: 10px;
height: 60px;
position: absolute;
background-color: transparent;
text-align: right;
bottom: 0;
left: 0;
right: 0;
.execute,
.cancel {
margin-right: 10px;
width: 74px;
height: 40px;
opacity: 1;
cursor: pointer;
border-radius: 4px;
font-size: 14px;
font-weight: 400;
border: 0;
margin-left: 10px;
}
.execute {
background: rgb(67, 136, 251);
color: white;
}
.cancel {
background: white;
color: black;
}
}
</style>