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="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"
: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="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;
8 months ago
// 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);
8 months ago
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>