gs_real_name_system_web/src/layout/index.vue

360 lines
11 KiB
Vue
Raw Normal View History

2025-10-29 10:02:22 +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>
<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: '', //'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(() => {
2025-11-06 15:12:09 +08:00
location.href =
process.env.VUE_APP_ENV === 'production'
? '/gs-realname/index'
: '/index'
2025-10-29 10:02:22 +08:00
})
},
// 连接 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>