diff --git a/package.json b/package.json index 0b43c319..434db7e3 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,8 @@ "vue-meta": "2.4.0", "vue-router": "3.4.9", "vuedraggable": "2.24.3", - "vuex": "3.6.0" + "vuex": "3.6.0", + "webstomp-client": "^1.2.6" }, "devDependencies": { "@vue/cli-plugin-babel": "4.4.6", diff --git a/src/App.vue b/src/App.vue index 97626af5..e8b1f8b7 100644 --- a/src/App.vue +++ b/src/App.vue @@ -9,6 +9,7 @@ import ThemePicker from "@/components/ThemePicker"; import { mapActions } from 'vuex' import { get } from '@/utils/config' +// import AlertNotification from "@/views/warning/AlertNotification.vue"; export default { name: "App", diff --git a/src/layout/index.vue b/src/layout/index.vue index 26f9ebf7..02e87b23 100644 --- a/src/layout/index.vue +++ b/src/layout/index.vue @@ -46,6 +46,7 @@ import { mapState } from 'vuex' import variables from '@/assets/styles/variables.scss' import { validateNewPassword } from '@/utils/validate' import { updateUserPwd, checkPasswordStatus } from '@/api/system/user' +import {MessageBox} from "element-ui"; export default { name: 'Layout', @@ -78,7 +79,12 @@ export default { { required: true, message: '确认密码不能为空', trigger: 'blur' }, { required: true, validator: equalToPassword, trigger: 'blur' } ] - } + }, + socket: null, + wsUrl: 'ws://localhost:18082/ws', // WebSocket 端点 + isConnected: false, // 连接状态 + reconnectInterval: 5000 // 自动重连时间间隔(毫秒 + } }, components: { @@ -113,6 +119,7 @@ export default { }, created() { this.checkPasswordStatus() + this.connectWebSocket(); }, methods: { checkPasswordStatus() { @@ -140,7 +147,100 @@ export default { this.$store.dispatch('LogOut').then(() => { location.href = '/index'; }) + }, + + // 连接 WebSocket + connectWebSocket() { + if (this.socket) { + console.log("WebSocket 已连接"); + return; + } + + 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) + const formattedTime = new Date(warning.warningTime).toLocaleString(); + + // 弹出告警信息 + MessageBox.alert( + ` +

事件:${warning.warningEvent}

+

内容:${warning.warningContent}

+

等级:${warning.warningGrade}

+

IP:${warning.warningIp}

+

时间:${formattedTime}

+ `, + '告警通知', + { + dangerouslyUseHTMLString: true, + confirmButtonText: '确认', + callback: () => { + this.notifyBackend(warning.warningId); + } + } + ); + }, + + // 通知后端告警已处理 + notifyBackend(warningId) { + if (this.socket && this.socket.readyState === WebSocket.OPEN) { + const message = { + warningId, + status: '1' // 1 表示已处理 + }; + this.socket.send(JSON.stringify(message)); + console.log(`已通知后端处理告警: ${warningId}`); + } } + }, + beforeDestroy() { + // 页面销毁时关闭 WebSocket 连接 + if (this.socket) { + this.socket.close(); + } + } } diff --git a/src/views/warning/AlertNotification.vue b/src/views/warning/AlertNotification.vue new file mode 100644 index 00000000..c583e09b --- /dev/null +++ b/src/views/warning/AlertNotification.vue @@ -0,0 +1,126 @@ + + + + +