<script setup name="Realtime">
|
import { ref, onMounted, reactive, watch, computed, watchEffect, onActivated } from "vue";
|
import lockRecord from "./lockRecord.vue";
|
import useWebSocket from "@/hooks/useWebsocket.js";
|
import stationList from '@/components/stationList.vue';
|
import useElement from "@/hooks/useElement.js";
|
import { useRouter, useRoute } from "vue-router";
|
const router = useRouter();
|
const route = useRoute();
|
|
import settings from './settings.vue';
|
|
import { storeToRefs } from "pinia";
|
import { getStationBaojiInfo } from "@/api/station.js";
|
|
import { useUserStore } from '@/store/user.js';
|
const userStore = useUserStore();
|
const { urole, permits } = storeToRefs(userStore);
|
|
import isHasPermit from '@/utils/isHasPermit';
|
import {
|
lockOpen,
|
openLockBl,
|
closeLockBl,
|
} from '@/api/lockManager.js';
|
import svgStation from '@/components/svg/svgStation.vue';
|
|
// 是否有控制权限
|
let isCanControl = isHasPermit("control_permit", permits.value);
|
|
const { $loading, $message, $confirm, $confirmPwdDo } = useElement();
|
const { sendData, message: listMessage } = useWebSocket("real");
|
|
const baojiId = ref();
|
const stationId = ref();
|
const tableData = ref([]);
|
const pageNum = ref(1);
|
const pageSize = ref(10);
|
const total = ref(0);
|
const offline_num = ref(0);
|
const online_num = ref(0);
|
const sum = ref(0);
|
const open_num = ref(0);
|
const close_num = ref(0);
|
const unLoad_num = ref(0);
|
const recordVisible = ref(false);
|
const recordTitle = ref('开启关闭记录');
|
const currLockId = ref();
|
const queryFlag = ref(0);
|
const activeName = ref('topology');
|
const settingsVisible = ref(false);
|
|
function itemClickHandler(item) {
|
console.log(item, '====item', item);
|
const [_baojiId, _stationId] = item.id.split('-');
|
// TODO
|
// areaId lockName lockState lockType pageNum pageSize
|
baojiId.value = _baojiId;
|
stationId.value = _stationId;
|
getStationInfo();
|
sendMessage();
|
}
|
|
const stationName = ref('');
|
const locationInfo = ref();
|
|
watchEffect(() => {
|
let _total = 0;
|
if (listMessage.value) {
|
let {
|
pageInfo,
|
offLineNum,
|
unLoadNum,
|
sumLinf,
|
openNum,
|
onlineNum,
|
closeNum
|
} = JSON.parse(listMessage.value)?.data2;
|
|
let control = JSON.parse(listMessage.value)?.data3 || [];
|
let all = JSON.parse(listMessage.value)?.data4 || [];
|
|
locationInfo.value = {
|
control,
|
all
|
};
|
|
offline_num.value = offLineNum;
|
online_num.value = onlineNum;
|
sum.value = sumLinf;
|
open_num.value = openNum;
|
close_num.value = closeNum;
|
unLoad_num.value = unLoadNum;
|
|
_total = pageInfo.total;
|
tableData.value = pageInfo.list.map(v => ({
|
...v,
|
onlineState: ['离线', '在线'][v.lockOnline],
|
state: { 0: '已闭锁', 1: '已开锁' }[v.lockState],
|
onlineState: { 0: '离线', 1: '在线' }[v.lockOnline],
|
modelStr: v.model == 1 ? '在线模式' : '离线模式',
|
blStateStr: v.blState == 0 ? '蓝牙关闭' : '蓝牙开启',
|
openTime: v.lockState == 1 ? v.lastUpdateTime : '--',
|
closeTime: v.lockState == 0 ? v.lastUpdateTime : '--',
|
}));
|
}
|
|
total.value = _total;
|
});
|
|
function getStationInfo() {
|
getStationBaojiInfo({
|
baojiId: baojiId.value,
|
stationId: stationId.value
|
}).then((res) => {
|
let { code, data, data2, data3 } = res;
|
if (code && data) {
|
console.log(data);
|
stationName.value = data2.stationName + ' ' + data3.baojiName;
|
}
|
})
|
.catch((err) => {
|
console.log(err);
|
});
|
|
}
|
|
function open(scope) {
|
console.log('scope', scope, '=============');
|
let {
|
row
|
} = scope;
|
|
$confirmPwdDo(() => {
|
let loading = $loading();
|
lockOpen(scope.row.lockId).then((res) => {
|
let { code, data } = res;
|
loading.close();
|
if (code && data) {
|
$message.success("操作成功");
|
sendMessage();
|
} else {
|
$message.error("操作失败");
|
}
|
})
|
.catch((err) => {
|
console.log(err);
|
loading.close();
|
});
|
|
});
|
}
|
|
function viewRecord(data) {
|
console.log(data, '999999999999-------');
|
let { row } = data;
|
// recordTitle.value = `开启关闭记录 - ${row.areaPath} ${row.lockName}`;
|
// currLockId.value = row.lockId;
|
// recordVisible.value = true;
|
router.push({
|
path: '/device/history',
|
query: {
|
stationId: stationId.value,
|
baojiId: baojiId.value,
|
lockId: row.lockId,
|
flag: Math.random()
|
}
|
});
|
|
}
|
|
function sendMessage() {
|
let params = {
|
stationId: stationId.value,
|
baojiId: baojiId.value,
|
pageNum: pageNum.value,
|
pageSize: pageSize.value,
|
};
|
sendData(JSON.stringify(params));
|
}
|
function handleSizeChange(val) {
|
pageSize.value = val;
|
sendMessage();
|
}
|
|
function handleCurrentChange(val) {
|
pageNum.value = val;
|
sendMessage();
|
}
|
|
function openBl(scope) {
|
$confirmPwdDo(() => {
|
let loading = $loading();
|
openLockBl(
|
scope.row.lockId
|
).then((res) => {
|
let { code, data } = res;
|
loading.close();
|
if (code && data) {
|
console.log(data);
|
$message.success("操作成功");
|
sendMessage();
|
} else {
|
$message.error("操作失败");
|
}
|
})
|
.catch((err) => {
|
loading.close();
|
console.log(err);
|
});
|
});
|
}
|
|
function closeBl(scope) {
|
$confirmPwdDo(() => {
|
let loading = $loading();
|
closeLockBl(
|
scope.row.lockId
|
).then((res) => {
|
let { code, data } = res;
|
loading.close();
|
if (code && data) {
|
console.log(data);
|
$message.success("操作成功");
|
sendMessage();
|
} else {
|
$message.error("操作失败");
|
}
|
})
|
.catch((err) => {
|
loading.close();
|
console.log(err);
|
});
|
});
|
}
|
|
function goHistory() {
|
router.push({
|
path: '/device/history',
|
query: {
|
stationId: stationId.value,
|
baojiId: baojiId.value,
|
flag: Math.random()
|
}
|
})
|
}
|
|
const tree = ref(null);
|
|
function settingsOk() {
|
settingsVisible.value = false;
|
sendMessage();
|
}
|
|
onActivated(() => {
|
if (queryFlag.value == route.query.flag) {
|
return;
|
}
|
queryFlag.value = route.query.flag || 0;
|
if (route.query.stationId && route.query.baojiId) {
|
baojiId.value = route.query.baojiId;
|
stationId.value = route.query.stationId;
|
|
tree.value.setCurrent(baojiId.value + '-' + stationId.value);
|
}
|
// console.log('baojiId, stationId', baojiId.value, stationId.value, '=============real');
|
|
})
|
</script>
|
|
<template>
|
<div class="page-wrapper">
|
<div class="page-header">
|
<div class="hdw-card-container">
|
<yc-card title="区域列表" is-full>
|
<hdw-tree ref="tree" @item-click="itemClickHandler"></hdw-tree>
|
</yc-card>
|
</div>
|
</div>
|
<div class="page-content">
|
<yc-card is-full>
|
<div class="page-content-wrapper">
|
<div class="p-title">
|
{{ stationName }}
|
<div class="btn-grp">
|
<el-tooltip
|
class="item"
|
effect="dark"
|
content="历史数据"
|
placement="bottom"
|
>
|
<div class="btn" @click="goHistory">
|
<svg-icon icon-class="history"></svg-icon>
|
</div>
|
</el-tooltip>
|
</div>
|
</div>
|
<div class="page-content-tools">
|
<div class="item">
|
<div class="label">设备总数量</div>
|
<div class="value">{{ sum }}</div>
|
</div>
|
<div class="item">
|
<div class="label">在线数量</div>
|
<div class="value">{{ online_num }}</div>
|
</div>
|
<div class="item">
|
<div class="label">离线数量</div>
|
<div class="value">{{ offline_num }}</div>
|
</div>
|
<!-- <div class="item">
|
<div class="label">未安装数量</div>
|
<div class="value">{{ unLoad_num }}</div>
|
</div> -->
|
<div class="item">
|
<div class="label">已开锁</div>
|
<div class="value">{{ open_num }}</div>
|
</div>
|
<div class="item">
|
<div class="label">已关闭</div>
|
<div class="value">{{ close_num }}</div>
|
</div>
|
</div>
|
<el-tabs type="border-card" v-model="activeName" class="tabs">
|
<el-tab-pane name="topology" label="拓扑图">
|
<div class="btn-settings" title="配置" @click="settingsVisible = true"></div>
|
<svg-station :rtData="tableData" :locationInfo="locationInfo" class="svg-station"></svg-station>
|
</el-tab-pane>
|
<el-tab-pane name="list" label="列表">
|
<div class="page-content-table">
|
<div class="pos-rel">
|
<div class="pos-abs">
|
<el-table
|
stripe
|
:data="tableData"
|
border
|
style="width: 100%; height: 100%"
|
>
|
<el-table-column type="index" fixed="left" width="50" />
|
<el-table-column prop="lockId" label="锁具ID" width="180" />
|
<el-table-column
|
prop="lockName"
|
label="锁具名称"
|
width="180"
|
/>
|
<el-table-column
|
prop="onlineState"
|
label="在线状态"
|
width="180"
|
/>
|
<el-table-column
|
prop="blStateStr"
|
label="蓝牙状态"
|
width="180"
|
/>
|
<el-table-column prop="state" label="状态" width="180" />
|
<el-table-column
|
prop="openTime"
|
label="开启时间"
|
width="180"
|
/>
|
<el-table-column
|
prop="closeTime"
|
label="关闭时间"
|
width="180"
|
/>
|
<el-table-column
|
align="center"
|
fixed="right"
|
label="操作"
|
width="320"
|
>
|
<template #default="scope">
|
<el-button
|
type="danger"
|
size="small"
|
v-if="isCanControl && scope.row.lockOnline == 1 && scope.row.lockState == 0"
|
@click="open(scope)"
|
>远程开锁</el-button
|
>
|
<el-button
|
type="primary"
|
v-if="isCanControl && scope.row.lockOnline == 1 && scope.row.blState == 0"
|
size="small"
|
@click="openBl(scope)"
|
>开启蓝牙</el-button
|
>
|
<el-button
|
type="primary"
|
v-if="isCanControl && scope.row.lockOnline == 1 && scope.row.blState == 1"
|
size="small"
|
@click="closeBl(scope)"
|
>关闭蓝牙</el-button
|
>
|
<el-button
|
type="primary"
|
size="small"
|
:disabled="scope.row.lockState == -1"
|
@click="viewRecord(scope)"
|
>历史开启关闭记录</el-button
|
>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
</div>
|
</div>
|
<div class="page-content-page">
|
<div class="page-tool"></div>
|
<div class="el-page-container">
|
<el-pagination
|
v-model:current-page="pageNum"
|
v-model:page-size="pageSize"
|
:page-sizes="[10,20, 40, 60, 80, 100, 200, 300, 400]"
|
size="small"
|
layout="total, sizes, prev, pager, next, jumper"
|
:total="total"
|
@size-change="handleSizeChange"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
<div class="page-tool"></div>
|
</div>
|
</el-tab-pane>
|
</el-tabs>
|
</div>
|
</yc-card>
|
</div>
|
<div class="page-footer"></div>
|
<!-- 配置机柜 -->
|
<el-dialog
|
v-model="settingsVisible"
|
title="配置"
|
width="780"
|
align-center
|
:close-on-click-modal="false"
|
>
|
<settings v-if="settingsVisible" :locationInfo="locationInfo" @cancel="settingsVisible = false" @success="settingsOk"></settings>
|
</el-dialog>
|
</div>
|
</template>
|
|
<style scoped lang="scss">
|
.page-wrapper {
|
display: flex;
|
flex-direction: row;
|
padding: 8px;
|
height: 100%;
|
|
.page-content {
|
flex: 1;
|
}
|
}
|
|
.p-title {
|
background: #0ff;
|
color: #000;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
height: 36px;
|
border-radius: 6px;
|
margin-bottom: 8px;
|
font-weight: 700;
|
position: relative;
|
|
.btn-grp {
|
position: absolute;
|
right: 10px;
|
|
.btn {
|
cursor: pointer;
|
}
|
}
|
}
|
|
.page-content-wrapper {
|
display: flex;
|
flex-direction: column;
|
height: 100%;
|
.tabs {
|
flex: 1;
|
:deep(.el-tab-pane) {
|
display: flex;
|
flex-direction: column;
|
height: 100%;
|
position: relative;
|
}
|
}
|
|
.page-content-tools {
|
padding-bottom: 8px;
|
}
|
|
.page-content-table {
|
border-top: 1px solid var(--border-light-color);
|
box-sizing: border-box;
|
flex: 1;
|
margin-left: -8px;
|
margin-right: -8px;
|
}
|
|
.page-content-page {
|
padding: 8px 8px 0 8px;
|
text-align: center;
|
|
.el-page-container {
|
display: inline-block;
|
padding: 0 16px;
|
}
|
|
.page-tool {
|
display: inline-block;
|
}
|
}
|
}
|
|
.hdw-card-container {
|
width: 320px;
|
padding-right: 8px;
|
height: 100%;
|
}
|
|
.pos-rel {
|
position: relative;
|
width: 100%;
|
height: 100%;
|
|
.pos-abs {
|
position: absolute;
|
top: 0;
|
bottom: 0;
|
left: 0;
|
right: 0;
|
width: 100%;
|
height: 100%;
|
}
|
}
|
|
.tools-filter {
|
display: inline-block;
|
font-size: 14px;
|
|
.tools-filter-item {
|
display: inline-block;
|
margin-right: 8px;
|
|
.filter-label {
|
display: inline-block;
|
}
|
|
.filter-content {
|
display: inline-block;
|
}
|
}
|
}
|
|
.page-content-tools {
|
display: flex;
|
|
.item {
|
display: flex;
|
align-items: center;
|
|
&+.item {
|
margin-left: 20px;
|
}
|
|
.label {
|
&::after {
|
content: ":";
|
}
|
}
|
|
.value {
|
margin-left: 8px;
|
font-weight: bold;
|
color: #090;
|
font-size: 18px;
|
}
|
}
|
}
|
|
.dialog-title {
|
color: #000;
|
font-size: 16px;
|
padding-left: 0.8em;
|
}
|
|
:deep(.el-dialog__body) {
|
flex: 1;
|
}
|
:deep(.el-tabs--border-card>.el-tabs__content) {
|
padding: 0;
|
position: relative;
|
}
|
.svg-station {
|
position: absolute;
|
top: 0;
|
left: 0;
|
right: 0;
|
bottom: 0;
|
}
|
|
.btn-settings {
|
position: absolute;
|
z-index: 1;
|
right: 200px;
|
top: 20px;
|
cursor: pointer;
|
width: 36px;
|
height: 36px;
|
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 1024 1024' %3e%3cpath d='M950.857143 402.285714h-51.748572a403.2 403.2 0 0 0-36.571428-86.308571l36.571428-36.571429a73.142857 73.142857 0 0 0 0-103.314285l-51.017142-51.931429a73.142857 73.142857 0 0 0-103.314286 0l-36.571429 36.571429A393.691429 393.691429 0 0 0 621.714286 125.074286V73.142857a73.142857 73.142857 0 0 0-73.142857-73.142857h-73.142858a73.142857 73.142857 0 0 0-73.142857 73.142857v51.931429a393.691429 393.691429 0 0 0-86.308571 35.657143l-36.571429-36.571429a73.142857 73.142857 0 0 0-103.314285 0L124.16 175.908571a73.142857 73.142857 0 0 0 0 103.314286l36.571429 36.571429a403.2 403.2 0 0 0-36.571429 86.308571H73.142857a73.142857 73.142857 0 0 0-73.142857 73.142857v73.142857a73.142857 73.142857 0 0 0 73.142857 73.142858h51.748572a403.2 403.2 0 0 0 36.571428 86.308571l-36.571428 36.571429a73.142857 73.142857 0 0 0 0 103.314285l51.748571 51.748572a73.142857 73.142857 0 0 0 103.314286 0l36.571428-36.571429A393.691429 393.691429 0 0 0 402.285714 898.925714V950.857143a73.142857 73.142857 0 0 0 73.142857 73.142857h73.142858a73.142857 73.142857 0 0 0 73.142857-73.142857v-51.931429a393.691429 393.691429 0 0 0 86.308571-35.657143l36.571429 36.571429a73.142857 73.142857 0 0 0 103.314285 0l51.748572-51.748571a73.142857 73.142857 0 0 0 0-103.314286l-36.571429-36.571429a403.2 403.2 0 0 0 36.571429-86.308571H950.857143a73.142857 73.142857 0 0 0 73.142857-73.142857V475.428571a73.142857 73.142857 0 0 0-73.142857-73.142857zM617.142857 613.668571a146.285714 146.285714 0 1 1-3.474286-206.811428 146.285714 146.285714 0 0 1 3.474286 206.811428z' fill='%230ff' %3e%3c/path%3e%3c/svg%3e") center center / contain no-repeat;
|
transform-origin: 50% 50%;
|
&:hover {
|
animation: rotate 12s linear infinite;
|
}
|
}
|
|
@keyframes rotate {
|
from {
|
transform: rotate(0deg);
|
}
|
to {
|
transform: rotate(360deg);
|
}
|
}
|
</style>
|