315 lines
8.6 KiB
Vue
315 lines
8.6 KiB
Vue
<template>
|
||
<div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
|
||
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
|
||
<sidebar v-if="!sidebar.hide" class="sidebar-container"/>
|
||
<div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container">
|
||
<div :class="{'fixed-header':fixedHeader}">
|
||
<navbar/>
|
||
<tags-view v-if="needTagsView"/>
|
||
</div>
|
||
<app-main/>
|
||
<right-panel>
|
||
<settings/>
|
||
</right-panel>
|
||
</div>
|
||
<el-dialog :title="title" :visible.sync="showChangePasswordDialog" width="30%" :close-on-click-modal="false"
|
||
:show-close="false"
|
||
>
|
||
<el-form ref="form" :model="user" :rules="rules" label-width="80px">
|
||
<el-form-item label="旧密码" prop="oldPassword">
|
||
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password/>
|
||
</el-form-item>
|
||
<el-form-item label="新密码" prop="newPassword">
|
||
<el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password/>
|
||
</el-form-item>
|
||
<el-form-item label="确认密码" prop="confirmPassword">
|
||
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password/>
|
||
</el-form-item>
|
||
</el-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button type="primary" @click="submit">确 定</el-button>
|
||
<el-button @click="close">取 消</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import RightPanel from '@/components/RightPanel'
|
||
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
|
||
import ResizeMixin from './mixin/ResizeHandler'
|
||
import { mapState } from 'vuex'
|
||
import variables from '@/assets/styles/variables.scss'
|
||
import { validateNewPassword } from '@/utils/validate'
|
||
import { updateUserPwd, checkPasswordStatus } from '@/api/system/user'
|
||
import { handleNoWarningLog } from '@/api/system/log'
|
||
import {MessageBox} from "element-ui";
|
||
|
||
export default {
|
||
name: 'Layout',
|
||
data() {
|
||
const equalToPassword = (rule, value, callback) => {
|
||
if (this.user.newPassword !== value) {
|
||
callback(new Error('两次输入的密码不一致'))
|
||
} else {
|
||
callback()
|
||
}
|
||
}
|
||
return {
|
||
showChangePasswordDialog: false, // 控制弹窗显示
|
||
title: '',
|
||
user: {
|
||
oldPassword: undefined,
|
||
newPassword: undefined,
|
||
confirmPassword: undefined
|
||
},
|
||
// 表单校验规则
|
||
rules: {
|
||
oldPassword: [
|
||
{ required: true, message: '旧密码不能为空', trigger: 'blur' }
|
||
],
|
||
newPassword: [
|
||
{ required: true, message: '新密码不能为空', trigger: 'blur' },
|
||
{ validator: validateNewPassword, trigger: 'blur' }
|
||
],
|
||
confirmPassword: [
|
||
{ required: true, message: '确认密码不能为空', trigger: 'blur' },
|
||
{ required: true, validator: equalToPassword, trigger: 'blur' }
|
||
]
|
||
},
|
||
socket: null,
|
||
wsUrl: JSON.parse(localStorage.getItem('systemConfig')).webSocketurl,//'ws://localhost:18082/ws', // WebSocket 端点
|
||
isConnected: false, // 连接状态
|
||
reconnectInterval: 5000 // 自动重连时间间隔(毫秒
|
||
|
||
}
|
||
},
|
||
components: {
|
||
AppMain,
|
||
Navbar,
|
||
RightPanel,
|
||
Settings,
|
||
Sidebar,
|
||
TagsView
|
||
},
|
||
mixins: [ResizeMixin],
|
||
computed: {
|
||
...mapState({
|
||
theme: state => state.settings.theme,
|
||
sideTheme: state => state.settings.sideTheme,
|
||
sidebar: state => state.app.sidebar,
|
||
device: state => state.app.device,
|
||
needTagsView: state => state.settings.tagsView,
|
||
fixedHeader: state => state.settings.fixedHeader,
|
||
roles: state => state.user.roles,
|
||
}),
|
||
classObj() {
|
||
return {
|
||
hideSidebar: !this.sidebar.opened,
|
||
openSidebar: this.sidebar.opened,
|
||
withoutAnimation: this.sidebar.withoutAnimation,
|
||
mobile: this.device === 'mobile'
|
||
}
|
||
},
|
||
variables() {
|
||
return variables
|
||
}
|
||
},
|
||
created() {
|
||
this.checkPasswordStatus()
|
||
if (this.roles.includes("audit") || this.roles.includes("systemAdmin")) {
|
||
this.connectWebSocket();
|
||
}
|
||
this.handleNoWarningLog()
|
||
},
|
||
methods: {
|
||
checkPasswordStatus() {
|
||
checkPasswordStatus().then(response => {
|
||
if (response.code === 200) {
|
||
this.showChangePasswordDialog = response.data
|
||
this.title = response.msg
|
||
}
|
||
})
|
||
},
|
||
|
||
handleNoWarningLog(){
|
||
handleNoWarningLog().then(response => {
|
||
|
||
})
|
||
},
|
||
|
||
handleClickOutside() {
|
||
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
||
},
|
||
submit() {
|
||
this.$refs['form'].validate(valid => {
|
||
if (valid) {
|
||
updateUserPwd(this.user.oldPassword, this.user.newPassword).then(response => {
|
||
this.showChangePasswordDialog = false
|
||
this.$modal.msgSuccess('修改成功')
|
||
})
|
||
}
|
||
})
|
||
},
|
||
close() {
|
||
this.$store.dispatch('LogOut').then(() => {
|
||
location.href = '/index';
|
||
})
|
||
},
|
||
|
||
// 连接 WebSocket
|
||
connectWebSocket() {
|
||
if (this.socket) {
|
||
console.log("WebSocket 已连接");
|
||
return;
|
||
}
|
||
console.log("WebSocket URL:{}",this.wsUrl)
|
||
this.socket = new WebSocket(this.wsUrl);
|
||
|
||
// 监听 WebSocket 连接成功事件
|
||
this.socket.onopen = () => {
|
||
console.log("WebSocket 连接成功");
|
||
this.isConnected = true;
|
||
};
|
||
|
||
// 接收消息
|
||
this.socket.onmessage = (event) => {
|
||
console.log("收到消息:", event.data);
|
||
const warning = JSON.parse(event.data);
|
||
this.handleWarning(warning);
|
||
};
|
||
|
||
// 监听连接关闭事件
|
||
this.socket.onclose = () => {
|
||
console.log("WebSocket 连接已关闭");
|
||
this.isConnected = false;
|
||
this.socket = null;
|
||
// 自动重连
|
||
this.reconnectWebSocket();
|
||
};
|
||
|
||
// 监听连接错误事件
|
||
this.socket.onerror = (error) => {
|
||
console.error("WebSocket 错误:", error);
|
||
this.isConnected = false;
|
||
this.socket = null;
|
||
// 自动重连
|
||
this.reconnectWebSocket();
|
||
};
|
||
},
|
||
|
||
// 自动重连 WebSocket
|
||
reconnectWebSocket() {
|
||
console.log("尝试重新连接 WebSocket...");
|
||
setTimeout(() => {
|
||
this.connectWebSocket();
|
||
}, this.reconnectInterval);
|
||
},
|
||
|
||
// 处理告警信息并显示弹窗
|
||
handleWarning(warning) {
|
||
console.log(warning)
|
||
let warningContent = '';
|
||
|
||
if (warning.operaUserName) {
|
||
warningContent += `<p><strong>操作人:</strong>${warning.operaUserName}</p>`;
|
||
}
|
||
|
||
if (warning.warningEvent) {
|
||
warningContent += `<p><strong>事件:</strong>${warning.warningEvent}</p>`;
|
||
}
|
||
|
||
if (warning.warningIp) {
|
||
warningContent += `<p><strong>IP:</strong>${warning.warningIp}</p>`;
|
||
}
|
||
|
||
if (warning.operaTime) {
|
||
warningContent += `<p><strong>时间:</strong>${warning.operaTime}</p>`;
|
||
}
|
||
|
||
if (warningContent) {
|
||
MessageBox.alert(
|
||
warningContent,
|
||
'告警通知',
|
||
{
|
||
dangerouslyUseHTMLString: true,
|
||
confirmButtonText: '确认',
|
||
customClass: 'custom-message-box',
|
||
callback: () => {
|
||
this.notifyBackend(warning.warningId);
|
||
}
|
||
}
|
||
);
|
||
}
|
||
|
||
},
|
||
|
||
// 通知后端告警已处理
|
||
notifyBackend(warningId) {
|
||
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
||
const message = {
|
||
warningId,
|
||
};
|
||
this.socket.send(warningId);
|
||
console.log(`已通知后端处理告警: ${warningId}`);
|
||
}
|
||
}
|
||
},
|
||
beforeDestroy() {
|
||
// 页面销毁时关闭 WebSocket 连接
|
||
if (this.socket) {
|
||
this.socket.close();
|
||
}
|
||
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
@import "~@/assets/styles/mixin.scss";
|
||
@import "~@/assets/styles/variables.scss";
|
||
|
||
.app-wrapper {
|
||
@include clearfix;
|
||
position: relative;
|
||
height: 100%;
|
||
width: 100%;
|
||
|
||
&.mobile.openSidebar {
|
||
position: fixed;
|
||
top: 0;
|
||
}
|
||
}
|
||
|
||
.drawer-bg {
|
||
background: #000;
|
||
opacity: 0.3;
|
||
width: 100%;
|
||
top: 0;
|
||
height: 100%;
|
||
position: absolute;
|
||
z-index: 999;
|
||
}
|
||
|
||
.fixed-header {
|
||
position: fixed;
|
||
top: 0;
|
||
right: 0;
|
||
z-index: 9;
|
||
width: calc(100% - #{$base-sidebar-width});
|
||
transition: width 0.28s;
|
||
}
|
||
|
||
.hideSidebar .fixed-header {
|
||
width: calc(100% - 54px);
|
||
}
|
||
|
||
.sidebarHide .fixed-header {
|
||
width: 100%;
|
||
}
|
||
|
||
.mobile .fixed-header {
|
||
width: 100%;
|
||
}
|
||
</style>
|