| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- /**
- * 聊天全局状态:会话列表、各会话消息列表,供 composables 与页面共享
- */
- import { reactive } from 'vue'
- export const chatStore = reactive({
- // 会话列表(来自 getContacts)
- contacts: [],
- loadingContacts: false,
- // 按 contactId 存消息列表
- messages: {},
- // 已加载过历史的 contactId 集合,避免重复拉取
- loadedContactIds: {},
- // 当前正在查看的会话,用于前台/后台消息通知判断
- activeContactId: '',
- // 某会话是否正在加载更多
- loadingMore: {},
- // 本地未读:WS 连接后收到的新消息(别人发的且不在当前会话)按会话计数,不请求未读接口
- unreadByContactId: {},
- setContacts(list) {
- this.contacts = list || []
- },
- /** 仅更新某会话在列表中的最后一条预览与时间(WS 收到新消息时本地更新,不整表刷新) */
- updateContactPreview(contactId, { lastMessage, time }) {
- const id = String(contactId)
- const list = this.contacts || []
- const idx = list.findIndex((c) => String(c.user_id || c.id) === id)
- if (idx === -1) return
- const next = list.slice()
- next[idx] = { ...next[idx], lastMessage: lastMessage ?? next[idx].lastMessage, time: time ?? next[idx].time }
- this.contacts = next
- },
- setMessagesForContact(contactId, list, append = false) {
- const id = String(contactId)
- if (!this.messages[id]) this.messages[id] = []
- if (append) {
- this.messages[id].push(...list)
- } else {
- const current = this.messages[id] || []
- const tempMessages = current.filter((m) => m.tempId != null)
- // 合并接口历史与 store 里已有消息(含 WS 推送),避免点进会话时把实时收到的消息冲掉
- const existingStable = current.filter((m) => !m.tempId)
- const apiList = list || []
- const seen = new Set()
- const merged = []
- for (const m of [...apiList, ...existingStable]) {
- const k = String(m.id || m.tempId || '')
- if (seen.has(k)) continue
- seen.add(k)
- merged.push(m)
- }
- merged.sort((a, b) => {
- const ta = (a.createdAt && new Date(a.createdAt).getTime()) || 0
- const tb = (b.createdAt && new Date(b.createdAt).getTime()) || 0
- return ta - tb
- })
- this.messages[id] = [...merged, ...tempMessages]
- }
- },
- prependMessages(contactId, list) {
- const id = String(contactId)
- if (!this.messages[id]) this.messages[id] = []
- const merged = (list || []).concat(this.messages[id])
- // 按 id 去重,保留首次出现(历史在前,避免重复)
- const seen = new Set()
- this.messages[id] = merged.filter((m) => {
- const k = m.id || m.tempId
- if (seen.has(k)) return false
- seen.add(k)
- return true
- })
- },
- appendMessage(contactId, message) {
- const id = String(contactId)
- const prev = this.messages[id] || []
- this.messages[id] = [...prev, message]
- },
- replaceTempMessage(contactId, tempId, serverMessage) {
- const id = String(contactId)
- const list = this.messages[id]
- if (!list || !list.length) return
- const idx = list.findIndex((m) => m.id === tempId || m.tempId === tempId)
- if (idx !== -1) {
- this.messages[id] = [...list.slice(0, idx), serverMessage, ...list.slice(idx + 1)]
- }
- },
- /** 按 id / tempId 移除一条(如再次提醒发送失败时撤回临时消息) */
- removeMessage(contactId, messageId) {
- const id = String(contactId)
- const list = this.messages[id]
- if (!list || !list.length) return
- this.messages[id] = list.filter((m) => m.id !== messageId && m.tempId !== messageId)
- },
- /** 更新某条消息(如 status: 'sending' / 'failed') */
- updateMessage(contactId, tempIdOrId, updates) {
- const id = String(contactId)
- const list = this.messages[id]
- if (!list || !list.length) return
- const idx = list.findIndex((m) => m.id === tempIdOrId || m.tempId === tempIdOrId)
- if (idx !== -1) {
- const next = list.slice()
- next[idx] = { ...next[idx], ...updates }
- this.messages[id] = next
- }
- },
- markContactLoaded(contactId) {
- this.loadedContactIds[String(contactId)] = true
- },
- hasContactLoaded(contactId) {
- return !!this.loadedContactIds[String(contactId)]
- },
- setActiveContact(contactId) {
- this.activeContactId = contactId ? String(contactId) : ''
- },
- /** 某会话未读 +1(仅由 WS 收到新消息且非当前会话时调用) */
- incrementUnread(contactId) {
- const id = String(contactId)
- const prev = this.unreadByContactId[id] ?? 0
- this.unreadByContactId[id] = prev + 1
- },
- /** 进入会话时清零该会话本地未读 */
- clearUnread(contactId) {
- const id = String(contactId)
- this.unreadByContactId[id] = 0
- },
- /** 取某会话的本地未读数,供列表展示 */
- getUnread(contactId) {
- if (contactId == null || contactId === '') return 0
- return this.unreadByContactId[String(contactId)] ?? 0
- },
- /** 所有会话未读之和,供底部消息 Tab 角标 */
- getTotalUnread() {
- const obj = this.unreadByContactId || {}
- return Object.values(obj).reduce((sum, n) => sum + (Number(n) || 0), 0)
- },
- /** 更新底部「消息」Tab 角标(index 0) */
- updateTabBarUnreadBadge() {
- try {
- const total = this.getTotalUnread()
- if (total <= 0) {
- uni.removeTabBarBadge({ index: 0 })
- } else {
- uni.setTabBarBadge({ index: 0, text: total > 99 ? '99+' : String(total) })
- }
- } catch (e) {
- // 非 Tab 页或未就绪时可能报错,忽略
- }
- }
- })
|