桌面通知(系统级消息提醒

This commit is contained in:
yml
2026-06-05 20:06:50 +08:00
parent e32362f425
commit bdd1ba6052
8 changed files with 383 additions and 17 deletions
+31 -15
View File
@@ -14,6 +14,7 @@ import {
import { uploadFile } from '@/shared/api/files'
import ChatAttachmentImage from '@/components/ChatAttachmentImage.vue'
import { useChatSSE, type ChatEvent } from '@/features/chats/composables/useChatSSE'
import { useDesktopNotification } from '@/features/chats/composables/useDesktopNotification'
import { formatDateMinute } from '@/utils/time'
const currentUserId = Number(localStorage.getItem('user_id') || 0)
@@ -38,24 +39,37 @@ const memberText = computed(() => {
return participants.map(item => `${roleLabel(item.role)}:${item.display_name}`).join(' / ')
})
// 桌面通知
const desktopNotification = useDesktopNotification('user')
function handleSSEEvent(event: ChatEvent) {
if (event.type === 'new_message' && event.conversation_id === conversationID.value) {
const msg = event.message
if (msg) appendMessage({
id: msg.id,
conversation_id: msg.conversation_id,
sender_type: msg.sender_type as ChatMessage['sender_type'],
sender_id: msg.sender_id,
sender_role: msg.sender_role as ChatMessage['sender_role'],
sender_name: msg.sender_name,
sender_avatar: '',
is_self: msg.sender_type === 'user' && msg.sender_id === currentUserId,
content_type: msg.content_type as ChatMessage['content_type'],
content: msg.content,
attachment_urls: msg.attachment_urls || [],
created_at: msg.created_at,
})
markChatRead(conversationID.value).catch(() => {})
if (msg) {
const isSelf = msg.sender_type === 'user' && msg.sender_id === currentUserId
appendMessage({
id: msg.id,
conversation_id: msg.conversation_id,
sender_type: msg.sender_type as ChatMessage['sender_type'],
sender_id: msg.sender_id,
sender_role: msg.sender_role as ChatMessage['sender_role'],
sender_name: msg.sender_name,
sender_avatar: '',
is_self: isSelf,
content_type: msg.content_type as ChatMessage['content_type'],
content: msg.content,
attachment_urls: msg.attachment_urls || [],
created_at: msg.created_at,
})
markChatRead(conversationID.value).catch(() => {})
// 不是自己发送的消息才发送通知
if (!isSelf) {
desktopNotification.notify(event, conversationID.value)
}
}
}
if (event.type === 'conversation_updated' && event.conversation_id === conversationID.value) {
loadConversation()
@@ -66,6 +80,8 @@ const { onEvent } = useChatSSE('user', '/api/chats/events')
onEvent(handleSSEEvent)
onMounted(async () => {
// 静默请求通知权限(用户交互后才会弹窗)
desktopNotification.requestPermissionSilently()
await loadAll()
})
@@ -5,6 +5,7 @@ import { ElMessage } from 'element-plus'
import { ChatDotRound, Refresh, Tickets } from '@element-plus/icons-vue'
import { fetchChats, type ChatConversation } from '@/features/chats/api/chats'
import { useChatSSE, type ChatEvent } from '@/features/chats/composables/useChatSSE'
import NotificationSettings from '@/features/chats/components/NotificationSettings.vue'
import { formatDateMinute } from '@/utils/time'
const router = useRouter()
@@ -69,6 +70,7 @@ function previewText(item: ChatConversation) {
<p>{{ unreadTotal > 0 ? `${unreadTotal} 条未读` : '查看订单群聊和平台客服消息。' }}</p>
</div>
<div class="header-actions">
<NotificationSettings scope="user" />
<el-button :icon="Refresh" :loading="loading" @click="loadChats(true)">刷新</el-button>
<el-button type="primary" :icon="Tickets" @click="router.push('/orders')">我的订单</el-button>
</div>
@@ -13,6 +13,7 @@ import {
import { uploadFile } from '@/shared/api/files'
import ChatAttachmentImage from '@/components/ChatAttachmentImage.vue'
import { useChatSSE, type ChatEvent } from '@/features/chats/composables/useChatSSE'
import { useDesktopNotification } from '@/features/chats/composables/useDesktopNotification'
import { formatDateMinute } from '@/utils/time'
const currentUserId = Number(localStorage.getItem('user_id') || 0)
@@ -37,10 +38,15 @@ const memberText = computed(() => {
return participants.map(item => `${roleLabel(item.role)}:${item.display_name}`).join(' / ')
})
// 桌面通知
const desktopNotification = useDesktopNotification('user')
function handleSSEEvent(event: ChatEvent) {
if (event.type === 'new_message' && event.conversation_id === conversationID.value) {
const msg = event.message
if (msg && !messages.value.some(m => m.id === msg.id)) {
const isSelf = msg.sender_type === 'user' && msg.sender_id === currentUserId
messages.value = [...messages.value, {
id: msg.id,
conversation_id: msg.conversation_id,
@@ -49,13 +55,18 @@ function handleSSEEvent(event: ChatEvent) {
sender_role: msg.sender_role as ChatMessage['sender_role'],
sender_name: msg.sender_name,
sender_avatar: '',
is_self: msg.sender_type === 'user' && msg.sender_id === currentUserId,
is_self: isSelf,
content_type: msg.content_type as ChatMessage['content_type'],
content: msg.content,
attachment_urls: msg.attachment_urls || [],
created_at: msg.created_at,
}]
nextTick(() => scrollBottom())
// 不是自己发送的消息才发送通知
if (!isSelf) {
desktopNotification.notify(event, conversationID.value)
}
}
}
if (event.type === 'conversation_updated' && event.conversation_id === conversationID.value) {
@@ -67,6 +78,8 @@ const { onEvent } = useChatSSE('user', '/api/chats/events')
onEvent(handleSSEEvent)
onMounted(async () => {
// 静默请求通知权限(用户交互后才会弹窗)
desktopNotification.requestPermissionSilently()
await loadAll()
})