/** * package api * 作用:房间管理相关API处理器 */ package api import ( "encoding/json" "fmt" "log" "strconv" "strings" "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_id 窥探 if !requireRoomMember(c, roomID) { return } room, err := service.RoomSvc.GetRoom(roomID) if err != nil { utils.NotFound(c, "房间不存在") return } utils.SuccessWithData(c, room, "获取成功") } /** * requireRoomMember * 功能:校验当前登录用户是否为该房间/群成员,不是则写 403 并返回 false。 * 为什么这样写:群信息、成员列表、公告、设置等读接口原先不校验调用者身份, * 任意登录用户凭 room_id 即可窥探任意群数据,这里统一收口做成员校验。 */ func requireRoomMember(c *gin.Context, roomID string) bool { uid, ok := c.Get("user_id") if !ok { utils.Unauthorized(c, "未认证") return false } if !service.RoomSvc.IsRoomMember(roomID, uid.(string)) { utils.Forbidden(c, "无权访问该群") return false } return true } /** * 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 } // 为所有成员创建会话记录 if service.ConversationSvc != nil { if err := service.ConversationSvc.EnsureGroupConversations(room.RoomID); err != nil { log.Printf("⚠️ 创建群聊会话失败 (roomID: %s): %v", room.RoomID, err) } } // 发送系统消息通知所有成员 if service.ChatSvc != nil && service.UserSvc != nil { // 获取创建者信息 creator, err := service.UserSvc.GetUserByID(creatorID) if err == nil { // 构建系统消息内容 content := fmt.Sprintf("%s 邀请你加入了群聊", creator.Name) extraData := map[string]interface{}{ "type": "group_created", "room_id": room.RoomID, "creator": creatorID, } extraJSON, _ := json.Marshal(extraData) // 为每个成员发送系统消息 for _, memberID := range members { if memberID != creatorID { // 创建系统消息 systemMsg := model.ChatMessage{ RoomID: room.RoomID, SenderUserID: creatorID, ReceiverUserID: room.RoomID, // 群聊时使用 roomID MessageType: model.MessageTypeSystem, Content: content, Extra: string(extraJSON), } // 持久化消息 if err := service.ChatSvc.DB.Create(&systemMsg).Error; err != nil { log.Printf("❌ 发送群聊系统消息失败 (memberID: %s): %v", memberID, err) continue } // 更新会话 if service.ConversationSvc != nil { _ = service.ConversationSvc.UpsertConversationOnMessage(memberID, room.RoomID, room.RoomID, systemMsg, false) } // 通过 WebSocket 推送消息 pushMsg := model.WsPayload{ RequestType: "receive_message", Data: systemMsg, } msgBytes, _ := json.Marshal(pushMsg) service.ChatSvc.DispatchMessage(memberID, msgBytes) } } } } 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") // 仅群成员可查看群信息 if !requireRoomMember(c, roomID) { return } 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") keyword := c.Query("keyword") // 仅群成员可查看成员列表 if !requireRoomMember(c, roomID) { return } var members []model.RoomMember var err error if keyword != "" { // 如果有搜索关键词,使用搜索方法 members, err = service.RoomSvc.SearchGroupMembers(roomID, keyword) } else { // 否则返回所有成员 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 } // 发送群通知和系统消息 if service.ChatSvc != nil && service.UserSvc != nil { // 获取操作者信息 operator, opErr := service.UserSvc.GetUserByID(userID.(string)) if opErr == nil { // 获取被邀请成员信息 invitedNames := make([]string, 0) for _, memberID := range req.MemberIDs { member, memErr := service.UserSvc.GetUserByID(memberID) if memErr == nil { invitedNames = append(invitedNames, member.Name) } } if len(invitedNames) > 0 { // 获取群成员列表(包括新加入的成员) memberIDs, mErr := service.RoomSvc.GetRoomMembers(roomID) if mErr == nil { // 构建群通知消息内容 var notifContent string if len(invitedNames) == 1 { notifContent = fmt.Sprintf("%s 邀请了 %s 加入群聊", operator.Name, invitedNames[0]) } else { notifContent = fmt.Sprintf("%s 邀请了 %s 加入群聊", operator.Name, strings.Join(invitedNames, "、")) } notifExtra := map[string]interface{}{ "type": "member_invite", "room_id": roomID, "operator": userID.(string), "operator_name": operator.Name, "targets": req.MemberIDs, "target_names": invitedNames, } notifExtraJSON, _ := json.Marshal(notifExtra) // 为所有成员发送群通知(包括新加入的成员):房间级落库一次,按成员推送 service.ChatSvc.BroadcastGroupNotification(userID.(string), roomID, notifContent, string(notifExtraJSON), memberIDs) // 为新加入的成员发送系统消息 for _, memberID := range req.MemberIDs { systemContent := fmt.Sprintf("你被 %s 邀请加入群聊", operator.Name) systemExtra := map[string]interface{}{ "type": "member_invited", "room_id": roomID, "operator": userID.(string), "operator_name": operator.Name, } systemExtraJSON, _ := json.Marshal(systemExtra) systemMsg := model.ChatMessage{ RoomID: roomID, SenderUserID: userID.(string), ReceiverUserID: roomID, MessageType: model.MessageTypeSystem, Content: systemContent, Extra: string(systemExtraJSON), } if err := service.ChatSvc.DB.Create(&systemMsg).Error; err == nil { // 更新会话 if service.ConversationSvc != nil { _ = service.ConversationSvc.UpsertConversationOnMessage(memberID, roomID, roomID, systemMsg, false) } // 推送消息 pushMsg := model.WsPayload{ RequestType: "receive_message", Data: systemMsg, } msgBytes, _ := json.Marshal(pushMsg) service.ChatSvc.DispatchMessage(memberID, msgBytes) } } } } } } 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 } // 发送群通知和系统消息 if service.ChatSvc != nil && service.UserSvc != nil { // 获取操作者和被移除成员信息 operator, opErr := service.UserSvc.GetUserByID(operatorID.(string)) member, memErr := service.UserSvc.GetUserByID(memberID) if opErr == nil && memErr == nil { // 获取群成员列表 memberIDs, mErr := service.RoomSvc.GetRoomMembers(roomID) if mErr == nil { // 构建群通知消息 notifContent := fmt.Sprintf("%s 将 %s 移出了群聊", operator.Name, member.Name) notifExtra := map[string]interface{}{ "type": "member_remove", "room_id": roomID, "operator": operatorID.(string), "target": memberID, "operator_name": operator.Name, "target_name": member.Name, } notifExtraJSON, _ := json.Marshal(notifExtra) // 构建系统消息 systemContent := fmt.Sprintf("你被 %s 移出了群聊", operator.Name) systemExtra := map[string]interface{}{ "type": "member_removed", "room_id": roomID, "operator": operatorID.(string), } systemExtraJSON, _ := json.Marshal(systemExtra) // 为所有成员发送群通知(被移除的成员不接收):房间级落库一次,按成员推送 remainIDs := make([]string, 0, len(memberIDs)) for _, uid := range memberIDs { if uid != memberID { remainIDs = append(remainIDs, uid) } } service.ChatSvc.BroadcastGroupNotification(operatorID.(string), roomID, notifContent, string(notifExtraJSON), remainIDs) // 为被移除的成员发送系统消息 systemMsg := model.ChatMessage{ RoomID: roomID, SenderUserID: operatorID.(string), ReceiverUserID: roomID, MessageType: model.MessageTypeSystem, Content: systemContent, Extra: string(systemExtraJSON), } if err := service.ChatSvc.DB.Create(&systemMsg).Error; err == nil { // 更新会话 if service.ConversationSvc != nil { _ = service.ConversationSvc.UpsertConversationOnMessage(memberID, roomID, roomID, systemMsg, false) } // 推送消息 pushMsg := model.WsPayload{ RequestType: "receive_message", Data: systemMsg, } msgBytes, _ := json.Marshal(pushMsg) service.ChatSvc.DispatchMessage(memberID, msgBytes) } } } } 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"` // 使用指针类型,允许 0 值(普通成员) } if err := c.ShouldBindJSON(&req); err != nil { utils.BadRequest(c, "参数错误: "+err.Error()) return } // 手动验证 role 是否提供 if req.Role == nil { utils.BadRequest(c, "参数错误: role 字段必须提供") 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 } // 发送群通知 if service.ChatSvc != nil && service.UserSvc != nil { // 获取退出成员信息 member, memErr := service.UserSvc.GetUserByID(userID.(string)) if memErr == nil { // 获取群成员列表(退出后剩余的成员) memberIDs, mErr := service.RoomSvc.GetRoomMembers(roomID) if mErr == nil { // 构建群通知消息 notifContent := fmt.Sprintf("%s 退出了群聊", member.Name) notifExtra := map[string]interface{}{ "type": "member_leave", "room_id": roomID, "target": userID.(string), "target_name": member.Name, } notifExtraJSON, _ := json.Marshal(notifExtra) // 为所有剩余成员发送群通知:房间级落库一次,按成员推送 service.ChatSvc.BroadcastGroupNotification(userID.(string), roomID, notifContent, string(notifExtraJSON), memberIDs) } } } 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") // 仅群成员可查看群公告 if !requireRoomMember(c, roomID) { return } 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, "更新成功") } /** * UpdateMyNicknameHandler * 功能:更新"我在本群的昵称"(群名片) * 路径:POST /api/groups/:room_id/nickname * 说明:操作者从 JWT 取,只能改自己的群名片;此前该接口缺失导致移动端改群昵称功能 100% 失败 */ func UpdateMyNicknameHandler(c *gin.Context) { userID, _ := c.Get("user_id") roomID := c.Param("room_id") var req struct { // 允许空串(清除群名片),因此不加 required Nickname string `json:"nickname"` } if err := c.ShouldBindJSON(&req); err != nil { utils.BadRequest(c, "参数错误: "+err.Error()) return } // 群名片长度限制,与数据库 varchar(100) 对齐(按字符数收紧到 30,避免界面溢出) if len([]rune(req.Nickname)) > 30 { utils.BadRequest(c, "群昵称不能超过30个字符") return } if err := service.RoomSvc.UpdateMemberNickname(roomID, userID.(string), req.Nickname); err != nil { utils.BadRequest(c, err.Error()) return } utils.Success(c, "修改成功") } /** * MuteGroupMemberHandler * 功能:禁言群成员 * 路径:POST /api/groups/:room_id/members/:user_id/mute */ func MuteGroupMemberHandler(c *gin.Context) { operatorID, _ := c.Get("user_id") roomID := c.Param("room_id") memberID := c.Param("user_id") var req struct { Duration int64 `json:"duration"` // 禁言时长(秒),0=永久,-1=解除禁言 } if err := c.ShouldBindJSON(&req); err != nil { utils.BadRequest(c, "参数错误: "+err.Error()) return } if err := service.RoomSvc.MuteGroupMember(roomID, operatorID.(string), memberID, req.Duration); err != nil { utils.BadRequest(c, err.Error()) return } if req.Duration == -1 { utils.Success(c, "已解除禁言") } else if req.Duration == 0 { utils.Success(c, "已永久禁言") } else { utils.Success(c, "禁言成功") } } /** * GetMemberMuteStatusHandler * 功能:获取成员禁言状态 * 路径:GET /api/groups/:room_id/members/:user_id/mute */ func GetMemberMuteStatusHandler(c *gin.Context) { roomID := c.Param("room_id") memberID := c.Param("user_id") // 鉴权:仅本群成员可查询,防止任意登录用户越权读取任意群成员的禁言状态 // (与同文件其他群接口的 requireRoomMember 校验保持一致) if !requireRoomMember(c, roomID) { return } isMuted, mutedUntil, err := service.RoomSvc.IsGroupMemberMuted(roomID, memberID) if err != nil { if err == gorm.ErrRecordNotFound { utils.NotFound(c, "成员不存在") return } utils.InternalError(c, "查询失败") return } utils.SuccessWithData(c, gin.H{ "is_muted": isMuted, "muted_until": mutedUntil, }, "获取成功") } /** * GetGroupSettingsHandler * 功能:获取群设置(名称、头像、公告、邀请权限等) * 路径:GET /api/groups/:room_id/settings */ func GetGroupSettingsHandler(c *gin.Context) { roomID := c.Param("room_id") // 仅群成员可查看群设置 if !requireRoomMember(c, roomID) { return } room, err := service.RoomSvc.GetRoom(roomID) if err != nil { utils.NotFound(c, "群聊不存在") return } utils.SuccessWithData(c, gin.H{ "name": room.RoomName, "avatar": room.RoomAvatar, "description": room.Announcement, "invite_permission": 0, "created_at": room.CreatedAt, "updated_at": room.UpdatedAt, }, "获取成功") } /** * UpdateGroupSettingsHandler * 功能:更新群设置 * 路径:POST /api/groups/:room_id/settings */ func UpdateGroupSettingsHandler(c *gin.Context) { userID, _ := c.Get("user_id") roomID := c.Param("room_id") ok, err := service.RoomSvc.IsGroupAdminOrOwner(roomID, userID.(string)) if err != nil || !ok { utils.Forbidden(c, "无权限修改群设置") return } var req struct { Name string `json:"name"` Avatar string `json:"avatar"` Description string `json:"description"` InvitePermission *int `json:"invite_permission"` } if err := c.ShouldBindJSON(&req); err != nil { utils.BadRequest(c, "参数错误") return } updates := map[string]interface{}{} if req.Name != "" { updates["room_name"] = req.Name } if req.Avatar != "" { updates["room_avatar"] = req.Avatar } if req.Description != "" { updates["announcement"] = req.Description } 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 } GetGroupSettingsHandler(c) } /** * GetCallHistoryHandler * 功能:获取当前用户的通话记录(基于 call_id 消息) * 路径:GET /api/calls/history */ func GetCallHistoryHandler(c *gin.Context) { userID, _ := c.Get("user_id") var messages []model.ChatMessage err := service.ChatSvc.DB. Where("(sender_user_id = ? OR receiver_user_id = ?) AND call_id <> '' AND call_id IS NOT NULL", userID, userID). Order("created_at DESC"). Limit(50). Find(&messages).Error if err != nil { utils.InternalError(c, "查询失败") return } utils.SuccessWithData(c, messages, "获取成功") }