IM聊天功能优化

This commit is contained in:
geht
2026-05-28 17:08:34 +08:00
parent 3539eab924
commit a63cd6ad1a
29 changed files with 3565 additions and 203 deletions

View File

@@ -1,65 +1,47 @@
<template>
<div :class="prefixCls">
<Badge :count="totalUnread" :overflowCount="99" :offset="[-4, 18]" :numberStyle="numberStyle" @click="openChat">
<MessageOutlined />
</Badge>
<div :class="[prefixCls, { 'is-disabled': imPageActive }]" @click="openChat">
<MessageOutlined />
<ImChatModal @register="registerModal" />
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, onUnmounted } from 'vue';
import { Badge } from 'ant-design-vue';
import { defineComponent, onMounted } from 'vue';
import { MessageOutlined } from '@ant-design/icons-vue';
import { useModal } from '/@/components/Modal';
import { useDesign } from '/@/hooks/web/useDesign';
import { ensureWebSocketConnected, onWebSocket, offWebSocket } from '/@/hooks/web/useWebSocket';
import ImChatModal from '/@/views/system/im/ImChatModal.vue';
import { prefetchImChatData, handleImChatSocket } from '/@/views/system/im/imCache';
import { useImUnread } from '/@/views/system/im/useImUnread';
import { prefetchImChatData } from '/@/views/system/im/imCache';
import { useImChat } from '/@/views/system/im/useImChat';
import { refreshImUnread } from '/@/views/system/im/useImUnread';
import { useImChatPageActive } from '/@/views/system/im/imSession';
export default defineComponent({
name: 'HeaderImChat',
components: {
Badge,
MessageOutlined,
ImChatModal,
},
setup() {
const { prefixCls } = useDesign('header-im-chat');
const { totalUnread } = useImUnread();
const [registerModal, { openModal }] = useModal();
const numberStyle = {
fontSize: '12px',
height: '16px',
minWidth: '16px',
lineHeight: '16px',
padding: '0 4px',
};
const imPageActive = useImChatPageActive();
const { openChatModal } = useImChat();
function openChat() {
openModal(true, {});
}
function onImSocket(data: Record<string, any>) {
handleImChatSocket(data);
//update-begin---author:xsl ---date:20260528 for【IM聊天-OA】头部打开 IM 时快照当前功能页名称-----------
openChatModal(openModal);
//update-end---author:xsl ---date:20260528 for【IM聊天-OA】头部打开 IM 时快照当前功能页名称-----------
}
onMounted(() => {
ensureWebSocketConnected();
prefetchImChatData();
onWebSocket(onImSocket);
});
onUnmounted(() => {
offWebSocket(onImSocket);
refreshImUnread(true);
});
return {
prefixCls,
totalUnread,
numberStyle,
imPageActive,
openChat,
registerModal,
};
@@ -73,22 +55,17 @@
.@{prefix-cls} {
cursor: pointer;
padding: 0 10px;
font-size: 18px;
display: inline-flex;
align-items: center;
.ant-badge {
font-size: 18px;
svg {
width: 0.9em;
}
.ant-badge-count {
@badget-size: 16px;
width: @badget-size;
height: @badget-size;
min-width: @badget-size;
line-height: @badget-size;
padding: 0;
}
svg {
width: 0.9em;
}
&.is-disabled {
cursor: not-allowed;
opacity: 0.45;
}
}
</style>

View File

@@ -1,19 +1,19 @@
<template>
<div :class="prefixCls">
<Badge :count="messageCount" :overflowCount="9" :offset="[-4, 18]" :numberStyle="numberStyle" @click="clickBadge('')">
<Badge :count="messageCount" :overflowCount="99" :offset="[-4, 18]" :numberStyle="numberStyle" @click="clickBadge('')">
<BellOutlined />
</Badge>
<DynamicNotice ref="dynamicNoticeRef" v-bind="dynamicNoticeProps" />
<DetailModal @register="registerDetail" />
<sys-message-modal @register="registerMessageModal" @refresh="reloadCount" :messageCount="messageCount"></sys-message-modal>
<sys-message-modal @register="registerMessageModal" @refresh="reloadCount" :systemMessageCount="systemMessageCount"></sys-message-modal>
<!-- 修改密码弹窗 -->
<ChangePasswordModal @register="changePwdModal"></ChangePasswordModal>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, ref, unref, reactive, onMounted, getCurrentInstance } from 'vue';
import { computed, defineComponent, ref, unref, reactive, onMounted, onUnmounted, getCurrentInstance } from 'vue';
import { Popover, Tabs, Badge } from 'ant-design-vue';
import { BellOutlined } from '@ant-design/icons-vue';
// import { tabListData } from './data';
@@ -25,7 +25,7 @@
import { useDesign } from '/@/hooks/web/useDesign';
import { useGlobSetting } from '/@/hooks/setting';
import { useUserStore } from '/@/store/modules/user';
import { connectWebSocket, onWebSocket, buildSystemWebSocketUrl } from '/@/hooks/web/useWebSocket';
import { connectWebSocket, onWebSocket, offWebSocket, buildSystemWebSocketUrl } from '/@/hooks/web/useWebSocket';
import { readAllMsg } from '/@/views/monitor/mynews/mynews.api';
import { useRouter } from 'vue-router';
@@ -33,6 +33,8 @@
import ChangePasswordModal from './ChangePasswordModal.vue'
import { ElectronEnum } from '/@/enums/jeecgEnum';
import { defHttp } from "@/utils/http/axios";
import { handleImChatSocket } from '/@/views/system/im/imCache';
import { useImUnread } from '/@/views/system/im/useImUnread';
export default defineComponent({
components: {
@@ -83,11 +85,20 @@
}
const popoverVisible = ref<boolean>(false);
const systemMessageCount = ref(0);
const { totalUnread: imUnreadCount, conversationUnreadCount: imConversationUnreadCount, refreshImUnread: refreshImUnreadCount } = useImUnread();
const messageCount = computed(() => (systemMessageCount.value || 0) + (imConversationUnreadCount.value || 0));
onMounted(() => {
initWebSocket();
initWebSocket();
refreshImUnreadCount(true);
loadData();
});
onUnmounted(() => {
offWebSocket(onWebSocketMessage);
});
const messageCount = ref<number>(0)
function mapAnnouncement(item) {
return {
...item,
@@ -111,7 +122,7 @@
let msgCount = await getUnreadMessageCount();
// 代码逻辑说明: 【QQYUN-12162】OA项目改造系统重消息拆分目前消息都在一起 需按分类进行拆分---
unReadNum.value = msgCount;
messageCount.value = msgCount.count?msgCount.count:0;
systemMessageCount.value = msgCount.count ? msgCount.count : 0;
// 代码逻辑说明: 【JHHB-13】桌面应用消息通知
if (glob.isElectronPlatform) {
window[ElectronEnum.ELECTRON_API].sendNotifyFlash(messageCount.value);
@@ -122,7 +133,21 @@
}
}
loadData();
function onWebSocketMessage(data) {
if (data.cmd === 'chat') {
handleImChatSocket(data);
refreshImUnreadCount(false);
return;
}
if (data.cmd === 'topic' || data.cmd === 'user') {
if (data.noticeType) {
noticeType.value = data.noticeType;
}
notification(data);
loadData();
window.setTimeout(() => loadData(), 800);
}
}
function onNoticeClick(record) {
try {
@@ -154,25 +179,9 @@
onWebSocket(onWebSocketMessage);
}
function onWebSocketMessage(data) {
if (data.cmd === 'topic' || data.cmd === 'user') {
// 代码逻辑说明: VUEN-1674【严重bug】系统通知为什么必须刷新右上角才提示
if(data.noticeType){
noticeType.value = data.noticeType;
}
//后台保存数据太慢 前端延迟刷新消息
setTimeout(()=>{
// 代码逻辑说明: 【JHHB-13】桌面应用消息通知
notification(data);
loadData();
}, 1000)
}
}
// 桌面应用通知
function notification(data) {
if (glob.isElectronPlatform && (data.noticeType || data.cmd == 'email')) {
// 流程、文件、日程、系统、会议
// flow、file、plan、system、meeting
let title = '';
let msgTxt = '';
let path = '';
@@ -199,6 +208,7 @@
window[ElectronEnum.ELECTRON_API].sendNotification(`有新的${title}消息`, msgTxt, path);
}
}
// 清空消息
function onEmptyNotify() {
popoverVisible.value = false;
@@ -208,6 +218,7 @@
try {
await editCementSend(id);
await loadData();
refreshImUnreadCount(true);
} catch (e) {
console.error(e);
}