Switch frontend group and conversation requests to RESTful endpoints.

Update service API paths and message reply payload handling to match the backend route changes.

Made-with: Cursor
This commit is contained in:
2026-03-10 20:52:50 +08:00
parent be84c01abd
commit f10c9cc1d7
2 changed files with 105 additions and 148 deletions

View File

@@ -1,7 +1,7 @@
/** /**
* 群组服务 * 群组服务
* 处理群组管理、成员管理、群设置、群公告等功能 * 处理群组管理、成员管理、群设置、群公告等功能
* 使用新的 API 接口: /api/v1/groups (RESTful action 风格) * 使用 RESTful API: /api/v1/groups
*/ */
import { api } from './api'; import { api } from './api';
@@ -29,7 +29,7 @@ import {
// SQLite/内存缓存编排由 groupManager 统一处理 // SQLite/内存缓存编排由 groupManager 统一处理
class GroupService { class GroupService {
async fetchGroupsFromApi(page = 1, pageSize = 20): Promise<GroupListResponse> { async fetchGroupsFromApi(page = 1, pageSize = 20): Promise<GroupListResponse> {
const response = await api.get<GroupListResponse>('/groups/list', { const response = await api.get<GroupListResponse>('/groups', {
page, page,
page_size: pageSize, page_size: pageSize,
}); });
@@ -37,9 +37,7 @@ class GroupService {
} }
async fetchGroupFromApi(id: number | string): Promise<GroupResponse> { async fetchGroupFromApi(id: number | string): Promise<GroupResponse> {
const response = await api.get<GroupResponse>('/groups/get', { const response = await api.get<GroupResponse>(`/groups/${encodeURIComponent(String(id))}`);
group_id: String(id),
});
return response.data; return response.data;
} }
@@ -49,9 +47,8 @@ class GroupService {
pageSize = 50 pageSize = 50
): Promise<GroupMemberListResponse> { ): Promise<GroupMemberListResponse> {
const response = await api.get<GroupMemberListResponse>( const response = await api.get<GroupMemberListResponse>(
'/groups/get_members', `/groups/${encodeURIComponent(String(groupId))}/members`,
{ {
group_id: String(groupId),
page, page,
page_size: pageSize, page_size: pageSize,
} }
@@ -63,16 +60,16 @@ class GroupService {
/** /**
* 创建群组 * 创建群组
* POST /api/v1/groups/create * POST /api/v1/groups
*/ */
async createGroup(data: CreateGroupRequest): Promise<GroupResponse> { async createGroup(data: CreateGroupRequest): Promise<GroupResponse> {
const response = await api.post<GroupResponse>('/groups/create', data); const response = await api.post<GroupResponse>('/groups', data);
return response.data; return response.data;
} }
/** /**
* 获取群组列表 * 获取群组列表
* GET /api/v1/groups/list * GET /api/v1/groups
*/ */
async getGroups(page = 1, pageSize = 20): Promise<GroupListResponse> { async getGroups(page = 1, pageSize = 20): Promise<GroupListResponse> {
return this.fetchGroupsFromApi(page, pageSize); return this.fetchGroupsFromApi(page, pageSize);
@@ -80,7 +77,7 @@ class GroupService {
/** /**
* 获取群组详情 * 获取群组详情
* GET /api/v1/groups/get?group_id=xxx * GET /api/v1/groups/:id
*/ */
async getGroup(id: number | string): Promise<GroupResponse> { async getGroup(id: number | string): Promise<GroupResponse> {
return this.fetchGroupFromApi(id); return this.fetchGroupFromApi(id);
@@ -88,93 +85,82 @@ class GroupService {
/** /**
* 获取当前用户在群组中的成员信息 * 获取当前用户在群组中的成员信息
* GET /api/v1/groups/get_my_info?group_id=xxx * GET /api/v1/groups/:id/me
*/ */
async getMyMemberInfo(groupId: number | string): Promise<MyMemberInfoResponse> { async getMyMemberInfo(groupId: number | string): Promise<MyMemberInfoResponse> {
const response = await api.get<MyMemberInfoResponse>('/groups/get_my_info', { const response = await api.get<MyMemberInfoResponse>(
group_id: String(groupId), `/groups/${encodeURIComponent(String(groupId))}/me`
}); );
return response.data; return response.data;
} }
/** /**
* 解散群组 * 解散群组
* POST /api/v1/groups/dissolve * DELETE /api/v1/groups/:id
* Body: { "group_id": "xxx" }
*/ */
async dissolveGroup(id: number | string): Promise<void> { async dissolveGroup(id: number | string): Promise<void> {
await api.post('/groups/dissolve', { await api.delete(`/groups/${encodeURIComponent(String(id))}`);
group_id: String(id),
});
} }
/** /**
* 转让群主 * 转让群主
* POST /api/v1/groups/transfer * POST /api/v1/groups/:id/transfer
* Body: { "group_id": "xxx", "new_owner_id": "xxx" }
*/ */
async transferOwner(id: number | string, data: TransferOwnerRequest): Promise<void> { async transferOwner(id: number | string, data: TransferOwnerRequest): Promise<void> {
await api.post('/groups/transfer', { await api.post(`/groups/${encodeURIComponent(String(id))}/transfer`, data);
group_id: String(id),
...data,
});
} }
// ==================== 成员管理 ==================== // ==================== 成员管理 ====================
/** /**
* 邀请成员加入群组 * 邀请成员加入群组
* POST /api/v1/groups/invite_members * POST /api/v1/groups/:id/invitations
* Body: { "group_id": "xxx", "user_ids": [...] }
*/ */
async inviteMembers(groupId: number | string, data: InviteMembersRequest): Promise<void> { async inviteMembers(groupId: number | string, data: InviteMembersRequest): Promise<void> {
await api.post('/groups/invite_members', { await api.post(`/groups/${encodeURIComponent(String(groupId))}/invitations`, data);
group_id: String(groupId),
...data,
});
} }
/** /**
* 申请加入群组 * 申请加入群组
* POST /api/v1/groups/join * POST /api/v1/groups/:id/join-requests
* Body: { "group_id": "xxx" }
*/ */
async joinGroup(groupId: number | string): Promise<void> { async joinGroup(groupId: number | string): Promise<void> {
await api.post('/groups/join', { await api.post(`/groups/${encodeURIComponent(String(groupId))}/join-requests`);
group_id: String(groupId),
});
} }
/** /**
* 响应群邀请 * 响应群邀请/申请
* POST /api/v1/groups/respond_invite * POST /api/v1/groups/:id/join-requests/respond
*/ */
async respondInvite(data: HandleGroupRequestAction): Promise<void> { async respondInvite(groupId: number | string, data: HandleGroupRequestAction): Promise<void> {
await api.post('/groups/respond_invite', data); await api.post(
`/groups/${encodeURIComponent(String(groupId))}/join-requests/respond`,
data
);
} }
/** /**
* 审批主动加群申请 * 审批主动加群申请
* POST /api/v1/groups/set_group_add_request * POST /api/v1/groups/:id/join-requests/handle
*/ */
async reviewJoinRequest(data: HandleGroupRequestAction): Promise<void> { async reviewJoinRequest(groupId: number | string, data: HandleGroupRequestAction): Promise<void> {
await api.post('/groups/set_group_add_request', data); await api.post(
`/groups/${encodeURIComponent(String(groupId))}/join-requests/handle`,
data
);
} }
/** /**
* 退出群组 * 退出群组
* POST /api/v1/groups/set_group_leave * POST /api/v1/groups/:id/leave
* Body: { "group_id": "xxx" }
*/ */
async leaveGroup(groupId: number | string): Promise<void> { async leaveGroup(groupId: number | string): Promise<void> {
await api.post('/groups/set_group_leave', { await api.post(`/groups/${encodeURIComponent(String(groupId))}/leave`);
group_id: String(groupId),
});
} }
/** /**
* 获取群组成员列表 * 获取群组成员列表
* GET /api/v1/groups/get_members?group_id=xxx * GET /api/v1/groups/:id/members
*/ */
async getMembers(groupId: number | string, page = 1, pageSize = 50): Promise<GroupMemberListResponse> { async getMembers(groupId: number | string, page = 1, pageSize = 50): Promise<GroupMemberListResponse> {
return this.fetchMembersFromApi(groupId, page, pageSize); return this.fetchMembersFromApi(groupId, page, pageSize);
@@ -182,12 +168,10 @@ class GroupService {
/** /**
* 移除群成员(踢人) * 移除群成员(踢人)
* POST /api/v1/groups/set_group_kick * POST /api/v1/groups/:id/members/kick
* Body: { "group_id": "xxx", "user_id": "xxx", "reject_add_request": false }
*/ */
async removeMember(groupId: number | string, userId: string): Promise<void> { async removeMember(groupId: number | string, userId: string): Promise<void> {
await api.post('/groups/set_group_kick', { await api.post(`/groups/${encodeURIComponent(String(groupId))}/members/kick`, {
group_id: String(groupId),
user_id: userId, user_id: userId,
reject_add_request: false, reject_add_request: false,
}); });
@@ -195,37 +179,32 @@ class GroupService {
/** /**
* 设置成员角色(设置/取消管理员) * 设置成员角色(设置/取消管理员)
* POST /api/v1/groups/set_group_admin * PUT /api/v1/groups/:id/members/:user_id/admin
* Body: { "group_id": "xxx", "user_id": "xxx", "enable": true }
*/ */
async setMemberRole( async setMemberRole(
groupId: number | string, groupId: number | string,
userId: string, userId: string,
data: SetRoleRequest data: SetRoleRequest
): Promise<void> { ): Promise<void> {
await api.post('/groups/set_group_admin', { await api.put(
group_id: String(groupId), `/groups/${encodeURIComponent(String(groupId))}/members/${encodeURIComponent(userId)}/admin`,
user_id: userId, {
enable: data.role === 'admin', enable: data.role === 'admin',
}); }
);
} }
/** /**
* 设置群昵称 * 设置群昵称
* POST /api/v1/groups/set_nickname * PUT /api/v1/groups/:id/members/me/nickname
* Body: { "group_id": "xxx", "nickname": "xxx" }
*/ */
async setNickname(groupId: number | string, data: SetNicknameRequest): Promise<void> { async setNickname(groupId: number | string, data: SetNicknameRequest): Promise<void> {
await api.post('/groups/set_nickname', { await api.put(`/groups/${encodeURIComponent(String(groupId))}/members/me/nickname`, data);
group_id: String(groupId),
...data,
});
} }
/** /**
* 禁言/解禁成员 * 禁言/解禁成员
* POST /api/v1/groups/set_group_ban * POST /api/v1/groups/:id/members/ban
* Body: { "group_id": "xxx", "user_id": "xxx", "duration": 3600 }
* @param groupId 群组ID * @param groupId 群组ID
* @param userId 用户ID * @param userId 用户ID
* @param duration 禁言时长0表示解除禁言 * @param duration 禁言时长0表示解除禁言
@@ -235,8 +214,7 @@ class GroupService {
userId: string, userId: string,
duration: number = 0 duration: number = 0
): Promise<void> { ): Promise<void> {
await api.post('/groups/set_group_ban', { await api.post(`/groups/${encodeURIComponent(String(groupId))}/members/ban`, {
group_id: String(groupId),
user_id: userId, user_id: userId,
duration: duration, duration: duration,
}); });
@@ -246,50 +224,43 @@ class GroupService {
/** /**
* 设置全员禁言 * 设置全员禁言
* POST /api/v1/groups/set_group_whole_ban * PUT /api/v1/groups/:id/ban
* Body: { "group_id": "xxx", "enable": true }
*/ */
async setMuteAll(groupId: number | string, data: SetMuteAllRequest): Promise<void> { async setMuteAll(groupId: number | string, data: SetMuteAllRequest): Promise<void> {
await api.post('/groups/set_group_whole_ban', { await api.put(`/groups/${encodeURIComponent(String(groupId))}/ban`, {
group_id: String(groupId),
enable: data.mute_all, enable: data.mute_all,
}); });
} }
/** /**
* 设置加群方式 * 设置加群方式
* POST /api/v1/groups/set_join_type * PUT /api/v1/groups/:id/join-type
* Body: { "group_id": "xxx", "join_type": 1 }
*/ */
async setJoinType(groupId: number | string, data: SetJoinTypeRequest): Promise<void> { async setJoinType(groupId: number | string, data: SetJoinTypeRequest): Promise<void> {
await api.post('/groups/set_join_type', { await api.put(`/groups/${encodeURIComponent(String(groupId))}/join-type`, data);
group_id: String(groupId),
...data,
});
} }
/** /**
* 设置群名称 * 设置群名称
* POST /api/v1/groups/set_group_name * PUT /api/v1/groups/:id/name
* Body: { "group_id": "xxx", "group_name": "xxx" }
*/ */
async setGroupName(groupId: number | string, groupName: string): Promise<void> { async setGroupName(groupId: number | string, groupName: string): Promise<void> {
await api.post('/groups/set_group_name', { await api.put(`/groups/${encodeURIComponent(String(groupId))}/name`, {
group_id: String(groupId),
group_name: groupName, group_name: groupName,
}); });
} }
/** /**
* 设置群头像 * 设置群头像
* POST /api/v1/groups/set_group_avatar * PUT /api/v1/groups/:id/avatar
* Body: { "group_id": "xxx", "avatar": "xxx" }
*/ */
async setGroupAvatar(groupId: number | string, avatarUrl: string): Promise<GroupResponse> { async setGroupAvatar(groupId: number | string, avatarUrl: string): Promise<GroupResponse> {
const response = await api.post<GroupResponse>('/groups/set_group_avatar', { const response = await api.put<GroupResponse>(
group_id: String(groupId), `/groups/${encodeURIComponent(String(groupId))}/avatar`,
avatar: avatarUrl, {
}); avatar: avatarUrl,
}
);
return response.data; return response.data;
} }
@@ -297,26 +268,22 @@ class GroupService {
/** /**
* 创建群公告 * 创建群公告
* POST /api/v1/groups/create_announcement * POST /api/v1/groups/:id/announcements
* Body: { "group_id": "xxx", "content": "xxx" }
*/ */
async createAnnouncement( async createAnnouncement(
groupId: number | string, groupId: number | string,
data: CreateAnnouncementRequest data: CreateAnnouncementRequest
): Promise<GroupAnnouncementResponse> { ): Promise<GroupAnnouncementResponse> {
const response = await api.post<GroupAnnouncementResponse>( const response = await api.post<GroupAnnouncementResponse>(
'/groups/create_announcement', `/groups/${encodeURIComponent(String(groupId))}/announcements`,
{ data
group_id: String(groupId),
...data,
}
); );
return response.data; return response.data;
} }
/** /**
* 获取群公告列表 * 获取群公告列表
* GET /api/v1/groups/get_announcements?group_id=xxx * GET /api/v1/groups/:id/announcements
*/ */
async getAnnouncements( async getAnnouncements(
groupId: number | string, groupId: number | string,
@@ -325,9 +292,8 @@ class GroupService {
): Promise<GroupAnnouncementListResponse> { ): Promise<GroupAnnouncementListResponse> {
try { try {
const response = await api.get<GroupAnnouncementListResponse>( const response = await api.get<GroupAnnouncementListResponse>(
'/groups/get_announcements', `/groups/${encodeURIComponent(String(groupId))}/announcements`,
{ {
group_id: String(groupId),
page, page,
page_size: pageSize, page_size: pageSize,
} }
@@ -347,14 +313,12 @@ class GroupService {
/** /**
* 删除群公告 * 删除群公告
* POST /api/v1/groups/delete_announcement * DELETE /api/v1/groups/:id/announcements/:announcement_id
* Body: { "group_id": "xxx", "announcement_id": "xxx" }
*/ */
async deleteAnnouncement(groupId: number | string, announcementId: number): Promise<void> { async deleteAnnouncement(groupId: number | string, announcementId: number): Promise<void> {
await api.post('/groups/delete_announcement', { await api.delete(
group_id: String(groupId), `/groups/${encodeURIComponent(String(groupId))}/announcements/${encodeURIComponent(String(announcementId))}`
announcement_id: announcementId, );
});
} }
// ==================== 兼容旧API的方法将逐步废弃 ==================== // ==================== 兼容旧API的方法将逐步废弃 ====================

View File

@@ -34,7 +34,7 @@ class MessageService {
page = 1, page = 1,
pageSize = 20 pageSize = 20
): Promise<ConversationListResponse> { ): Promise<ConversationListResponse> {
const response = await api.get<ConversationListResponse>('/conversations/list', { const response = await api.get<ConversationListResponse>('/conversations', {
page, page,
page_size: pageSize, page_size: pageSize,
}); });
@@ -56,8 +56,7 @@ class MessageService {
private async refreshConversationDetailFromServer(id: string): Promise<ConversationDetailResponse> { private async refreshConversationDetailFromServer(id: string): Promise<ConversationDetailResponse> {
const response = await api.get<ConversationDetailResponse>( const response = await api.get<ConversationDetailResponse>(
'/conversations/get', `/conversations/${encodeURIComponent(id)}`
{ conversation_id: id }
); );
await saveConversationCache(response.data); await saveConversationCache(response.data);
if (response.data.participants?.length) { if (response.data.participants?.length) {
@@ -135,11 +134,11 @@ class MessageService {
/** /**
* 创建私聊会话 * 创建私聊会话
* POST /api/v1/conversations/create * POST /api/v1/conversations
* @param userId 目标用户ID (UUID格式) * @param userId 目标用户ID (UUID格式)
*/ */
async createConversation(userId: string): Promise<ConversationResponse> { async createConversation(userId: string): Promise<ConversationResponse> {
const response = await api.post<ConversationResponse>('/conversations/create', { const response = await api.post<ConversationResponse>('/conversations', {
user_id: userId, user_id: userId,
}); });
await saveConversationCache(response.data); await saveConversationCache(response.data);
@@ -151,7 +150,7 @@ class MessageService {
/** /**
* 获取会话详情 * 获取会话详情
* GET /api/v1/conversations/get?conversation_id=xxx * GET /api/v1/conversations/:id
*/ */
async getConversationById(id: string): Promise<ConversationDetailResponse> { async getConversationById(id: string): Promise<ConversationDetailResponse> {
const cached = await getConversationCache(id); const cached = await getConversationCache(id);
@@ -180,11 +179,10 @@ class MessageService {
/** /**
* 设置会话置顶 * 设置会话置顶
* POST /api/v1/conversations/set_pinned * PUT /api/v1/conversations/:id/pinned
*/ */
async setConversationPinned(conversationId: string, isPinned: boolean): Promise<void> { async setConversationPinned(conversationId: string, isPinned: boolean): Promise<void> {
await api.post('/conversations/set_pinned', { await api.put(`/conversations/${encodeURIComponent(conversationId)}/pinned`, {
conversation_id: conversationId,
is_pinned: isPinned, is_pinned: isPinned,
}); });
} }
@@ -193,7 +191,7 @@ class MessageService {
/** /**
* 获取消息列表(支持增量同步和历史消息加载) * 获取消息列表(支持增量同步和历史消息加载)
* GET /api/v1/conversations/get_messages?conversation_id=xxx * GET /api/v1/conversations/:id/messages
* @param conversationId 会话ID * @param conversationId 会话ID
* @param afterSeq 获取此序号之后的消息(增量同步,获取新消息) * @param afterSeq 获取此序号之后的消息(增量同步,获取新消息)
* @param beforeSeq 获取此序号之前的历史消息(下拉加载更多,获取旧消息) * @param beforeSeq 获取此序号之前的历史消息(下拉加载更多,获取旧消息)
@@ -205,9 +203,7 @@ class MessageService {
beforeSeq?: number, beforeSeq?: number,
limit?: number limit?: number
): Promise<MessageListResponse> { ): Promise<MessageListResponse> {
const params: Record<string, any> = { const params: Record<string, any> = {};
conversation_id: conversationId,
};
if (afterSeq !== undefined) { if (afterSeq !== undefined) {
params.after_seq = afterSeq; params.after_seq = afterSeq;
} }
@@ -220,7 +216,7 @@ class MessageService {
try { try {
const response = await api.get<any>( const response = await api.get<any>(
'/conversations/get_messages', `/conversations/${encodeURIComponent(conversationId)}/messages`,
params params
); );
@@ -255,8 +251,8 @@ class MessageService {
/** /**
* 发送消息(新格式) * 发送消息(新格式)
* POST /api/v1/conversations/send_message * POST /api/v1/conversations/:id/messages
* Body: { detail_type, conversation_id, message } * Body: { detail_type, segments }
*/ */
async sendMessage( async sendMessage(
conversationId: string, conversationId: string,
@@ -271,32 +267,38 @@ class MessageService {
return this.sendMessageByAction( return this.sendMessageByAction(
detailType, detailType,
conversationId, conversationId,
data.segments data.segments,
data.reply_to_id
); );
} }
/** /**
* 通过 HTTP POST 发送消息(新格式) * 通过 HTTP POST 发送消息(新格式)
* 请求格式: POST /api/v1/conversations/send_message * 请求格式: POST /api/v1/conversations/:id/messages
* Body: { "detail_type": "private", "conversation_id": "xxx", "segments": [...] } * Body: { "detail_type": "private", "segments": [...] }
* @param detailType 消息类型: 'private' 私聊, 'group' 群聊 * @param detailType 消息类型: 'private' 私聊, 'group' 群聊
* @param conversationId 会话ID * @param conversationId 会话ID
* @param message 消息段数组 [{"type": "text", "data": {"text": "xxx"}}] * @param message 消息段数组 [{"type": "text", "data": {"text": "xxx"}}]
* @param replyToId 回复的消息ID可选
* @returns 消息响应 * @returns 消息响应
*/ */
async sendMessageByAction( async sendMessageByAction(
detailType: 'private' | 'group', detailType: 'private' | 'group',
conversationId: string, conversationId: string,
message: MessageSegment[] message: MessageSegment[],
replyToId?: string
): Promise<MessageResponse> { ): Promise<MessageResponse> {
try { try {
const body: Record<string, any> = {
detail_type: detailType,
segments: message,
};
if (replyToId) {
body.reply_to_id = replyToId;
}
const response = await api.post<MessageResponse>( const response = await api.post<MessageResponse>(
'/conversations/send_message', `/conversations/${encodeURIComponent(conversationId)}/messages`,
{ body
detail_type: detailType,
conversation_id: conversationId,
segments: message,
}
); );
return response.data; return response.data;
} catch (error) { } catch (error) {
@@ -393,14 +395,8 @@ class MessageService {
replyToId: string, replyToId: string,
detailType: 'private' | 'group' = 'private' detailType: 'private' | 'group' = 'private'
): Promise<MessageResponse> { ): Promise<MessageResponse> {
// 添加回复段到消息开头 // 使用 reply_to_id 参数发送回复消息
const replySegment: MessageSegment = { return this.sendMessageByAction(detailType, conversationId, segments, replyToId);
type: 'reply',
data: {
id: replyToId,
},
};
return this.sendMessageByAction(detailType, conversationId, [replySegment, ...segments]);
} }
/** /**
@@ -426,13 +422,12 @@ class MessageService {
/** /**
* 标记已读 * 标记已读
* POST /api/v1/conversations/mark_read * POST /api/v1/conversations/:id/read
* @param conversationId 会话ID * @param conversationId 会话ID
* @param seq 已读到的消息序号 * @param seq 已读到的消息序号
*/ */
async markAsRead(conversationId: string, seq: number): Promise<void> { async markAsRead(conversationId: string, seq: number): Promise<void> {
await api.post('/conversations/mark_read', { await api.post(`/conversations/${encodeURIComponent(conversationId)}/read`, {
conversation_id: conversationId,
last_read_seq: Number(seq), last_read_seq: Number(seq),
}); });
// 立即清零本地缓存中的 unread_count避免回到列表时仍显示旧红点 // 立即清零本地缓存中的 unread_count避免回到列表时仍显示旧红点
@@ -443,12 +438,10 @@ class MessageService {
/** /**
* 上报输入状态 * 上报输入状态
* POST /api/v1/conversations/typing * POST /api/v1/conversations/:id/typing
*/ */
async sendTyping(conversationId: string): Promise<void> { async sendTyping(conversationId: string): Promise<void> {
await api.post('/conversations/typing', { await api.post(`/conversations/${encodeURIComponent(conversationId)}/typing`);
conversation_id: conversationId,
});
} }
/** /**