2025-05-27 16:37:49 +08:00
|
|
|
|
<template>
|
2025-07-15 16:42:03 +08:00
|
|
|
|
<div :class="classObj" class="app-wrapper" :style="{ '--current-color': $store.state.settings.theme }">
|
|
|
|
|
|
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
|
|
|
|
|
<sidebar class="sidebar-container"
|
|
|
|
|
|
:style="{ backgroundColor: $store.state.settings.themeStyle === 'dark' ? variables.menuBg : variables.menuLightBg }" />
|
|
|
|
|
|
<div :class="{ hasTagsView: needTagsView }" class="main-container">
|
|
|
|
|
|
<div :class="{ 'fixed-header': fixedHeader }">
|
2025-05-27 16:37:49 +08:00
|
|
|
|
<navbar />
|
|
|
|
|
|
<tags-view v-if="needTagsView" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<app-main />
|
|
|
|
|
|
<right-panel v-if="showSettings">
|
|
|
|
|
|
<settings />
|
|
|
|
|
|
</right-panel>
|
|
|
|
|
|
</div>
|
2025-07-18 18:07:44 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 绑定谷歌验证码弹窗 -->
|
|
|
|
|
|
<set-google-secret :visible.sync="showSetGooleSecret" :otpAuthUrl="needGoolAuthData.otpAuthUrl"
|
|
|
|
|
|
:secret="needGoolAuthData.secret" @success="handleBindSuccess"></set-google-secret>
|
2025-05-27 16:37:49 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import RightPanel from '@/components/RightPanel'
|
2025-07-18 18:07:44 +08:00
|
|
|
|
import { needGoolAuth, setGoogleAuth } from '@/api/admin/sys-user'
|
2025-05-27 16:37:49 +08:00
|
|
|
|
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
|
2025-07-18 18:07:44 +08:00
|
|
|
|
import SetGoogleSecret from './SetGoogleSecret'
|
2025-05-27 16:37:49 +08:00
|
|
|
|
import ResizeMixin from './mixin/ResizeHandler'
|
|
|
|
|
|
import { mapState } from 'vuex'
|
|
|
|
|
|
import variables from '@/styles/variables.scss'
|
2025-07-18 18:07:44 +08:00
|
|
|
|
// import dingSound from '@/assets/tiktok/sisfus.mp3'
|
2025-07-15 16:42:03 +08:00
|
|
|
|
import checkPermisAction from '@/utils/permisaction'
|
2025-05-27 16:37:49 +08:00
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: 'Layout',
|
|
|
|
|
|
components: {
|
|
|
|
|
|
AppMain,
|
|
|
|
|
|
Navbar,
|
|
|
|
|
|
RightPanel,
|
|
|
|
|
|
Settings,
|
|
|
|
|
|
Sidebar,
|
2025-07-18 18:07:44 +08:00
|
|
|
|
TagsView,
|
|
|
|
|
|
SetGoogleSecret
|
2025-05-27 16:37:49 +08:00
|
|
|
|
},
|
2025-07-15 16:42:03 +08:00
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
voice: null,
|
2025-07-18 18:07:44 +08:00
|
|
|
|
showSetGooleSecret: false,
|
|
|
|
|
|
needGoolAuthData: {}
|
2025-07-15 16:42:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-05-27 16:37:49 +08:00
|
|
|
|
mixins: [ResizeMixin],
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
...mapState({
|
|
|
|
|
|
sidebar: state => state.app.sidebar,
|
|
|
|
|
|
device: state => state.app.device,
|
|
|
|
|
|
showSettings: state => state.settings.showSettings,
|
|
|
|
|
|
needTagsView: state => state.settings.tagsView,
|
|
|
|
|
|
fixedHeader: state => state.settings.fixedHeader
|
|
|
|
|
|
}),
|
|
|
|
|
|
classObj() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
hideSidebar: !this.sidebar.opened,
|
|
|
|
|
|
openSidebar: this.sidebar.opened,
|
|
|
|
|
|
withoutAnimation: this.sidebar.withoutAnimation,
|
|
|
|
|
|
mobile: this.device === 'mobile'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
variables() {
|
|
|
|
|
|
return variables
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-07-15 16:42:03 +08:00
|
|
|
|
|
|
|
|
|
|
created() {
|
2025-07-18 18:07:44 +08:00
|
|
|
|
this.getNeedGoolAuth()
|
2025-07-15 16:42:03 +08:00
|
|
|
|
|
|
|
|
|
|
if (checkPermisAction(['admin:mmAlarmLog:notice'])) {
|
2025-07-18 18:07:44 +08:00
|
|
|
|
// this.$confirm('是否接收警告?', '提示', {
|
|
|
|
|
|
// distinguishCancelAndClose: true,
|
|
|
|
|
|
// confirmButtonText: '确定',
|
|
|
|
|
|
// cancelButtonText: '取消',
|
|
|
|
|
|
// type: 'warning'
|
|
|
|
|
|
// }).then(() => {
|
|
|
|
|
|
// this.voice = new Audio(dingSound)
|
|
|
|
|
|
|
|
|
|
|
|
this.initWebSocket()
|
|
|
|
|
|
// }).catch(() => {
|
|
|
|
|
|
// console.log('取消')
|
|
|
|
|
|
// });
|
2025-07-15 16:42:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
destroyed() {
|
|
|
|
|
|
console.log('断开websocket连接')
|
|
|
|
|
|
this.websock.close() // 离开路由之后断开websocket连接
|
|
|
|
|
|
},
|
2025-05-27 16:37:49 +08:00
|
|
|
|
methods: {
|
2025-07-15 16:42:03 +08:00
|
|
|
|
checkPermisAction,
|
2025-07-18 18:07:44 +08:00
|
|
|
|
getNeedGoolAuth() {
|
|
|
|
|
|
const loading = this.$loading({
|
|
|
|
|
|
lock: true,
|
|
|
|
|
|
text: 'Loading',
|
|
|
|
|
|
spinner: 'el-icon-loading',
|
|
|
|
|
|
background: 'rgba(0, 0, 0, 0.7)'
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
needGoolAuth()
|
|
|
|
|
|
.then(response => {
|
|
|
|
|
|
console.log("needGoogleAuth", response)
|
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
|
if (response.data.needGooglAuth) {
|
|
|
|
|
|
this.needGoolAuthData.otpAuthUrl = response.data.otpAuthUrl
|
|
|
|
|
|
this.needGoolAuthData.secret = response.data.secret
|
|
|
|
|
|
this.showSetGooleSecret = true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
loading.close()
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
2025-07-15 16:42:03 +08:00
|
|
|
|
initWebSocket() { // 初始化weosocket
|
|
|
|
|
|
const wsuri = `ws://${process.env.VUE_APP_WEBSOCKET_URL}/ws?token=${this.$store.state.user.token}`
|
|
|
|
|
|
|
|
|
|
|
|
this.websock = new WebSocket(wsuri)
|
|
|
|
|
|
this.websock.onmessage = this.websocketonmessage
|
|
|
|
|
|
this.websock.onopen = this.websocketonopen
|
|
|
|
|
|
this.websock.onerror = this.websocketonerror
|
|
|
|
|
|
this.websock.onclose = this.websocketclose
|
|
|
|
|
|
},
|
|
|
|
|
|
websocketonopen() { // 连接建立之后执行send方法发送数据
|
|
|
|
|
|
console.log('ws连接打开')
|
|
|
|
|
|
// const actions = { 'test': '12345' }
|
|
|
|
|
|
// this.websocketsend(JSON.stringify(actions))
|
|
|
|
|
|
},
|
|
|
|
|
|
websocketonerror() { // 连接建立失败重连
|
|
|
|
|
|
this.initWebSocket()
|
|
|
|
|
|
},
|
|
|
|
|
|
websocketonmessage(e) { // 数据接收
|
|
|
|
|
|
try {
|
|
|
|
|
|
let data = JSON.parse(e.data)
|
|
|
|
|
|
|
|
|
|
|
|
this.$notify({
|
|
|
|
|
|
title: '钱包警告',
|
|
|
|
|
|
dangerouslyUseHTMLString: true,
|
|
|
|
|
|
message: `<p>设备id:${data.machineId}</p><p>设备码:${data.biosId}</p><p style="text-align:left;">内容:${data.content}</p>`,
|
|
|
|
|
|
type: 'warning',
|
|
|
|
|
|
duration: 0
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-07-18 18:07:44 +08:00
|
|
|
|
// this.playVoice("钱包告警")
|
2025-07-15 16:42:03 +08:00
|
|
|
|
} catch (err) {
|
|
|
|
|
|
console.log("接收websocket数据失败:", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
playVoice(text) {
|
|
|
|
|
|
|
|
|
|
|
|
this.voice.play().catch(err => {
|
|
|
|
|
|
console.error('音频播放失败:', err)
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
websocketsend(Data) { // 数据发送
|
|
|
|
|
|
// this.websock.send(Data)
|
|
|
|
|
|
},
|
|
|
|
|
|
websocketclose(e) { // 关闭
|
|
|
|
|
|
// unWsLogout(this.id, this.group).then(response => {
|
|
|
|
|
|
// console.log(response.data)
|
|
|
|
|
|
// }
|
|
|
|
|
|
// )
|
|
|
|
|
|
// console.log('断开连接', e)
|
|
|
|
|
|
},
|
2025-05-27 16:37:49 +08:00
|
|
|
|
handleClickOutside() {
|
|
|
|
|
|
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
2025-07-18 18:07:44 +08:00
|
|
|
|
},
|
|
|
|
|
|
handleBindSuccess() {
|
|
|
|
|
|
this.showSetGooleSecret = false
|
2025-05-27 16:37:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
2025-07-15 16:42:03 +08:00
|
|
|
|
@import "~@/styles/mixin.scss";
|
|
|
|
|
|
@import "~@/styles/variables.scss";
|
2025-05-27 16:37:49 +08:00
|
|
|
|
|
2025-07-15 16:42:03 +08:00
|
|
|
|
.app-wrapper {
|
|
|
|
|
|
@include clearfix;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
width: 100%;
|
2025-05-27 16:37:49 +08:00
|
|
|
|
|
2025-07-15 16:42:03 +08:00
|
|
|
|
&.mobile.openSidebar {
|
2025-05-27 16:37:49 +08:00
|
|
|
|
position: fixed;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
}
|
2025-07-15 16:42:03 +08:00
|
|
|
|
}
|
2025-05-27 16:37:49 +08:00
|
|
|
|
|
2025-07-15 16:42:03 +08:00
|
|
|
|
.drawer-bg {
|
|
|
|
|
|
background: #000;
|
|
|
|
|
|
opacity: 0.3;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
z-index: 999;
|
|
|
|
|
|
}
|
2025-05-27 16:37:49 +08:00
|
|
|
|
|
2025-07-15 16:42:03 +08:00
|
|
|
|
.fixed-header {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
z-index: 9;
|
|
|
|
|
|
width: calc(100% - #{$sideBarWidth});
|
|
|
|
|
|
transition: width 0.28s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.hideSidebar .fixed-header {
|
|
|
|
|
|
width: calc(100% - 54px)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mobile .fixed-header {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
2025-05-27 16:37:49 +08:00
|
|
|
|
</style>
|