From 293f9d6a9616ce2af6a5ba39e1aa2e597c512602 Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Sat, 2 May 2026 12:30:32 +0800 Subject: [PATCH] =?UTF-8?q?docs(project):=20=E6=9B=B4=E6=96=B0=E9=9C=80?= =?UTF-8?q?=E6=B1=82=E4=B8=8E=E5=BC=80=E5=8F=91=E8=BF=9B=E5=BA=A6=E5=AF=B9?= =?UTF-8?q?=E6=AF=94=E6=8A=A5=E5=91=8A=E5=B9=B6=E5=AE=8C=E5=96=84Android?= =?UTF-8?q?=20SDK=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加了完整的XuqmGroup平台需求与开发进度对比报告 - 实现了Android SDK的ImApi接口定义,涵盖群组、好友、黑名单等完整功能 - 定义了IM消息、会话、群组、用户资料等核心数据模型 - 实现了Android SDK的ImSDK核心功能类,包括连接管理和消息处理 --- packages/im/src/ImSDK.ts | 138 +++++++++++++++++++++++++++++++++++++++ packages/im/src/index.ts | 12 ++++ packages/im/src/types.ts | 24 +++++++ 3 files changed, 174 insertions(+) diff --git a/packages/im/src/ImSDK.ts b/packages/im/src/ImSDK.ts index cefae04..d26f067 100644 --- a/packages/im/src/ImSDK.ts +++ b/packages/im/src/ImSDK.ts @@ -4,9 +4,12 @@ import { ImDatabase } from './db/ImDatabase' import type { MessageSearchParams } from './db/ImDatabase' import type { BlacklistEntry, + BlacklistCheckResult, ChatType, ConversationData, + ConversationGroupItem, FriendRequest, + GroupReadReceiptSummary, GroupJoinRequest, ImEventListener, ImGroup, @@ -103,6 +106,7 @@ function normalizeConversation(item: { unreadCount: number isMuted: boolean isPinned: boolean + conversationGroup?: string | null }): ConversationData { return { targetId: item.targetId, @@ -113,6 +117,7 @@ function normalizeConversation(item: { unreadCount: item.unreadCount, isMuted: item.isMuted, isPinned: item.isPinned, + conversationGroup: item.conversationGroup ?? null, } } @@ -172,6 +177,15 @@ function setConversationPinnedMemory(targetId: string, chatType: ChatType, pinne emitConversationMemory() } +function setConversationGroupMemory(targetId: string, chatType: ChatType, groupName?: string | null): void { + conversationMemory = conversationMemory.map(item => + item.targetId === targetId && item.chatType === chatType + ? { ...item, conversationGroup: groupName ?? null } + : item, + ) + emitConversationMemory() +} + function deleteConversationMemory(targetId: string, chatType: ChatType): void { conversationMemory = conversationMemory.filter( item => !(item.targetId === targetId && item.chatType === chatType), @@ -779,6 +793,27 @@ export const ImSDK = { }) }, + async transferGroupOwner(groupId: string, newOwnerId: string): Promise { + return apiRequest(`/api/im/groups/${encodeURIComponent(groupId)}/owner`, { + method: 'POST', + body: { newOwnerId }, + }) + }, + + async updateGroupAttributes(groupId: string, attributes: Record): Promise { + return apiRequest(`/api/im/groups/${encodeURIComponent(groupId)}/attributes`, { + method: 'PUT', + body: attributes, + }) + }, + + async removeGroupAttributes(groupId: string, keys: string[]): Promise { + return apiRequest(`/api/im/groups/${encodeURIComponent(groupId)}/attributes/delete`, { + method: 'POST', + body: { keys }, + }) + }, + async dismissGroup(groupId: string): Promise { await apiRequest(`/api/im/groups/${encodeURIComponent(groupId)}`, { method: 'DELETE' }) }, @@ -851,6 +886,42 @@ export const ImSDK = { }) }, + async removeAllFriends(): Promise { + const config = getConfig() + await apiRequest('/api/im/friends', { + method: 'DELETE', + params: { appId: config.appId }, + }) + }, + + async setFriendGroup(friendId: string, groupName?: string): Promise { + const config = getConfig() + await apiRequest(`/api/im/friends/${encodeURIComponent(friendId)}/group`, { + method: 'PUT', + params: { + appId: config.appId, + ...(groupName ? { groupName } : {}), + }, + }) + }, + + async listFriendGroups(): Promise { + const config = getConfig() + const res = await apiRequest('/api/im/friends/groups', { + params: { appId: config.appId }, + }) + return Array.isArray(res) ? res : (res.content ?? []) + }, + + async listFriendsByGroup(groupName: string): Promise { + const config = getConfig() + const res = await apiRequest( + `/api/im/friends/groups/${encodeURIComponent(groupName)}`, + { params: { appId: config.appId } }, + ) + return Array.isArray(res) ? res : (res.content ?? []) + }, + async listFriendRequests(direction: 'incoming' | 'outgoing' = 'incoming'): Promise { const config = getConfig() const res = await apiRequest('/api/im/friend-requests', { @@ -914,6 +985,13 @@ export const ImSDK = { }) }, + async checkBlacklist(targetUserId: string): Promise { + const config = getConfig() + return apiRequest('/api/im/blacklist/check', { + params: { appId: config.appId, targetUserId }, + }) + }, + async getProfile(userId: string): Promise { const config = getConfig() return apiRequest(`/api/im/accounts/${encodeURIComponent(userId)}`, { @@ -977,6 +1055,7 @@ export const ImSDK = { unreadCount: model.unreadCount, isMuted: model.isMuted, isPinned: model.isPinned, + conversationGroup: null, })) conversationMemory = conversations emitConversationMemory() @@ -1013,6 +1092,7 @@ export const ImSDK = { unreadCount: c.unreadCount, isMuted: c.isMuted, isPinned: c.isPinned, + conversationGroup: null, })) callback(data) }) @@ -1074,6 +1154,64 @@ export const ImSDK = { } }, + async setConversationHidden(targetId: string, chatType: ChatType, hidden: boolean): Promise { + const config = getConfig() + await apiRequest(`/api/im/conversations/${encodeURIComponent(targetId)}/hidden`, { + method: 'PUT', + params: { + appId: config.appId, + chatType, + hidden: String(hidden), + }, + }) + if (hidden) { + deleteConversationMemory(targetId, chatType) + } + }, + + async setConversationGroup(targetId: string, chatType: ChatType, groupName?: string): Promise { + const config = getConfig() + await apiRequest(`/api/im/conversations/${encodeURIComponent(targetId)}/group`, { + method: 'PUT', + params: { + appId: config.appId, + chatType, + ...(groupName ? { groupName } : {}), + }, + }) + setConversationGroupMemory(targetId, chatType, groupName ?? null) + }, + + async listConversationGroups(): Promise { + const config = getConfig() + const res = await apiRequest('/api/im/conversation-groups', { + params: { appId: config.appId }, + }) + return Array.isArray(res) ? res : (res.content ?? []) + }, + + async listConversationGroupItems(groupName: string): Promise { + const config = getConfig() + const res = await apiRequest( + `/api/im/conversation-groups/${encodeURIComponent(groupName)}`, + { params: { appId: config.appId } }, + ) + return Array.isArray(res) ? res : (res.content ?? []) + }, + + async adminGroupReadReceipts(groupId: string, messageIds: string[]): Promise { + const config = getConfig() + const res = await apiRequest( + `/api/im/admin/groups/${encodeURIComponent(groupId)}/read-receipts`, + { + method: 'POST', + params: { appId: config.appId }, + body: { messageIds }, + }, + ) + return Array.isArray(res) ? res : (res.content ?? []) + }, + async getDraft(targetId: string, chatType: ChatType): Promise { const config = getConfig() if (ImDatabase.isInitialized()) { diff --git a/packages/im/src/index.ts b/packages/im/src/index.ts index 43c9f05..c787cf2 100644 --- a/packages/im/src/index.ts +++ b/packages/im/src/index.ts @@ -5,10 +5,19 @@ import { ImSDK as _ImSDK } from './ImSDK' export const listFriends = (): Promise => _ImSDK.listFriends() export const addFriend = (friendId: string): Promise => _ImSDK.addFriend(friendId) export const removeFriend = (friendId: string): Promise => _ImSDK.removeFriend(friendId) +export const removeAllFriends = (): Promise => _ImSDK.removeAllFriends() +export const setFriendGroup = (friendId: string, groupName?: string): Promise => _ImSDK.setFriendGroup(friendId, groupName) +export const listFriendGroups = (): ReturnType => _ImSDK.listFriendGroups() +export const listFriendsByGroup = (groupName: string): ReturnType => _ImSDK.listFriendsByGroup(groupName) +export const checkBlacklist = (targetUserId: string): ReturnType => _ImSDK.checkBlacklist(targetUserId) export const searchUsers = (keyword: string, size?: number): ReturnType => _ImSDK.searchUsers(keyword, size) export const searchGroups = (keyword: string, size?: number): ReturnType => _ImSDK.searchGroups(keyword, size) export const searchMessages = (params: Parameters[0]): ReturnType => _ImSDK.searchMessages(params) export const editMessage = (messageId: string, content: string): ReturnType => _ImSDK.editMessage(messageId, content) +export const setConversationHidden = (targetId: string, chatType: Parameters[1], hidden: boolean): ReturnType => _ImSDK.setConversationHidden(targetId, chatType, hidden) +export const setConversationGroup = (targetId: string, chatType: Parameters[1], groupName?: string): ReturnType => _ImSDK.setConversationGroup(targetId, chatType, groupName) +export const listConversationGroups = (): ReturnType => _ImSDK.listConversationGroups() +export const listConversationGroupItems = (groupName: string): ReturnType => _ImSDK.listConversationGroupItems(groupName) export const locateHistoryPage = (toId: string, messageId: string, pageSize?: number, maxPages?: number): ReturnType => _ImSDK.locateHistoryPage(toId, messageId, pageSize, maxPages) export const locateGroupHistoryPage = (groupId: string, messageId: string, pageSize?: number, maxPages?: number): ReturnType => _ImSDK.locateGroupHistoryPage(groupId, messageId, pageSize, maxPages) export { ImClient } from './ImClient' @@ -18,11 +27,14 @@ export type { ImMessage, ImGroup, ChatType, MsgType, MsgStatus, ImEventListener, SendMessageParams, ConversationData, + ConversationGroupItem, HistoryQuery, PageResult, FriendRequest, GroupJoinRequest, BlacklistEntry, + BlacklistCheckResult, + GroupReadReceiptSummary, UserProfile, } from './types' export { uploadFile } from './upload' diff --git a/packages/im/src/types.ts b/packages/im/src/types.ts index f4072c1..2b58a34 100644 --- a/packages/im/src/types.ts +++ b/packages/im/src/types.ts @@ -65,6 +65,8 @@ export interface ImGroup { memberIds: string adminIds: string announcement?: string | null + memberInfo?: string | null + extAttributes?: string | null createdAt: number } @@ -77,6 +79,13 @@ export interface ConversationData { unreadCount: number isMuted: boolean isPinned: boolean + conversationGroup?: string | null +} + +export interface ConversationGroupItem { + targetId: string + chatType: ChatType + groupName: string } export interface HistoryQuery { @@ -130,6 +139,21 @@ export interface BlacklistEntry { createdAt: number } +export interface BlacklistCheckResult { + targetUserId: string + blockedByMe: boolean + blockedByTarget: boolean + eitherBlocked: boolean +} + +export interface GroupReadReceiptSummary { + messageId: string + groupId: string + memberCount: number + readCount: number + unreadCount: number +} + export interface UserProfile { id?: string appId?: string