前端:

1、更新界面图标
2、修改消息缓存逻辑
3、新增清空未读消息数
后端:
1、修复不同时区导致的时间显示问题
2、新增清空未读消息数接口
This commit is contained in:
2026-01-21 18:48:05 +08:00
parent bedcf97c9d
commit 77744015de
21 changed files with 943 additions and 42 deletions
@@ -46,8 +46,10 @@ namespace IM_API.Application.EventHandlers
}
userAConversation.LastMessage = @event.MessageContent;
userAConversation.LastReadMessageId = @event.MessageId;
userAConversation.LastMessageTime = @event.MessageCreated;
userBConversation.LastMessage = @event.MessageContent;
userBConversation.UnreadCount += 1;
userBConversation.LastMessageTime = @event.MessageCreated;
_context.UpdateRange(userAConversation,userBConversation);
await _context.SaveChangesAsync();
}
@@ -23,7 +23,17 @@ namespace IM_API.Application.EventHandlers
{
if(@event.ChatType == Models.ChatType.PRIVATE)
{
MessageBaseDto messageBaseDto = _mapper.Map<MessageBaseDto>(_mapper.Map<Message>(@event));
MessageBaseDto messageBaseDto = new MessageBaseDto
{
MsgId = @event.MessageId.ToString(),
ChatType = @event.ChatType.ToString(),
Content = @event.MessageContent,
GroupMemberId = null,
ReceiverId = @event.MsgRecipientId,
SenderId = @event.MsgSenderId,
TimeStamp = @event.MessageCreated,
Type = @event.MessageMsgType.ToString()
};
await _hub.Clients.Users(@event.MsgRecipientId.ToString()).SendAsync("ReceiveMessage", messageBaseDto);
}
}
+2 -2
View File
@@ -41,7 +41,7 @@ namespace IM_API.Configs
CreateMap<FriendRequestDto, FriendRequest>()
.ForMember(dest => dest.RequestUser , opt => opt.MapFrom(src => src.FromUserId))
.ForMember(dest => dest.ResponseUser , opt => opt.MapFrom(src => src.ToUserId))
.ForMember(dest => dest.Created , opt => opt.MapFrom(src => DateTime.Now))
.ForMember(dest => dest.Created , opt => opt.MapFrom(src => DateTime.UtcNow))
.ForMember(dest => dest.StateEnum , opt => opt.MapFrom(src => FriendRequestState.Pending))
.ForMember(dest => dest.Description , opt => opt.MapFrom(src => src.Description))
;
@@ -101,7 +101,7 @@ namespace IM_API.Configs
.ForMember(dest => dest.TargetId, opt => opt.MapFrom(src => src.MsgRecipientId))
.ForMember(dest => dest.UnreadCount, opt => opt.MapFrom(src => 0))
.ForMember(dest => dest.StreamKey, opt => opt.MapFrom(src => src.StreamKey))
.ForMember(dest => dest.LastMessageTime, opt => opt.MapFrom(src => DateTime.Now))
.ForMember(dest => dest.LastMessageTime, opt => opt.MapFrom(src => DateTime.UtcNow))
;
//创建会话对象
+12
View File
@@ -60,5 +60,17 @@ namespace IM_API.Hubs
}
return;
}
public async Task ClearUnreadCount(int conversationId)
{
if (!Context.User.Identity.IsAuthenticated)
{
await Clients.Caller.SendAsync("ReceiveMessage", new BaseResponse<object?>(CodeDefine.AUTH_FAILED));
Context.Abort();
return;
}
var userIdStr = Context.User.FindFirstValue(ClaimTypes.NameIdentifier);
await _conversationService.ClearUnreadCountAsync(int.Parse(userIdStr), conversationId);
return;
}
}
}
@@ -35,5 +35,12 @@ namespace IM_API.Interface.Services
/// <param name="conversationId"></param>
/// <returns></returns>
Task<ConversationDto> GetConversationByIdAsync(int userId, int conversationId);
/// <summary>
/// 清空未读消息
/// </summary>
/// <param name="userId"></param>
/// <param name="conversationId"></param>
/// <returns></returns>
Task<bool> ClearUnreadCountAsync(int userId, int conversationId);
}
}
+5
View File
@@ -3,6 +3,7 @@ using IM_API.Configs;
using IM_API.Filters;
using IM_API.Hubs;
using IM_API.Models;
using IM_API.Tools;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
@@ -103,6 +104,10 @@ namespace IM_API
builder.Services.AddControllers(options =>
{
options.Filters.Add<GlobalExceptionFilter>();
}).AddJsonOptions(options =>
{
// 保持 ISO 8601 格式
options.JsonSerializerOptions.Converters.Add(new UtcDateTimeConverter());
});
builder.Services.AddModelValidation(configuration);
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
@@ -118,5 +118,21 @@ namespace IM_API.Services
return dto;
}
#endregion
public async Task<bool> 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.Id)
.FirstOrDefaultAsync();
conversation.LastReadMessage = message;
conversation.UnreadCount = 0;
_context.Conversations.Update(conversation);
await _context.SaveChangesAsync();
return true;
}
}
}
+18
View File
@@ -0,0 +1,18 @@
using System.Text.Json;
namespace IM_API.Tools
{
public class UtcDateTimeConverter : System.Text.Json.Serialization.JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> reader.GetDateTime();
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
// 如果 Kind 已经是 Utc,直接输出。
// 如果不是,先 SpecifyKind 再输出,确保不会发生时区偏移计算
var utcDate = value.Kind == DateTimeKind.Utc ? value : DateTime.SpecifyKind(value, DateTimeKind.Utc);
writer.WriteStringValue(utcDate.ToString("yyyy-MM-ddTHH:mm:ssZ"));
}
}
}