优化客服消息通知提醒
This commit is contained in:
@@ -34,7 +34,8 @@ const conversationID = computed(() => Number(route.params.id || 0))
|
||||
const canSend = computed(() => content.value.trim() !== '' || attachments.value.length > 0)
|
||||
const memberText = computed(() => {
|
||||
const participants = conversation.value?.participants || []
|
||||
if (participants.length === 0) return conversation.value?.type === 'general_support' ? '平台客服' : '订单群聊'
|
||||
if (participants.length === 0)
|
||||
return conversation.value?.type === 'general_support' ? '平台客服' : '订单群聊'
|
||||
return participants.map(item => `${roleLabel(item.role)}:${item.display_name}`).join(' / ')
|
||||
})
|
||||
|
||||
@@ -42,26 +43,33 @@ const memberText = computed(() => {
|
||||
const desktopNotification = useDesktopNotification('user')
|
||||
|
||||
function handleSSEEvent(event: ChatEvent) {
|
||||
if (event.type === 'new_message' && event.conversation_id === conversationID.value) {
|
||||
if (event.type === 'new_message') {
|
||||
const msg = event.message
|
||||
if (msg && !messages.value.some(m => m.id === msg.id)) {
|
||||
if (msg) {
|
||||
const isSelf = msg.sender_type === 'user' && msg.sender_id === currentUserId
|
||||
|
||||
messages.value = [...messages.value, {
|
||||
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,
|
||||
}]
|
||||
nextTick(() => scrollBottom())
|
||||
if (
|
||||
event.conversation_id === conversationID.value &&
|
||||
!messages.value.some(m => m.id === msg.id)
|
||||
) {
|
||||
messages.value = [
|
||||
...messages.value,
|
||||
{
|
||||
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,
|
||||
},
|
||||
]
|
||||
nextTick(() => scrollBottom())
|
||||
}
|
||||
|
||||
// 不是自己发送的消息才发送通知
|
||||
if (!isSelf) {
|
||||
@@ -87,10 +95,7 @@ async function loadAll() {
|
||||
if (!conversationID.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
const [chat] = await Promise.all([
|
||||
fetchChat(conversationID.value),
|
||||
loadMessages(false),
|
||||
])
|
||||
const [chat] = await Promise.all([fetchChat(conversationID.value), loadMessages(false)])
|
||||
conversation.value = chat
|
||||
await markChatRead(conversationID.value)
|
||||
} catch {
|
||||
@@ -104,7 +109,9 @@ async function loadConversation() {
|
||||
if (!conversationID.value) return
|
||||
try {
|
||||
conversation.value = await fetchChat(conversationID.value)
|
||||
} catch { /* ignore */ }
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
async function loadMessages(scrollToBottom = true) {
|
||||
@@ -175,7 +182,10 @@ async function uploadImages(files: File[]) {
|
||||
uploading.value = true
|
||||
try {
|
||||
for (const file of files.slice(0, slots)) {
|
||||
if (!['image/jpeg', 'image/png', 'image/webp'].includes(file.type) || file.size > 25 * 1024 * 1024) {
|
||||
if (
|
||||
!['image/jpeg', 'image/png', 'image/webp'].includes(file.type) ||
|
||||
file.size > 25 * 1024 * 1024
|
||||
) {
|
||||
showToast(`${file.name} 不符合图片规则`)
|
||||
continue
|
||||
}
|
||||
@@ -234,7 +244,12 @@ function senderLabel(message: ChatMessage) {
|
||||
<h1>{{ conversation?.title || '客服会话' }}</h1>
|
||||
<p>{{ memberText }}</p>
|
||||
</div>
|
||||
<button v-if="conversation?.order_id" class="icon-btn" type="button" @click="router.push(`/m/orders/${conversation.order_id}`)">
|
||||
<button
|
||||
v-if="conversation?.order_id"
|
||||
class="icon-btn"
|
||||
type="button"
|
||||
@click="router.push(`/m/orders/${conversation.order_id}`)"
|
||||
>
|
||||
<van-icon name="orders-o" :size="20" />
|
||||
</button>
|
||||
<span v-else class="icon-placeholder"></span>
|
||||
@@ -249,7 +264,7 @@ function senderLabel(message: ChatMessage) {
|
||||
:class="{
|
||||
self: item.is_self,
|
||||
system: item.sender_type === 'system',
|
||||
admin: item.sender_role === 'admin' && !item.is_self
|
||||
admin: item.sender_role === 'admin' && !item.is_self,
|
||||
}"
|
||||
>
|
||||
<template v-if="item.sender_type === 'system'">
|
||||
@@ -258,16 +273,15 @@ function senderLabel(message: ChatMessage) {
|
||||
<template v-else>
|
||||
<div class="avatar">{{ roleLabel(item.sender_role).slice(0, 1) }}</div>
|
||||
<div class="bubble-wrap">
|
||||
<span class="sender-name" :class="{ 'admin-label': item.sender_role === 'admin' && !item.is_self }">
|
||||
<span
|
||||
class="sender-name"
|
||||
:class="{ 'admin-label': item.sender_role === 'admin' && !item.is_self }"
|
||||
>
|
||||
{{ senderLabel(item) }}
|
||||
</span>
|
||||
<div v-if="item.content" class="bubble">{{ item.content }}</div>
|
||||
<div v-if="item.attachment_urls.length > 0" class="message-attachments">
|
||||
<ChatAttachmentImage
|
||||
v-for="url in item.attachment_urls"
|
||||
:key="url"
|
||||
:source="url"
|
||||
/>
|
||||
<ChatAttachmentImage v-for="url in item.attachment_urls" :key="url" :source="url" />
|
||||
</div>
|
||||
<span class="message-time">{{ formatDateMinute(item.created_at) }}</span>
|
||||
</div>
|
||||
@@ -283,7 +297,7 @@ function senderLabel(message: ChatMessage) {
|
||||
accept="image/jpeg,image/png,image/webp"
|
||||
multiple
|
||||
@change="handleImageChange"
|
||||
>
|
||||
/>
|
||||
<div v-if="attachments.length > 0" class="pending-attachments">
|
||||
<div v-for="(url, index) in attachments" :key="url" class="pending-item">
|
||||
<ChatAttachmentImage :source="url" />
|
||||
@@ -292,7 +306,12 @@ function senderLabel(message: ChatMessage) {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button class="tool-btn" type="button" :disabled="uploading || attachments.length >= 9" @click="pickImages">
|
||||
<button
|
||||
class="tool-btn"
|
||||
type="button"
|
||||
:disabled="uploading || attachments.length >= 9"
|
||||
@click="pickImages"
|
||||
>
|
||||
<van-icon name="photo-o" :size="20" />
|
||||
</button>
|
||||
<van-field
|
||||
@@ -306,7 +325,12 @@ function senderLabel(message: ChatMessage) {
|
||||
@keydown.enter.prevent="handleSend"
|
||||
@paste="handlePaste"
|
||||
/>
|
||||
<button class="send-btn" type="button" :disabled="!canSend || sending || uploading" @click="handleSend">
|
||||
<button
|
||||
class="send-btn"
|
||||
type="button"
|
||||
:disabled="!canSend || sending || uploading"
|
||||
@click="handleSend"
|
||||
>
|
||||
<van-icon name="guide-o" :size="20" />
|
||||
</button>
|
||||
</footer>
|
||||
|
||||
Reference in New Issue
Block a user