- 新增 Android SDK 使用文档,包含模块结构、集成方式和快速开始指南 - 添加 SDK API 重设计规范,统一初始化和登录接口设计 - 补充安全设计规范,完善 UserSig 鉴权和敏感数据处理方案 - 创建平台 REST API 规范,定义服务端到服务端的调用接口 - 添加离线推送架构设计,集成各大厂商推送服务与 IM 联动方案
484 行
12 KiB
TypeScript
484 行
12 KiB
TypeScript
import axios from 'axios'
|
|
|
|
const imClient = axios.create({
|
|
baseURL: 'http://192.168.116.9:8082',
|
|
timeout: 15000,
|
|
})
|
|
|
|
if (import.meta.env.DEV) {
|
|
imClient.interceptors.request.use((config) => {
|
|
console.debug('[tenant-platform][IM] request', {
|
|
method: config.method?.toUpperCase(),
|
|
url: config.baseURL ? `${config.baseURL}${config.url ?? ''}` : config.url,
|
|
params: config.params,
|
|
})
|
|
return config
|
|
})
|
|
imClient.interceptors.response.use((res) => {
|
|
console.debug('[tenant-platform][IM] response', {
|
|
status: res.status,
|
|
url: res.config.url,
|
|
})
|
|
return res
|
|
})
|
|
}
|
|
|
|
imClient.interceptors.request.use((config) => {
|
|
const token = localStorage.getItem('token')
|
|
if (token) config.headers.Authorization = `Bearer ${token}`
|
|
return config
|
|
})
|
|
|
|
export interface ImUser {
|
|
id: string
|
|
appId: string
|
|
userId: string
|
|
nickname: string
|
|
avatar?: string
|
|
status: 'ACTIVE' | 'BANNED'
|
|
gender: 'UNKNOWN' | 'MALE' | 'FEMALE'
|
|
createdAt: number
|
|
}
|
|
|
|
export interface ImProfile {
|
|
id?: string
|
|
appId?: string
|
|
userId: string
|
|
nickname?: string | null
|
|
avatar?: string | null
|
|
gender?: 'UNKNOWN' | 'MALE' | 'FEMALE' | string | null
|
|
status?: 'ACTIVE' | 'BANNED' | string | null
|
|
createdAt?: number | null
|
|
}
|
|
|
|
export interface ImGroup {
|
|
id: string
|
|
appId: string
|
|
name: string
|
|
creatorId: string
|
|
groupType?: string | null
|
|
memberIds: string
|
|
adminIds: string
|
|
announcement?: string | null
|
|
createdAt: number
|
|
}
|
|
|
|
export interface ImMessage {
|
|
id: string
|
|
appId: string
|
|
fromUserId: string
|
|
toId: string
|
|
chatType: 'SINGLE' | 'GROUP'
|
|
msgType: string
|
|
content: string
|
|
status: string
|
|
mentionedUserIds?: string | null
|
|
groupReadCount?: number | null
|
|
createdAt: number
|
|
}
|
|
|
|
export interface PagedResult<T> {
|
|
content: T[]
|
|
totalElements: number
|
|
totalPages: number
|
|
size: number
|
|
number: number
|
|
}
|
|
|
|
export interface ImStats {
|
|
totalMessages: number
|
|
totalUsers: number
|
|
totalGroups: number
|
|
todayMessages: number
|
|
}
|
|
|
|
export interface OperationLog {
|
|
id: string
|
|
appId: string
|
|
operatorId: string
|
|
action: string
|
|
resourceType: string
|
|
resourceId?: string | null
|
|
detail?: string | null
|
|
createdAt: number
|
|
}
|
|
|
|
export interface KeywordFilter {
|
|
id: string
|
|
appId: string
|
|
pattern: string
|
|
replacement?: string | null
|
|
action: 'REPLACE' | 'BLOCK'
|
|
enabled: boolean
|
|
createdAt: number
|
|
}
|
|
|
|
export interface GlobalMute {
|
|
id: string
|
|
appId: string
|
|
enabled: boolean
|
|
createdAt: number
|
|
updatedAt: number
|
|
}
|
|
|
|
export interface WebhookConfig {
|
|
id: string
|
|
appId: string
|
|
url: string
|
|
secret?: string | null
|
|
enabled: boolean
|
|
createdAt: number
|
|
}
|
|
|
|
export interface WebhookConfigForm {
|
|
url: string
|
|
secret?: string
|
|
enabled?: boolean
|
|
}
|
|
|
|
export interface GroupJoinRequest {
|
|
id: string
|
|
appId: string
|
|
groupId: string
|
|
requesterId: string
|
|
remark?: string | null
|
|
status: 'PENDING' | 'ACCEPTED' | 'REJECTED'
|
|
createdAt: number
|
|
reviewedAt?: number | null
|
|
}
|
|
|
|
export const imAdminApi = {
|
|
listUsers(appId: string, page = 0, size = 20) {
|
|
return imClient.get<{ data: PagedResult<ImUser> }>(
|
|
'/api/im/admin/users', { params: { appId, page, size } },
|
|
)
|
|
},
|
|
|
|
updateUserStatus(appId: string, userId: string, status: 'ACTIVE' | 'BANNED') {
|
|
return imClient.put(`/api/im/admin/users/${encodeURIComponent(userId)}/status`, { status }, { params: { appId } })
|
|
},
|
|
|
|
listGroups(appId: string) {
|
|
return imClient.get<{ data: ImGroup[] }>('/api/im/admin/groups', { params: { appId } })
|
|
},
|
|
|
|
getStats(appId: string) {
|
|
return imClient.get<{ data: ImStats }>('/api/im/admin/stats', { params: { appId } })
|
|
},
|
|
|
|
getOperationLogs(appId: string, page = 0, size = 20) {
|
|
return imClient.get<{ data: PagedResult<OperationLog> }>('/api/im/admin/operation-logs', {
|
|
params: { appId, page, size },
|
|
})
|
|
},
|
|
|
|
listWebhooks(appId: string) {
|
|
return imClient.get<{ data: WebhookConfig[] }>('/api/im/admin/webhooks', {
|
|
params: { appId },
|
|
})
|
|
},
|
|
|
|
createWebhook(appId: string, form: WebhookConfigForm) {
|
|
return imClient.post<{ data: WebhookConfig }>('/api/im/admin/webhooks', form, {
|
|
params: { appId },
|
|
})
|
|
},
|
|
|
|
updateUser(
|
|
appId: string,
|
|
userId: string,
|
|
form: { nickname?: string; avatar?: string; gender?: string; status?: string },
|
|
) {
|
|
return imClient.put<{ data: ImUser }>(
|
|
`/api/im/admin/users/${encodeURIComponent(userId)}`,
|
|
form,
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
updateWebhook(appId: string, webhookId: string, form: WebhookConfigForm) {
|
|
return imClient.put<{ data: WebhookConfig }>(`/api/im/admin/webhooks/${encodeURIComponent(webhookId)}`, form, {
|
|
params: { appId },
|
|
})
|
|
},
|
|
|
|
deleteWebhook(appId: string, webhookId: string) {
|
|
return imClient.delete<{ data: null }>(`/api/im/admin/webhooks/${encodeURIComponent(webhookId)}`, {
|
|
params: { appId },
|
|
})
|
|
},
|
|
|
|
listKeywordFilters(appId: string) {
|
|
return imClient.get<{ data: KeywordFilter[] }>('/api/im/admin/keyword-filters', {
|
|
params: { appId },
|
|
})
|
|
},
|
|
|
|
createKeywordFilter(
|
|
appId: string,
|
|
form: { pattern: string; replacement?: string; action: 'REPLACE' | 'BLOCK'; enabled: boolean },
|
|
) {
|
|
return imClient.post<{ data: KeywordFilter }>('/api/im/admin/keyword-filters', form, {
|
|
params: { appId },
|
|
})
|
|
},
|
|
|
|
updateKeywordFilter(
|
|
appId: string,
|
|
filterId: string,
|
|
form: { pattern: string; replacement?: string; action: 'REPLACE' | 'BLOCK'; enabled: boolean },
|
|
) {
|
|
return imClient.put<{ data: KeywordFilter }>(`/api/im/admin/keyword-filters/${encodeURIComponent(filterId)}`, form, {
|
|
params: { appId },
|
|
})
|
|
},
|
|
|
|
deleteKeywordFilter(appId: string, filterId: string) {
|
|
return imClient.delete<{ data: null }>(`/api/im/admin/keyword-filters/${encodeURIComponent(filterId)}`, {
|
|
params: { appId },
|
|
})
|
|
},
|
|
|
|
getGlobalMute(appId: string) {
|
|
return imClient.get<{ data: GlobalMute }>('/api/im/admin/global-mute', {
|
|
params: { appId },
|
|
})
|
|
},
|
|
|
|
setGlobalMute(appId: string, enabled: boolean) {
|
|
return imClient.put<{ data: GlobalMute }>('/api/im/admin/global-mute', null, {
|
|
params: { appId, enabled },
|
|
})
|
|
},
|
|
|
|
listGroupMembers(appId: string, groupId: string) {
|
|
return imClient.get<{ data: ImUser[] }>(
|
|
`/api/im/admin/groups/${encodeURIComponent(groupId)}/members`,
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
searchGroupMembers(appId: string, groupId: string, keyword: string, size = 20) {
|
|
return imClient.get<{ data: ImUser[] }>(
|
|
`/api/im/admin/groups/${encodeURIComponent(groupId)}/members/search`,
|
|
{ params: { appId, keyword, size } },
|
|
)
|
|
},
|
|
|
|
addGroupMember(appId: string, groupId: string, userId: string) {
|
|
return imClient.post<{ data: ImGroup }>(
|
|
`/api/im/admin/groups/${encodeURIComponent(groupId)}/members`,
|
|
{ userId },
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
removeGroupMember(appId: string, groupId: string, userId: string) {
|
|
return imClient.delete<{ data: ImGroup }>(
|
|
`/api/im/admin/groups/${encodeURIComponent(groupId)}/members/${encodeURIComponent(userId)}`,
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
setGroupRole(appId: string, groupId: string, userId: string, role: 'ADMIN' | 'MEMBER') {
|
|
return imClient.post<{ data: ImGroup }>(
|
|
`/api/im/admin/groups/${encodeURIComponent(groupId)}/roles`,
|
|
{ userId, role },
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
muteGroupMember(appId: string, groupId: string, userId: string, minutes: number) {
|
|
return imClient.post<{ data: ImGroup }>(
|
|
`/api/im/admin/groups/${encodeURIComponent(groupId)}/mute`,
|
|
{ userId, minutes },
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
listGroupJoinRequests(appId: string, groupId: string) {
|
|
return imClient.get<{ data: GroupJoinRequest[] }>(
|
|
`/api/im/admin/groups/${encodeURIComponent(groupId)}/join-requests`,
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
sendGroupJoinRequest(appId: string, groupId: string, remark?: string) {
|
|
return imClient.post<{ data: GroupJoinRequest }>(
|
|
`/api/im/groups/${encodeURIComponent(groupId)}/join-requests`,
|
|
null,
|
|
{
|
|
params: {
|
|
appId,
|
|
...(remark ? { remark } : {}),
|
|
},
|
|
},
|
|
)
|
|
},
|
|
|
|
acceptGroupJoinRequest(appId: string, groupId: string, requestId: string) {
|
|
return imClient.post<{ data: GroupJoinRequest }>(
|
|
`/api/im/admin/groups/${encodeURIComponent(groupId)}/join-requests/${encodeURIComponent(requestId)}/accept`,
|
|
null,
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
rejectGroupJoinRequest(appId: string, groupId: string, requestId: string) {
|
|
return imClient.post<{ data: GroupJoinRequest }>(
|
|
`/api/im/admin/groups/${encodeURIComponent(groupId)}/join-requests/${encodeURIComponent(requestId)}/reject`,
|
|
null,
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
getMessages(
|
|
appId: string,
|
|
userA: string,
|
|
userB: string,
|
|
page = 0,
|
|
size = 20,
|
|
filters?: {
|
|
msgType?: string
|
|
keyword?: string
|
|
startTime?: string
|
|
endTime?: string
|
|
},
|
|
) {
|
|
return imClient.get<{ data: PagedResult<ImMessage> }>('/api/im/admin/messages', {
|
|
params: {
|
|
appId,
|
|
userA,
|
|
userB,
|
|
page,
|
|
size,
|
|
...(filters?.msgType ? { msgType: filters.msgType } : {}),
|
|
...(filters?.keyword ? { keyword: filters.keyword } : {}),
|
|
...(filters?.startTime ? { startTime: filters.startTime } : {}),
|
|
...(filters?.endTime ? { endTime: filters.endTime } : {}),
|
|
},
|
|
})
|
|
},
|
|
|
|
revokeMessage(appId: string, messageId: string) {
|
|
return imClient.post<{ data: ImMessage }>(
|
|
`/api/im/admin/messages/${encodeURIComponent(messageId)}/revoke`,
|
|
{},
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
dismissGroup(appId: string, groupId: string) {
|
|
return imClient.delete<{ data: null }>(`/api/im/admin/groups/${encodeURIComponent(groupId)}`, { params: { appId } })
|
|
},
|
|
|
|
registerUser(
|
|
appId: string,
|
|
userId: string,
|
|
nickname?: string,
|
|
avatar?: string,
|
|
gender?: string,
|
|
status?: string,
|
|
) {
|
|
return imClient.post<{ data: ImUser }>(
|
|
'/api/im/admin/users',
|
|
{
|
|
userId,
|
|
nickname,
|
|
avatar,
|
|
...(gender ? { gender } : {}),
|
|
...(status ? { status } : {}),
|
|
},
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
createGroup(
|
|
appId: string,
|
|
name: string,
|
|
creatorId: string,
|
|
memberIds: string[],
|
|
groupType?: string,
|
|
announcement?: string,
|
|
) {
|
|
return imClient.post<{ data: ImGroup }>(
|
|
'/api/im/admin/groups',
|
|
{
|
|
name,
|
|
creatorId,
|
|
memberIds,
|
|
...(groupType ? { groupType } : {}),
|
|
...(announcement ? { announcement } : {}),
|
|
},
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
updateGroup(
|
|
appId: string,
|
|
groupId: string,
|
|
form: { name?: string; groupType?: string; announcement?: string },
|
|
) {
|
|
return imClient.put<{ data: ImGroup }>(
|
|
`/api/im/admin/groups/${encodeURIComponent(groupId)}`,
|
|
form,
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
searchUsers(appId: string, keyword: string, size = 20) {
|
|
return imClient.get<{ data: ImUser[] }>(
|
|
'/api/im/admin/users/search',
|
|
{ params: { appId, keyword, size } },
|
|
)
|
|
},
|
|
|
|
searchMessages(
|
|
appId: string,
|
|
filters: {
|
|
keyword?: string
|
|
chatType?: string
|
|
msgType?: string
|
|
startTime?: string
|
|
endTime?: string
|
|
page?: number
|
|
size?: number
|
|
} = {},
|
|
) {
|
|
return imClient.get<{ data: PagedResult<ImMessage> }>('/api/im/admin/messages/search', {
|
|
params: {
|
|
appId,
|
|
...(filters.keyword ? { keyword: filters.keyword } : {}),
|
|
...(filters.chatType ? { chatType: filters.chatType } : {}),
|
|
...(filters.msgType ? { msgType: filters.msgType } : {}),
|
|
...(filters.startTime ? { startTime: filters.startTime } : {}),
|
|
...(filters.endTime ? { endTime: filters.endTime } : {}),
|
|
page: filters.page ?? 0,
|
|
size: filters.size ?? 20,
|
|
},
|
|
})
|
|
},
|
|
|
|
getProfile(appId: string, userId: string) {
|
|
return imClient.get<{ data: ImProfile }>(
|
|
`/api/im/accounts/${encodeURIComponent(userId)}`,
|
|
{ params: { appId } },
|
|
)
|
|
},
|
|
|
|
updateProfile(appId: string, userId: string, nickname?: string, avatar?: string, gender?: string) {
|
|
return imClient.put<{ data: ImProfile }>(
|
|
`/api/im/accounts/${encodeURIComponent(userId)}`,
|
|
{},
|
|
{
|
|
params: {
|
|
appId,
|
|
...(nickname ? { nickname } : {}),
|
|
...(avatar ? { avatar } : {}),
|
|
...(gender ? { gender } : {}),
|
|
},
|
|
},
|
|
)
|
|
},
|
|
}
|