1320 lines
55 KiB
C#
1320 lines
55 KiB
C#
using FreeSql;
|
||
|
||
using LiveForum.Code.Base;
|
||
using LiveForum.Code.JwtInfrastructure;
|
||
using LiveForum.IService.Messages;
|
||
using LiveForum.IService.Others;
|
||
using LiveForum.IService.Users;
|
||
using LiveForum.Model;
|
||
using LiveForum.Model.Dto.Messages;
|
||
using LiveForum.Model.Dto.Users;
|
||
|
||
using Newtonsoft.Json;
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace LiveForum.Service.Messages
|
||
{
|
||
public class MessagesService : IMessagesService
|
||
{
|
||
private readonly JwtUserInfoModel _userInfoModel;
|
||
private readonly IBaseRepository<T_Messages> _messagesRepository;
|
||
private readonly IBaseRepository<T_SystemNotifications> _notificationsRepository;
|
||
private readonly IBaseRepository<T_Users> _usersRepository;
|
||
private readonly IBaseRepository<T_Comments> _commentsRepository;
|
||
private readonly IBaseRepository<T_Posts> _postsRepository;
|
||
private readonly IBaseRepository<T_Likes> _likesRepository;
|
||
private readonly IBaseRepository<T_Follows> _followsRepository;
|
||
private readonly IBaseRepository<T_SystemNotificationParticipants> _participantsRepository;
|
||
private readonly IUserInfoService _userInfoService;
|
||
private readonly IFreeSql _freeSql;
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
/// <param name="userInfoModel">JWT用户信息模型</param>
|
||
/// <param name="messagesRepository">消息仓储</param>
|
||
/// <param name="notificationsRepository">系统通知仓储</param>
|
||
/// <param name="usersRepository">用户仓储</param>
|
||
/// <param name="commentsRepository">评论仓储</param>
|
||
/// <param name="postsRepository">帖子仓储</param>
|
||
/// <param name="likesRepository">点赞仓储</param>
|
||
/// <param name="followsRepository">关注仓储</param>
|
||
/// <param name="participantsRepository">系统通知参与记录仓储</param>
|
||
/// <param name="userInfoService">用户信息转换服务</param>
|
||
/// <param name="freeSql">FreeSql实例</param>
|
||
public MessagesService(
|
||
JwtUserInfoModel userInfoModel,
|
||
IBaseRepository<T_Messages> messagesRepository,
|
||
IBaseRepository<T_SystemNotifications> notificationsRepository,
|
||
IBaseRepository<T_Users> usersRepository,
|
||
IBaseRepository<T_Comments> commentsRepository,
|
||
IBaseRepository<T_Posts> postsRepository,
|
||
IBaseRepository<T_Likes> likesRepository,
|
||
IBaseRepository<T_Follows> followsRepository,
|
||
IBaseRepository<T_SystemNotificationParticipants> participantsRepository,
|
||
IUserInfoService userInfoService,
|
||
IFreeSql freeSql)
|
||
{
|
||
_userInfoModel = userInfoModel;
|
||
_messagesRepository = messagesRepository;
|
||
_notificationsRepository = notificationsRepository;
|
||
_usersRepository = usersRepository;
|
||
_commentsRepository = commentsRepository;
|
||
_postsRepository = postsRepository;
|
||
_likesRepository = likesRepository;
|
||
_followsRepository = followsRepository;
|
||
_participantsRepository = participantsRepository;
|
||
_userInfoService = userInfoService;
|
||
_freeSql = freeSql;
|
||
}
|
||
|
||
#region 快照相关辅助方法
|
||
|
||
/// <summary>
|
||
/// 尝试从快照反序列化发送者信息
|
||
/// </summary>
|
||
private UserInfoDto TryDeserializeSenderInfo(string senderInfoJson)
|
||
{
|
||
if (string.IsNullOrEmpty(senderInfoJson))
|
||
{
|
||
return null;
|
||
}
|
||
|
||
try
|
||
{
|
||
var userInfo = JsonConvert.DeserializeObject<UserInfoDto>(senderInfoJson);
|
||
return userInfo;
|
||
}
|
||
catch
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 尝试从快照反序列化内容信息
|
||
/// </summary>
|
||
private MessageRelatedContentDto TryDeserializeContentSnapshot(string contentSnapshotJson)
|
||
{
|
||
if (string.IsNullOrEmpty(contentSnapshotJson))
|
||
{
|
||
return null;
|
||
}
|
||
|
||
try
|
||
{
|
||
var snapshot = JsonConvert.DeserializeObject<Model.Events.ContentSnapshot>(contentSnapshotJson);
|
||
if (snapshot == null) return null;
|
||
|
||
return new MessageRelatedContentDto
|
||
{
|
||
PostId = snapshot.PostId,
|
||
PostTitle = snapshot.PostTitle,
|
||
CommentContent = snapshot.CommentContent
|
||
};
|
||
}
|
||
catch
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 批量回填消息快照数据
|
||
/// </summary>
|
||
private async Task BackfillMessageSnapshots(
|
||
List<T_Messages> messages,
|
||
Dictionary<long, T_Users> users,
|
||
Dictionary<long, T_Posts> posts,
|
||
Dictionary<long, T_Comments> comments)
|
||
{
|
||
var messagesToUpdate = new List<T_Messages>();
|
||
|
||
foreach (var message in messages)
|
||
{
|
||
bool needUpdate = false;
|
||
|
||
// 回填发送者信息快照
|
||
if (string.IsNullOrEmpty(message.SenderInfo) && message.SenderId.HasValue)
|
||
{
|
||
if (users.ContainsKey(message.SenderId.Value))
|
||
{
|
||
var user = users[message.SenderId.Value];
|
||
var senderInfo = await _userInfoService.ToUserInfoDtoAsync(user);
|
||
message.SenderInfo = JsonConvert.SerializeObject(senderInfo, new JsonSerializerSettings
|
||
{
|
||
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
|
||
});
|
||
needUpdate = true;
|
||
}
|
||
else
|
||
{
|
||
// 发送者已不存在,保存占位快照
|
||
var deletedUserInfo = new UserInfoDto
|
||
{
|
||
UserId = 0,
|
||
NickName = "已删除的用户",
|
||
Avatar = "",
|
||
IsVip = false,
|
||
IsCertified = false,
|
||
CertifiedType = null
|
||
};
|
||
message.SenderInfo = JsonConvert.SerializeObject(deletedUserInfo, new JsonSerializerSettings
|
||
{
|
||
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
|
||
});
|
||
needUpdate = true;
|
||
}
|
||
}
|
||
|
||
// 回填内容快照
|
||
if (string.IsNullOrEmpty(message.ContentSnapshot) && message.ContentId.HasValue)
|
||
{
|
||
var contentSnapshot = new Model.Events.ContentSnapshot();
|
||
|
||
if (message.ContentType == 1 && posts.ContainsKey(message.ContentId.Value))
|
||
{
|
||
// 帖子快照
|
||
var post = posts[message.ContentId.Value];
|
||
contentSnapshot.PostId = post.Id;
|
||
contentSnapshot.PostTitle = post.Title;
|
||
message.ContentSnapshot = JsonConvert.SerializeObject(contentSnapshot);
|
||
needUpdate = true;
|
||
}
|
||
else if (message.ContentType == 2 && comments.ContainsKey(message.ContentId.Value))
|
||
{
|
||
// 评论快照
|
||
var comment = comments[message.ContentId.Value];
|
||
contentSnapshot.CommentId = comment.Id;
|
||
contentSnapshot.CommentContent = comment.Content;
|
||
|
||
// 同时获取帖子标题
|
||
if (posts.ContainsKey(comment.PostId))
|
||
{
|
||
contentSnapshot.PostId = comment.PostId;
|
||
contentSnapshot.PostTitle = posts[comment.PostId].Title;
|
||
}
|
||
|
||
message.ContentSnapshot = JsonConvert.SerializeObject(contentSnapshot);
|
||
needUpdate = true;
|
||
}
|
||
else if (!posts.ContainsKey(message.ContentId.Value) && !comments.ContainsKey(message.ContentId.Value))
|
||
{
|
||
// 内容已被删除,保存占位快照
|
||
contentSnapshot.PostTitle = "[已删除]";
|
||
contentSnapshot.CommentContent = "[已删除]";
|
||
message.ContentSnapshot = JsonConvert.SerializeObject(contentSnapshot);
|
||
needUpdate = true;
|
||
}
|
||
}
|
||
|
||
if (needUpdate)
|
||
{
|
||
messagesToUpdate.Add(message);
|
||
}
|
||
}
|
||
|
||
// 批量更新数据库
|
||
if (messagesToUpdate.Any())
|
||
{
|
||
await _messagesRepository.UpdateAsync(messagesToUpdate);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 确保系统通知消息已创建
|
||
/// 查询未创建消息记录的系统通知,并根据目标用户类型筛选,为用户创建消息记录
|
||
/// </summary>
|
||
/// <param name="userId">用户ID</param>
|
||
private async Task EnsureSystemNotificationsCreated(long userId)
|
||
{
|
||
var now = DateTime.Now;
|
||
|
||
// 查询未创建消息记录的系统通知
|
||
// SQL: select n.* from T_SystemNotifications n
|
||
// left join T_Messages m on n.Id=m.SenderId and m.MessageType=3 and m.ReceiverId=userId
|
||
// where m.Id is null and (ExpireTime>NOW() or ExpireTime is null) and PublishTime<=NOW()
|
||
var allNotificationsWithoutMessages = _freeSql.Select<T_SystemNotifications, T_Messages>()
|
||
.LeftJoin((n, m) => n.Id == m.SenderId && m.MessageType == 3 && m.ReceiverId == userId)
|
||
.Where((n, m) => m == null && (n.ExpireTime > now || n.ExpireTime == null) && n.PublishTime <= now && n.IsActive)
|
||
.ToList((a, b) => a);
|
||
|
||
if (!allNotificationsWithoutMessages.Any())
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 根据目标用户类型筛选通知
|
||
var notificationsForUser = new List<T_SystemNotifications>();
|
||
|
||
foreach (var notification in allNotificationsWithoutMessages)
|
||
{
|
||
// TargetUserType: null或0-所有用户,1-指定用户列表,2-按认证类型筛选
|
||
if (notification.TargetUserType == null || notification.TargetUserType == 0)
|
||
{
|
||
// 所有用户
|
||
notificationsForUser.Add(notification);
|
||
}
|
||
else if (notification.TargetUserType == 1)
|
||
{
|
||
// 指定用户列表
|
||
if (!string.IsNullOrEmpty(notification.TargetUserIds))
|
||
{
|
||
try
|
||
{
|
||
var targetUserIds = JsonConvert.DeserializeObject<List<long>>(notification.TargetUserIds);
|
||
if (targetUserIds != null && targetUserIds.Contains(userId))
|
||
{
|
||
notificationsForUser.Add(notification);
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// JSON解析失败,跳过该通知
|
||
}
|
||
}
|
||
}
|
||
else if (notification.TargetUserType == 2)
|
||
{
|
||
// 按认证类型筛选
|
||
if (notification.TargetCertifiedType.HasValue)
|
||
{
|
||
var user = await _usersRepository.Select.Where(u => u.Id == userId).FirstAsync();
|
||
if (user != null)
|
||
{
|
||
// 直接比较认证类型ID
|
||
if (user.CertifiedType.HasValue && user.CertifiedType.Value == notification.TargetCertifiedType.Value)
|
||
{
|
||
notificationsForUser.Add(notification);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果存在未创建消息的系统通知,需要为它们创建消息记录
|
||
if (notificationsForUser.Any())
|
||
{
|
||
var newMessages = notificationsForUser.Select(n => new T_Messages
|
||
{
|
||
ReceiverId = userId,
|
||
SenderId = n.Id, // 使用通知ID作为SenderId
|
||
MessageType = 3, // 系统消息
|
||
MessageContent = $"{n.Content}",
|
||
IsRead = false,
|
||
CreatedAt = DateTime.Now,
|
||
MessageTitle = n.Title,
|
||
}).ToList();
|
||
|
||
await _messagesRepository.InsertAsync(newMessages);
|
||
}
|
||
}
|
||
|
||
public async Task<BaseResponse<GetMessagesRespDto>> GetMessages(GetMessagesReq request)
|
||
{
|
||
var currentUserId = (long)_userInfoModel.UserId;
|
||
|
||
// 构建查询条件
|
||
var query = _messagesRepository.Select
|
||
.Where(x => x.ReceiverId == currentUserId);
|
||
|
||
// 过滤消息类型
|
||
if (request.MessageType.HasValue)
|
||
{
|
||
query = query.Where(x => x.MessageType == request.MessageType.Value);
|
||
if (request.MessageType == 3)
|
||
{
|
||
// 确保系统消息已创建
|
||
await EnsureSystemNotificationsCreated(currentUserId);
|
||
}
|
||
}
|
||
|
||
// 过滤是否已读
|
||
if (request.IsRead.HasValue)
|
||
{
|
||
query = query.Where(x => x.IsRead == request.IsRead.Value);
|
||
}
|
||
|
||
// 排序
|
||
query = query.OrderByDescending(x => x.CreatedAt);
|
||
|
||
// 获取总数
|
||
var total = await query.CountAsync();
|
||
|
||
// 分页
|
||
var messages = await query
|
||
.Skip((request.PageIndex - 1) * request.PageSize)
|
||
.Take(request.PageSize)
|
||
.ToListAsync();
|
||
|
||
if (!messages.Any())
|
||
{
|
||
// 获取未读总数
|
||
var unreadCount = await query.Where(x => !x.IsRead)
|
||
.CountAsync();
|
||
|
||
return new BaseResponse<GetMessagesRespDto>(new GetMessagesRespDto
|
||
{
|
||
PageIndex = request.PageIndex,
|
||
PageSize = request.PageSize,
|
||
Total = (int)total,
|
||
TotalPages = (int)Math.Ceiling((double)total / request.PageSize),
|
||
UnreadCount = (int)unreadCount,
|
||
Items = new List<MessageListItemDto>()
|
||
});
|
||
}
|
||
|
||
// 分类消息:有快照的和没快照的
|
||
var messagesWithSnapshot = messages.Where(x => !string.IsNullOrEmpty(x.SenderInfo) || x.MessageType == 3).ToList();
|
||
var messagesWithoutSnapshot = messages.Where(x => string.IsNullOrEmpty(x.SenderInfo) && x.MessageType != 3).ToList();
|
||
|
||
// 对于没有快照的消息,收集需要查询的ID
|
||
var senderIds = messagesWithoutSnapshot.Where(x => x.SenderId.HasValue).Select(x => x.SenderId!.Value).Distinct().ToList();
|
||
var contentIds = messagesWithoutSnapshot.Where(x => x.ContentId.HasValue && string.IsNullOrEmpty(x.ContentSnapshot))
|
||
.Select(x => new { x.ContentType, x.ContentId!.Value }).ToList();
|
||
|
||
// 获取用户信息(仅查询无快照的消息需要的)
|
||
var users = new Dictionary<long, T_Users>();
|
||
if (senderIds.Any())
|
||
{
|
||
var usersList = await _usersRepository.Select
|
||
.Where(x => senderIds.Contains(x.Id))
|
||
.ToListAsync();
|
||
foreach (var user in usersList)
|
||
{
|
||
users[user.Id] = user;
|
||
}
|
||
}
|
||
|
||
// 获取帖子信息
|
||
var postIds = contentIds.Where(x => x.ContentType == 1).Select(x => x.Value).Distinct().ToList();
|
||
var posts = new Dictionary<long, T_Posts>();
|
||
if (postIds.Any())
|
||
{
|
||
var postsList = await _postsRepository.Select
|
||
.Where(x => postIds.Contains(x.Id))
|
||
.ToListAsync();
|
||
foreach (var post in postsList)
|
||
{
|
||
posts[post.Id] = post;
|
||
}
|
||
}
|
||
|
||
// 获取评论信息
|
||
var commentIds = contentIds.Where(x => x.ContentType == 2).Select(x => x.Value).Distinct().ToList();
|
||
var comments = new Dictionary<long, T_Comments>();
|
||
if (commentIds.Any())
|
||
{
|
||
var commentsList = await _commentsRepository.Select
|
||
.Where(x => commentIds.Contains(x.Id))
|
||
.ToListAsync();
|
||
foreach (var comment in commentsList)
|
||
{
|
||
comments[comment.Id] = comment;
|
||
}
|
||
|
||
// 同时获取评论关联的帖子
|
||
var commentPostIds = commentsList.Select(x => x.PostId).Where(x => !posts.ContainsKey(x)).Distinct().ToList();
|
||
if (commentPostIds.Any())
|
||
{
|
||
var commentPostsList = await _postsRepository.Select
|
||
.Where(x => commentPostIds.Contains(x.Id))
|
||
.ToListAsync();
|
||
foreach (var post in commentPostsList)
|
||
{
|
||
posts[post.Id] = post;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 批量回填无快照的消息
|
||
if (messagesWithoutSnapshot.Any())
|
||
{
|
||
await BackfillMessageSnapshots(messagesWithoutSnapshot, users, posts, comments);
|
||
}
|
||
|
||
// 获取系统通知信息(仅当有系统消息时)
|
||
var systemNotificationIds = messages.Where(x => x.MessageType == 3 && x.SenderId.HasValue).Select(x => x.SenderId!.Value).Distinct().ToList();
|
||
var systemNotifications = new Dictionary<long, T_SystemNotifications>();
|
||
if (systemNotificationIds.Any())
|
||
{
|
||
var notificationsList = await _notificationsRepository.Select
|
||
.Where(x => systemNotificationIds.Contains(x.Id))
|
||
.ToListAsync();
|
||
foreach (var notification in notificationsList)
|
||
{
|
||
systemNotifications[notification.Id] = notification;
|
||
}
|
||
}
|
||
|
||
// 获取用户参与状态(仅当有活动通知时)
|
||
var activityNotificationIds = systemNotifications.Values
|
||
.Where(n => n.NotificationType == 2)
|
||
.Select(n => n.Id)
|
||
.ToList();
|
||
var participants = new Dictionary<long, T_SystemNotificationParticipants>();
|
||
if (activityNotificationIds.Any())
|
||
{
|
||
var participantsList = await _participantsRepository.Select
|
||
.Where(x => activityNotificationIds.Contains(x.NotificationId) && x.UserId == currentUserId)
|
||
.ToListAsync();
|
||
foreach (var participant in participantsList)
|
||
{
|
||
participants[participant.NotificationId] = participant;
|
||
}
|
||
}
|
||
var unreadCountTotal = await _messagesRepository.Select
|
||
.Where(x => x.ReceiverId == currentUserId && !x.IsRead)
|
||
.CountAsync();
|
||
|
||
// 批量转换用户信息(自动获取认证类型数据)
|
||
var usersDict = await _userInfoService.ToUserInfoDtoDictionaryAsync(users.Values);
|
||
|
||
// 构建返回数据
|
||
var items = messages.Select(message =>
|
||
{
|
||
// 优先使用快照,如果没有快照则使用实时查询的数据
|
||
UserInfoDto sender = null;
|
||
|
||
if (message.MessageType != 3)
|
||
{
|
||
// 先尝试从快照反序列化(非系统消息)
|
||
sender = TryDeserializeSenderInfo(message.SenderInfo);
|
||
|
||
// 如果快照为空,尝试从实时数据获取
|
||
if (sender == null && message.SenderId.HasValue && usersDict.ContainsKey(message.SenderId.Value))
|
||
{
|
||
sender = usersDict[message.SenderId.Value];
|
||
}
|
||
}
|
||
|
||
sender ??= new UserInfoDto();
|
||
|
||
// 优先使用内容快照
|
||
var relatedContent = TryDeserializeContentSnapshot(message.ContentSnapshot);
|
||
|
||
// 如果快照为空,尝试从实时数据获取
|
||
if (relatedContent == null && message.ContentId.HasValue)
|
||
{
|
||
relatedContent = new MessageRelatedContentDto();
|
||
|
||
if (message.ContentType == 1 && posts.ContainsKey(message.ContentId.Value))
|
||
{
|
||
var post = posts[message.ContentId.Value];
|
||
relatedContent.PostId = post.Id;
|
||
relatedContent.PostTitle = post.Title;
|
||
}
|
||
else if (message.ContentType == 2 && comments.ContainsKey(message.ContentId.Value))
|
||
{
|
||
var comment = comments[message.ContentId.Value];
|
||
relatedContent.CommentContent = comment.Content;
|
||
if (posts.ContainsKey(comment.PostId))
|
||
{
|
||
relatedContent.PostId = comment.PostId;
|
||
relatedContent.PostTitle = posts[comment.PostId].Title;
|
||
}
|
||
}
|
||
}
|
||
|
||
relatedContent ??= new MessageRelatedContentDto();
|
||
|
||
// 组装活动信息(仅当系统消息为活动类型时)
|
||
ActivityInfoDto? activityInfo = null;
|
||
if (message.MessageType == 3 && message.SenderId.HasValue && systemNotifications.ContainsKey(message.SenderId.Value))
|
||
{
|
||
var notification = systemNotifications[message.SenderId.Value];
|
||
if (notification.NotificationType == 2)
|
||
{
|
||
var isParticipated = participants.ContainsKey(notification.Id);
|
||
if (isParticipated)
|
||
{
|
||
var _participants = participants[notification.Id];
|
||
var status = _participants?.Status ?? 0;
|
||
if (notification?.ActivityEndTime != null && notification?.ActivityEndTime < DateTime.Now)
|
||
{
|
||
//活动已经结束
|
||
status = 3;
|
||
}
|
||
activityInfo = new ActivityInfoDto
|
||
{
|
||
IsActivity = true,
|
||
ActivityEndTime = notification.ActivityEndTime,
|
||
ActivityButtonText = "已提交",
|
||
IsParticipated = isParticipated,
|
||
ParticipatedAt = _participants.SubmittedAt,
|
||
ContactInfo = _participants.ContactInfo ?? "",
|
||
ShippingAddress = _participants.ShippingAddress ?? "",
|
||
Status = status
|
||
};
|
||
}
|
||
else
|
||
{
|
||
activityInfo = new ActivityInfoDto
|
||
{
|
||
IsActivity = true,
|
||
ActivityEndTime = notification.ActivityEndTime,
|
||
ActivityButtonText = notification.ActivityButtonText ?? "参与活动",
|
||
IsParticipated = isParticipated,
|
||
ParticipatedAt = null,
|
||
ContactInfo = "",
|
||
ShippingAddress = "",
|
||
Status = 0
|
||
};
|
||
}
|
||
}
|
||
}
|
||
|
||
return new MessageListItemDto
|
||
{
|
||
MessageId = message.Id,
|
||
MessageType = message.MessageType,
|
||
MessageTitle = message.MessageTitle ?? "",
|
||
MessageContent = message.MessageContent ?? "",
|
||
ContentType = message.ContentType,
|
||
ContentId = message.ContentId ?? 0,
|
||
IsRead = message.IsRead,
|
||
CreatedAt = message.CreatedAt,
|
||
Sender = sender,
|
||
RelatedContent = relatedContent,
|
||
ActivityInfo = activityInfo
|
||
};
|
||
}).ToList();
|
||
|
||
return new BaseResponse<GetMessagesRespDto>(new GetMessagesRespDto
|
||
{
|
||
PageIndex = request.PageIndex,
|
||
PageSize = request.PageSize,
|
||
Total = (int)total,
|
||
TotalPages = (int)Math.Ceiling((double)total / request.PageSize),
|
||
UnreadCount = (int)unreadCountTotal,
|
||
Items = items
|
||
});
|
||
}
|
||
|
||
public async Task<BaseResponse<GetSystemNotificationsRespDto>> GetSystemNotifications(GetSystemNotificationsReq request)
|
||
{
|
||
var currentUserId = (long)_userInfoModel.UserId;
|
||
var now = DateTime.Now;
|
||
|
||
// 构建查询条件
|
||
var query = _notificationsRepository.Select
|
||
.Where(x => x.IsActive &&
|
||
(x.ExpireTime == null || x.ExpireTime > now) &&
|
||
(x.PublishTime == null || x.PublishTime <= now));
|
||
|
||
// 过滤通知类型
|
||
//if (request.NotificationType.HasValue)
|
||
//{
|
||
// query = query.Where(x => x.NotificationType == request.NotificationType.Value);
|
||
//}
|
||
|
||
// 排序
|
||
query = query.OrderByDescending(x => x.PublishTime ?? x.CreatedAt);
|
||
|
||
// 获取总数
|
||
var total = await query.CountAsync();
|
||
|
||
// 分页
|
||
var notifications = await query
|
||
.Skip((request.PageIndex - 1) * request.PageSize)
|
||
.Take(request.PageSize)
|
||
.ToListAsync();
|
||
|
||
var items = notifications.Select(n => new SystemNotificationDto
|
||
{
|
||
NotificationId = n.Id,
|
||
Title = n.Title,
|
||
Content = n.Content,
|
||
//NotificationType = n.NotificationType,
|
||
PublishTime = n.PublishTime ?? n.CreatedAt,
|
||
ExpireTime = n.ExpireTime
|
||
}).ToList();
|
||
|
||
return new BaseResponse<GetSystemNotificationsRespDto>(new GetSystemNotificationsRespDto
|
||
{
|
||
PageIndex = request.PageIndex,
|
||
PageSize = request.PageSize,
|
||
Total = (int)total,
|
||
TotalPages = (int)Math.Ceiling((double)total / request.PageSize),
|
||
Items = items
|
||
});
|
||
}
|
||
|
||
public async Task<BaseResponse<ReadMessageRespDto>> ReadMessage(ReadMessageReq request)
|
||
{
|
||
var currentUserId = (long)_userInfoModel.UserId;
|
||
|
||
// 获取消息
|
||
var message = await _messagesRepository.Select
|
||
.Where(x => x.Id == request.MessageId && x.ReceiverId == currentUserId)
|
||
.FirstAsync();
|
||
|
||
if (message == null)
|
||
{
|
||
return new BaseResponse<ReadMessageRespDto>(ResponseCode.Error, "消息不存在或无权限访问");
|
||
}
|
||
|
||
// 标记为已读
|
||
message.IsRead = true;
|
||
message.ReadAt = DateTime.Now;
|
||
await _messagesRepository.UpdateAsync(message);
|
||
|
||
return new BaseResponse<ReadMessageRespDto>(new ReadMessageRespDto
|
||
{
|
||
MessageId = message.Id,
|
||
IsRead = true,
|
||
ReadAt = message.ReadAt!.Value
|
||
});
|
||
}
|
||
|
||
public async Task<BaseResponse<ReadBatchMessagesRespDto>> ReadBatchMessages(ReadBatchMessagesReq request)
|
||
{
|
||
var currentUserId = (long)_userInfoModel.UserId;
|
||
|
||
if (request.MessageIds == null || !request.MessageIds.Any())
|
||
{
|
||
return new BaseResponse<ReadBatchMessagesRespDto>(ResponseCode.Error, "消息ID列表不能为空");
|
||
}
|
||
|
||
if (request.MessageIds.Count > 100)
|
||
{
|
||
return new BaseResponse<ReadBatchMessagesRespDto>(ResponseCode.Error, "批量操作数量超过限制");
|
||
}
|
||
|
||
var now = DateTime.Now;
|
||
|
||
// 更新消息状态
|
||
var result = await _messagesRepository.UpdateDiy
|
||
.Set(x => x.IsRead == true)
|
||
.Set(x => x.ReadAt == now)
|
||
.Where(x => x.ReceiverId == currentUserId && request.MessageIds.Contains(x.Id))
|
||
.ExecuteAffrowsAsync();
|
||
|
||
return new BaseResponse<ReadBatchMessagesRespDto>(new ReadBatchMessagesRespDto
|
||
{
|
||
SuccessCount = (int)result,
|
||
ReadAt = now
|
||
});
|
||
}
|
||
|
||
public async Task<BaseResponse<ReadAllMessagesRespDto>> ReadAllMessages(ReadAllMessagesReq request)
|
||
{
|
||
var currentUserId = (long)_userInfoModel.UserId;
|
||
var now = DateTime.Now;
|
||
|
||
// 构建查询条件
|
||
ISelect<T_Messages> query = _messagesRepository.Select
|
||
.Where(x => x.ReceiverId == currentUserId && !x.IsRead);
|
||
|
||
// 如果指定了消息类型
|
||
if (request.MessageType.HasValue)
|
||
{
|
||
query = query.Where(x => x.MessageType == request.MessageType.Value);
|
||
}
|
||
|
||
// 获取未读消息
|
||
var messages = await query.ToListAsync();
|
||
|
||
if (!messages.Any())
|
||
{
|
||
return new BaseResponse<ReadAllMessagesRespDto>(new ReadAllMessagesRespDto
|
||
{
|
||
SuccessCount = 0,
|
||
ReadAt = now
|
||
});
|
||
}
|
||
|
||
// 批量更新消息
|
||
foreach (var message in messages)
|
||
{
|
||
message.IsRead = true;
|
||
message.ReadAt = now;
|
||
}
|
||
|
||
await _messagesRepository.UpdateAsync(messages);
|
||
|
||
return new BaseResponse<ReadAllMessagesRespDto>(new ReadAllMessagesRespDto
|
||
{
|
||
SuccessCount = messages.Count,
|
||
ReadAt = now
|
||
});
|
||
}
|
||
|
||
public async Task<BaseResponseBool> DeleteMessage(DeleteMessageReq request)
|
||
{
|
||
var currentUserId = (long)_userInfoModel.UserId;
|
||
|
||
// 检查消息是否存在且属于当前用户
|
||
var message = await _messagesRepository.Select
|
||
.Where(x => x.Id == request.MessageId && x.ReceiverId == currentUserId)
|
||
.FirstAsync();
|
||
|
||
if (message == null)
|
||
{
|
||
return new BaseResponseBool { Code = ResponseCode.Error, Message = "消息不存在或无权限删除" };
|
||
}
|
||
|
||
// 软删除消息(设置为已读并标记为已删除,或者物理删除)
|
||
await _messagesRepository.DeleteAsync(message);
|
||
|
||
return new BaseResponseBool { Code = ResponseCode.Success, Data = true };
|
||
}
|
||
|
||
public async Task<BaseResponse<UnreadCountRespDto>> GetUnreadCount()
|
||
{
|
||
var currentUserId = (long)_userInfoModel.UserId;
|
||
|
||
// 确保系统通知消息已创建,以便统计未读数量
|
||
await EnsureSystemNotificationsCreated(currentUserId);
|
||
|
||
var result = await _messagesRepository.Select
|
||
.Where(x => x.ReceiverId == currentUserId && !x.IsRead)
|
||
.ToListAsync(x => new { x.MessageType });
|
||
|
||
var totalUnread = result.Count;
|
||
var commentReplyUnread = result.Count(x => x.MessageType == 1);
|
||
var likeUnread = result.Count(x => x.MessageType == 2);
|
||
var systemUnread = result.Count(x => x.MessageType == 3);
|
||
|
||
return new BaseResponse<UnreadCountRespDto>(new UnreadCountRespDto
|
||
{
|
||
TotalUnread = totalUnread,
|
||
CommentReplyUnread = commentReplyUnread,
|
||
LikeUnread = likeUnread,
|
||
SystemUnread = systemUnread
|
||
});
|
||
}
|
||
|
||
public async Task<BaseResponse<GetCommentRepliesMessagesRespDto>> GetCommentRepliesMessages(GetCommentRepliesMessagesReq request)
|
||
{
|
||
var currentUserId = (long)_userInfoModel.UserId;
|
||
|
||
// 构建查询条件 - 只获取评论回复消息
|
||
var query = _messagesRepository.Select
|
||
.Where(x => x.ReceiverId == currentUserId && x.MessageType == 1);
|
||
|
||
// 过滤是否已读
|
||
if (request.IsRead.HasValue)
|
||
{
|
||
query = query.Where(x => x.IsRead == request.IsRead.Value);
|
||
}
|
||
|
||
// 排序
|
||
query = query.OrderByDescending(x => x.CreatedAt);
|
||
|
||
// 获取总数
|
||
var total = await query.CountAsync();
|
||
|
||
// 分页
|
||
var messages = await query
|
||
.Skip((request.PageIndex - 1) * request.PageSize)
|
||
.Take(request.PageSize)
|
||
.ToListAsync();
|
||
|
||
if (!messages.Any())
|
||
{
|
||
var unreadCount = await _messagesRepository.Select
|
||
.Where(x => x.ReceiverId == currentUserId && x.MessageType == 1 && !x.IsRead)
|
||
.CountAsync();
|
||
|
||
return new BaseResponse<GetCommentRepliesMessagesRespDto>(new GetCommentRepliesMessagesRespDto
|
||
{
|
||
PageIndex = request.PageIndex,
|
||
PageSize = request.PageSize,
|
||
Total = (int)total,
|
||
TotalPages = (int)Math.Ceiling((double)total / request.PageSize),
|
||
UnreadCount = (int)unreadCount,
|
||
Items = new List<CommentReplyMessageDto>()
|
||
});
|
||
}
|
||
|
||
// 分类消息:有快照的和没快照的
|
||
var messagesWithoutSnapshot = messages.Where(x => string.IsNullOrEmpty(x.SenderInfo) || string.IsNullOrEmpty(x.ContentSnapshot)).ToList();
|
||
|
||
// 收集需要查询的ID(仅针对无快照的消息)
|
||
var senderIds = messagesWithoutSnapshot.Where(x => x.SenderId.HasValue && string.IsNullOrEmpty(x.SenderInfo))
|
||
.Select(x => x.SenderId!.Value).Distinct().ToList();
|
||
var commentIds = messagesWithoutSnapshot.Where(x => x.ContentType == 2 && x.ContentId.HasValue && string.IsNullOrEmpty(x.ContentSnapshot))
|
||
.Select(x => x.ContentId!.Value).ToList();
|
||
|
||
// 获取用户信息
|
||
var users = new Dictionary<long, T_Users>();
|
||
if (senderIds.Any())
|
||
{
|
||
var usersList = await _usersRepository.Select
|
||
.Where(x => senderIds.Contains(x.Id))
|
||
.ToListAsync();
|
||
foreach (var user in usersList)
|
||
{
|
||
users[user.Id] = user;
|
||
}
|
||
}
|
||
|
||
// 获取评论信息
|
||
var comments = new Dictionary<long, T_Comments>();
|
||
var posts = new Dictionary<long, T_Posts>();
|
||
if (commentIds.Any())
|
||
{
|
||
var commentsList = await _commentsRepository.Select
|
||
.Where(x => commentIds.Contains(x.Id))
|
||
.ToListAsync();
|
||
foreach (var comment in commentsList)
|
||
{
|
||
comments[comment.Id] = comment;
|
||
if (!posts.ContainsKey(comment.PostId))
|
||
{
|
||
var post = await _postsRepository.Select
|
||
.Where(x => x.Id == comment.PostId)
|
||
.FirstAsync();
|
||
if (post != null)
|
||
{
|
||
posts[comment.PostId] = post;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 获取当前用户被回复的评论(父评论)
|
||
var myCommentIds = new List<long>();
|
||
foreach (var message in messagesWithoutSnapshot)
|
||
{
|
||
if (message.ContentType == 2 && message.ContentId.HasValue)
|
||
{
|
||
if (comments.ContainsKey(message.ContentId.Value))
|
||
{
|
||
var comment = comments[message.ContentId.Value];
|
||
if (comment.ParentCommentId.HasValue && !myCommentIds.Contains(comment.ParentCommentId.Value))
|
||
{
|
||
myCommentIds.Add(comment.ParentCommentId.Value);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
var myComments = new Dictionary<long, T_Comments>();
|
||
if (myCommentIds.Any())
|
||
{
|
||
var myCommentsList = await _commentsRepository.Select
|
||
.Where(x => myCommentIds.Contains(x.Id))
|
||
.ToListAsync();
|
||
foreach (var comment in myCommentsList)
|
||
{
|
||
myComments[comment.Id] = comment;
|
||
}
|
||
}
|
||
|
||
// 批量回填无快照的消息
|
||
if (messagesWithoutSnapshot.Any())
|
||
{
|
||
await BackfillMessageSnapshots(messagesWithoutSnapshot, users, posts, comments);
|
||
}
|
||
|
||
var unreadCountTotal = await _messagesRepository.Select
|
||
.Where(x => x.ReceiverId == currentUserId && x.MessageType == 1 && !x.IsRead)
|
||
.CountAsync();
|
||
|
||
// 批量转换用户信息(自动获取认证类型数据)
|
||
var usersDict = await _userInfoService.ToUserInfoDtoDictionaryAsync(users.Values);
|
||
|
||
// 构建返回数据
|
||
var items = messages.Select(message =>
|
||
{
|
||
// 优先使用快照
|
||
var sender = TryDeserializeSenderInfo(message.SenderInfo);
|
||
|
||
// 如果快照为空,使用实时数据
|
||
if (sender == null && message.SenderId.HasValue && usersDict.ContainsKey(message.SenderId.Value))
|
||
{
|
||
sender = usersDict[message.SenderId.Value];
|
||
}
|
||
|
||
sender ??= new UserInfoDto();
|
||
|
||
// 优先从快照获取评论信息
|
||
var contentSnapshot = TryDeserializeContentSnapshot(message.ContentSnapshot);
|
||
var commentDto = new CommentInfoDto();
|
||
var myCommentDto = new MyCommentInfoDto();
|
||
|
||
if (contentSnapshot != null)
|
||
{
|
||
// 使用快照数据
|
||
commentDto = new CommentInfoDto
|
||
{
|
||
//CommentId = contentSnapshot.Id ?? 0,
|
||
Content = contentSnapshot.CommentContent ?? "",
|
||
PostId = contentSnapshot.PostId ?? 0,
|
||
PostTitle = contentSnapshot.PostTitle ?? ""
|
||
};
|
||
|
||
// 父评论信息也在快照中(ContentSnapshot 中的 CommentContent 是父评论)
|
||
myCommentDto = new MyCommentInfoDto
|
||
{
|
||
CommentId = 0, // 快照中不保存父评论ID
|
||
Content = "" // 需要单独查询或从消息内容中提取
|
||
};
|
||
}
|
||
else if (message.ContentType == 2 && message.ContentId.HasValue)
|
||
{
|
||
// 使用实时数据
|
||
var comment = comments.ContainsKey(message.ContentId.Value)
|
||
? comments[message.ContentId.Value]
|
||
: null;
|
||
|
||
var myComment = comment != null && comment.ParentCommentId.HasValue && myComments.ContainsKey(comment.ParentCommentId.Value)
|
||
? myComments[comment.ParentCommentId.Value]
|
||
: null;
|
||
|
||
commentDto = comment != null
|
||
? new CommentInfoDto
|
||
{
|
||
CommentId = comment.Id,
|
||
Content = comment.Content,
|
||
PostId = comment.PostId,
|
||
PostTitle = posts.ContainsKey(comment.PostId) ? posts[comment.PostId].Title : ""
|
||
}
|
||
: new CommentInfoDto
|
||
{
|
||
CommentId = 0,
|
||
Content = "",
|
||
PostId = 0,
|
||
PostTitle = ""
|
||
};
|
||
|
||
myCommentDto = myComment != null
|
||
? new MyCommentInfoDto
|
||
{
|
||
CommentId = myComment.Id,
|
||
Content = myComment.Content
|
||
}
|
||
: new MyCommentInfoDto
|
||
{
|
||
CommentId = 0,
|
||
Content = ""
|
||
};
|
||
}
|
||
|
||
return new CommentReplyMessageDto
|
||
{
|
||
MessageId = message.Id,
|
||
IsRead = message.IsRead,
|
||
CreatedAt = message.CreatedAt,
|
||
Sender = sender,
|
||
Comment = commentDto,
|
||
MyComment = myCommentDto
|
||
};
|
||
}).ToList();
|
||
|
||
return new BaseResponse<GetCommentRepliesMessagesRespDto>(new GetCommentRepliesMessagesRespDto
|
||
{
|
||
PageIndex = request.PageIndex,
|
||
PageSize = request.PageSize,
|
||
Total = (int)total,
|
||
TotalPages = (int)Math.Ceiling((double)total / request.PageSize),
|
||
UnreadCount = (int)unreadCountTotal,
|
||
Items = items
|
||
});
|
||
}
|
||
|
||
public async Task<BaseResponse<GetLikesMessagesRespDto>> GetLikesMessages(GetLikesMessagesReq request)
|
||
{
|
||
var currentUserId = (long)_userInfoModel.UserId;
|
||
|
||
// 构建查询条件 - 只获取点赞消息
|
||
var query = _messagesRepository.Select
|
||
.Where(x => x.ReceiverId == currentUserId && x.MessageType == 2);
|
||
|
||
// 过滤是否已读
|
||
if (request.IsRead.HasValue)
|
||
{
|
||
query = query.Where(x => x.IsRead == request.IsRead.Value);
|
||
}
|
||
|
||
// 排序
|
||
query = query.OrderByDescending(x => x.CreatedAt);
|
||
|
||
// 获取总数
|
||
var total = await query.CountAsync();
|
||
|
||
// 分页
|
||
var messages = await query
|
||
.Skip((request.PageIndex - 1) * request.PageSize)
|
||
.Take(request.PageSize)
|
||
.ToListAsync();
|
||
|
||
if (!messages.Any())
|
||
{
|
||
var unreadCount = await _messagesRepository.Select
|
||
.Where(x => x.ReceiverId == currentUserId && x.MessageType == 2 && !x.IsRead)
|
||
.CountAsync();
|
||
|
||
return new BaseResponse<GetLikesMessagesRespDto>(new GetLikesMessagesRespDto
|
||
{
|
||
PageIndex = request.PageIndex,
|
||
PageSize = request.PageSize,
|
||
Total = (int)total,
|
||
TotalPages = (int)Math.Ceiling((double)total / request.PageSize),
|
||
UnreadCount = (int)unreadCount,
|
||
Items = new List<LikeMessageDto>()
|
||
});
|
||
}
|
||
|
||
// 分类消息:有快照的和没快照的
|
||
var messagesWithoutSnapshot = messages.Where(x => string.IsNullOrEmpty(x.SenderInfo) || string.IsNullOrEmpty(x.ContentSnapshot)).ToList();
|
||
|
||
// 收集需要查询的ID
|
||
var senderIds = messagesWithoutSnapshot.Where(x => x.SenderId.HasValue && string.IsNullOrEmpty(x.SenderInfo))
|
||
.Select(x => x.SenderId!.Value).Distinct().ToList();
|
||
var contentIds = messagesWithoutSnapshot.Where(x => x.ContentId.HasValue && string.IsNullOrEmpty(x.ContentSnapshot))
|
||
.Select(x => new { x.ContentType, x.ContentId!.Value }).ToList();
|
||
|
||
// 获取用户信息
|
||
var users = new Dictionary<long, T_Users>();
|
||
if (senderIds.Any())
|
||
{
|
||
var usersList = await _usersRepository.Select
|
||
.Where(x => senderIds.Contains(x.Id))
|
||
.ToListAsync();
|
||
foreach (var user in usersList)
|
||
{
|
||
users[user.Id] = user;
|
||
}
|
||
}
|
||
|
||
// 获取帖子信息
|
||
var postIds = contentIds.Where(x => x.ContentType == 1).Select(x => x.Value).Distinct().ToList();
|
||
var posts = new Dictionary<long, T_Posts>();
|
||
if (postIds.Any())
|
||
{
|
||
var postsList = await _postsRepository.Select
|
||
.Where(x => postIds.Contains(x.Id))
|
||
.ToListAsync();
|
||
foreach (var post in postsList)
|
||
{
|
||
posts[post.Id] = post;
|
||
}
|
||
}
|
||
|
||
// 获取评论信息
|
||
var commentIds = contentIds.Where(x => x.ContentType == 2).Select(x => x.Value).Distinct().ToList();
|
||
var comments = new Dictionary<long, T_Comments>();
|
||
if (commentIds.Any())
|
||
{
|
||
var commentsList = await _commentsRepository.Select
|
||
.Where(x => commentIds.Contains(x.Id))
|
||
.ToListAsync();
|
||
foreach (var comment in commentsList)
|
||
{
|
||
comments[comment.Id] = comment;
|
||
}
|
||
|
||
// 获取评论对应的帖子
|
||
var commentPostIds = commentsList.Select(x => x.PostId).Where(x => !posts.ContainsKey(x)).Distinct().ToList();
|
||
if (commentPostIds.Any())
|
||
{
|
||
var commentPostsList = await _postsRepository.Select
|
||
.Where(x => commentPostIds.Contains(x.Id))
|
||
.ToListAsync();
|
||
foreach (var post in commentPostsList)
|
||
{
|
||
posts[post.Id] = post;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 批量回填无快照的消息
|
||
if (messagesWithoutSnapshot.Any())
|
||
{
|
||
await BackfillMessageSnapshots(messagesWithoutSnapshot, users, posts, comments);
|
||
}
|
||
|
||
var unreadCountTotal = await _messagesRepository.Select
|
||
.Where(x => x.ReceiverId == currentUserId && x.MessageType == 2 && !x.IsRead)
|
||
.CountAsync();
|
||
|
||
// 批量转换用户信息(自动获取认证类型数据)
|
||
var usersDict = await _userInfoService.ToUserInfoDtoDictionaryAsync(users.Values);
|
||
|
||
// 构建返回数据
|
||
var items = messages.Select(message =>
|
||
{
|
||
// 优先使用快照
|
||
var sender = TryDeserializeSenderInfo(message.SenderInfo);
|
||
|
||
// 如果快照为空,使用实时数据
|
||
if (sender == null && message.SenderId.HasValue && usersDict.ContainsKey(message.SenderId.Value))
|
||
{
|
||
sender = usersDict[message.SenderId.Value];
|
||
}
|
||
|
||
sender ??= new UserInfoDto();
|
||
|
||
// 优先从快照获取内容信息
|
||
var contentSnapshot = TryDeserializeContentSnapshot(message.ContentSnapshot);
|
||
var likedContent = new LikedContentDto
|
||
{
|
||
ContentType = message.ContentType,
|
||
ContentId = message.ContentId ?? 0
|
||
};
|
||
|
||
if (contentSnapshot != null)
|
||
{
|
||
// 使用快照数据
|
||
likedContent.PostTitle = contentSnapshot.PostTitle;
|
||
likedContent.CommentContent = contentSnapshot.CommentContent;
|
||
}
|
||
else if (message.ContentId.HasValue)
|
||
{
|
||
// 使用实时数据
|
||
if (message.ContentType == 1 && posts.ContainsKey(message.ContentId.Value))
|
||
{
|
||
likedContent.PostTitle = posts[message.ContentId.Value].Title;
|
||
}
|
||
else if (message.ContentType == 2 && comments.ContainsKey(message.ContentId.Value))
|
||
{
|
||
likedContent.CommentContent = comments[message.ContentId.Value].Content;
|
||
// 评论的帖子标题需要额外查询
|
||
var comment = comments[message.ContentId.Value];
|
||
if (posts.ContainsKey(comment.PostId))
|
||
{
|
||
likedContent.PostTitle = posts[comment.PostId].Title;
|
||
}
|
||
}
|
||
}
|
||
|
||
return new LikeMessageDto
|
||
{
|
||
MessageId = message.Id,
|
||
IsRead = message.IsRead,
|
||
CreatedAt = message.CreatedAt,
|
||
Sender = sender,
|
||
LikedContent = likedContent
|
||
};
|
||
}).ToList();
|
||
|
||
return new BaseResponse<GetLikesMessagesRespDto>(new GetLikesMessagesRespDto
|
||
{
|
||
PageIndex = request.PageIndex,
|
||
PageSize = request.PageSize,
|
||
Total = (int)total,
|
||
TotalPages = (int)Math.Ceiling((double)total / request.PageSize),
|
||
UnreadCount = (int)unreadCountTotal,
|
||
Items = items
|
||
});
|
||
}
|
||
|
||
public async Task<BaseResponse<ParticipateActivityResp>> ParticipateActivity(ParticipateActivityReq request)
|
||
{
|
||
var currentUserId = (long)_userInfoModel.UserId;
|
||
var now = DateTime.Now;
|
||
|
||
// 验证通知是否存在且为活动类型
|
||
var message = await _messagesRepository.Select.Where(it => it.Id == request.NotificationId).FirstAsync();
|
||
if (message == null || message.SenderId == null)
|
||
{
|
||
return new BaseResponse<ParticipateActivityResp>(ResponseCode.Error, "消息不存在或已删除");
|
||
}
|
||
var notification = await _notificationsRepository.Select
|
||
.Where(x => x.Id == message.SenderId && x.IsActive)
|
||
.FirstAsync();
|
||
|
||
if (notification == null)
|
||
{
|
||
return new BaseResponse<ParticipateActivityResp>(ResponseCode.Error, "活动通知不存在或已禁用");
|
||
}
|
||
|
||
if (notification.NotificationType != 2)
|
||
{
|
||
return new BaseResponse<ParticipateActivityResp>(ResponseCode.Error, "该通知不是活动类型");
|
||
}
|
||
|
||
// 验证活动是否已过期
|
||
if (notification.ActivityEndTime.HasValue && notification.ActivityEndTime.Value < now)
|
||
{
|
||
return new BaseResponse<ParticipateActivityResp>(ResponseCode.Error, "活动已结束");
|
||
}
|
||
|
||
// 验证活动是否已发布
|
||
if (notification.PublishTime.HasValue && notification.PublishTime.Value > now)
|
||
{
|
||
return new BaseResponse<ParticipateActivityResp>(ResponseCode.Error, "活动尚未开始");
|
||
}
|
||
|
||
// 验证用户是否已参与(防止重复提交)
|
||
var existingParticipant = await _participantsRepository.Select
|
||
.Where(x => x.NotificationId == notification.Id && x.UserId == currentUserId)
|
||
.FirstAsync();
|
||
|
||
if (existingParticipant != null && existingParticipant.Status == 3)
|
||
{
|
||
return new BaseResponse<ParticipateActivityResp>(ResponseCode.Error, "活动奖品已发货,无法修改地址!");
|
||
}
|
||
|
||
// 验证必填字段
|
||
if (string.IsNullOrWhiteSpace(request.ContactInfo))
|
||
{
|
||
return new BaseResponse<ParticipateActivityResp>(ResponseCode.Error, "联系方式不能为空");
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(request.ShippingAddress))
|
||
{
|
||
return new BaseResponse<ParticipateActivityResp>(ResponseCode.Error, "收货地址不能为空");
|
||
}
|
||
|
||
// 验证字段长度
|
||
if (request.ContactInfo.Length > 100)
|
||
{
|
||
return new BaseResponse<ParticipateActivityResp>(ResponseCode.Error, "联系方式长度不能超过100字符");
|
||
}
|
||
|
||
if (request.ShippingAddress.Length > 500)
|
||
{
|
||
return new BaseResponse<ParticipateActivityResp>(ResponseCode.Error, "收货地址长度不能超过500字符");
|
||
}
|
||
// 判断是新增还是更新
|
||
var isUpdate = existingParticipant != null;
|
||
if (existingParticipant == null)
|
||
{
|
||
// 创建新的参与记录
|
||
existingParticipant = new T_SystemNotificationParticipants
|
||
{
|
||
NotificationId = notification.Id,
|
||
UserId = currentUserId,
|
||
ContactInfo = request.ContactInfo,
|
||
ShippingAddress = request.ShippingAddress,
|
||
Status = 1, // 已提交
|
||
SubmittedAt = now,
|
||
CreatedAt = now,
|
||
UpdatedAt = now,
|
||
SenerId = message.Id,
|
||
SenerTitle = notification.Title,
|
||
};
|
||
}
|
||
else
|
||
{
|
||
// 更新现有参与记录(保留 Id、CreatedAt、SubmittedAt 等字段)
|
||
existingParticipant.ContactInfo = request.ContactInfo;
|
||
existingParticipant.ShippingAddress = request.ShippingAddress;
|
||
existingParticipant.Status = 1; // 已提交
|
||
existingParticipant.UpdatedAt = now;
|
||
existingParticipant.SenerId = message.Id;
|
||
existingParticipant.SenerTitle = notification.Title;
|
||
// 注意:不更新 SubmittedAt,保持首次提交时间
|
||
}
|
||
|
||
await _participantsRepository.InsertOrUpdateAsync(existingParticipant);
|
||
|
||
return new BaseResponse<ParticipateActivityResp>(isUpdate ? "修改成功!" : "提交成功!", new ParticipateActivityResp
|
||
{
|
||
ParticipantId = existingParticipant.Id,
|
||
SubmittedAt = existingParticipant.SubmittedAt
|
||
});
|
||
}
|
||
}
|
||
}
|