1027 lines
27 KiB
Go
1027 lines
27 KiB
Go
/**
|
||
* 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, 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
|
||
}
|
||
|
||
// 为所有成员创建会话记录
|
||
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")
|
||
|
||
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")
|
||
|
||
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)
|
||
|
||
// 为所有成员发送群通知(包括新加入的成员)
|
||
for _, uid := range memberIDs {
|
||
// 群通知消息
|
||
notifMsg := model.ChatMessage{
|
||
RoomID: roomID,
|
||
SenderUserID: userID.(string),
|
||
ReceiverUserID: roomID,
|
||
MessageType: model.MessageTypeGroupNotif,
|
||
Content: notifContent,
|
||
Extra: string(notifExtraJSON),
|
||
}
|
||
|
||
if err := service.ChatSvc.DB.Create(¬ifMsg).Error; err == nil {
|
||
// 更新会话
|
||
if service.ConversationSvc != nil {
|
||
_ = service.ConversationSvc.UpsertConversationOnMessage(uid, roomID, roomID, notifMsg, false)
|
||
}
|
||
|
||
// 推送消息
|
||
pushMsg := model.WsPayload{
|
||
RequestType: "receive_message",
|
||
Data: notifMsg,
|
||
}
|
||
msgBytes, _ := json.Marshal(pushMsg)
|
||
service.ChatSvc.DispatchMessage(uid, msgBytes)
|
||
}
|
||
}
|
||
|
||
// 为新加入的成员发送系统消息
|
||
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)
|
||
|
||
// 为所有成员发送群通知
|
||
for _, uid := range memberIDs {
|
||
if uid == memberID {
|
||
continue // 被移除的成员不接收群通知
|
||
}
|
||
|
||
// 群通知消息
|
||
notifMsg := model.ChatMessage{
|
||
RoomID: roomID,
|
||
SenderUserID: operatorID.(string),
|
||
ReceiverUserID: roomID,
|
||
MessageType: model.MessageTypeGroupNotif,
|
||
Content: notifContent,
|
||
Extra: string(notifExtraJSON),
|
||
}
|
||
|
||
if err := service.ChatSvc.DB.Create(¬ifMsg).Error; err == nil {
|
||
// 更新会话
|
||
if service.ConversationSvc != nil {
|
||
_ = service.ConversationSvc.UpsertConversationOnMessage(uid, roomID, roomID, notifMsg, false)
|
||
}
|
||
|
||
// 推送消息
|
||
pushMsg := model.WsPayload{
|
||
RequestType: "receive_message",
|
||
Data: notifMsg,
|
||
}
|
||
msgBytes, _ := json.Marshal(pushMsg)
|
||
service.ChatSvc.DispatchMessage(uid, msgBytes)
|
||
}
|
||
}
|
||
|
||
// 为被移除的成员发送系统消息
|
||
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)
|
||
|
||
// 为所有剩余成员发送群通知
|
||
for _, uid := range memberIDs {
|
||
notifMsg := model.ChatMessage{
|
||
RoomID: roomID,
|
||
SenderUserID: userID.(string),
|
||
ReceiverUserID: roomID,
|
||
MessageType: model.MessageTypeGroupNotif,
|
||
Content: notifContent,
|
||
Extra: string(notifExtraJSON),
|
||
}
|
||
|
||
if err := service.ChatSvc.DB.Create(¬ifMsg).Error; err == nil {
|
||
// 更新会话
|
||
if service.ConversationSvc != nil {
|
||
_ = service.ConversationSvc.UpsertConversationOnMessage(uid, roomID, roomID, notifMsg, false)
|
||
}
|
||
|
||
// 推送消息
|
||
pushMsg := model.WsPayload{
|
||
RequestType: "receive_message",
|
||
Data: notifMsg,
|
||
}
|
||
msgBytes, _ := json.Marshal(pushMsg)
|
||
service.ChatSvc.DispatchMessage(uid, msgBytes)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
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, "更新成功")
|
||
}
|
||
|
||
/**
|
||
* 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")
|
||
|
||
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")
|
||
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, "获取成功")
|
||
}
|