/** * package api * 作用:房间管理相关API处理器 */ package api import ( "log" "strconv" "xk-websocket-v2/internal/model" "xk-websocket-v2/internal/service" "xk-websocket-v2/internal/utils" "github.com/gin-gonic/gin" "gorm.io/gorm" ) /** * CreateRoomHandler * 功能:创建房间 * 路径:POST /api/rooms */ func CreateRoomHandler(c *gin.Context) { userID, _ := c.Get("user_id") var req struct { RoomType string `json:"room_type" binding:"required,oneof=p2p group"` Members []string `json:"members" binding:"required"` RoomName string `json:"room_name"` RoomAvatar string `json:"room_avatar"` } if err := c.ShouldBindJSON(&req); err != nil { utils.BadRequest(c, "参数错误: "+err.Error()) return } room, err := service.RoomSvc.CreateRoom(req.RoomType, req.Members, userID.(string)) if err != nil { utils.BadRequest(c, err.Error()) return } // 如果提供了房间名称和头像,更新 if req.RoomName != "" || req.RoomAvatar != "" { updates := make(map[string]interface{}) if req.RoomName != "" { updates["room_name"] = req.RoomName } if req.RoomAvatar != "" { updates["room_avatar"] = req.RoomAvatar } service.RoomSvc.DB.Model(room).Updates(updates) } utils.SuccessWithData(c, room, "创建成功") } /** * GetRoomHandler * 功能:获取房间信息 * 路径:GET /api/rooms/:id */ func GetRoomHandler(c *gin.Context) { roomID := c.Param("id") room, err := service.RoomSvc.GetRoom(roomID) if err != nil { utils.NotFound(c, "房间不存在") return } utils.SuccessWithData(c, room, "获取成功") } /** * CreateChatGroupHandler * 功能:创建群聊 * 路径:POST /api/groups */ func CreateChatGroupHandler(c *gin.Context) { userID, _ := c.Get("user_id") var req struct { Name string `json:"name" binding:"required"` Avatar string `json:"avatar"` MemberIDs []string `json:"member_ids" binding:"required"` AdminIDs []string `json:"admin_ids"` } if err := c.ShouldBindJSON(&req); err != nil { utils.BadRequest(c, "参数错误: "+err.Error()) return } creatorID := userID.(string) members := req.MemberIDs // 确保创建者在成员列表中 found := false for _, id := range members { if id == creatorID { found = true break } } if !found { members = append(members, creatorID) } room, err := service.RoomSvc.CreateGroupRoom(creatorID, members, req.Name, req.Avatar, req.AdminIDs) if err != nil { utils.BadRequest(c, err.Error()) return } utils.SuccessWithData(c, room, "创建群聊成功") } /** * ListUserGroupsHandler * 功能:获取用户所在的所有群聊列表(带分组信息) * 路径:GET /api/groups */ func ListUserGroupsHandler(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { utils.Unauthorized(c, "未授权") return } groups, members, err := service.RoomSvc.ListUserGroups(userID.(string)) if err != nil { utils.InternalError(c, "查询失败") return } // 确保返回空数组而不是null if groups == nil { groups = []model.ChatRoom{} } if members == nil { members = []model.RoomMember{} } // 为每个群的所有成员创建缺失的会话记录 if service.ConversationSvc != nil { for _, group := range groups { if err := service.ConversationSvc.EnsureGroupConversations(group.RoomID); err != nil { // 记录错误但不中断流程 log.Printf("⚠️ 创建群聊会话失败 (roomID: %s): %v", group.RoomID, err) } } } // 创建成员映射表,方便快速查找 memberMap := make(map[string]model.RoomMember) for _, member := range members { memberMap[member.RoomID] = member } // 转换为前端期望的格式,包含 category 和 role result := make([]map[string]interface{}, 0, len(groups)) for _, group := range groups { // 获取用户在群中的角色 member, exists := memberMap[group.RoomID] if !exists { continue // 跳过无法获取成员信息的群 } // 确定分类:created/managed/joined category := "joined" if group.CreatorID == userID.(string) { category = "created" } else if member.Role == 1 || member.Role == 2 { category = "managed" } // 格式化时间 var lastMessageTime *string if group.LastMessageTime != nil { timeStr := group.LastMessageTime.Format("2006-01-02T15:04:05Z07:00") lastMessageTime = &timeStr } result = append(result, map[string]interface{}{ "room_id": group.RoomID, "room_type": group.RoomType, "room_name": group.RoomName, "room_avatar": group.RoomAvatar, "owner_id": group.OwnerID, "creator_id": group.CreatorID, "category": category, "role": int(member.Role), "last_message_time": lastMessageTime, "last_message": group.LastMessage, "created_at": group.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), "updated_at": group.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"), }) } utils.SuccessWithData(c, result, "获取成功") } /** * GetGroupInfoHandler * 功能:获取群聊基础信息及成员数量 * 路径:GET /api/groups/:room_id */ func GetGroupInfoHandler(c *gin.Context) { roomID := c.Param("room_id") room, err := service.RoomSvc.GetRoom(roomID) if err != nil { if err == gorm.ErrRecordNotFound { utils.NotFound(c, "群聊不存在") return } utils.InternalError(c, "查询失败") return } members, err := service.RoomSvc.ListGroupMembers(roomID) if err != nil { utils.InternalError(c, "查询成员失败") return } // 统计管理员ID adminIDs := make([]string, 0) for _, m := range members { if m.Role == 1 { adminIDs = append(adminIDs, m.UserID) } } utils.SuccessWithData(c, gin.H{ "room": room, "member_count": len(members), "admin_ids": adminIDs, "owner_id": room.OwnerID, }, "获取成功") } /** * ListGroupMembersHandler * 功能:获取群成员列表 * 路径:GET /api/groups/:room_id/members */ func ListGroupMembersHandler(c *gin.Context) { roomID := c.Param("room_id") members, err := service.RoomSvc.ListGroupMembers(roomID) if err != nil { utils.InternalError(c, "查询失败") return } utils.SuccessWithData(c, members, "获取成功") } /** * AddGroupMembersHandler * 功能:邀请/拉人入群 * 路径:POST /api/groups/:room_id/members */ func AddGroupMembersHandler(c *gin.Context) { userID, _ := c.Get("user_id") roomID := c.Param("room_id") var req struct { MemberIDs []string `json:"member_ids" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { utils.BadRequest(c, "参数错误: "+err.Error()) return } if err := service.RoomSvc.AddGroupMembers(roomID, userID.(string), req.MemberIDs); err != nil { utils.BadRequest(c, err.Error()) return } utils.Success(c, "添加成员成功") } /** * RemoveGroupMemberHandler * 功能:移除群成员或退群 * 路径:POST /api/groups/:room_id/members/:user_id/remove */ func RemoveGroupMemberHandler(c *gin.Context) { operatorID, _ := c.Get("user_id") roomID := c.Param("room_id") memberID := c.Param("user_id") // 自己移除自己 = 退群 if operatorID.(string) == memberID { if err := service.RoomSvc.QuitGroup(roomID, memberID); err != nil { utils.BadRequest(c, err.Error()) return } utils.Success(c, "已退出群聊") return } // 否则为管理员/群主踢人 if err := service.RoomSvc.RemoveGroupMember(roomID, operatorID.(string), memberID); err != nil { utils.BadRequest(c, err.Error()) return } utils.Success(c, "已移除成员") } /** * UpdateGroupInfoHandler * 功能:修改群名称/头像 * 路径:POST /api/groups/:room_id/update */ func UpdateGroupInfoHandler(c *gin.Context) { userID, _ := c.Get("user_id") roomID := c.Param("room_id") var req struct { Name string `json:"name"` Avatar string `json:"avatar"` } if err := c.ShouldBindJSON(&req); err != nil { utils.BadRequest(c, "参数错误: "+err.Error()) return } // 仅群主或管理员可修改群信息 ok, err := service.RoomSvc.IsGroupAdminOrOwner(roomID, userID.(string)) if err != nil { utils.InternalError(c, "权限校验失败") return } if !ok { utils.Forbidden(c, "无权限修改群信息") return } updates := make(map[string]interface{}) if req.Name != "" { updates["room_name"] = req.Name } if req.Avatar != "" { updates["room_avatar"] = req.Avatar } if len(updates) == 0 { utils.BadRequest(c, "没有可更新的字段") return } // 更新群基础信息 if err := service.RoomSvc.DB.Model(&model.ChatRoom{}). Where("room_id = ?", roomID). Updates(updates).Error; err != nil { utils.InternalError(c, "更新失败") return } utils.Success(c, "更新成功") } /** * ChangeMemberRoleHandler * 功能:调整成员角色 * 路径:POST /api/groups/:room_id/members/:user_id/role */ func ChangeMemberRoleHandler(c *gin.Context) { operatorID, _ := c.Get("user_id") roomID := c.Param("room_id") memberID := c.Param("user_id") var req struct { Role int8 `json:"role" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { utils.BadRequest(c, "参数错误: "+err.Error()) return } if err := service.RoomSvc.ChangeMemberRole(roomID, operatorID.(string), memberID, req.Role); err != nil { utils.BadRequest(c, err.Error()) return } utils.Success(c, "角色已更新") } /** * QuitGroupHandler * 功能:群成员主动退出群聊 * 路径:POST /api/groups/:room_id/quit */ func QuitGroupHandler(c *gin.Context) { userID, _ := c.Get("user_id") roomID := c.Param("room_id") // 校验用户是否为该群的成员 members, err := service.RoomSvc.ListGroupMembers(roomID) if err != nil { utils.InternalError(c, "查询成员失败") return } isMember := false for _, m := range members { if m.UserID == userID.(string) { isMember = true break } } if !isMember { utils.BadRequest(c, "您不是该群的成员") return } // 调用服务层退出群聊 if err := service.RoomSvc.QuitGroup(roomID, userID.(string)); err != nil { utils.BadRequest(c, err.Error()) return } utils.Success(c, "已退出群聊") } /** * DissolveGroupHandler * 功能:群主解散群聊 * 路径:POST /api/groups/:room_id/dissolve */ func DissolveGroupHandler(c *gin.Context) { userID, _ := c.Get("user_id") roomID := c.Param("room_id") // 调用服务层解散群聊 if err := service.RoomSvc.DissolveGroup(roomID, userID.(string)); err != nil { utils.BadRequest(c, err.Error()) return } utils.Success(c, "群聊已解散") } /** * GetGroupNotificationsHandler * 功能:获取群通知列表 * 路径:GET /api/group-notifications */ func GetGroupNotificationsHandler(c *gin.Context) { userID, _ := c.Get("user_id") // 分页参数 page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) isReadStr := c.Query("is_read") if page < 1 { page = 1 } if pageSize < 1 || pageSize > 100 { pageSize = 20 } // 构建查询条件 query := service.ChatSvc.DB.Model(&model.ChatMessage{}). Where("message_type = ?", model.MessageTypeGroupNotif). Where("room_id IN (SELECT room_id FROM room_members WHERE user_id = ?)", userID) // 可选:按已读状态过滤 if isReadStr == "true" || isReadStr == "false" { // 注意:chat_messages 表可能没有 is_read 字段,这里先不实现 // 如果需要,可以在 extra 字段中存储或使用其他方式 } // 获取总数 var total int64 query.Count(&total) // 分页查询 offset := (page - 1) * pageSize var messages []model.ChatMessage if err := query.Order("created_at desc"). Offset(offset). Limit(pageSize). Find(&messages).Error; err != nil { utils.InternalError(c, "查询失败") return } // 确保返回空数组而不是null if messages == nil { messages = []model.ChatMessage{} } utils.SuccessWithData(c, gin.H{ "data": messages, "total": total, "page": page, "page_size": pageSize, }, "获取成功") } /** * GetGroupAnnouncementHandler * 功能:获取群公告 * 路径:GET /api/groups/:room_id/announcement */ func GetGroupAnnouncementHandler(c *gin.Context) { roomID := c.Param("room_id") announcement, err := service.RoomSvc.GetGroupAnnouncement(roomID) if err != nil { if err == gorm.ErrRecordNotFound { utils.NotFound(c, "群聊不存在") return } utils.InternalError(c, "查询失败") return } utils.SuccessWithData(c, gin.H{ "announcement": announcement, }, "获取成功") } /** * UpdateGroupAnnouncementHandler * 功能:更新群公告 * 路径:POST /api/groups/:room_id/announcement */ func UpdateGroupAnnouncementHandler(c *gin.Context) { userID, _ := c.Get("user_id") roomID := c.Param("room_id") var req struct { Announcement string `json:"announcement" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { utils.BadRequest(c, "参数错误: "+err.Error()) return } if err := service.RoomSvc.UpdateGroupAnnouncement(roomID, userID.(string), req.Announcement); err != nil { utils.BadRequest(c, err.Error()) return } utils.Success(c, "更新成功") }