using AutoMapper; using IM_API.Dtos.Conversation; using IM_API.Exceptions; using IM_API.Interface.Services; using IM_API.Models; using IM_API.Tools; using IM_API.VOs.Conversation; using Microsoft.EntityFrameworkCore; namespace IM_API.Services { public class ConversationService : IConversationService { private readonly ImContext _context; private readonly IMapper _mapper; public ConversationService(ImContext context, IMapper mapper) { _context = context; _mapper = mapper; } #region 删除用户会话 public async Task ClearConversationsAsync(int userId) { await _context.Conversations.Where(x => x.UserId == userId).ExecuteDeleteAsync(); return true; } #endregion #region 获取用户会话列表 public async Task> GetConversationsAsync(int userId) { // 1. 获取私聊会话 var privateList = await (from c in _context.Conversations join f in _context.Friends on new { c.UserId, c.TargetId } equals new { UserId = f.UserId, TargetId = f.FriendId } where c.UserId == userId && c.ChatType == ChatType.PRIVATE select new { c, f.Avatar, f.RemarkName }) .ToListAsync(); // 2. 获取群聊会话 var groupList = await (from c in _context.Conversations join g in _context.Groups on c.TargetId equals g.Id where c.UserId == userId && c.ChatType == ChatType.GROUP select new { c, g.Avatar, g.Name,g.MaxSequenceId,g.LastMessage }) .ToListAsync(); var privateDtos = privateList.Select(x => { var dto = _mapper.Map(x.c); dto.TargetAvatar = x.Avatar; dto.TargetName = x.RemarkName; return dto; }); var groupDtos = groupList.Select(x => { var dto = _mapper.Map(x.c); dto.TargetAvatar = x.Avatar; dto.TargetName = x.Name; dto.UnreadCount = (int)(x.MaxSequenceId - x.c.LastReadSequenceId ?? 0); dto.LastSequenceId = x.MaxSequenceId; dto.LastMessage = x.LastMessage; return dto; }); // 4. 合并并排序 return privateDtos.Concat(groupDtos) .OrderByDescending(x => x.DateTime) .ToList(); } #endregion #region 删除单个会话 public async Task DeleteConversationAsync(int conversationId) { var conversation = await _context.Conversations.FirstOrDefaultAsync(x => x.Id == conversationId); if (conversation == null) throw new BaseException(CodeDefine.CONVERSATION_NOT_FOUND); _context.Conversations.Remove(conversation); await _context.SaveChangesAsync(); return true; } #endregion #region 获取用户所有统一聊天凭证 public async Task> GetUserAllStreamKeyAsync(int userId) { return await _context.Conversations.Where(x => x.UserId == userId) .Select(x => x.StreamKey) .Distinct() .ToListAsync(); } #endregion #region 获取单个会话信息 public async Task GetConversationByIdAsync(int userId, int conversationId) { var conversation = await _context.Conversations .FirstOrDefaultAsync( x => x.UserId == userId && x.Id == conversationId ); if (conversation is null) throw new BaseException(CodeDefine.CONVERSATION_NOT_FOUND); var dto = _mapper.Map(conversation); if(conversation.ChatType == ChatType.PRIVATE) { var friendInfo = await _context.Friends.Include(n => n.FriendNavigation).FirstOrDefaultAsync( x => x.UserId == conversation.UserId && x.FriendId == conversation.TargetId ); if (friendInfo is null) throw new BaseException(CodeDefine.FRIEND_RELATION_NOT_FOUND); _mapper.Map(friendInfo,dto); } if(conversation.ChatType == ChatType.GROUP) { var groupInfo = await _context.Groups.FirstOrDefaultAsync( x => x.Id == conversation.TargetId ); if (groupInfo is null) throw new BaseException(CodeDefine.GROUP_NOT_FOUND); _mapper.Map(groupInfo, dto); } return dto; } #endregion public async Task ClearUnreadCountAsync(int userId, int conversationId) { var conversation = await _context.Conversations.FirstOrDefaultAsync(x => x.UserId == userId && x.Id == conversationId); if (conversation is null) throw new BaseException(CodeDefine.CONVERSATION_NOT_FOUND); var message = await _context.Messages .Where(x => x.StreamKey == conversation.StreamKey) .OrderByDescending(x => x.SequenceId) .FirstOrDefaultAsync(); if(message != null) { conversation.UnreadCount = 0; conversation.LastMessage = message.Content; conversation.LastReadSequenceId = message.SequenceId; conversation.LastMessageTime = message.Created; _context.Conversations.Update(conversation); await _context.SaveChangesAsync(); } return true; } public async Task MakeConversationAsync(int userAId, int userBId, ChatType chatType) { var userAcExist = await _context.Conversations.AnyAsync(x => x.UserId == userAId && x.TargetId == userBId); if (userAcExist) return; var streamKey = chatType == ChatType.PRIVATE ? StreamKeyBuilder.Private(userAId, userBId) : StreamKeyBuilder.Group(userBId); var conversation = new Conversation() { ChatType = chatType, LastMessage = "", LastMessageTime = DateTime.Now, LastReadSequenceId = null, StreamKey = streamKey, TargetId = userBId, UnreadCount = 0, UserId = userAId }; _context.Conversations.Add(conversation); await _context.SaveChangesAsync(); } public async Task UpdateConversationAfterSentAsync(UpdateConversationDto dto) { var cList = await _context.Conversations.Where(x => x.StreamKey == dto.StreamKey).ToListAsync(); foreach(var c in cList) { bool isSender = dto.SenderId == c.UserId; c.LastMessage = dto.LastMessage; c.LastMessageTime = dto.DateTime; c.LastReadSequenceId = isSender ? dto.LastSequenceId : c.LastReadSequenceId; c.UnreadCount = isSender ? 0 : c.UnreadCount + 1; } _context.Conversations.UpdateRange(cList); await _context.SaveChangesAsync(); } } }