/** * 群组服务 * 处理群组管理、成员管理、群设置、群公告等功能 * 使用 RESTful API: /api/v1/groups */ import { api } from '../core/api'; import { GroupResponse, GroupMemberResponse, GroupAnnouncementResponse, GroupListResponse, GroupMemberListResponse, GroupAnnouncementListResponse, CreateGroupRequest, InviteMembersRequest, TransferOwnerRequest, SetRoleRequest, SetNicknameRequest, SetMuteAllRequest, SetJoinTypeRequest, CreateAnnouncementRequest, MyMemberInfoResponse, SetGroupAvatarRequest, HandleGroupRequestAction, CursorPaginationRequest, CursorPaginationResponse, } from '@/types/dto'; function asGroupId(raw: unknown): string { return String(raw); } function normalizeGroup(g: GroupResponse): GroupResponse { return { ...g, id: asGroupId(g.id) }; } function normalizeMember(m: GroupMemberResponse): GroupMemberResponse { return { ...m, group_id: asGroupId(m.group_id) }; } function normalizeAnnouncement(a: GroupAnnouncementResponse): GroupAnnouncementResponse { return { ...a, group_id: asGroupId(a.group_id) }; } function normalizeGroupListResponse(r: GroupListResponse): GroupListResponse { return { ...r, list: r.list.map(normalizeGroup) }; } function normalizeMemberListResponse(r: GroupMemberListResponse): GroupMemberListResponse { return { ...r, list: r.list.map(normalizeMember) }; } function normalizeAnnouncementListResponse( r: GroupAnnouncementListResponse ): GroupAnnouncementListResponse { return { ...r, list: r.list.map(normalizeAnnouncement) }; } function normalizeGroupCursor( r: CursorPaginationResponse ): CursorPaginationResponse { return { ...r, list: r.list.map(normalizeGroup) }; } function normalizeMemberCursor( r: CursorPaginationResponse ): CursorPaginationResponse { return { ...r, list: r.list.map(normalizeMember) }; } function normalizeAnnouncementCursor( r: CursorPaginationResponse ): CursorPaginationResponse { return { ...r, list: r.list.map(normalizeAnnouncement) }; } // 群组服务类(纯 API 层) // SQLite/内存缓存编排由 groupManager 统一处理 class GroupService { // ==================== 群组管理 ==================== /** * 获取群组列表 * GET /api/v1/groups */ async getGroups(page = 1, pageSize = 20): Promise { const response = await api.get('/groups', { page, page_size: pageSize, }); return normalizeGroupListResponse(response.data); } /** * 获取群组详情 * GET /api/v1/groups/:id */ async getGroup(id: string): Promise { const response = await api.get(`/groups/${encodeURIComponent(id)}`); return normalizeGroup(response.data); } /** * 获取群组成员列表 * GET /api/v1/groups/:id/members */ async getMembers(groupId: string, page = 1, pageSize = 50): Promise { const response = await api.get( `/groups/${encodeURIComponent(groupId)}/members`, { page, page_size: pageSize, } ); return normalizeMemberListResponse(response.data); } /** * 创建群组 * POST /api/v1/groups */ async createGroup(data: CreateGroupRequest): Promise { const response = await api.post('/groups', data); return normalizeGroup(response.data); } /** * 获取当前用户在群组中的成员信息 * GET /api/v1/groups/:id/me */ async getMyMemberInfo(groupId: string): Promise { const response = await api.get( `/groups/${encodeURIComponent(groupId)}/me` ); return { ...response.data, member: normalizeMember(response.data.member), }; } /** * 解散群组 * DELETE /api/v1/groups/:id */ async dissolveGroup(id: string): Promise { await api.delete(`/groups/${encodeURIComponent(id)}`); } /** * 转让群主 * POST /api/v1/groups/:id/transfer */ async transferOwner(id: string, data: TransferOwnerRequest): Promise { await api.post(`/groups/${encodeURIComponent(id)}/transfer`, data); } // ==================== 成员管理 ==================== /** * 邀请成员加入群组 * POST /api/v1/groups/:id/invitations */ async inviteMembers(groupId: string, data: InviteMembersRequest): Promise { await api.post(`/groups/${encodeURIComponent(groupId)}/invitations`, data); } /** * 申请加入群组 * POST /api/v1/groups/:id/join-requests */ async joinGroup(groupId: string): Promise { await api.post(`/groups/${encodeURIComponent(groupId)}/join-requests`); } /** * 响应群邀请/申请 * POST /api/v1/groups/:id/join-requests/respond */ async respondInvite(groupId: string, data: HandleGroupRequestAction): Promise { await api.post( `/groups/${encodeURIComponent(groupId)}/join-requests/respond`, data ); } /** * 审批主动加群申请 * POST /api/v1/groups/:id/join-requests/handle */ async reviewJoinRequest(groupId: string, data: HandleGroupRequestAction): Promise { await api.post( `/groups/${encodeURIComponent(groupId)}/join-requests/handle`, data ); } /** * 退出群组 * POST /api/v1/groups/:id/leave */ async leaveGroup(groupId: string): Promise { await api.post(`/groups/${encodeURIComponent(groupId)}/leave`); } /** * 移除群成员(踢人) * POST /api/v1/groups/:id/members/kick */ async removeMember(groupId: string, userId: string): Promise { await api.post(`/groups/${encodeURIComponent(groupId)}/members/kick`, { user_id: userId, reject_add_request: false, }); } /** * 设置成员角色(设置/取消管理员) * PUT /api/v1/groups/:id/members/:user_id/admin */ async setMemberRole( groupId: string, userId: string, data: SetRoleRequest ): Promise { await api.put( `/groups/${encodeURIComponent(groupId)}/members/${encodeURIComponent(userId)}/admin`, { enable: data.role === 'admin', } ); } /** * 设置群昵称 * PUT /api/v1/groups/:id/members/me/nickname */ async setNickname(groupId: string, data: SetNicknameRequest): Promise { await api.put(`/groups/${encodeURIComponent(groupId)}/members/me/nickname`, data); } /** * 禁言/解禁成员 * POST /api/v1/groups/:id/members/ban * @param groupId 群组ID * @param userId 用户ID * @param duration 禁言时长(秒),0表示解除禁言 */ async muteMember( groupId: string, userId: string, duration: number = 0 ): Promise { await api.post(`/groups/${encodeURIComponent(groupId)}/members/ban`, { user_id: userId, duration: duration, }); } // ==================== 群设置 ==================== /** * 设置全员禁言 * PUT /api/v1/groups/:id/ban */ async setMuteAll(groupId: string, data: SetMuteAllRequest): Promise { await api.put(`/groups/${encodeURIComponent(groupId)}/ban`, { enable: data.mute_all, }); } /** * 设置加群方式 * PUT /api/v1/groups/:id/join-type */ async setJoinType(groupId: string, data: SetJoinTypeRequest): Promise { await api.put(`/groups/${encodeURIComponent(groupId)}/join-type`, data); } /** * 设置群名称 * PUT /api/v1/groups/:id/name */ async setGroupName(groupId: string, groupName: string): Promise { await api.put(`/groups/${encodeURIComponent(groupId)}/name`, { group_name: groupName, }); } /** * 设置群头像 * PUT /api/v1/groups/:id/avatar */ async setGroupAvatar(groupId: string, avatarUrl: string): Promise { const response = await api.put( `/groups/${encodeURIComponent(groupId)}/avatar`, { avatar: avatarUrl, } ); return normalizeGroup(response.data); } // ==================== 群公告 ==================== /** * 创建群公告 * POST /api/v1/groups/:id/announcements */ async createAnnouncement( groupId: string, data: CreateAnnouncementRequest ): Promise { const response = await api.post( `/groups/${encodeURIComponent(groupId)}/announcements`, data ); return normalizeAnnouncement(response.data); } /** * 获取群公告列表 * GET /api/v1/groups/:id/announcements */ async getAnnouncements( groupId: string, page = 1, pageSize = 20 ): Promise { try { const response = await api.get( `/groups/${encodeURIComponent(groupId)}/announcements`, { page, page_size: pageSize, } ); return normalizeAnnouncementListResponse(response.data); } catch (error) { console.error('获取群公告列表失败:', error); return { list: [], total: 0, page: 1, page_size: pageSize, total_pages: 0, }; } } /** * 删除群公告 * DELETE /api/v1/groups/:id/announcements/:announcement_id */ async deleteAnnouncement(groupId: string, announcementId: number): Promise { await api.delete( `/groups/${encodeURIComponent(groupId)}/announcements/${encodeURIComponent(String(announcementId))}` ); } // ==================== 游标分页方法 ==================== /** * 获取群组列表(游标分页) * GET /api/v1/groups/cursor * @param params 游标分页请求参数 */ async getGroupsCursor( params: CursorPaginationRequest = {} ): Promise> { try { const response = await api.get>('/groups/cursor', params); return normalizeGroupCursor(response.data); } catch (error) { console.error('获取群组列表失败:', error); return { list: [], next_cursor: null, prev_cursor: null, has_more: false, }; } } /** * 获取群组成员列表(游标分页) * GET /api/v1/groups/:id/members/cursor * @param groupId 群组ID * @param params 游标分页请求参数 */ async getGroupMembersCursor( groupId: string, params: CursorPaginationRequest = {} ): Promise> { try { const response = await api.get>( `/groups/${encodeURIComponent(groupId)}/members/cursor`, params ); return normalizeMemberCursor(response.data); } catch (error) { console.error('获取群组成员列表失败:', error); return { list: [], next_cursor: null, prev_cursor: null, has_more: false, }; } } /** * 获取群公告列表(游标分页) * GET /api/v1/groups/:id/announcements/cursor * @param groupId 群组ID * @param params 游标分页请求参数 */ async getGroupAnnouncementsCursor( groupId: string, params: CursorPaginationRequest = {} ): Promise> { try { const response = await api.get>( `/groups/${encodeURIComponent(groupId)}/announcements/cursor`, params ); return normalizeAnnouncementCursor(response.data); } catch (error) { console.error('获取群公告列表失败:', error); return { list: [], next_cursor: null, prev_cursor: null, has_more: false, }; } } } // 导出群组服务实例 export const groupService = new GroupService(); // 导出类型以方便使用 export type { GroupResponse, GroupMemberResponse, GroupAnnouncementResponse, GroupListResponse, GroupMemberListResponse, GroupAnnouncementListResponse, CreateGroupRequest, InviteMembersRequest, TransferOwnerRequest, SetRoleRequest, SetNicknameRequest, SetMuteAllRequest, SetJoinTypeRequest, CreateAnnouncementRequest, SetGroupAvatarRequest, };