/** * 腾讯 IM SDK 封装(群聊模式) * 每个订单一个群,消息按订单隔离 */ import TencentCloudChat from '@tencentcloud/chat' import TIMUploadPlugin from 'tim-upload-plugin' import request from './request' let chat = null let isReady = false let onMessageCallback = null /** 获取 IM 实例 */ export function getChatInstance() { return chat } /** 初始化并登录 IM */ export async function initIM() { const res = await request({ url: '/api/im/usersig' }) const { sdkAppId, userId, userSig } = res if (!chat) { chat = TencentCloudChat.create({ SDKAppID: sdkAppId }) chat.registerPlugin({ 'tim-upload-plugin': TIMUploadPlugin }) chat.setLogLevel(1) chat.on(TencentCloudChat.EVENT.SDK_READY, () => { console.log('[IM] SDK 就绪') isReady = true // SDK就绪后同步用户头像和昵称到腾讯 IM try { const userInfo = uni.getStorageSync('userInfo') if (userInfo) { const parsed = typeof userInfo === 'string' ? JSON.parse(userInfo) : userInfo chat.updateMyProfile({ nick: parsed.nickname || '', avatar: parsed.avatarUrl || '' }) } } catch (e) { console.warn('[IM] 同步资料失败:', e) } }) chat.on(TencentCloudChat.EVENT.MESSAGE_RECEIVED, (event) => { if (onMessageCallback) onMessageCallback(event.data) }) chat.on(TencentCloudChat.EVENT.KICKED_OUT, () => { console.log('[IM] 被踢下线') isReady = false }) } await chat.login({ userID: userId, userSig }) console.log('[IM] 登录成功:', userId) return { sdkAppId, userId } } /** 登出 IM */ export async function logoutIM() { if (chat) { await chat.logout() isReady = false } } /** 设置新消息回调 */ export function onNewMessage(callback) { onMessageCallback = callback } /** 移除新消息回调 */ export function offNewMessage() { onMessageCallback = null } /** 获取群会话 ID */ export function getGroupConversationId(groupId) { return `GROUP${groupId}` } /** 获取会话列表(群聊模式) */ export async function getConversationList() { if (!chat || !isReady) return [] try { const res = await chat.getConversationList() const list = res.data.conversationList || [] return list .filter(c => c.type === TencentCloudChat.TYPES.CONV_GROUP) .map(c => { const lastMsg = c.lastMessage let lastMessageText = '' if (lastMsg) { if (lastMsg.type === TencentCloudChat.TYPES.MSG_TEXT) { lastMessageText = lastMsg.payload?.text || '' } else if (lastMsg.type === TencentCloudChat.TYPES.MSG_IMAGE) { lastMessageText = '[图片]' } else if (lastMsg.type === TencentCloudChat.TYPES.MSG_CUSTOM) { lastMessageText = lastMsg.payload?.description || '[消息]' } else { lastMessageText = '[消息]' } } return { conversationID: c.conversationID, groupId: c.groupProfile?.groupID || c.conversationID.replace('GROUP', ''), lastMessage: lastMessageText, lastMessageTime: lastMsg ? lastMsg.lastTime * 1000 : 0, unreadCount: c.unreadCount || 0 } }) .sort((a, b) => b.lastMessageTime - a.lastMessageTime) } catch (e) { console.error('[IM] 获取会话列表失败:', e) return [] } } /** 拉取群历史消息 */ export async function getMessageList(groupId, nextReqMessageID) { const conversationID = getGroupConversationId(groupId) const res = await chat.getMessageList({ conversationID, nextReqMessageID, count: 20 }) return { messageList: res.data.messageList || [], isCompleted: res.data.isCompleted, nextReqMessageID: res.data.nextReqMessageID } } /** 标记群会话已读 */ export async function setMessageRead(groupId) { if (!chat || !isReady) return try { const conversationID = getGroupConversationId(groupId) await chat.setMessageRead({ conversationID }) } catch (e) { console.error('[IM] 标记已读失败:', e) } } /** 发送群文本消息 */ export async function sendTextMessage(groupId, text) { const message = chat.createTextMessage({ to: groupId, conversationType: TencentCloudChat.TYPES.CONV_GROUP, payload: { text } }) const res = await chat.sendMessage(message) return res.data.message } /** 发送群图片消息 */ export async function sendImageMessage(groupId, fileRes) { const message = chat.createImageMessage({ to: groupId, conversationType: TencentCloudChat.TYPES.CONV_GROUP, payload: { file: fileRes } }) const res = await chat.sendMessage(message) return res.data.message } /** 发送群自定义消息 */ export async function sendCustomMessage(groupId, customData) { const message = chat.createCustomMessage({ to: groupId, conversationType: TencentCloudChat.TYPES.CONV_GROUP, payload: { data: JSON.stringify(customData), description: customData.description || '', extension: customData.extension || '' } }) const res = await chat.sendMessage(message) return res.data.message } /** 将 IM 消息转换为聊天页展示格式 */ export function formatIMMessage(msg, currentImUserId, avatarMap = {}) { const isSelf = msg.from === currentImUserId const avatar = avatarMap[msg.from] || msg.avatar || '/static/logo.png' // 文本消息 if (msg.type === TencentCloudChat.TYPES.MSG_TEXT) { return { id: msg.ID, type: 'text', content: msg.payload.text, isSelf, avatar, time: msg.time * 1000 } } // 图片消息 if (msg.type === TencentCloudChat.TYPES.MSG_IMAGE) { const imgArr = msg.payload.imageInfoArray || [] const displayUrl = imgArr[1]?.url || imgArr[0]?.url || '' const originUrl = imgArr[0]?.url || imgArr[1]?.url || '' return { id: msg.ID, type: 'image', content: displayUrl, originUrl, isSelf, avatar, time: msg.time * 1000 } } // 自定义消息 if (msg.type === TencentCloudChat.TYPES.MSG_CUSTOM) { try { const data = JSON.parse(msg.payload.data) if (data.bizType === 'price-change') { return { id: msg.ID, type: 'price-change', isSelf, priceChangeId: data.priceChangeId, changeTypeLabel: data.changeTypeLabel, originalPrice: data.originalPrice, newPrice: data.newPrice, difference: data.difference, status: data.status, time: msg.time * 1000 } } if (data.bizType === 'price-change-response') { return { id: msg.ID, type: 'price-change-response', priceChangeId: data.priceChangeId, action: data.action, status: data.status, changeTypeLabel: data.changeTypeLabel, isSelf, time: msg.time * 1000 } } if (data.bizType === 'order-status') { return { id: msg.ID, type: 'system', content: data.description || '[订单状态变更]', time: msg.time * 1000 } } } catch (e) {} return { id: msg.ID, type: 'text', content: msg.payload.description || '[消息]', isSelf, avatar, time: msg.time * 1000 } } return { id: msg.ID, type: 'text', content: '[暂不支持的消息类型]', isSelf, avatar, time: msg.time * 1000 } }