会话
This commit is contained in:
@@ -175,6 +175,8 @@ type UserContact struct {
|
||||
UserID string `gorm:"type:varchar(100);index;comment:用户ID" json:"user_id"`
|
||||
// 联系人ID - 好友的用户ID
|
||||
ContactID string `gorm:"type:varchar(100);index;comment:联系人ID" json:"contact_id"`
|
||||
// 房间ID - 关联的房间ID
|
||||
RoomID string `gorm:"type:varchar(100);index;comment:房间ID" json:"room_id"`
|
||||
// 备注名称 - 用户自定义的好友备注
|
||||
RemarkName string `gorm:"type:varchar(100);comment:备注名称" json:"remark_name"`
|
||||
// 分组ID - 好友所属分组
|
||||
@@ -241,8 +243,10 @@ type ChatRoom struct {
|
||||
RoomName string `gorm:"type:varchar(200);comment:房间名称" json:"room_name"`
|
||||
// 房间头像 - 群聊时显示
|
||||
RoomAvatar string `gorm:"type:varchar(500);comment:房间头像" json:"room_avatar"`
|
||||
// 成员列表 - JSON数组
|
||||
Members string `gorm:"type:text;comment:成员列表JSON" json:"members"`
|
||||
// 群主ID - 群聊必填,单聊为0
|
||||
OwnerID string `gorm:"type:varchar(100);index;default:0;comment:群主ID(群聊必填,单聊为0)" json:"owner_id"`
|
||||
// 管理员ID列表 - 逗号分隔
|
||||
AdminIDs string `gorm:"type:varchar(500);comment:管理员ID列表(逗号分隔)" json:"admin_ids"`
|
||||
// 创建者ID
|
||||
CreatorID string `gorm:"type:varchar(100);index;comment:创建者ID" json:"creator_id"`
|
||||
// 最后消息时间
|
||||
@@ -260,6 +264,25 @@ func (ChatRoom) TableName() string {
|
||||
return "chat_rooms"
|
||||
}
|
||||
|
||||
/**
|
||||
* RoomMember
|
||||
* 对应数据库表:room_members
|
||||
* 作用:房间成员表,存储房间与用户的关联关系
|
||||
*/
|
||||
type RoomMember struct {
|
||||
// 房间ID
|
||||
RoomID string `gorm:"type:varchar(100);primaryKey;comment:房间ID" json:"room_id"`
|
||||
// 用户ID
|
||||
UserID string `gorm:"type:varchar(100);primaryKey;comment:用户ID" json:"user_id"`
|
||||
// 加入时间
|
||||
JoinedAt time.Time `gorm:"type:datetime;autoCreateTime;comment:加入时间" json:"joined_at"`
|
||||
}
|
||||
|
||||
// TableName 指定表名和注释
|
||||
func (RoomMember) TableName() string {
|
||||
return "room_members"
|
||||
}
|
||||
|
||||
/**
|
||||
* FriendRequest
|
||||
* 对应数据库表:friend_requests
|
||||
@@ -416,6 +439,8 @@ type ChatConversation struct {
|
||||
CreatedAt time.Time `gorm:"autoCreateTime;comment:创建时间" json:"created_at"`
|
||||
// 更新时间
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime;comment:更新时间" json:"updated_at"`
|
||||
// 目标用户信息(关联查询,不存储在数据库中)
|
||||
TargetUser *User `gorm:"foreignKey:TargetID;references:ID" json:"target_user,omitempty"`
|
||||
}
|
||||
|
||||
// TableName 指定表名和注释
|
||||
|
||||
@@ -5,8 +5,12 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"xk-websocket-v2/internal/model"
|
||||
"xk-websocket-v2/internal/utils"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -69,10 +73,14 @@ func (s *ContactService) AddFriend(fromUserID, toUserID, message string) error {
|
||||
/**
|
||||
* GetFriendRequests
|
||||
* 功能:获取好友申请列表
|
||||
* 包括:
|
||||
* 1. 发送给当前用户的待处理申请 (to_user_id = userID AND status = 'pending')
|
||||
* 2. 当前用户发送的被拒绝的申请 (from_user_id = userID AND status = 'rejected')
|
||||
*/
|
||||
func (s *ContactService) GetFriendRequests(userID string) ([]model.FriendRequest, error) {
|
||||
var requests []model.FriendRequest
|
||||
result := s.DB.Where("to_user_id = ? AND status = ?", userID, "pending").
|
||||
result := s.DB.Where("(to_user_id = ? AND status = ?) OR (from_user_id = ? AND status = ?)",
|
||||
userID, "pending", userID, "rejected").
|
||||
Order("created_at DESC").
|
||||
Find(&requests)
|
||||
return requests, result.Error
|
||||
@@ -96,6 +104,11 @@ func (s *ContactService) AcceptFriendRequest(requestID uint, userID string) erro
|
||||
|
||||
// 开始事务
|
||||
tx := s.DB.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
// 更新申请状态
|
||||
if err := tx.Model(&request).Update("status", "accepted").Error; err != nil {
|
||||
@@ -103,14 +116,53 @@ func (s *ContactService) AcceptFriendRequest(requestID uint, userID string) erro
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建双向好友关系
|
||||
// 使用雪花ID生成唯一的房间ID
|
||||
roomID, err := utils.NextIDString()
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return fmt.Errorf("生成房间ID失败: %v", err)
|
||||
}
|
||||
|
||||
// 创建房间(p2p类型)
|
||||
room := model.ChatRoom{
|
||||
RoomID: roomID,
|
||||
RoomType: "p2p",
|
||||
OwnerID: "0", // 单聊群主为0
|
||||
CreatorID: request.ToUserID, // 接受者为创建者
|
||||
}
|
||||
if err := tx.Create(&room).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建房间成员记录(两个用户)
|
||||
member1 := model.RoomMember{
|
||||
RoomID: roomID,
|
||||
UserID: request.FromUserID,
|
||||
}
|
||||
member2 := model.RoomMember{
|
||||
RoomID: roomID,
|
||||
UserID: request.ToUserID,
|
||||
}
|
||||
if err := tx.Create(&member1).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&member2).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建双向好友关系,并绑定房间ID
|
||||
contact1 := model.UserContact{
|
||||
UserID: request.FromUserID,
|
||||
ContactID: request.ToUserID,
|
||||
RoomID: roomID,
|
||||
}
|
||||
contact2 := model.UserContact{
|
||||
UserID: request.ToUserID,
|
||||
ContactID: request.FromUserID,
|
||||
RoomID: roomID,
|
||||
}
|
||||
|
||||
if err := tx.Create(&contact1).Error; err != nil {
|
||||
@@ -122,7 +174,76 @@ func (s *ContactService) AcceptFriendRequest(requestID uint, userID string) erro
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit().Error
|
||||
// 为双方创建会话记录
|
||||
now := time.Now()
|
||||
conv1 := model.ChatConversation{
|
||||
UserID: request.FromUserID,
|
||||
TargetID: request.ToUserID,
|
||||
RoomID: roomID,
|
||||
Type: 1, // 私聊
|
||||
LastTime: now,
|
||||
}
|
||||
conv2 := model.ChatConversation{
|
||||
UserID: request.ToUserID,
|
||||
TargetID: request.FromUserID,
|
||||
RoomID: roomID,
|
||||
Type: 1, // 私聊
|
||||
LastTime: now,
|
||||
}
|
||||
|
||||
if err := tx.Create(&conv1).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&conv2).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
// 提交事务
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 发送欢迎消息(在事务外执行,避免影响主流程)
|
||||
go s.sendWelcomeMessage(request.ToUserID, request.FromUserID, roomID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/**
|
||||
* sendWelcomeMessage
|
||||
* 功能:发送欢迎消息
|
||||
*/
|
||||
func (s *ContactService) sendWelcomeMessage(senderID, receiverID, roomID string) {
|
||||
// 创建消息记录
|
||||
msg := model.ChatMessage{
|
||||
RoomID: roomID,
|
||||
SenderUserID: senderID,
|
||||
ReceiverUserID: receiverID,
|
||||
MessageType: 0, // 文本消息
|
||||
Content: "我已经通过了你的好友申请,开始和我聊天吧~",
|
||||
}
|
||||
|
||||
if err := s.DB.Create(&msg).Error; err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 更新会话列表
|
||||
if ConversationSvc != nil {
|
||||
_ = ConversationSvc.UpsertConversationOnMessage(senderID, receiverID, roomID, msg, true)
|
||||
_ = ConversationSvc.UpsertConversationOnMessage(receiverID, senderID, roomID, msg, false)
|
||||
}
|
||||
|
||||
// 通过 WebSocket 推送消息
|
||||
if ChatSvc != nil {
|
||||
pushMsg := model.WsPayload{
|
||||
RequestType: "receive_message",
|
||||
Data: msg,
|
||||
}
|
||||
msgBytes, _ := json.Marshal(pushMsg)
|
||||
ChatSvc.DispatchMessage(receiverID, msgBytes)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,19 +409,24 @@ func (s *ContactService) GetContactsWithUserInfo(userID string) ([]map[string]in
|
||||
}
|
||||
user.Password = ""
|
||||
|
||||
// 组合数据
|
||||
// 组合数据,包含 user 对象
|
||||
item := map[string]interface{}{
|
||||
"id": contact.ContactID,
|
||||
"name": user.Name,
|
||||
"avatar": user.Avatar,
|
||||
"desc": user.Desc,
|
||||
"remark_name": contact.RemarkName,
|
||||
"group_id": contact.GroupID,
|
||||
"is_top": contact.IsTop,
|
||||
"is_muted": contact.IsMuted,
|
||||
"id": contact.ContactID,
|
||||
"user_id": contact.ContactID,
|
||||
"contact_user_id": contact.ContactID,
|
||||
"user": user, // 包含完整的用户信息对象
|
||||
"remark_name": contact.RemarkName,
|
||||
"room_id": contact.RoomID,
|
||||
"group_id": contact.GroupID,
|
||||
"is_top": contact.IsTop,
|
||||
"is_muted": contact.IsMuted,
|
||||
"is_special_care": contact.IsSpecialCare,
|
||||
"is_blocked": contact.IsBlocked,
|
||||
"last_chat_time": contact.LastChatTime,
|
||||
"last_message": contact.LastMessage,
|
||||
"unread_count": contact.UnreadCount,
|
||||
"last_message": contact.LastMessage,
|
||||
"last_msg": contact.LastMessage,
|
||||
"unread_count": contact.UnreadCount,
|
||||
"unread": contact.UnreadCount,
|
||||
}
|
||||
result = append(result, item)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ func InitConversationService(db *gorm.DB) {
|
||||
func (s *ConversationService) GetConversations(userID string) ([]model.ChatConversation, error) {
|
||||
var list []model.ChatConversation
|
||||
err := s.DB.Where("user_id = ?", userID).
|
||||
Preload("TargetUser").
|
||||
Order("is_top DESC, last_time DESC, id DESC").
|
||||
Find(&list).Error
|
||||
return list, err
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
"xk-websocket-v2/internal/model"
|
||||
@@ -62,6 +61,8 @@ func GenerateGroupRoomID() string {
|
||||
*/
|
||||
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个成员")
|
||||
@@ -69,6 +70,8 @@ func (s *RoomService) CreateRoom(roomType string, members []string, creatorID st
|
||||
roomID = GenerateP2PRoomID(members[0], members[1])
|
||||
} else {
|
||||
roomID = GenerateGroupRoomID()
|
||||
// 群聊时,创建者就是群主
|
||||
ownerID = creatorID
|
||||
}
|
||||
|
||||
// 检查房间是否已存在
|
||||
@@ -77,16 +80,19 @@ func (s *RoomService) CreateRoom(roomType string, members []string, creatorID st
|
||||
return &existingRoom, nil
|
||||
}
|
||||
|
||||
// 序列化成员列表
|
||||
membersJSON, err := json.Marshal(members)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 开始事务
|
||||
tx := s.DB.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
// 创建房间
|
||||
room := model.ChatRoom{
|
||||
RoomID: roomID,
|
||||
RoomType: roomType,
|
||||
Members: string(membersJSON),
|
||||
RoomID: roomID,
|
||||
RoomType: roomType,
|
||||
OwnerID: ownerID,
|
||||
CreatorID: creatorID,
|
||||
}
|
||||
|
||||
@@ -94,7 +100,24 @@ func (s *RoomService) CreateRoom(roomType string, members []string, creatorID st
|
||||
room.RoomName = "群聊"
|
||||
}
|
||||
|
||||
if err := s.DB.Create(&room).Error; err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -146,3 +169,41 @@ func (s *RoomService) UpdateRoomLastMessage(roomID, message string) error {
|
||||
}).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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user