diff --git a/src/im/ImClient.ts b/src/im/ImClient.ts index b88e2e4..796276f 100644 --- a/src/im/ImClient.ts +++ b/src/im/ImClient.ts @@ -49,7 +49,14 @@ export class ImClient { try { const frame = JSON.parse(event.data as string) if (frame.type === 'MESSAGE') { - this.emit('message', this.normalizeMessage(frame.payload as ImMessage)) + const message = this.normalizeMessage(frame.payload as ImMessage) + if (message.status === 'READ') { + this.emit('read', message) + } + if (message.revoked || message.status === 'REVOKED' || message.msgType === 'REVOKED') { + this.emit('revoke', { msgId: message.id, operatorId: message.fromId ?? message.fromUserId }) + } + this.emit('message', message) } else if (frame.type === 'REVOKE') { this.emit('revoke', frame.payload as { msgId: string; operatorId: string }) } diff --git a/src/im/api.ts b/src/im/api.ts index ca9776c..de938e8 100644 --- a/src/im/api.ts +++ b/src/im/api.ts @@ -48,6 +48,54 @@ export function fetchGroupHistory(groupId: string, query: HistoryQuery = {}): Pr ) } +export async function locateHistoryPage( + toId: string, + messageId: string, + pageSize = 20, + maxPages = 20, +): Promise { + for (let page = 0; page < Math.max(maxPages, 1); page += 1) { + const result = await fetchHistory(toId, { page, size: pageSize }) + if (result.content.some((item) => item.id === messageId)) { + return result.content + } + if (result.content.length < pageSize) return null + } + return null +} + +export async function locateGroupHistoryPage( + groupId: string, + messageId: string, + pageSize = 20, + maxPages = 20, +): Promise { + for (let page = 0; page < Math.max(maxPages, 1); page += 1) { + const result = await fetchGroupHistory(groupId, { page, size: pageSize }) + if (result.content.some((item) => item.id === messageId)) { + return result.content + } + if (result.content.length < pageSize) return null + } + return null +} + +export function editMessage(messageId: string, content: string): Promise { + return http.put( + `/api/im/messages/${encodeURIComponent(messageId)}`, + { content }, + appQuery(), + ) +} + +export function revokeMessage(messageId: string): Promise { + return http.post( + `/api/im/messages/${encodeURIComponent(messageId)}/revoke`, + undefined, + appQuery(), + ) +} + export function markRead(targetId: string, chatType: ChatType = 'SINGLE'): Promise { return http.put( `/api/im/conversations/${encodeURIComponent(targetId)}/read`, diff --git a/src/im/useIm.ts b/src/im/useIm.ts index 60b6f64..2862d53 100644 --- a/src/im/useIm.ts +++ b/src/im/useIm.ts @@ -7,6 +7,10 @@ import { getGroupInfo, fetchGroupHistory, fetchHistory, + editMessage, + locateGroupHistoryPage, + locateHistoryPage, + revokeMessage, listFriendRequests, listFriends, listGroupJoinRequests, @@ -64,6 +68,14 @@ export function useIm() { return fetchGroupHistory(groupId, query) } + function jumpToMessagePage(toId: string, messageId: string, pageSize = 20, maxPages = 20) { + return locateHistoryPage(toId, messageId, pageSize, maxPages) + } + + function jumpToGroupMessagePage(groupId: string, messageId: string, pageSize = 20, maxPages = 20) { + return locateGroupHistoryPage(groupId, messageId, pageSize, maxPages) + } + function connect() { const im = new ImClient() im.on('connected', () => { @@ -75,6 +87,10 @@ export function useIm() { upsertMessage(msg) void refreshConversations().catch(() => {}) }) + im.on('read', (msg) => { + upsertMessage(msg) + void refreshConversations().catch(() => {}) + }) im.on('error', (e) => { error.value = e }) im.connect() client.value = im @@ -89,7 +105,11 @@ export function useIm() { } function revoke(msgId: string) { - client.value?.revoke(msgId) + return revokeMessage(msgId) + } + + function edit(msgId: string, content: string) { + return editMessage(msgId, content) } function disconnect() { @@ -168,6 +188,7 @@ export function useIm() { connect, send, revoke, + edit, disconnect, messages, conversations, @@ -176,6 +197,8 @@ export function useIm() { refreshConversations, loadHistory, loadGroupHistory, + jumpToMessagePage, + jumpToGroupMessagePage, setConversationRead, setConversationPinnedState, setConversationMutedState, diff --git a/src/index.ts b/src/index.ts index 78ab265..97072c2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,10 @@ export { getGroupInfo, fetchGroupHistory, fetchHistory, + editMessage, + locateGroupHistoryPage, + locateHistoryPage, + revokeMessage, listFriendRequests, listFriends, listGroupJoinRequests, diff --git a/src/types/index.ts b/src/types/index.ts index f517088..09440d4 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -130,6 +130,7 @@ export interface SendMessageParams { export interface ImEventMap { message: (msg: ImMessage) => void + read: (msg: ImMessage) => void revoke: (data: { msgId: string; operatorId: string }) => void connected: () => void disconnected: (code: number, reason: string) => void