Browse Source

add:新增给排水页面/接口及功能

temp
chenpingsen 3 weeks ago
parent
commit
3cf535351e
  1. 13
      hx-ai-intelligent/src/api/waterSystem.ts
  2. 38
      hx-ai-intelligent/src/router/equipmentControl.ts
  3. 429
      hx-ai-intelligent/src/view/equipmentControl/waterSystem/component/logTab.vue
  4. 381
      hx-ai-intelligent/src/view/equipmentControl/waterSystem/component/planTab.vue
  5. 282
      hx-ai-intelligent/src/view/equipmentControl/waterSystem/device.ts
  6. 150
      hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceInfo.vue
  7. 291
      hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceItem.vue
  8. 30
      hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceLine.vue
  9. 663
      hx-ai-intelligent/src/view/equipmentControl/waterSystem/index.vue

13
hx-ai-intelligent/src/api/waterSystem.ts

@ -2,6 +2,8 @@
const prefix = '/carbon-smart/api';
// 通风系统相关接口
export enum waterSys {
// 首页 ====================================================
// 获得污水池状态
getPool1 = prefix + '/waterSysCtrl/getSewagePoolState',
// 获得阀门状态
@ -10,4 +12,15 @@ export enum waterSys {
getPool2 = prefix + '/waterSysCtrl/getCollectPoolState',
// 获得水泵状态
getPump = prefix + '/waterSysCtrl/getPumpState',
// 提交场景模式修改
submitList = prefix + '/waterSysCtrl/changeToSceneMode',
// 计划 tab1 ===============================================
submitTableData = prefix + '/waterSysCtrl/refreshPlanStatus',
// 日志 tab2 ===============================================
// 获得设备日志
getLog = prefix + '/waterSysInfo/pageAbleLog',
// 获得日志详情
getLogDetail = prefix + '/waterSysInfo/fullLog',
}

38
hx-ai-intelligent/src/router/equipmentControl.ts

@ -119,25 +119,25 @@ const equipmentControl = {
},
],
},
// {
// path: 'waterSystem',
// name: 'waterSystem',
// meta: { title: '给排水系统', hideChildren: true, icon: 'shebeiqunkong' },
// component: Base,
// redirect: { name: 'waternControlSystemIndex' },
// children: [
// {
// path: 'index',
// name: 'waternControlSystemIndex',
// component: () => import('/@/view/equipmentControl/waterSystem/index.vue'),
// meta: {
// title: '给排水系统',
// keepAlive: false,
// // backApi: [],
// },
// },
// ],
// },
{
path: 'waterSystem',
name: 'waterSystem',
meta: { title: '给排水系统', hideChildren: true, icon: 'shebeiqunkong' },
component: Base,
redirect: { name: 'waternControlSystemIndex' },
children: [
{
path: 'index',
name: 'waternControlSystemIndex',
component: () => import('/@/view/equipmentControl/waterSystem/index.vue'),
meta: {
title: '给排水系统',
keepAlive: false,
// backApi: [],
},
},
],
},
{
path: 'planToAdd',
name: 'planToAdd',

429
hx-ai-intelligent/src/view/equipmentControl/waterSystem/component/logTab.vue

@ -0,0 +1,429 @@
<template>
<table class="custom-table table1">
<thead>
<tr :style="{ background: 'rgba(35,45,69)' }">
<th>序号</th>
<th>执行时间</th>
<th>操作内容</th>
<th>操作人</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr
:style="{ color: row.ctrlResult == 1 ? 'red' : 'white' }"
v-for="(row, index) in dataSource"
:key="index"
@click="handleRowClick(row.id, index)"
:class="index === trIndex ? 'isTrIndex' : ''">
<td>{{ index + 1 }}</td>
<td>{{ row.startTime }}</td>
<td>{{ row.operationContent }}</td>
<td>{{ row.createUser }}</td>
<td>{{ row.ctrlResult ? '失败' : '成功' }}</td>
</tr>
</tbody>
</table>
<a-pagination
style="margin-top: 10px; text-align: right"
v-model:current="pagination.pageNum"
v-model:pageSize="pagination.pageSize"
show-size-changer
:total="pagination.total"
@change="getTable(true)" />
<div style="width: 100%; height: 40px"></div>
<div class="out-dialog" :class="{ showDialog: logModalVisible }" v-if="logModalVisible">
<div class="content">
<div>
<div class="div-operation"></div>
<span class="text-operation">变更内容 </span>
</div>
<div>
<button :class="{ btn: true, selected: activeButton == 1 }" @click="changeBtn(1)"
>阀门</button
>
<button :class="{ btn: true, selected: activeButton == 2 }" @click="changeBtn(2)"
>水泵</button
>
</div>
<div class="device-list" v-if="activeButton == 1">
<div class="device-list-item" v-for="(item, index) in valveLogList" :key="index">
<div class="list-item-title">
<div class="item-title">
<img src="../images/device1.png" alt="" />
<span>{{ item.deviceGroupName }}</span>
</div>
</div>
<div class="list-item-main">
<div>
<div class="info">开度</div>
<div class="text">
<span>{{ item.openPercentBefore + '%' }}</span>
<img src="/asset/image/bulbLogo/22406.png" alt="" />
<span>{{ item.openPercentAfter + '%' }}</span>
</div>
</div>
<div></div>
</div>
</div>
<a-empty style="margin-top: 100px" v-if="valveLogList.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 pumpLogList" :key="index">
<div class="list-item-title">
<div class="item-title">
<img src="../images/device2.png" alt="" />
<span>{{ item.deviceGroupName }}</span>
</div>
</div>
<div class="list-item-main">
<div>
<div class="info">频率</div>
<div class="text">
<span>{{ item.frequencyBefore + 'MHz' }}</span>
<img src="/asset/image/bulbLogo/22406.png" alt="" />
<span>{{ item.frequencyAfter + 'MHz' }}</span>
</div>
</div>
<div>
<div class="info">开关</div>
<div class="text">
<span>{{ item.switchStatusBefore.label }}</span>
<img src="/asset/image/bulbLogo/22406.png" alt="" />
<span>{{ item.switchStatusAfter.label }}</span>
</div>
</div>
</div>
</div>
<a-empty style="margin-top: 100px" v-if="pumpLogList.length == 0">
<template #description> <span style="color: white">暂无数据</span></template>
</a-empty>
</div>
</div>
<div style="width: 100%; height: 160px"></div>
<div class="button-box">
<button class="cancel" @click="logModalVisible = false">关闭</button>
</div>
</div>
<div class="div-add">
<button class="add" @click="reset">刷新</button>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { message } from 'ant-design-vue';
import { Pagination } from 'ant-design-vue';
import { http } from '/nerv-lib/util/http';
import { waterSys } from '/@/api/waterSystem';
//
import { items } from '/@/store/item';
// =======================================================
//
defineOptions({
components: {
'a-pagination': Pagination,
},
});
//
onMounted(() => {
getTable();
});
//
const state = items();
// ======================================================
//
const pagination = ref({
pageSize: 10,
pageNum: 1,
total: 0,
});
//
const dataSource = ref([]);
//
let trIndex = ref(-1);
//
const getTable = (changePage = false) => {
state.setLoading(true);
//
if (changePage) {
trIndex.value = -1;
logModalVisible.value = false;
pumpLogList.value.length = 0;
valveLogList.value.length = 0;
}
http
.get(waterSys.getLog, {
pageSize: pagination.value.pageSize,
pageNum: pagination.value.pageNum,
})
.then((res) => {
state.setLoading(false);
let data = res.data;
dataSource.value = data.records;
pagination.value.total = data.total;
})
.catch(() => {
state.setLoading(false);
});
};
//
const reset = () => {
trIndex.value = -1;
logModalVisible.value = false;
pagination.value = {
pageSize: 10,
pageNum: 1,
total: 0,
};
getTable();
};
//
const handleRowClick = (id: any, index: any) => {
trIndex.value = index;
getLogDetail(id);
};
// ==================================================
//
const logModalVisible = ref(false);
const getLogDetail = (id: any) => {
state.setLoading(true);
http
.get(waterSys.getLogDetail, { logId: id })
.then((res) => {
state.setLoading(false);
const data = res.data;
if (data.pumpLogList.length || data.valveLogList.length) {
//
logModalVisible.value = true;
pumpLogList.value = data.pumpLogList;
valveLogList.value = data.valveLogList;
} else {
return message.info('返回值无效');
}
})
.catch(() => {
state.setLoading(false);
});
};
// =1/=2
const activeButton = ref(1);
//
const changeBtn = (key: number) => {
activeButton.value = key;
};
//
const pumpLogList = ref<any>([]);
//
const valveLogList = ref<any>([]);
//
defineExpose({
reset,
});
</script>
<style lang="less" scoped>
@import '../../style/dialogStyle.less';
//
.div-add {
height: 64px;
display: flex;
justify-content: flex-end;
align-items: center;
position: fixed;
bottom: 0;
right: 0;
margin-right: 20px;
.add {
width: 74px;
height: 40px;
opacity: 1;
border-radius: 4px;
background: rgba(67, 136, 251, 1);
border: rgba(67, 136, 251, 1);
font-size: 14px;
font-weight: 400;
color: rgba(255, 255, 255, 1);
cursor: pointer;
}
}
//
.custom-table {
border-collapse: collapse;
width: 416px;
min-height: 60px;
max-height: 500px;
overflow-y: auto;
cursor: pointer;
color: rgba(255, 255, 255, 1);
}
.custom-table th,
.custom-table td {
border: 1px solid rgba(163, 192, 243, 1);
text-align: left;
padding: 8px;
text-align: center;
}
.table1 {
margin-top: 20px;
width: 100%;
border: 1px solid rgba(255, 255, 255);
border-radius: 5px;
background: rgba(255, 255, 255, 0.1);
.tabReboot,
.tabDelete {
border: none;
background-color: rgba(0, 0, 0, 0);
font-size: 14px;
font-weight: 400;
letter-spacing: 0;
line-height: 20px;
color: rgba(67, 136, 251, 1);
}
.tabReboot {
margin-right: 8px;
}
.isTrIndex {
background: rgba(67, 136, 251, 1);
}
}
::v-deep(.ant-transfer) {
// hover
.ant-transfer-list-content-item:hover {
background: black;
}
}
.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);
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: 1px solid white;
}
.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: calc(100% - 15px);
font-size: 13px;
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;
> 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;
}
}
}
}
}
}
</style>

