Files
nl-um-vue-ts/src/stores/conversation.ts
2025-12-05 15:23:14 +08:00

183 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { Conversation } from '@/types/conversation'
import type { ChatMessage } from '@/types/api'
import * as conversationApi from '@/api/modules/conversation'
import { getMessageSummary } from '@/utils/messageTypes'
import { useChatStore } from './chat'
export const useConversationStore = defineStore('conversation', () => {
const conversations = ref<Conversation[]>([])
const loading = ref(false)
// 计算总未读数
const totalUnread = computed(() =>
conversations.value.reduce((acc, c) => acc + (c.is_muted ? 0 : c.unread_count), 0)
)
/**
* 初始化加载会话列表
*/
async function loadConversations() {
loading.value = true
try {
const list = await conversationApi.getConversationList()
// 后端返回的数据需要简单处理一下
conversations.value = list.map((c: any) => {
const isGroup = c.type === 2 // type: 1=私聊, 2=群聊
const roomType = isGroup ? 'group' : 'p2p'
// 将后端的 room 字段映射为前端的 target_group
const targetGroup = c.room || c.target_group
return {
...c,
room_type: roomType,
is_group: isGroup,
// 群聊显示群名称,单聊显示用户名称
name: isGroup
? (targetGroup?.room_name || targetGroup?.name || c.name || '未知群聊')
: (c.target_user?.name || c.name || '未知用户'),
avatar: isGroup
? (targetGroup?.room_avatar || targetGroup?.avatar || c.avatar || '')
: (c.target_user?.avatar || c.avatar || ''),
// 群聊相关字段
room_id: isGroup ? (c.room_id || c.target_id) : c.room_id,
member_count: targetGroup?.member_count,
owner_id: targetGroup?.owner_id,
// 映射 room 为 target_group前端期望的字段名
target_group: targetGroup ? {
id: targetGroup.room_id || targetGroup.id,
room_id: targetGroup.room_id,
room_type: 'group',
name: targetGroup.room_name || targetGroup.name,
avatar: targetGroup.room_avatar || targetGroup.avatar,
owner_id: targetGroup.owner_id,
member_count: targetGroup.member_count,
created_at: targetGroup.created_at,
} : undefined,
}
})
} catch (error) {
console.error('Fetch conversations failed:', error)
} finally {
loading.value = false
}
}
/**
* 处理新消息 (发送或接收)
* 实时更新前端列表:这里只做前端 UI 层的兜底,后端已更新会话表
* @param isCurrentChat 是否是当前选中的聊天,如果是则不增加未读数
*/
function handleMessageUpdate(message: ChatMessage, isSelf: boolean, isCurrentChat: boolean = false) {
// 群聊和单聊统一使用 room_id 定位会话
const roomId = message.room_id
if (!roomId) return
// 优先按 room_id 匹配(群聊和单聊都支持)
let conv = conversations.value.find(c => c.room_id === roomId)
// 如果没有 room_id回退到按 target_id 匹配(兼容旧逻辑)
if (!conv) {
const targetId = isSelf ? message.receiver_user_id : message.sender_user_id
if (targetId) {
conv = conversations.value.find(c => c.target_id === targetId)
}
}
// 判断是否为群聊
const isGroupChat = conv?.type === 2 || conv?.is_group
// 生成摘要:群聊时需要包含发送者信息
let summary = getMessageSummary(message)
if (isGroupChat && !isSelf && message.sender_user_id) {
// 从 chatStore 中查找发送者信息
const chatStore = useChatStore()
const senderContact = chatStore.contacts.find(
c => c.user_id === message.sender_user_id || c.id === message.sender_user_id
)
if (senderContact) {
const senderName = senderContact.remark_name || senderContact.user?.name || '未知用户'
summary = `${senderName}${summary}`
}
}
const now = new Date(message.created_at || Date.now()).getTime()
if (conv) {
conv.last_message = summary
conv.last_time = now
// 如果不是自己发送的,且不是当前选中的聊天,且未设置免打扰,则增加未读数
if (!isSelf && !isCurrentChat && !conv.is_muted) {
conv.unread_count = (conv.unread_count || 0) + 1
}
} else {
// 新会话直接重新拉取,保证与后端一致
loadConversations()
return
}
sortConversations()
}
/**
* 增加未读数 (仅前端UI用于收到消息且不在当前窗口时)
* 支持按 room_id 或 target_id 匹配
*/
function incrementUnread(targetIdOrRoomId: string) {
// 优先按 room_id 匹配(群聊场景)
let conv = conversations.value.find(c => c.room_id === targetIdOrRoomId)
// 如果没有找到,再按 target_id 匹配(单聊场景)
if (!conv) {
conv = conversations.value.find(c => c.target_id === targetIdOrRoomId)
}
if (conv) {
conv.unread_count = (conv.unread_count || 0) + 1
}
}
/**
* 清除未读数 (同步后端)
* 支持按 room_id 或 target_id 匹配
*/
async function clearUnread(targetIdOrRoomId: string) {
// 优先按 room_id 匹配(群聊场景)
let conv = conversations.value.find(c => c.room_id === targetIdOrRoomId)
// 如果没有找到,再按 target_id 匹配(单聊场景)
if (!conv) {
conv = conversations.value.find(c => c.target_id === targetIdOrRoomId)
}
if (conv && conv.unread_count > 0) {
conv.unread_count = 0
// 调用后端接口(后端可能需要 target_id这里传入 target_id 或 room_id
try {
await conversationApi.resetUnread(conv.target_id || targetIdOrRoomId)
} catch (e) { console.error(e) }
}
}
/**
* 排序
*/
function sortConversations() {
conversations.value.sort((a, b) => {
if (a.is_top !== b.is_top) return a.is_top ? -1 : 1
return b.last_time - a.last_time
})
}
function getMsgSummary(msg: ChatMessage): string {
return getMessageSummary(msg)
}
return {
conversations,
loading,
totalUnread,
loadConversations,
handleMessageUpdate,
incrementUnread,
clearUnread
}
})