bonus-ui/src/layout/index.vue

315 lines
8.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>