381
hx-ai-intelligent/src/view/equipmentControl/waterSystem/component/planTab.vue

@ -0,0 +1,381 @@
<template>
<div class="div-add">
<button class="add" @click="addModal">添加</button>
<a-popconfirm
title="是否提交以上修改?"
placement="bottomLeft"
ok-text="确定"
cancel-text="取消"
@confirm="sendTable">
<button class="add" style="margin-left: 20px">执行</button>
</a-popconfirm>
</div>
<div class="buttons">
<span style="color: red; padding-top: 20px">*以下修改需执行后生效</span>
<div class="plans">
<button class="plan enabled" style="margin-right: 10px" @click="togglePlan(1)">
计划启用
</button>
<button class="plan disabled" @click="togglePlan(3)"> 计划禁用 </button>
</div>
</div>
<table class="custom-table table1">
<thead>
<tr :style="{ background: 'rgba(35,45,69)' }">
<th>序号</th>
<th>执行时间</th>
<th>计划名称</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in dataSource" v-show="row.executeStatus.value != 0" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ row.startTime }}</td>
<td>{{ row.planName }}</td>
<td>
<button
:style="{
'font-size': '12px',
width: '5em',
background: 'rgb(47, 47, 47)',
color: setStateColor(row.executeStatus.value),
border: '1px solid',
}">
{{ setStateText(row.executeStatus.value) }}
</button>
</td>
<td>
<div class="tabReboot" @click="startPlan(row)">启用</div>
<a-popconfirm
title="此操作将移除该数据"
ok-text="确定"
cancel-text="取消"
placement="topRight"
@confirm="deletePlan(row)">
<div class="tabDelete">删除</div>
</a-popconfirm>
</td>
</tr>
</tbody>
</table>
<div class="out-dialog" v-if="addVisible">
<div class="content">
<div class="div-operation"></div>
<span class="text-operation">计划库</span>
</div>
<div style="margin-top: 20px">
<a-transfer
v-model:target-keys="targetKeys"
:data-source="transferData"
show-search
:filter-option="filterOption"
:render="(item: any) => item.title"
@change="handleChange"
:style="{ color: 'rgba(255,255,255,1)' }"
@search="handleSearch"
:listStyle="{ border: '2px solid rgba(25,74,125,1)', height: 'calc(100vh - 200px)' }" />
</div>
<div style="width: 100%; height: 60px"></div>
<div class="button-box">
<button class="cancel" @click="addVisible = false">取消</button>
<button class="execute" @click="sendPlan">确定</button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
//
import { http } from '/nerv-lib/util/http';
import { planManage } from '/@/api/planManage';
import { waterSys } from '/@/api/waterSystem';
import { message } from 'ant-design-vue';
import { getEnum } from '/@/api';
//
import { items } from '/@/store/item';
// ===========================================================
onMounted(() => {
//
getStateEnum();
// 穿
reset();
});
//
const state = items();
//
const getStateEnum = async () => {
let enumData = await getEnum({ params: { enumType: 'PlanExecuteStatus' } });
stateList.value = enumData.data;
};
/**
* @method resetAll 刷新3个tab中的全部数据修改计划会影响tab1数据信息生成tab3日志
*/
const emit = defineEmits(['resetAll']);
// tab ========================================================
//
const stateList = ref([]);
//
const setStateColor = (state: number) => {
if (state == 0) {
return '#ccc';
} else if (state == 1) {
return 'orange';
} else if (state == 2) {
return 'rgb(57, 215, 187)';
} else if (state == 3) {
return 'rgb(255, 0, 0)';
}
};
//
const setStateText = (state: number) => {
const res = stateList.value.find((item) => {
return item.value == state;
});
return res.label;
};
// /
const togglePlan = (state: number) => {
dataSource.value.forEach((item: any) => {
//
if (state == 1) {
if (item.executeStatus.value != 2) {
item.executeStatus.value = state;
}
//
} else {
item.executeStatus.value = state;
}
});
};
//
const dataSource = ref([]);
//
const getTable = () => {
http
.get(planManage.getTableData, {
projectId: state.projectId,
siteId: state.siteId,
// (1,2,3,4,5,6)
ctrlType: 6,
})
.then((res) => {
dataSource.value = res.data;
});
};
// =0
const deletePlan = (row: any) => {
row.executeStatus.value = 0;
};
// = 1
const startPlan = (row: any) => {
if (row.executeStatus.value == 1) {
return message.info('该数据已是待执行状态,无需再次修改');
}
if (row.executeStatus.value == 2) {
return message.info('执行中的状态已被启用,无需修改');
}
row.executeStatus.value = 1;
};
//
const sendTable = () => {
if (!dataSource.value.length) {
return message.info('没有任何数据可以提交');
}
state.setLoading(true);
http
.post(
waterSys.submitTableData +
`?projectId=${state.projectId}${state.siteId ? `&siteId=${state.siteId}` : ''}`,
dataSource.value,
)
.then((res) => {
state.setLoading(false);
if (res.retcode == 0) {
message.success('操作成功');
//
emit('resetAll');
} else {
message.info(res.msg);
}
})
.catch(() => {
state.setLoading(false);
});
};
const reset = () => {
//
getTable();
// 穿
getLeftPlan();
};
// tab ====================================================
//
const addVisible = ref(false);
//
const addModal = () => {
addVisible.value = true;
};
// 穿 =======================================================
// 穿
const transferData = ref([]) as any;
// 穿
const getLeftPlan = () => {
http
.get(planManage.getTransData, {
projectId: state.projectId,
siteId: state.siteId,
// (1,2,3,4,5,6)
ctrlType: 6,
})
.then((res) => {
let arr: Array<Object> = [];
res.data.forEach((item: any) => {
arr.push({
key: item.id,
title: item.planName,
});
});
transferData.value = arr;
});
};
const handleChange = (keys: string[], direction: string, moveKeys: string[]) => {
console.log(keys, direction, moveKeys);
};
const handleSearch = (dir: string, value: string) => {
console.log('search:', dir, value);
};
// 穿
const targetKeys = ref<string[]>([]);
// 穿
const sendPlan = () => {
if (targetKeys.value.length < 1) {
return message.info('没有选择任何计划');
}
http.post(planManage.submitTransData, targetKeys.value).then(() => {
message.success('添加成功');
//
reset();
});
};
const filterOption = (inputValue: string, option: any) => {
return option.description.indexOf(inputValue) > -1;
};
//
defineExpose({
reset,
});
</script>
<style lang="less" scoped>
@import '../../style/dialogStyle.less';
.buttons {
display: flex;
justify-content: space-between;
.plan {
border: none;
font-size: 14px;
font-weight: 400;
border-radius: 5px;
width: 88px;
height: 32px;
color: white;
cursor: pointer;
margin: 15px 0;
vertical-align: middle;
}
.plan.enabled {
background: linear-gradient(180deg, rgba(103, 222, 0, 1) 0%, rgba(0, 181, 6, 1) 100%);
}
.plan.disabled {
background-color: red;
}
.plan:disabled {
cursor: not-allowed;
}
}
//
.div-add {
height: 64px;
display: flex;
justify-content: flex-end;
align-items: center;
position: fixed;
bottom: 0;
right: 0;
margin-right: 10px;
.add {
width: 74px;
height: 40px;
opacity: 1;
border-radius: 4px;
background: rgba(67, 136, 251, 1);
border: rgba(67, 136, 251, 1);
font-size: 14px;
font-weight: 400;
color: rgba(255, 255, 255, 1);
cursor: pointer;
}
}
//
.custom-table {
border-collapse: collapse;
width: 416px;
height: 40px;
color: rgba(255, 255, 255, 1);
}
.custom-table th,
.custom-table td {
border: 1px solid rgba(163, 192, 243, 1);
text-align: left;
padding: 8px;
text-align: center;
}
.table1 {
width: 100%;
border: 1px solid rgba(255, 255, 255);
border-radius: 5px;
background: rgba(255, 255, 255, 0.1);
//
.tabReboot,
.tabDelete {
border: none;
display: inline-block;
background-color: rgba(0, 0, 0, 0);
font-size: 14px;
font-weight: 400;
letter-spacing: 0;
line-height: 20px;
color: rgba(67, 136, 251, 1);
cursor: pointer;
}
.tabReboot {
margin-right: 8px;
}
.tabReboot::active {
color: white !important;
}
.tabDelete::active {
color: white;
}
}
::v-deep(.ant-transfer) {
// hover
.ant-transfer-list-content-item:hover {
background: black;
}
}
</style>

