feat(im): 添加即时消息SDK核心功能实现
- 实现了聊天消息发送功能,支持文本、图片、视频、音频、文件等多种消息类型 - 集成了文件上传下载功能,支持多媒体文件的传输和管理 - 添加了群组管理功能,包括创建群组、成员管理、权限控制等操作 - 实现了好友系统,支持好友添加、删除、分组等功能 - 集成了黑名单管理,提供用户屏蔽和解除屏蔽功能 - 添加了会话管理功能,支持对话列表、未读消息统计等 - 实现了历史消息查询和搜索功能 - 添加了实时连接状态管理和自动重连机制
这个提交包含在:
父节点
91aa1dbbea
当前提交
7a5e79d419
@ -42,6 +42,22 @@ async function request<T>(
|
||||
return json.data
|
||||
}
|
||||
|
||||
export async function uploadFile(file: File): Promise<{ url: string; thumbnailUrl?: string; hash: string; size: number; originalName: string; mimeType: string; ext: string }> {
|
||||
const token = _tokenGetter()
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
|
||||
const res = await fetch(`${_baseUrl}/api/file/upload`, {
|
||||
method: 'POST',
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
body: formData,
|
||||
})
|
||||
|
||||
const json: ApiResponse<unknown> = await res.json()
|
||||
if (json.code !== 200) throw new Error(json.message)
|
||||
return json.data as { url: string; thumbnailUrl?: string; hash: string; size: number; originalName: string; mimeType: string; ext: string }
|
||||
}
|
||||
|
||||
export const http = {
|
||||
get: <T>(path: string, query?: Record<string, QueryValue>) => request<T>('GET', path, undefined, query),
|
||||
post: <T>(path: string, body?: unknown, query?: Record<string, QueryValue>) => request<T>('POST', path, body, query),
|
||||
|
||||
@ -140,6 +140,7 @@ export class ImClient {
|
||||
// Don't return early — also emit as message for consistency with old behavior
|
||||
}
|
||||
this.emit('message', message)
|
||||
this.emit('conversations')
|
||||
} catch {
|
||||
// ignore malformed frames
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { getConfig } from '../core/sdk'
|
||||
import { http } from '../core/http'
|
||||
import { http, uploadFile } from '../core/http'
|
||||
import type {
|
||||
BlacklistCheckResult,
|
||||
BlacklistEntry,
|
||||
@ -39,6 +39,48 @@ export function sendMessage(params: { toId: string; chatType: ChatType; msgType:
|
||||
return http.post<ImMessage>('/api/im/messages/send', params, appQuery())
|
||||
}
|
||||
|
||||
export async function sendImageMessage(toId: string, chatType: ChatType, file: File, width?: number, height?: number): Promise<ImMessage> {
|
||||
const result = await uploadFile(file)
|
||||
const content = JSON.stringify({
|
||||
url: result.url,
|
||||
...(width !== undefined ? { width } : {}),
|
||||
...(height !== undefined ? { height } : {}),
|
||||
...(result.thumbnailUrl ? { thumbnailUrl: result.thumbnailUrl } : {}),
|
||||
})
|
||||
return sendMessage({ toId, chatType, msgType: 'IMAGE', content })
|
||||
}
|
||||
|
||||
export async function sendVideoMessage(toId: string, chatType: ChatType, file: File, width?: number, height?: number, duration?: number): Promise<ImMessage> {
|
||||
const result = await uploadFile(file)
|
||||
const content = JSON.stringify({
|
||||
url: result.url,
|
||||
...(width !== undefined ? { width } : {}),
|
||||
...(height !== undefined ? { height } : {}),
|
||||
...(duration !== undefined ? { duration } : {}),
|
||||
...(result.thumbnailUrl ? { thumbnailUrl: result.thumbnailUrl } : {}),
|
||||
})
|
||||
return sendMessage({ toId, chatType, msgType: 'VIDEO', content })
|
||||
}
|
||||
|
||||
export async function sendFileMessage(toId: string, chatType: ChatType, file: File): Promise<ImMessage> {
|
||||
const result = await uploadFile(file)
|
||||
const content = JSON.stringify({
|
||||
url: result.url,
|
||||
name: result.originalName,
|
||||
size: result.size,
|
||||
})
|
||||
return sendMessage({ toId, chatType, msgType: 'FILE', content })
|
||||
}
|
||||
|
||||
export async function sendAudioMessage(toId: string, chatType: ChatType, file: File, duration?: number): Promise<ImMessage> {
|
||||
const result = await uploadFile(file)
|
||||
const content = JSON.stringify({
|
||||
url: result.url,
|
||||
...(duration !== undefined ? { duration } : {}),
|
||||
})
|
||||
return sendMessage({ toId, chatType, msgType: 'AUDIO', content })
|
||||
}
|
||||
|
||||
export function createGroup(params: { name: string; memberIds: string[]; groupType?: string; avatar?: string; announcement?: string }): Promise<ImGroup> {
|
||||
return http.post<ImGroup>('/api/im/groups', params, appQuery())
|
||||
}
|
||||
|
||||
@ -174,6 +174,9 @@ export function useIm(): UseImReturn {
|
||||
markMessageRevoked(msgId)
|
||||
void refreshConversations().catch(() => {})
|
||||
})
|
||||
im.on('conversations', () => {
|
||||
void refreshConversations().catch(() => {})
|
||||
})
|
||||
im.on('error', (e) => { error.value = e })
|
||||
im.connect()
|
||||
client.value = im
|
||||
|
||||
@ -41,6 +41,10 @@ export {
|
||||
sendFriendRequest,
|
||||
sendGroupJoinRequest,
|
||||
sendMessage,
|
||||
sendImageMessage,
|
||||
sendVideoMessage,
|
||||
sendFileMessage,
|
||||
sendAudioMessage,
|
||||
setConversationGroup,
|
||||
setConversationHidden,
|
||||
setConversationMuted,
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
export interface SDKConfig {
|
||||
appKey: string
|
||||
appSecret: string
|
||||
debug?: boolean
|
||||
baseUrl?: string
|
||||
wsUrl?: string
|
||||
@ -170,6 +169,7 @@ export interface ImEventMap {
|
||||
connected: () => void
|
||||
disconnected: (code: number, reason: string) => void
|
||||
error: (err: Event) => void
|
||||
conversations: () => void
|
||||
}
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户