feat(websocket): 实现 WebSocket 消息推送功能

- 配置 ASGI 支持 WebSocket 连接
- 新增 WebSocket 路由和消费者类 MegCenter
- 实现消息序列化和推送逻辑
- 前端集成 WebSocket 连接状态管理和重连机制
- 添加用户在线状态提示和未读消息提醒- 更新角色权限配置显示条件
- 扩展用户信息存储结构支持 WebSocket 状态字段
This commit is contained in:
1638245306
2025-10-19 16:03:16 +08:00
parent fa734dd479
commit abe2db3c82
10 changed files with 321 additions and 2 deletions

View File

@@ -57,6 +57,26 @@
:class="!state.isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'"
></i>
</div>
<div>
<span v-if="!isSocketOpen" class="online-status-span">
<el-popconfirm
width="250"
ref="onlinePopoverRef"
:confirm-button-text="$t('message.user.retry')"
:icon="InfoFilled"
trigger="hover"
icon-color="#626AEF"
:title="$t('message.user.onlinePrompt')"
@confirm="onlineConfirmEvent"
>
<template #reference>
<el-badge is-dot class="item" :class="{'online-status': isSocketOpen,'online-down':!isSocketOpen}">
<img :src="getBaseURL(userInfos.avatar) || headerImage" class="layout-navbars-breadcrumb-user-link-photo mr5" />
</el-badge>
</template>
</el-popconfirm>
</span>
</div>
<div></div>
<el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick">
<span class="layout-navbars-breadcrumb-user-link">
@@ -95,6 +115,7 @@ import mittBus from '/@/utils/mitt';
import { Session, Local } from '/@/utils/storage';
import headerImage from '/@/assets/img/headerImage.png';
import { InfoFilled } from '@element-plus/icons-vue';
import websocket from '/@/utils/websocket';
// 引入组件
const UserNews = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/userNews.vue'));
const Search = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/search.vue'));
@@ -123,6 +144,21 @@ const layoutUserFlexNum = computed(() => {
return num;
});
// 定义变量内容
const { isSocketOpen } = storeToRefs(useUserInfo());
// websocket状态
const onlinePopoverRef = ref()
const onlineConfirmEvent = () => {
if (!isSocketOpen.value) {
websocket.is_reonnect = true
websocket.reconnect_current = 1
websocket.reconnect()
}
// 手动隐藏弹出
unref(onlinePopoverRef).popperRef?.delayHide?.()
}
// 全屏点击时
const onScreenfullClick = () => {
if (!screenfull.isEnabled) {