282
hx-ai-intelligent/src/view/equipmentControl/waterSystem/device.ts

@ -0,0 +1,282 @@
import { ref } from 'vue';
// 流动线条样式与定位
export const linePosition = [
// 雨水池 - 控制阀
{
left: '4%',
top: '44%',
transform: 'rotateZ(-30deg)',
transformOrigin: 'left',
zIndex: '6',
width: '6%',
},
{
left: '4%',
top: '84%',
transform: 'rotateZ(-30deg)',
transformOrigin: 'left',
zIndex: '6',
width: '6%',
},
// 控制阀 - 进水阀
{ left: '12%', top: '34%', width: '10%' },
{ left: '12%', top: '74%', width: '10%' },
// 进水阀 - 集水池
{ left: '23%', top: '34%', width: '8%' },
{ left: '23%', top: '74%', width: '8%' },
// 集水池 - 排水泵 - 横线
{ left: '35%', top: '34%', width: '4%' },
{ left: '35%', top: '74%', width: '4%' },
// 上半集水池右侧分线
{ left: '39%', top: '34%', transform: 'rotateZ(90deg)', transformOrigin: 'left', width: '4%' },
{ left: '39%', top: '34%', transform: 'rotateZ(-90deg)', transformOrigin: 'left', width: '4%' },
// 下半集水池右侧分线
{ left: '39%', top: '74%', transform: 'rotateZ(90deg)', transformOrigin: 'left', width: '4%' },
{ left: '39%', top: '74%', transform: 'rotateZ(-90deg)', transformOrigin: 'left', width: '4%' },
// 上半-左侧水泵分线
{ left: '39%', top: '25%', width: '8%' },
{ left: '39%', top: '43%', width: '8%' },
// 下半-左侧水泵分线
{ left: '39%', top: '65%', width: '8%' },
{ left: '39%', top: '83%', width: '8%' },
// 水泵右侧合线 下半
{ left: '47%', top: '83%', transform: 'rotateZ(-90deg)', transformOrigin: 'left', width: '14%' },
// 水泵右侧合线 上半
{ left: '47%', top: '25%', transform: 'rotateZ(90deg)', transformOrigin: 'left', width: '12%' },
// 汇入总闸连线
{ left: '47%', top: '52%', width: '4%' },
// 汇入总集水池
{ left: '51%', top: '52%', transform: 'rotateZ(-25deg)', transformOrigin: 'left', width: '7%' },
// 汇入总排水闸
{ left: '58%', top: '45%', width: '9%' },
// 汇入市政管道 - 途径水泵2
{ left: '68%', top: '45%', width: '28%' },
// 总排水闸 - 总排水泵1 上半
{ left: '75%', top: '45%', transform: 'rotateZ(-90deg)', transformOrigin: 'left', width: '10%' },
{ left: '75%', top: '23%', width: '11%' },
{ left: '86%', top: '22.5%', transform: 'rotateZ(90deg)', transformOrigin: 'left', width: '10%' },
// 总排水闸 - 总排水泵3 下半
{ left: '75%', top: '45%', transform: 'rotateZ(90deg)', transformOrigin: 'left', width: '9%' },
{ left: '75%', top: '65%', width: '11%' },
{
left: '86%',
top: '65%',
transform: 'rotateZ(-90deg)',
transformOrigin: 'left',
width: '9%',
},
];
/**
* 1.
* 2.
* 3.
* @param icon =1/=2/=3//进水阀=4//排水泵=5
* @param type =1/=2/=3/=4
* @param open =true/=false
* @param control false
* @param edited
*/
// 污水池
export const device1 = ref([
{
control: false,
type: 1,
icon: 1,
styleObject: {
left: '1%',
top: '40%',
zIndex: '9',
},
},
{
control: false,
type: 1,
icon: 1,
styleObject: {
left: '1%',
top: '80%',
zIndex: '9',
},
},
]);
// 阀门
export const device2 = ref([
{
control: true,
open: true,
type: 2,
icon: 3,
edited: false,
styleObject: {
left: '8%',
top: '28%',
},
},
{
control: true,
open: false,
type: 2,
icon: 3,
edited: false,
styleObject: {
left: '8%',
top: '68%',
},
},
{
control: true,
open: true,
type: 2,
icon: 4,
edited: false,
styleObject: {
left: '20%',
top: '28%',
},
},
{
control: true,
open: true,
type: 2,
icon: 4,
edited: false,
styleObject: {
left: '20%',
top: '68%',
},
},
{
control: true,
open: true,
type: 2,
icon: 3,
edited: false,
styleObject: {
left: '48%',
top: '46%',
},
},
{
control: true,
open: true,
type: 2,
icon: 3,
edited: false,
styleObject: {
left: '65%',
top: '38%',
},
},
]);
// 集水池
export const device3 = ref([
{
control: false,
type: 3,
icon: 2,
styleObject: {
left: '30%',
top: '68%',
},
},
{
control: false,
type: 3,
icon: 2,
styleObject: {
left: '30%',
top: '28%',
},
},
{
control: false,
type: 3,
icon: 2,
styleObject: {
left: '56%',
top: '40%',
},
},
]);
// 水泵
export const device4 = ref([
{
control: true,
open: false,
type: 4,
icon: 5,
edited: false,
styleObject: {
left: '40%',
top: '20%',
},
},
{
control: true,
open: true,
type: 4,
icon: 5,
edited: false,
styleObject: {
left: '40%',
top: '40%',
},
},
{
control: true,
open: true,
type: 4,
icon: 5,
edited: false,
styleObject: {
left: '40%',
top: '60%',
},
},
{
control: true,
open: true,
type: 4,
icon: 5,
edited: false,
styleObject: {
left: '40%',
top: '80%',
},
},
// 右上3水泵
{
control: true,
open: true,
type: 4,
icon: 5,
edited: false,
styleObject: {
left: '78%',
top: '20%',
},
},
{
control: true,
open: true,
type: 4,
icon: 5,
edited: false,
styleObject: {
left: '78%',
top: '40%',
},
},
{
control: true,
open: true,
type: 4,
icon: 5,
edited: false,
styleObject: {
left: '78%',
top: '60%',
},
},
]);

