2024-06-26 15:11:05 +08:00
|
|
|
|
<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>
|
2024-09-08 20:13:32 +08:00
|
|
|
|
<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>
|
2024-06-26 15:11:05 +08:00
|
|
|
|
</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'
|
2024-09-08 20:13:32 +08:00
|
|
|
|
import { validateNewPassword } from '@/utils/validate'
|
|
|
|
|
|
import { updateUserPwd, checkPasswordStatus } from '@/api/system/user'
|
2024-11-12 14:56:22 +08:00
|
|
|
|
import { handleNoWarningLog } from '@/api/system/log'
|
2024-11-10 08:55:36 +08:00
|
|
|
|
import {MessageBox} from "element-ui";
|
2024-06-26 15:11:05 +08:00
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: 'Layout',
|
2024-09-08 20:13:32 +08:00
|
|
|
|
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' }
|
|
|
|
|
|
]
|
2024-11-10 08:55:36 +08:00
|
|
|
|
},
|
|
|
|
|
|
socket: null,
|
2024-11-12 10:53:58 +08:00
|
|
|
|
wsUrl: JSON.parse(localStorage.getItem('systemConfig')).webSocketurl,//'ws://localhost:18082/ws', // WebSocket 端点
|
2024-11-10 08:55:36 +08:00
|
|
|
|
isConnected: false, // 连接状态
|
|
|
|
|
|
reconnectInterval: 5000 // 自动重连时间间隔(毫秒
|
|
|
|
|
|
|
2024-09-08 20:13:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2024-06-26 15:11:05 +08:00
|
|
|
|
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,
|
2024-11-11 13:42:53 +08:00
|
|
|
|
fixedHeader: state => state.settings.fixedHeader,
|
|
|
|
|
|
roles: state => state.user.roles,
|
2024-06-26 15:11:05 +08:00
|
|
|
|
}),
|
|
|
|
|
|
classObj() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
hideSidebar: !this.sidebar.opened,
|
|
|
|
|
|
openSidebar: this.sidebar.opened,
|
|
|
|
|
|
withoutAnimation: this.sidebar.withoutAnimation,
|
|
|
|
|
|
mobile: this.device === 'mobile'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
variables() {
|
2024-09-08 20:13:32 +08:00
|
|
|
|
return variables
|
2024-06-26 15:11:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2024-09-08 20:13:32 +08:00
|
|
|
|
created() {
|
|
|
|
|
|
this.checkPasswordStatus()
|
2024-11-12 14:56:22 +08:00
|
|
|
|
if (this.roles.includes("audit") || this.roles.includes("systemAdmin")) {
|
2024-11-11 13:42:53 +08:00
|
|
|
|
this.connectWebSocket();
|
|
|
|
|
|
}
|
2024-11-12 14:56:22 +08:00
|
|
|
|
this.handleNoWarningLog()
|
2024-09-08 20:13:32 +08:00
|
|
|
|
},
|
2024-06-26 15:11:05 +08:00
|
|
|
|
methods: {
|
2024-09-08 20:13:32 +08:00
|
|
|
|
checkPasswordStatus() {
|
|
|
|
|
|
checkPasswordStatus().then(response => {
|
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
|
this.showChangePasswordDialog = response.data
|
|
|
|
|
|
this.title = response.msg
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
2024-11-12 14:56:22 +08:00
|
|
|
|
|
|
|
|
|
|
handleNoWarningLog(){
|
|
|
|
|
|
handleNoWarningLog().then(response => {
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2024-06-26 15:11:05 +08:00
|
|
|
|
handleClickOutside() {
|
|
|
|
|
|
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
2024-09-08 20:13:32 +08:00
|
|
|
|
},
|
|
|
|
|
|
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';
|
|
|
|
|
|
})
|
2024-11-10 08:55:36 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 连接 WebSocket
|
|
|
|
|
|
connectWebSocket() {
|
|
|
|
|
|
if (this.socket) {
|
|
|
|
|
|
console.log("WebSocket 已连接");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-11-12 10:53:58 +08:00
|
|
|
|
console.log("WebSocket URL:{}",this.wsUrl)
|
2024-11-10 08:55:36 +08:00
|
|
|
|
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)
|
2024-11-12 14:56:22 +08:00
|
|
|
|
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);
|
|
|
|
|
|
}
|
2024-11-10 08:55:36 +08:00
|
|
|
|
}
|
2024-11-12 14:56:22 +08:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-10 08:55:36 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 通知后端告警已处理
|
|
|
|
|
|
notifyBackend(warningId) {
|
|
|
|
|
|
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
|
|
|
|
const message = {
|
|
|
|
|
|
warningId,
|
|
|
|
|
|
};
|
2024-11-11 09:49:34 +08:00
|
|
|
|
this.socket.send(warningId);
|
2024-11-10 08:55:36 +08:00
|
|
|
|
console.log(`已通知后端处理告警: ${warningId}`);
|
|
|
|
|
|
}
|
2024-06-26 15:11:05 +08:00
|
|
|
|
}
|
2024-11-10 08:55:36 +08:00
|
|
|
|
},
|
|
|
|
|
|
beforeDestroy() {
|
|
|
|
|
|
// 页面销毁时关闭 WebSocket 连接
|
|
|
|
|
|
if (this.socket) {
|
|
|
|
|
|
this.socket.close();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-26 15:11:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
2024-09-08 20:13:32 +08:00
|
|
|
|
@import "~@/assets/styles/mixin.scss";
|
|
|
|
|
|
@import "~@/assets/styles/variables.scss";
|
2024-06-26 15:11:05 +08:00
|
|
|
|
|
2024-09-08 20:13:32 +08:00
|
|
|
|
.app-wrapper {
|
|
|
|
|
|
@include clearfix;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
width: 100%;
|
2024-06-26 15:11:05 +08:00
|
|
|
|
|
2024-09-08 20:13:32 +08:00
|
|
|
|
&.mobile.openSidebar {
|
2024-06-26 15:11:05 +08:00
|
|
|
|
position: fixed;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
}
|
2024-09-08 20:13:32 +08:00
|
|
|
|
}
|
2024-06-26 15:11:05 +08:00
|
|
|
|
|
2024-09-08 20:13:32 +08:00
|
|
|
|
.drawer-bg {
|
|
|
|
|
|
background: #000;
|
|
|
|
|
|
opacity: 0.3;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
z-index: 999;
|
|
|
|
|
|
}
|
2024-06-26 15:11:05 +08:00
|
|
|
|
|
2024-09-08 20:13:32 +08:00
|
|
|
|
.fixed-header {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
z-index: 9;
|
|
|
|
|
|
width: calc(100% - #{$base-sidebar-width});
|
|
|
|
|
|
transition: width 0.28s;
|
|
|
|
|
|
}
|
2024-06-26 15:11:05 +08:00
|
|
|
|
|
2024-09-08 20:13:32 +08:00
|
|
|
|
.hideSidebar .fixed-header {
|
|
|
|
|
|
width: calc(100% - 54px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sidebarHide .fixed-header {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mobile .fixed-header {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
2024-06-26 15:11:05 +08:00
|
|
|
|
</style>
|