feat(im-sdk): 添加 Flutter IM SDK 和 Go 服务端 SDK

- 实现了完整的 Flutter IM SDK,支持消息发送、历史记录、会话管理、好友功能和群组操作
- 添加了 Go 服务端 SDK 骨架,包含登录、消息发送、撤回、编辑等核心功能
- 实现了认证和授权机制,支持 token 管理和请求签名验证
- 添加了会话列表、好友申请、群组管理和消息搜索功能
- 提供了用户资料管理、头像上传和账户导入导出功能
- 实现了消息撤回、编辑和已读状态管理功能
- 添加了群组加入申请、审批和成员管理功能
- 提供了消息历史分页查询和定位功能
- 实现了会话置顶、免打扰和草稿保存功能
- 添加了用户和群组搜索功能,支持关键词检索
这个提交包含在:
XuqmGroup 2026-04-29 00:39:25 +08:00
父节点 cc139e14e2
当前提交 fefd8d191b
共有 2 个文件被更改,包括 46 次插入2 次删除

查看文件

@ -187,6 +187,14 @@ export function getGroupInfo(groupId: string): Promise<ImGroup> {
return http.get<ImGroup>(`/api/im/groups/${encodeURIComponent(groupId)}`, appQuery()) return http.get<ImGroup>(`/api/im/groups/${encodeURIComponent(groupId)}`, appQuery())
} }
export function listGroupMembers(groupId: string): Promise<UserProfile[]> {
return http.get<UserProfile[]>(`/api/im/groups/${encodeURIComponent(groupId)}/members`, appQuery())
}
export function searchGroupMembers(groupId: string, keyword: string, size = 20): Promise<UserProfile[]> {
return http.get<UserProfile[]>(`/api/im/groups/${encodeURIComponent(groupId)}/members/search`, appQuery({ keyword, size }))
}
export function sendFriendRequest(toUserId: string, remark?: string): Promise<FriendRequest> { export function sendFriendRequest(toUserId: string, remark?: string): Promise<FriendRequest> {
return http.post<FriendRequest>( return http.post<FriendRequest>(
'/api/im/friend-requests', '/api/im/friend-requests',

查看文件

@ -52,6 +52,20 @@ export function useIm() {
messages.value = [...messages.value, message] messages.value = [...messages.value, message]
} }
function markMessageRevoked(msgId: string) {
const index = messages.value.findIndex((item) => item.id === msgId)
if (index < 0) return
const next = [...messages.value]
next[index] = {
...next[index],
status: 'REVOKED',
msgType: 'REVOKED',
revoked: true,
content: '',
}
messages.value = next
}
async function refreshConversations() { async function refreshConversations() {
const items = await listConversations() const items = await listConversations()
conversations.value = [...items].sort((a, b) => { conversations.value = [...items].sort((a, b) => {
@ -60,6 +74,14 @@ export function useIm() {
}) })
} }
function markConversationRead(targetId: string, chatType: ChatType = 'SINGLE') {
conversations.value = conversations.value.map((item) =>
item.targetId === targetId && item.chatType === chatType
? { ...item, unreadCount: 0 }
: item,
)
}
async function loadHistory(toId: string, query: HistoryQuery = {}): Promise<PageResult<ImMessage>> { async function loadHistory(toId: string, query: HistoryQuery = {}): Promise<PageResult<ImMessage>> {
return fetchHistory(toId, query) return fetchHistory(toId, query)
} }
@ -91,6 +113,10 @@ export function useIm() {
upsertMessage(msg) upsertMessage(msg)
void refreshConversations().catch(() => {}) void refreshConversations().catch(() => {})
}) })
im.on('revoke', ({ msgId }) => {
markMessageRevoked(msgId)
void refreshConversations().catch(() => {})
})
im.on('error', (e) => { error.value = e }) im.on('error', (e) => { error.value = e })
im.connect() im.connect()
client.value = im client.value = im
@ -105,11 +131,19 @@ export function useIm() {
} }
function revoke(msgId: string) { function revoke(msgId: string) {
return revokeMessage(msgId) return revokeMessage(msgId).then((message) => {
upsertMessage(message)
void refreshConversations().catch(() => {})
return message
})
} }
function edit(msgId: string, content: string) { function edit(msgId: string, content: string) {
return editMessage(msgId, content) return editMessage(msgId, content).then((message) => {
upsertMessage(message)
void refreshConversations().catch(() => {})
return message
})
} }
function disconnect() { function disconnect() {
@ -119,6 +153,8 @@ export function useIm() {
} }
function setConversationRead(targetId: string, chatType: ChatType = 'SINGLE') { function setConversationRead(targetId: string, chatType: ChatType = 'SINGLE') {
markConversationRead(targetId, chatType)
void refreshConversations().catch(() => {})
return markRead(targetId, chatType) return markRead(targetId, chatType)
} }