150
hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceInfo.vue

@ -0,0 +1,150 @@
<template>
<div class="left-top">
<div class="info">
<div class="title-item">
<div class="title-back">设备状态</div>
</div>
<div class="info-item">
<div v-for="(item, index) in deviceState" :key="index">
<img v-if="item.type == props.state" :src="item.icon" alt="" />
<img v-else :src="item.default" alt="" />
<div class="mode-item-text">{{ item.name }}</div>
</div>
</div>
</div>
<div class="mode">
<div class="title-item">
<div class="title-back">控制模式</div>
<div class="title-button">计划启用</div>
</div>
<div class="mode-item"></div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
//
import { items } from '/@/store/item';
//
import type1 from './images/type1.png';
import type2 from './images/type2.png';
import type3 from './images/type3.png';
import type1off from './images/type1off.png';
import type2off from './images/type2off.png';
import type3off from './images/type3off.png';
//
const props = defineProps({
//
state: {
type: Number,
},
});
const deviceState = [
{
icon: type1,
default: type1off,
name: '运行',
type: 1,
},
{
icon: type2,
default: type2off,
name: '故障',
type: 2,
},
{
icon: type3,
default: type3off,
name: '强排',
type: 3,
},
];
//
onMounted(() => {});
</script>
<style lang="less" scoped>
.left-top {
--pad: 12px;
position: absolute;
left: var(--pad);
top: var(--pad);
width: auto;
height: 110px;
display: flex;
z-index: 99;
gap: var(--pad);
> div {
background: black;
display: flex;
flex-direction: column;
gap: 3px;
box-sizing: border-box;
padding: 10px;
border-radius: 4px;
.title-item {
padding: 5px;
position: relative;
.title-back {
margin-left: 10px;
padding-left: 5px;
background: linear-gradient(to right, #1aaefb, transparent);
width: 7em;
color: white;
position: relative;
font-size: 14px;
vertical-align: middle;
}
.title-back::before {
position: absolute;
content: '';
display: block;
width: 5px;
height: 100%;
left: -12px;
background: #1aaefb;
}
.title-button {
position: absolute;
right: 2px;
top: 2px;
padding: 3px 8px;
color: white;
border-radius: 4px;
user-select: none;
cursor: pointer;
background: linear-gradient(180deg, rgba(103, 222, 0, 1) 0%, rgba(0, 181, 6, 1) 100%);
}
}
}
//
.info {
width: 230px;
.info-item {
display: flex;
padding-top: 3px;
div {
flex: 1;
display: flex;
flex-direction: column;
gap: 5px;
align-items: center;
.mode-item-text {
color: white;
user-select: none;
}
img {
width: 23px;
display: block;
user-select: none;
}
}
}
}
//
.mode {
width: 200px;
.mode-item {
}
}
}
</style>

291
hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceItem.vue

@ -0,0 +1,291 @@
<template>
<div class="deviceItem" :style="info.styleObject">
<!-- 点击编辑弹出框 -->
<a-popover
color="rgba(0, 0, 0, 0.8)"
placement="right"
v-model:visible="visible"
trigger="click">
<template #content>
<div class="item-box">
<div class="item-box-title">
<img v-if="info.type == 2" src="./images/device1.png" alt="" />
<img v-if="info.type == 4" src="./images/device2.png" alt="" />
<span>{{ info.name }}</span>
</div>
<!-- 开关 -->
<div v-if="info.type == 4" class="item-box-switch">
<div>开关</div>
<a-switch style="margin-top: 3px" size="small" v-model:checked="info.open" />
</div>
<div v-if="info.type == 2" class="item-box-range">
<div>开度</div>
<!-- <a-slider v-model:value="info.value" :tooltip-visible="true" :marks="range" :step="1"> -->
<a-slider v-model:value="info.value" :marks="range" :step="1">
<template #mark="{ label, point }">
<template v-if="point === 100">
<strong>{{ label }}</strong>
</template>
<template v-else>{{ label }}</template>
</template>
</a-slider>
</div>
<div v-if="info.type == 4" class="item-box-range">
<div>频率</div>
<a-slider v-model:value="info.value" :marks="range" :step="1">
<template #mark="{ label, point }">
<template v-if="point === 100">
<strong>{{ label }}</strong>
</template>
<template v-else>{{ label }}</template>
</template>
</a-slider>
</div>
<div class="item-box-button">
<a-button class="item-btn" @click="refresh">刷新</a-button>
<a-popconfirm
title="此操作只保存修改,需右下角按钮提交"
ok-text="确定"
cancel-text="取消"
@confirm="editDevice">
<a-button class="item-btn" type="primary">执行</a-button>
</a-popconfirm>
</div>
</div>
</template>
<div v-if="!info.edited && info.control" class="device-button-back">
<img src="./images/edit.png" alt="" />
编辑</div
>
</a-popover>
<a-popconfirm
title="撤销将移除已保存的修改"
ok-text="确定"
cancel-text="取消"
@confirm="backConfirm">
<div v-if="info.edited && info.control" class="device-button">
<img src="./images/back.png" alt="" />
撤销</div
>
</a-popconfirm>
<!-- 设备图标 - 当前共5种单位 -->
<img v-if="info.icon == 1" src="./images/pond1.png" alt="" />
<img v-if="info.icon == 2" src="./images/pond2.png" alt="" />
<img v-if="info.icon == 3" src="./images/valve1.png" alt="" />
<img v-if="info.icon == 4" src="./images/valve2.png" alt="" />
<img v-if="info.icon == 5" style="width: 70px; height: 70px" src="./images/pump.png" alt="" />
<div class="info-name">
<span>{{ info.name }}</span>
<div class="img-box">
<img
v-if="(info.type == 2 || info.type == 4) && info.state == 0"
src="./images/alarm1.png"
alt="" />
<img
v-if="(info.type == 2 || info.type == 4) && info.state > 0"
src="./images/alarm2.png"
alt="" />
</div>
</div>
<!-- 只有水池会显示容量 -->
<div class="info-value" v-if="info.type == 1 || info.type == 3">
容量 : {{ info.value + info.unit }}</div
>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue';
import { message } from 'ant-design-vue';
//
// ===============================================================
//
onMounted(() => {});
//
const props = defineProps({
//
info: {
type: Object,
default: () => {},
},
});
//
const info = computed(() => props.info);
// =============================================================
//
const visible = ref(false);
//
const range = ref({
0: {
style: {
color: '#0DFFFF',
},
label: 'min',
},
100: {
style: {
color: '#0DFFFF',
},
label: 'max',
},
});
//
const refresh = () => {
info.value.value = info.value.oldVal;
};
//
const backConfirm = () => {
info.value.value = info.value.oldVal;
info.value.edited = false;
//
if (info.value.type == 4) {
console.log(info.value);
info.value.open = info.value.opened;
}
};
// -
const editDevice = () => {
//
if (info.value.value == info.value.oldVal && info.value.open === info.value.opened) {
return message.info('未产生任何修改');
}
//
visible.value = false;
info.value.edited = true;
message.success('保存成功');
};
</script>
<style lang="less" scoped>
//
.deviceItem {
--size: 90px;
width: var(--size);
height: var(--size);
position: absolute;
top: 20%;
text-align: center;
// 使3
z-index: 3;
> img {
user-select: none;
}
//
.info-name {
color: white;
font-size: 15px;
text-align: center;
position: relative;
> span {
vertical-align: middle;
}
.img-box {
display: inline-block;
position: absolute;
margin-left: 8px;
width: 22px;
> img {
width: 22px;
}
}
}
//
.info-value {
text-align: center;
color: #23fdab;
font-size: 13px;
}
//
.device-button {
position: absolute;
top: -35px;
left: 0;
right: 0;
margin: auto;
width: 5em;
padding: 5px 0;
text-align: center;
border-radius: 4px;
font-weight: 700;
cursor: pointer;
background: linear-gradient(#ffd700, #ffa403);
color: #674330;
user-select: none;
> img {
width: 13px;
}
}
//
.device-button-back {
position: absolute;
top: -35px;
left: 0;
right: 0;
margin: auto;
width: 5em;
padding: 5px 0;
text-align: center;
border-radius: 4px;
font-weight: 700;
cursor: pointer;
background: linear-gradient(#00f92c, #00fe9f);
color: #003d5a;
user-select: none;
> img {
width: 13px;
}
}
> img {
width: 100%;
height: 100%;
}
}
//
.ant-popover-inner {
//
.item-box {
width: 250px;
display: flex;
flex-direction: column;
gap: 15px;
color: white;
img {
width: 20px;
margin-right: 10px;
vertical-align: middle;
}
}
//
.item-box-switch {
padding: 10px 15px;
display: flex;
justify-content: space-between;
border-radius: 4px;
background: rgba(67, 136, 251, 0.3);
.ant-switch-checked {
background: linear-gradient(180deg, rgba(1, 206, 255, 1) 0%, rgba(0, 150, 229, 1) 100%);
}
}
//
.item-box-range {
padding: 10px 15px 10px 15px;
box-sizing: border-box;
border-radius: 4px;
background: rgba(67, 136, 251, 0.3);
.ant-slider-handle {
border: 2px solid red !important;
}
}
//
.item-box-button {
text-align: right;
.item-btn {
text-align: center;
margin-left: 10px;
}
}
}
</style>

30
hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceLine.vue

@ -0,0 +1,30 @@
<template>
<div class="line-item" :style="position"></div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
//
const props = defineProps({
// 线
position: {
type: Object,
default: () => {},
},
});
const position = computed(() => {
return props.position;
});
</script>
<style lang="less" scoped>
.line-item {
position: absolute;
height: 10px;
width: 250px;
z-index: 1;
background-image: url(./images/back.gif);
background-color: rgba(13, 255, 164, 0.3);
background-size: 200px 10px;
border-radius: 5px;
}
</style>

663
hx-ai-intelligent/src/view/equipmentControl/waterSystem/index.vue

@ -0,0 +1,663 @@
<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="openDrawer1">执行</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>
</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 openDrawer1 = () => {
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('修改完成');
// allSucceedtrue
} 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;
});
};
// ==========================================================================================
// tabtab
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%;
}
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);
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: 1px solid white;
}
.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;
> 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>
Loading…
Cancel
Save