862 lines
21 KiB
Go
862 lines
21 KiB
Go
/**
|
||
* package service
|
||
* 作用:房间管理服务
|
||
*/
|
||
package service
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
"xk-websocket-v2/internal/model"
|
||
"xk-websocket-v2/internal/utils"
|
||
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// RoomService 房间服务结构体
|
||
type RoomService struct {
|
||
DB *gorm.DB
|
||
}
|
||
|
||
// RoomSvc 全局单例
|
||
var RoomSvc *RoomService
|
||
|
||
/**
|
||
* InitRoomService
|
||
* 功能:初始化房间服务
|
||
*/
|
||
func InitRoomService(db *gorm.DB) {
|
||
RoomSvc = &RoomService{DB: db}
|
||
}
|
||
|
||
/**
|
||
* GenerateP2PRoomID
|
||
* 功能:生成点对点聊天房间ID
|
||
* 规则:将两个用户ID按字母序排序后,用下划线连接
|
||
*/
|
||
func GenerateP2PRoomID(userID1, userID2 string) string {
|
||
if userID1 < userID2 {
|
||
return fmt.Sprintf("%s_%s", userID1, userID2)
|
||
}
|
||
return fmt.Sprintf("%s_%s", userID2, userID1)
|
||
}
|
||
|
||
/**
|
||
* GenerateGroupRoomID
|
||
* 功能:生成群聊房间ID
|
||
* 规则:使用雪花ID生成全局唯一ID
|
||
*/
|
||
func GenerateGroupRoomID() string {
|
||
id, err := utils.NextID()
|
||
if err != nil {
|
||
// 如果雪花ID生成失败,使用备用方案
|
||
return fmt.Sprintf("group_%d", time.Now().UnixNano())
|
||
}
|
||
return fmt.Sprintf("group_%d", id)
|
||
}
|
||
|
||
/**
|
||
* CreateRoom
|
||
* 功能:创建房间
|
||
*/
|
||
func (s *RoomService) CreateRoom(roomType string, members []string, creatorID string) (*model.ChatRoom, error) {
|
||
var roomID string
|
||
var ownerID string = "0" // 单聊默认为0
|
||
|
||
if roomType == "p2p" {
|
||
if len(members) != 2 {
|
||
return nil, fmt.Errorf("点对点房间需要2个成员")
|
||
}
|
||
roomID = GenerateP2PRoomID(members[0], members[1])
|
||
} else {
|
||
roomID = GenerateGroupRoomID()
|
||
// 群聊时,创建者就是群主
|
||
ownerID = creatorID
|
||
}
|
||
|
||
// 检查房间是否已存在
|
||
var existingRoom model.ChatRoom
|
||
if err := s.DB.Where("room_id = ?", roomID).First(&existingRoom).Error; err == nil {
|
||
return &existingRoom, nil
|
||
}
|
||
|
||
// 开始事务
|
||
tx := s.DB.Begin()
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
tx.Rollback()
|
||
}
|
||
}()
|
||
|
||
// 创建房间
|
||
room := model.ChatRoom{
|
||
RoomID: roomID,
|
||
RoomType: roomType,
|
||
OwnerID: ownerID,
|
||
CreatorID: creatorID,
|
||
}
|
||
|
||
if roomType == "group" {
|
||
room.RoomName = "群聊"
|
||
}
|
||
|
||
if err := tx.Create(&room).Error; err != nil {
|
||
tx.Rollback()
|
||
return nil, err
|
||
}
|
||
|
||
// 创建房间成员记录
|
||
for _, userID := range members {
|
||
member := model.RoomMember{
|
||
RoomID: roomID,
|
||
UserID: userID,
|
||
}
|
||
if err := tx.Create(&member).Error; err != nil {
|
||
tx.Rollback()
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
if err := tx.Commit().Error; err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &room, nil
|
||
}
|
||
|
||
/**
|
||
* GetRoom
|
||
* 功能:获取房间信息
|
||
*/
|
||
func (s *RoomService) GetRoom(roomID string) (*model.ChatRoom, error) {
|
||
var room model.ChatRoom
|
||
result := s.DB.Where("room_id = ?", roomID).First(&room)
|
||
if result.Error != nil {
|
||
return nil, result.Error
|
||
}
|
||
return &room, nil
|
||
}
|
||
|
||
/**
|
||
* GetOrCreateP2PRoom
|
||
* 功能:获取或创建点对点房间
|
||
*/
|
||
func (s *RoomService) GetOrCreateP2PRoom(userID1, userID2 string) (*model.ChatRoom, error) {
|
||
roomID := GenerateP2PRoomID(userID1, userID2)
|
||
|
||
// 尝试获取现有房间
|
||
var room model.ChatRoom
|
||
if err := s.DB.Where("room_id = ?", roomID).First(&room).Error; err == nil {
|
||
return &room, nil
|
||
}
|
||
|
||
// 创建新房间
|
||
members := []string{userID1, userID2}
|
||
return s.CreateRoom("p2p", members, userID1)
|
||
}
|
||
|
||
/**
|
||
* UpdateRoomLastMessage
|
||
* 功能:更新房间最后消息
|
||
*/
|
||
func (s *RoomService) UpdateRoomLastMessage(roomID, message string) error {
|
||
now := time.Now()
|
||
return s.DB.Model(&model.ChatRoom{}).
|
||
Where("room_id = ?", roomID).
|
||
Updates(map[string]interface{}{
|
||
"last_message": message,
|
||
"last_message_time": now,
|
||
}).Error
|
||
}
|
||
|
||
/**
|
||
* GetRoomMembers
|
||
* 功能:获取房间成员列表
|
||
*/
|
||
func (s *RoomService) GetRoomMembers(roomID string) ([]string, error) {
|
||
var members []model.RoomMember
|
||
if err := s.DB.Where("room_id = ?", roomID).Find(&members).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
userIDs := make([]string, len(members))
|
||
for i, member := range members {
|
||
userIDs[i] = member.UserID
|
||
}
|
||
return userIDs, nil
|
||
}
|
||
|
||
/**
|
||
* GetRoomMember
|
||
* 功能:获取房间中指定成员的信息
|
||
*/
|
||
func (s *RoomService) GetRoomMember(roomID, userID string) (*model.RoomMember, error) {
|
||
var member model.RoomMember
|
||
err := s.DB.Where("room_id = ? AND user_id = ?", roomID, userID).First(&member).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &member, nil
|
||
}
|
||
|
||
/**
|
||
* AddRoomMember
|
||
* 功能:添加房间成员
|
||
*/
|
||
func (s *RoomService) AddRoomMember(roomID, userID string) error {
|
||
member := model.RoomMember{
|
||
RoomID: roomID,
|
||
UserID: userID,
|
||
}
|
||
return s.DB.Create(&member).Error
|
||
}
|
||
|
||
/**
|
||
* RemoveRoomMember
|
||
* 功能:移除房间成员
|
||
*/
|
||
func (s *RoomService) RemoveRoomMember(roomID, userID string) error {
|
||
return s.DB.Where("room_id = ? AND user_id = ?", roomID, userID).
|
||
Delete(&model.RoomMember{}).Error
|
||
}
|
||
|
||
/**
|
||
* CreateGroupRoom
|
||
* 功能:创建群聊房间,并为成员写入角色(群主/管理员/成员)
|
||
*/
|
||
func (s *RoomService) CreateGroupRoom(creatorID string, memberIDs []string, name string, avatar string, adminIDs []string) (*model.ChatRoom, error) {
|
||
if len(memberIDs) == 0 {
|
||
return nil, fmt.Errorf("成员列表不能为空")
|
||
}
|
||
|
||
// 1. 先通过通用的 CreateRoom 创建群聊和基础成员关系(角色默认都是 0)
|
||
room, err := s.CreateRoom("group", memberIDs, creatorID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 2. 更新群名称和头像(如果提供)
|
||
updates := map[string]interface{}{}
|
||
if name != "" {
|
||
updates["room_name"] = name
|
||
}
|
||
if avatar != "" {
|
||
updates["room_avatar"] = avatar
|
||
}
|
||
if len(updates) > 0 {
|
||
if err := s.DB.Model(room).Updates(updates).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
// 3. 为成员设置角色:群主=2 管理员=1 成员=0
|
||
roomID := room.RoomID
|
||
|
||
// 创建者作为群主
|
||
if err := s.DB.Model(&model.RoomMember{}).
|
||
Where("room_id = ? AND user_id = ?", roomID, creatorID).
|
||
Update("role", 2).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 管理员列表去重并排除群主
|
||
adminSet := map[string]struct{}{}
|
||
for _, id := range adminIDs {
|
||
if id == "" || id == creatorID {
|
||
continue
|
||
}
|
||
adminSet[id] = struct{}{}
|
||
}
|
||
|
||
if len(adminSet) > 0 {
|
||
for adminID := range adminSet {
|
||
if err := s.DB.Model(&model.RoomMember{}).
|
||
Where("room_id = ? AND user_id = ?", roomID, adminID).
|
||
Update("role", 1).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
}
|
||
|
||
return room, nil
|
||
}
|
||
|
||
/**
|
||
* ListGroupMembers
|
||
* 功能:返回群成员及其角色信息(包含用户信息)
|
||
*/
|
||
func (s *RoomService) ListGroupMembers(roomID string) ([]model.RoomMember, error) {
|
||
var members []model.RoomMember
|
||
if err := s.DB.Where("room_id = ?", roomID).
|
||
Preload("User").
|
||
Order("role DESC, joined_at ASC").
|
||
Find(&members).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
// 清除用户密码
|
||
for i := range members {
|
||
if members[i].User != nil {
|
||
members[i].User.Password = ""
|
||
}
|
||
}
|
||
return members, nil
|
||
}
|
||
|
||
/**
|
||
* SearchGroupMembers
|
||
* 功能:搜索群成员(根据用户名或昵称)
|
||
*/
|
||
func (s *RoomService) SearchGroupMembers(roomID, keyword string) ([]model.RoomMember, error) {
|
||
var members []model.RoomMember
|
||
keywordPattern := "%" + keyword + "%"
|
||
|
||
if err := s.DB.Where("room_id = ?", roomID).
|
||
Preload("User", "name LIKE ? OR email LIKE ? OR phone LIKE ?", keywordPattern, keywordPattern, keywordPattern).
|
||
Order("role DESC, joined_at ASC").
|
||
Find(&members).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 过滤掉 User 为 nil 或不符合搜索条件的成员
|
||
filtered := make([]model.RoomMember, 0)
|
||
for _, m := range members {
|
||
if m.User != nil {
|
||
// 检查用户名、邮箱、手机号是否匹配
|
||
if strings.Contains(strings.ToLower(m.User.Name), strings.ToLower(keyword)) ||
|
||
strings.Contains(strings.ToLower(m.User.Email), strings.ToLower(keyword)) ||
|
||
strings.Contains(strings.ToLower(m.User.Phone), strings.ToLower(keyword)) ||
|
||
(m.Nickname != "" && strings.Contains(strings.ToLower(m.Nickname), strings.ToLower(keyword))) {
|
||
filtered = append(filtered, m)
|
||
}
|
||
}
|
||
}
|
||
|
||
return filtered, nil
|
||
}
|
||
|
||
/**
|
||
* ListUserGroups
|
||
* 功能:查询用户所在的所有群聊房间
|
||
* 返回:群聊列表和用户在每个群中的角色信息
|
||
*/
|
||
func (s *RoomService) ListUserGroups(userID string) ([]model.ChatRoom, []model.RoomMember, error) {
|
||
var rooms []model.ChatRoom
|
||
var members []model.RoomMember
|
||
|
||
// 查询用户所在的所有群聊
|
||
err := s.DB.
|
||
Joins("JOIN room_members ON room_members.room_id = chat_rooms.room_id").
|
||
Where("room_members.user_id = ? AND chat_rooms.room_type = ?", userID, "group").
|
||
Find(&rooms).Error
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
|
||
// 获取用户在这些群中的角色信息
|
||
if len(rooms) > 0 {
|
||
roomIDs := make([]string, len(rooms))
|
||
for i, room := range rooms {
|
||
roomIDs[i] = room.RoomID
|
||
}
|
||
err = s.DB.Where("room_id IN ? AND user_id = ?", roomIDs, userID).Find(&members).Error
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
}
|
||
|
||
return rooms, members, nil
|
||
}
|
||
|
||
/**
|
||
* AddGroupMembers
|
||
* 功能:批量添加群成员(仅群主或管理员可操作)
|
||
*/
|
||
func (s *RoomService) AddGroupMembers(roomID, operatorID string, memberIDs []string) error {
|
||
if len(memberIDs) == 0 {
|
||
return nil
|
||
}
|
||
|
||
// 权限校验:必须是群主或管理员
|
||
isAdmin, err := s.isGroupAdminOrOwner(roomID, operatorID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if !isAdmin {
|
||
return fmt.Errorf("无权限添加成员")
|
||
}
|
||
|
||
for _, uid := range memberIDs {
|
||
if uid == "" {
|
||
continue
|
||
}
|
||
member := model.RoomMember{
|
||
RoomID: roomID,
|
||
UserID: uid,
|
||
Role: 0, // 默认成员
|
||
}
|
||
if err := s.DB.Create(&member).Error; err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
/**
|
||
* RemoveGroupMember
|
||
* 功能:踢出群成员(群主或管理员),或作为封装调用 RemoveRoomMember
|
||
*/
|
||
func (s *RoomService) RemoveGroupMember(roomID, operatorID, memberID string) error {
|
||
// 群主或管理员才能踢人
|
||
isAdmin, err := s.isGroupAdminOrOwner(roomID, operatorID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if !isAdmin {
|
||
return fmt.Errorf("无权限移除成员")
|
||
}
|
||
|
||
// 不允许移除群主
|
||
room, err := s.GetRoom(roomID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if memberID == room.OwnerID {
|
||
return fmt.Errorf("不能移除群主")
|
||
}
|
||
|
||
return s.RemoveRoomMember(roomID, memberID)
|
||
}
|
||
|
||
/**
|
||
* QuitGroup
|
||
* 功能:成员主动退出群聊
|
||
*/
|
||
func (s *RoomService) QuitGroup(roomID, userID string) error {
|
||
room, err := s.GetRoom(roomID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 群主不能直接退群
|
||
if userID == room.OwnerID {
|
||
return fmt.Errorf("群主不能直接退出群聊,请先转让群主或解散群")
|
||
}
|
||
|
||
return s.RemoveRoomMember(roomID, userID)
|
||
}
|
||
|
||
/**
|
||
* DissolveGroup
|
||
* 功能:群主解散群聊
|
||
*/
|
||
func (s *RoomService) DissolveGroup(roomID, ownerID string) error {
|
||
room, err := s.GetRoom(roomID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 只有群主可以解散群
|
||
if ownerID != room.OwnerID {
|
||
return fmt.Errorf("只有群主可以解散群聊")
|
||
}
|
||
|
||
// 删除所有成员记录
|
||
if err := s.DB.Where("room_id = ?", roomID).Delete(&model.RoomMember{}).Error; err != nil {
|
||
return fmt.Errorf("删除成员记录失败: %v", err)
|
||
}
|
||
|
||
// 可选:标记房间为已解散(或直接删除房间)
|
||
// 这里选择删除房间记录
|
||
if err := s.DB.Where("room_id = ?", roomID).Delete(&model.ChatRoom{}).Error; err != nil {
|
||
return fmt.Errorf("删除房间记录失败: %v", err)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
/**
|
||
* ChangeMemberRole
|
||
* 功能:修改成员角色(仅群主可设置/取消管理员)
|
||
*/
|
||
func (s *RoomService) ChangeMemberRole(roomID, operatorID, memberID string, role int8) error {
|
||
// 仅允许 0/1/2
|
||
if role < 0 || role > 2 {
|
||
return fmt.Errorf("非法角色值")
|
||
}
|
||
|
||
room, err := s.GetRoom(roomID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 只有群主可以调整角色
|
||
if operatorID != room.OwnerID {
|
||
return fmt.Errorf("只有群主可以调整成员角色")
|
||
}
|
||
|
||
// 防止将群主本人的角色修改为其他值
|
||
if memberID == room.OwnerID && role != 2 {
|
||
return fmt.Errorf("不能修改群主自身角色")
|
||
}
|
||
|
||
// 获取原角色
|
||
var oldMember model.RoomMember
|
||
s.DB.Where("room_id = ? AND user_id = ?", roomID, memberID).First(&oldMember)
|
||
oldRole := oldMember.Role
|
||
|
||
if err := s.DB.Model(&model.RoomMember{}).
|
||
Where("room_id = ? AND user_id = ?", roomID, memberID).
|
||
Update("role", role).Error; err != nil {
|
||
return err
|
||
}
|
||
|
||
// 如果是转让群主,需要把原群主降级
|
||
if role == 2 && memberID != room.OwnerID {
|
||
// 将原群主降级为管理员
|
||
s.DB.Model(&model.RoomMember{}).
|
||
Where("room_id = ? AND user_id = ?", roomID, operatorID).
|
||
Update("role", 1)
|
||
// 更新房间的 owner_id
|
||
s.DB.Model(&model.ChatRoom{}).
|
||
Where("room_id = ?", roomID).
|
||
Update("owner_id", memberID)
|
||
}
|
||
|
||
// 发送角色变更通知(异步)
|
||
go s.sendRoleChangeNotification(roomID, operatorID, memberID, oldRole, role)
|
||
|
||
return nil
|
||
}
|
||
|
||
/**
|
||
* IsGroupAdminOrOwner
|
||
* 功能:对外暴露的权限判断:是否为群主或管理员
|
||
*/
|
||
func (s *RoomService) IsGroupAdminOrOwner(roomID, userID string) (bool, error) {
|
||
return s.isGroupAdminOrOwner(roomID, userID)
|
||
}
|
||
|
||
/**
|
||
* IsGroupOwner
|
||
* 功能:判断用户是否为群主
|
||
*/
|
||
func (s *RoomService) IsGroupOwner(roomID, userID string) (bool, error) {
|
||
room, err := s.GetRoom(roomID)
|
||
if err != nil {
|
||
if err == gorm.ErrRecordNotFound {
|
||
return false, nil
|
||
}
|
||
return false, err
|
||
}
|
||
return room.OwnerID == userID, nil
|
||
}
|
||
|
||
/**
|
||
* isGroupAdminOrOwner
|
||
* 功能:判断用户是否是群主或管理员
|
||
*/
|
||
func (s *RoomService) isGroupAdminOrOwner(roomID, userID string) (bool, error) {
|
||
if userID == "" {
|
||
return false, nil
|
||
}
|
||
var member model.RoomMember
|
||
err := s.DB.Where("room_id = ? AND user_id = ?", roomID, userID).First(&member).Error
|
||
if err != nil {
|
||
if err == gorm.ErrRecordNotFound {
|
||
return false, nil
|
||
}
|
||
return false, err
|
||
}
|
||
return member.Role == 1 || member.Role == 2, nil
|
||
}
|
||
|
||
/**
|
||
* GetGroupAnnouncement
|
||
* 功能:获取群公告
|
||
*/
|
||
func (s *RoomService) GetGroupAnnouncement(roomID string) (string, error) {
|
||
var room model.ChatRoom
|
||
err := s.DB.Where("room_id = ? AND room_type = ?", roomID, "group").First(&room).Error
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
return room.Announcement, nil
|
||
}
|
||
|
||
/**
|
||
* UpdateGroupAnnouncement
|
||
* 功能:更新群公告(仅群主或管理员可操作)
|
||
*/
|
||
func (s *RoomService) UpdateGroupAnnouncement(roomID, userID, announcement string) error {
|
||
// 权限校验:必须是群主或管理员
|
||
isAdmin, err := s.isGroupAdminOrOwner(roomID, userID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if !isAdmin {
|
||
return fmt.Errorf("无权限更新群公告")
|
||
}
|
||
|
||
// 更新群公告
|
||
return s.DB.Model(&model.ChatRoom{}).
|
||
Where("room_id = ? AND room_type = ?", roomID, "group").
|
||
Update("announcement", announcement).Error
|
||
}
|
||
|
||
/**
|
||
* MuteGroupMember
|
||
* 功能:禁言群成员(仅群主或管理员可操作)
|
||
* @param roomID 房间ID
|
||
* @param operatorID 操作者ID
|
||
* @param memberID 被禁言的成员ID
|
||
* @param duration 禁言时长(秒),0表示永久禁言,-1表示解除禁言
|
||
*/
|
||
func (s *RoomService) MuteGroupMember(roomID, operatorID, memberID string, duration int64) error {
|
||
// 权限校验:必须是群主或管理员
|
||
isAdmin, err := s.isGroupAdminOrOwner(roomID, operatorID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if !isAdmin {
|
||
return fmt.Errorf("无权限禁言成员")
|
||
}
|
||
|
||
// 检查被禁言的成员是否存在
|
||
var member model.RoomMember
|
||
err = s.DB.Where("room_id = ? AND user_id = ?", roomID, memberID).First(&member).Error
|
||
if err != nil {
|
||
if err == gorm.ErrRecordNotFound {
|
||
return fmt.Errorf("成员不存在")
|
||
}
|
||
return err
|
||
}
|
||
|
||
// 不能禁言群主
|
||
if member.Role == 2 {
|
||
return fmt.Errorf("不能禁言群主")
|
||
}
|
||
|
||
// 管理员不能禁言其他管理员
|
||
var operator model.RoomMember
|
||
s.DB.Where("room_id = ? AND user_id = ?", roomID, operatorID).First(&operator)
|
||
if operator.Role == 1 && member.Role == 1 {
|
||
return fmt.Errorf("管理员不能禁言其他管理员")
|
||
}
|
||
|
||
// 计算禁言到期时间
|
||
var mutedUntil *time.Time
|
||
if duration == -1 {
|
||
// 解除禁言
|
||
mutedUntil = nil
|
||
} else if duration == 0 {
|
||
// 永久禁言(设置为100年后)
|
||
t := time.Now().AddDate(100, 0, 0)
|
||
mutedUntil = &t
|
||
} else {
|
||
// 指定时长禁言
|
||
t := time.Now().Add(time.Duration(duration) * time.Second)
|
||
mutedUntil = &t
|
||
}
|
||
|
||
// 更新禁言状态
|
||
if err := s.DB.Model(&model.RoomMember{}).
|
||
Where("room_id = ? AND user_id = ?", roomID, memberID).
|
||
Update("muted_until", mutedUntil).Error; err != nil {
|
||
return err
|
||
}
|
||
|
||
// 发送群通知(异步)
|
||
go s.sendMuteNotification(roomID, operatorID, memberID, duration, mutedUntil)
|
||
|
||
return nil
|
||
}
|
||
|
||
/**
|
||
* IsGroupMemberMuted
|
||
* 功能:检查成员是否被禁言
|
||
*/
|
||
func (s *RoomService) IsGroupMemberMuted(roomID, userID string) (bool, *time.Time, error) {
|
||
var member model.RoomMember
|
||
err := s.DB.Where("room_id = ? AND user_id = ?", roomID, userID).First(&member).Error
|
||
if err != nil {
|
||
return false, nil, err
|
||
}
|
||
return member.IsMuted(), member.MutedUntil, nil
|
||
}
|
||
|
||
/**
|
||
* sendMuteNotification
|
||
* 功能:发送禁言/解除禁言通知给所有群成员
|
||
*/
|
||
func (s *RoomService) sendMuteNotification(roomID, operatorID, memberID string, duration int64, mutedUntil *time.Time) {
|
||
if ChatSvc == nil || UserSvc == nil {
|
||
return
|
||
}
|
||
|
||
// 获取操作者和被禁言成员信息
|
||
operator, opErr := UserSvc.GetUserByID(operatorID)
|
||
member, memErr := UserSvc.GetUserByID(memberID)
|
||
if opErr != nil || memErr != nil {
|
||
return
|
||
}
|
||
|
||
// 获取群成员列表
|
||
memberIDs, err := s.GetRoomMembers(roomID)
|
||
if err != nil {
|
||
return
|
||
}
|
||
|
||
// 构建通知内容
|
||
var notifContent string
|
||
var eventType string
|
||
if duration == -1 {
|
||
notifContent = fmt.Sprintf("%s 解除了 %s 的禁言", operator.Name, member.Name)
|
||
eventType = "member_unmute"
|
||
} else if duration == 0 {
|
||
notifContent = fmt.Sprintf("%s 将 %s 永久禁言", operator.Name, member.Name)
|
||
eventType = "member_mute"
|
||
} else {
|
||
durationText := formatDuration(duration)
|
||
notifContent = fmt.Sprintf("%s 将 %s 禁言 %s", operator.Name, member.Name, durationText)
|
||
eventType = "member_mute"
|
||
}
|
||
|
||
// 构建 extra 数据
|
||
notifExtra := map[string]interface{}{
|
||
"type": eventType,
|
||
"room_id": roomID,
|
||
"operator": operatorID,
|
||
"operator_name": operator.Name,
|
||
"target": memberID,
|
||
"target_name": member.Name,
|
||
"duration": duration,
|
||
"muted_until": mutedUntil,
|
||
}
|
||
notifExtraJSON, _ := json.Marshal(notifExtra)
|
||
|
||
// 为所有成员发送群通知
|
||
for _, uid := range memberIDs {
|
||
notifMsg := model.ChatMessage{
|
||
RoomID: roomID,
|
||
SenderUserID: operatorID,
|
||
ReceiverUserID: roomID,
|
||
MessageType: model.MessageTypeGroupNotif,
|
||
Content: notifContent,
|
||
Extra: string(notifExtraJSON),
|
||
}
|
||
|
||
if err := ChatSvc.DB.Create(¬ifMsg).Error; err == nil {
|
||
// 更新会话
|
||
if ConversationSvc != nil {
|
||
_ = ConversationSvc.UpsertConversationOnMessage(uid, roomID, roomID, notifMsg, false)
|
||
}
|
||
|
||
// 推送消息
|
||
pushMsg := model.WsPayload{
|
||
RequestType: "receive_message",
|
||
Data: notifMsg,
|
||
}
|
||
msgBytes, _ := json.Marshal(pushMsg)
|
||
ChatSvc.DispatchMessage(uid, msgBytes)
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* formatDuration
|
||
* 功能:格式化时长为可读字符串
|
||
*/
|
||
func formatDuration(seconds int64) string {
|
||
if seconds < 60 {
|
||
return fmt.Sprintf("%d秒", seconds)
|
||
} else if seconds < 3600 {
|
||
return fmt.Sprintf("%d分钟", seconds/60)
|
||
} else if seconds < 86400 {
|
||
return fmt.Sprintf("%d小时", seconds/3600)
|
||
} else {
|
||
return fmt.Sprintf("%d天", seconds/86400)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* sendRoleChangeNotification
|
||
* 功能:发送角色变更通知给所有群成员
|
||
*/
|
||
func (s *RoomService) sendRoleChangeNotification(roomID, operatorID, memberID string, oldRole, newRole int8) {
|
||
if ChatSvc == nil || UserSvc == nil {
|
||
return
|
||
}
|
||
|
||
// 获取操作者和目标成员信息
|
||
operator, opErr := UserSvc.GetUserByID(operatorID)
|
||
member, memErr := UserSvc.GetUserByID(memberID)
|
||
if opErr != nil || memErr != nil {
|
||
return
|
||
}
|
||
|
||
// 获取群成员列表
|
||
memberIDs, err := s.GetRoomMembers(roomID)
|
||
if err != nil {
|
||
return
|
||
}
|
||
|
||
// 构建通知内容
|
||
var notifContent string
|
||
roleNames := map[int8]string{0: "普通成员", 1: "管理员", 2: "群主"}
|
||
|
||
if newRole == 2 {
|
||
// 转让群主
|
||
notifContent = fmt.Sprintf("%s 将群主转让给了 %s", operator.Name, member.Name)
|
||
} else if newRole == 1 && oldRole == 0 {
|
||
// 设置管理员
|
||
notifContent = fmt.Sprintf("%s 被设置为管理员", member.Name)
|
||
} else if newRole == 0 && oldRole == 1 {
|
||
// 取消管理员
|
||
notifContent = fmt.Sprintf("%s 被取消管理员", member.Name)
|
||
} else {
|
||
notifContent = fmt.Sprintf("%s 的角色变更为 %s", member.Name, roleNames[newRole])
|
||
}
|
||
|
||
// 构建 extra 数据
|
||
notifExtra := map[string]interface{}{
|
||
"type": "role_change",
|
||
"room_id": roomID,
|
||
"operator": operatorID,
|
||
"operator_name": operator.Name,
|
||
"target": memberID,
|
||
"target_name": member.Name,
|
||
"old_role": oldRole,
|
||
"new_role": newRole,
|
||
}
|
||
notifExtraJSON, _ := json.Marshal(notifExtra)
|
||
|
||
// 为所有成员发送群通知
|
||
for _, uid := range memberIDs {
|
||
notifMsg := model.ChatMessage{
|
||
RoomID: roomID,
|
||
SenderUserID: operatorID,
|
||
ReceiverUserID: roomID,
|
||
MessageType: model.MessageTypeGroupNotif,
|
||
Content: notifContent,
|
||
Extra: string(notifExtraJSON),
|
||
}
|
||
|
||
if err := ChatSvc.DB.Create(¬ifMsg).Error; err == nil {
|
||
// 更新会话
|
||
if ConversationSvc != nil {
|
||
_ = ConversationSvc.UpsertConversationOnMessage(uid, roomID, roomID, notifMsg, false)
|
||
}
|
||
|
||
// 推送消息
|
||
pushMsg := model.WsPayload{
|
||
RequestType: "receive_message",
|
||
Data: notifMsg,
|
||
}
|
||
msgBytes, _ := json.Marshal(pushMsg)
|
||
ChatSvc.DispatchMessage(uid, msgBytes)
|
||
}
|
||
}
|
||
}
|