diff --git a/src/CloudGaming/Api/CloudGaming.Api/Controllers/MessagesController.cs b/src/CloudGaming/Api/CloudGaming.Api/Controllers/MessagesController.cs new file mode 100644 index 0000000..ead903d --- /dev/null +++ b/src/CloudGaming/Api/CloudGaming.Api/Controllers/MessagesController.cs @@ -0,0 +1,78 @@ +using CloudGaming.Api.Base; +using CloudGaming.Code.DataAccess; +using CloudGaming.Code.Other; +using CloudGaming.DtoModel.Messages; + +using HuanMeng.DotNetCore.Base; + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace CloudGaming.Api.Controllers; + +/// +/// 消息 +/// +public class MessagesController : CloudGamingControllerBase +{ + public MessagesController(IServiceProvider _serviceProvider) : base(_serviceProvider) + { + } + + /// + /// 获取用户消息列表 + /// + /// + [HttpGet] + public async Task> GetUserMessageList() + { + MessagesBLL messagesBLL = new MessagesBLL(ServiceProvider); + return await messagesBLL.GetUserMessageList(); + } + + /// + /// 获取消息详情,获取详情后会自动已读 + /// + /// + /// + [HttpGet] + public async Task GetUserMessageInfo([FromQuery] int messageId) + { + MessagesBLL messagesBLL = new MessagesBLL(ServiceProvider); + return await messagesBLL.GetUserMessageInfo(messageId); + } + + /// + /// 用户消息读取 + /// + /// + /// + [HttpPost] + public async Task UserMessageRead([FromBody] UserMessageRequest userMessageRequest) + { + MessagesBLL messagesBLL = new MessagesBLL(ServiceProvider); + return await messagesBLL.UserMessageRead(userMessageRequest.MessageId); + } + + /// + /// 全部已读 + /// + /// + [HttpPost] + public async Task UserAllMessageRead() + { + MessagesBLL messagesBLL = new MessagesBLL(ServiceProvider); + return await messagesBLL.UserAllMessageRead(); + } + + /// + /// 获取未读取消息的数量 + /// + /// + [HttpGet] + public async Task GetUserMessageNotReadCount() + { + MessagesBLL messagesBLL = new MessagesBLL(ServiceProvider); + return await messagesBLL.GetUserMessageNotReadCount(); + } +} diff --git a/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs index 2c599ae..bfe0a57 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountBLL.cs @@ -530,7 +530,9 @@ namespace CloudGaming.Code.Account UserId = _UserId, Ip = HttpContextAccessor.HttpContext.GetClientIpAddress() }; - await this.UserConsumeDiamondMoneyAsync(10, "实名认证赠送"); + await this.UserConsumeDiamondMoneyAsync(UserCurrencyType.钻石, 10, "实名认证赠送"); + await this.SendUserMessageAsync("实名认证赠送",$"实名认证成功!您已获得钻石*{10}"); + await Dao.DaoUser.Context.T_User_LimitActionLog.AddAsync(limitActionLog); await Dao.DaoUser.Context.SaveChangesAsync(); return "奖励已经发送,钻石*10"; diff --git a/src/CloudGaming/Code/CloudGaming.Code/Account/AccountExtend.cs b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountExtend.cs index 094e0ee..8bd6f53 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Account/AccountExtend.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Account/AccountExtend.cs @@ -4,9 +4,11 @@ using CloudGaming.Code.Account.Contract; using CloudGaming.Code.Account.Login; using CloudGaming.Code.Account.UserCurrency; using CloudGaming.Code.DataAccess; +using CloudGaming.Code.Other; using CloudGaming.DtoModel.Account.Login; using CloudGaming.DtoModel.Account.User; using CloudGaming.DtoModel.Account.User.Cache; +using CloudGaming.DtoModel.Messages; using HuanMeng.DotNetCore.Redis; @@ -326,10 +328,58 @@ namespace CloudGaming.Code.Account public static async Task UserConsumeDiamondMoneyAsync(this CloudGamingBase cloudGamingBase, decimal money, string title = "", string orderId = "") { - return await UserConsumeDiamondMoneyAsync(cloudGamingBase, money, it => { it.Title = title; it.OrderCode = orderId; }); } + /// + /// + /// + /// + /// 金额 + /// 资产支出标题 + /// 订单号 + /// + + public static async Task UserConsumeDiamondMoneyAsync(this CloudGamingBase cloudGamingBase, UserCurrencyType userCurrencyType, decimal money, string title = "", string orderId = "") + { + if (userCurrencyType == UserCurrencyType.钻石) + { + return await UserConsumeDiamondMoneyAsync(cloudGamingBase, money, it => { it.Title = title; it.OrderCode = orderId; }); + } + return await UserConsumeDiamondMoneyAsync(cloudGamingBase, money, it => { it.Title = title; it.OrderCode = orderId; }); + } + + /// + /// 发送消息 + /// + /// + /// + /// + /// + public static async Task SendUserMessageAsync(this CloudGamingBase cloudGamingBase, string title, string content) + { + if (cloudGamingBase._UserId == 0) + { + return false; + + } + T_User_Messages t_User_Messages = new T_User_Messages() + { + Content = content, + CreateAt = DateTime.Now, + MessageType = MessageType.user.ToString(), + IsRead = false, + SendAt = DateTime.Now, + SystemId = 0, + Title = title, + UserId = cloudGamingBase._UserId + }; + await cloudGamingBase.Dao.DaoPhone.Context.T_User_Messages.AddAsync(t_User_Messages); + await cloudGamingBase.Dao.DaoPhone.Context.SaveChangesAsync(); + return true; + } + + /// /// 扣除当前用户钻石 /// diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/CloudGamingCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/CloudGamingCache.cs index 966fdef..49063cd 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Cache/CloudGamingCache.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/CloudGamingCache.cs @@ -261,7 +261,7 @@ namespace CloudGaming.Code.Cache /// /// 获取实体缓存 /// - public static CommonDataEntityCache GetDataEntityCache(CloudGamingBase cloudGamingBase, Expression>? expWhere = null) where T : class + public static CommonDataEntityCache GetDataEntityCache(CloudGamingBase cloudGamingBase, Expression>? expWhere = null, int cacheTime =36000) where T : class { var typeLock = typeof(T); var namespaceKey = typeLock.Namespace; @@ -275,7 +275,7 @@ namespace CloudGaming.Code.Cache object cacheLock = GetOrAddCacheLock(typeLock, cacheList); CacheBaseConfig cacheBaseConfig = cloudGamingBase.ToCacheBaseConfig(dbType); - return new DataBaseEntityCache(cacheBaseConfig, cacheLock, expWhere: expWhere); + return new DataBaseEntityCache(cacheBaseConfig, cacheLock, expWhere: expWhere, cacheTime: cacheTime); } /// diff --git a/src/CloudGaming/Code/CloudGaming.Code/Other/MessagesBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Other/MessagesBLL.cs new file mode 100644 index 0000000..422fcfa --- /dev/null +++ b/src/CloudGaming/Code/CloudGaming.Code/Other/MessagesBLL.cs @@ -0,0 +1,181 @@ +using CloudGaming.Code.Cache; +using CloudGaming.Code.DataAccess; +using CloudGaming.DtoModel.Messages; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using static SKIT.FlurlHttpClient.Wechat.TenpayV3.Models.CreateNewTaxControlFapiaoApplicationRequest.Types.Fapiao.Types; + +namespace CloudGaming.Code.Other; + +/// +/// 消息 +/// +public class MessagesBLL : CloudGamingBase +{ + public MessagesBLL(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + /// + /// 给用户发送消息 + /// + /// + /// + /// + /// + public async Task SendUserMessage(int userId, string title, string content) + { + T_User_Messages t_User_Messages = new T_User_Messages() + { + Content = content, + CreateAt = DateTime.Now, + MessageType = MessageType.user.ToString(), + IsRead = false, + SendAt = DateTime.Now, + SystemId = 0, + Title = title, + UserId = userId + }; + await Dao.DaoPhone.Context.T_User_Messages.AddAsync(t_User_Messages); + await Dao.DaoPhone.Context.SaveChangesAsync(); + } + /// + /// 获取用户消息列表 + /// + /// + public async Task> GetUserMessageList() + { + List messageListDtos = new List(); + if (_UserId == 0) + { + return messageListDtos; + } + await InitSystemMessage(); + var list = await Dao.DaoPhone.Context.T_User_Messages.AsNoTracking().Where(it => it.UserId == _UserId).OrderBy(it => it.IsRead).ThenByDescending(it => it.SendAt).Take(100).ToListAsync(); + + list.ForEach(it => + { + MessageListDto messageListDto = new MessageListDto() + { + Content = it.Content, + MessageId = it.Id, + SendDateTime = it.SendAt.ToString("yyyy-MM-dd"), + Title = it.Title, + IsRead = it.IsRead, + }; + if (messageListDto.Content.Length > 20) + { + messageListDto.Content = messageListDto.Content[..20] + "..."; + } + messageListDtos.Add(messageListDto); + }); + return messageListDtos; + } + + /// + /// 获取消息详情 + /// + /// + /// + public async Task GetUserMessageInfo(int messageId) + { + var userMessages = await Dao.DaoPhone.Context.T_User_Messages.Where(it => it.UserId == _UserId && it.Id == messageId).FirstOrDefaultAsync(); + if (userMessages == null) + { + throw MessageBox.ErrorShow("消息不存在"); + } + userMessages.IsRead = true; + userMessages.ReadAt = DateTime.Now; + await Dao.DaoPhone.Context.SaveChangesAsync(); + MessageListDto messageListDto = new MessageListDto() + { + Content = userMessages.Content, + IsRead = userMessages.IsRead, + MessageId = messageId, + SendDateTime = userMessages.SendAt.ToString("yyyy-MM-dd HH:mm:ss") + }; + return messageListDto; + } + + /// + /// 用户消息读取 + /// + /// + /// + public async Task UserMessageRead(int messageId) + { + var userMessages = await Dao.DaoPhone.Context.T_User_Messages.Where(it => it.UserId == _UserId && it.Id == messageId).FirstOrDefaultAsync(); + if (userMessages == null) + { + throw MessageBox.ErrorShow("消息不存在"); + } + userMessages.ReadAt = DateTime.Now; + userMessages.IsRead = true; + await Dao.DaoPhone.Context.SaveChangesAsync(); + return true; + } + + /// + /// 全部已读 + /// + /// + public async Task UserAllMessageRead() + { + var userMessages = await Dao.DaoPhone.Context.T_User_Messages.Where(it => it.UserId == _UserId && !it.IsRead).ToListAsync(); + userMessages.ForEach(item => + { + item.IsRead = true; + item.ReadAt = DateTime.Now; + }); + await Dao.DaoPhone.Context.SaveChangesAsync(); + return true; + } + + /// + /// 获取未读取消息的数量 + /// + /// + public async Task GetUserMessageNotReadCount() + { + if (_UserId == 0) + { + return 0; + } + await InitSystemMessage(); + var coun = await Dao.DaoPhone.Context.T_User_Messages.Where(it => it.UserId == _UserId && !it.IsRead).CountAsync(); + return coun; + } + + /// + /// 初始话系统消息 + /// + /// + private async Task InitSystemMessage() + { + var systemIds = Dao.DaoPhone.Context.T_User_Messages.Where(it => it.UserId == _UserId && it.MessageType == MessageType.system.ToString()).Select(it => it.SystemId).ToList(); + var sysMessage = await Dao.DaoPhone.Context.T_Sys_Message.Where(it => !systemIds.Contains(it.Id)).ToListAsync(); + if (sysMessage != null && sysMessage.Count > 0) + { + sysMessage.ForEach(item => + { + T_User_Messages t_User_Messages = new T_User_Messages() + { + Content = item.Content, + CreateAt = item.CreatedAt, + MessageType = MessageType.system.ToString(), + IsRead = false, + SendAt = item.CreatedAt, + SystemId = item.Id, + Title = item.Title, + UserId = _UserId + }; + Dao.DaoPhone.Context.T_User_Messages.Add(t_User_Messages); + }); + await Dao.DaoPhone.Context.SaveChangesAsync(); + } + } +} diff --git a/src/CloudGaming/Code/CloudGaming.Code/Other/RedemptionBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Other/RedemptionBLL.cs index f54277a..64727cd 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Other/RedemptionBLL.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Other/RedemptionBLL.cs @@ -81,7 +81,7 @@ namespace CloudGaming.Code.Other string m = await SendReward(code, red); return new BaseResponse(ResonseCode.Success, m, true) { }; } - + private async Task SendReward(string code, RedemptionCodeCache? red) { T_User_RedemptionUsage t_User_RedemptionUsage = new T_User_RedemptionUsage() @@ -94,14 +94,13 @@ namespace CloudGaming.Code.Other }; await Dao.DaoPhone.Context.T_User_RedemptionUsage.AddAsync(t_User_RedemptionUsage); await Dao.DaoPhone.Context.SaveChangesAsync(); - var msg = "领取成功!"; + var msg = "兑换码领取成功!"; //发放奖励 if (red.RewardConfigs != null && red.RewardConfigs.Count > 0) { foreach (var raw in red.RewardConfigs) { - var isSuccess = await this.UserConsumeDiamondMoneyAsync(raw.AwardNum, $"兑换码礼包"); - + var isSuccess = await this.UserConsumeDiamondMoneyAsync((UserCurrencyType)raw.CurrencyType, raw.AwardNum, $"兑换码礼包"); if (!isSuccess) { t_User_RedemptionUsage.Status = (int)RedemptionUsageStatus.领取失败; @@ -113,8 +112,11 @@ namespace CloudGaming.Code.Other await Dao.DaoPhone.Context.SaveChangesAsync(); throw MessageBox.Show(ResonseCode.Error, "奖励发放失败"); } - msg += $"获得{(UserCurrencyType)raw.CurrencyType}*{raw.AwardNum}"; + msg += $"获得{(UserCurrencyType)raw.CurrencyType}*{raw.AwardNum},"; } + msg = msg.TrimEnd(','); + msg += "。"; + await this.SendUserMessageAsync("兑换码领取成功!", msg); t_User_RedemptionUsage.Remarks = msg; if (t_User_RedemptionUsage.Remarks.Length > 250) { diff --git a/src/CloudGaming/Code/CloudGaming.Code/Other/SevenSignBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Other/SevenSignBLL.cs index 9a0b624..c0e5a47 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Other/SevenSignBLL.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Other/SevenSignBLL.cs @@ -104,15 +104,17 @@ public class SevenSignBLL : CloudGamingBase { foreach (var raw in sevenRaw) { - var isSuccess = await this.UserConsumeDiamondMoneyAsync(raw.AwardNum, $"七天签到-第{userSevenInfo.ConsecutiveSignDays + 1}天礼包"); + var isSuccess = await this.UserConsumeDiamondMoneyAsync((UserCurrencyType)raw.CurrencyType, raw.AwardNum, $"七天签到-第{userSevenInfo.ConsecutiveSignDays + 1}天礼包"); if (!isSuccess) { throw MessageBox.Show(ResonseCode.Error, "奖励发放失败"); } - msg += $"获得{(UserCurrencyType)raw.CurrencyType}*{raw.AwardNum}"; + msg += $"获得{(UserCurrencyType)raw.CurrencyType}*{raw.AwardNum},"; } - + msg = msg.TrimEnd(','); + msg += "。"; + await this.SendUserMessageAsync("七天签到奖励", msg); } T_User_SignDays t_User_SignDays = new T_User_SignDays() { diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/Messages/MessageListDto.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/Messages/MessageListDto.cs new file mode 100644 index 0000000..ba66822 --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/Messages/MessageListDto.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.DtoModel.Messages +{ + /// + /// + /// + public class MessageListDto + { + /// + /// 消息id + /// + public int MessageId { get; set; } + + /// + /// 标题 + /// + public string Title { get; set; } + + /// + /// 内容 + /// + public string Content { get; set; } + + /// + /// 消息发送时间 + /// + public string SendDateTime { get; set; } + + /// + /// 已读,未读 + /// + public bool IsRead { get; set; } + } +} diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/Messages/MessageType.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/Messages/MessageType.cs new file mode 100644 index 0000000..ffe8501 --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/Messages/MessageType.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.DtoModel.Messages; + +/// +/// 消息类型 +/// +public enum MessageType +{ + /// + /// 系统消息 + /// + system, + /// + /// 用户消息 + /// + user +} diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/Messages/UserMessageRequest.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/Messages/UserMessageRequest.cs new file mode 100644 index 0000000..ab994db --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/Messages/UserMessageRequest.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.DtoModel.Messages +{ + /// + /// + /// + public class UserMessageRequest + { + /// + /// 消息Id + /// + public int MessageId { get; set; } + } +} diff --git a/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_Phone/CloudGamingPhoneContext.cs b/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_Phone/CloudGamingPhoneContext.cs index fa997c4..cdcd419 100644 --- a/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_Phone/CloudGamingPhoneContext.cs +++ b/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_Phone/CloudGamingPhoneContext.cs @@ -153,6 +153,11 @@ public partial class CloudGamingPhoneContext : MultiTenantDbContext//DbContext /// public virtual DbSet T_SysMessage { get; set; } + /// + /// 系统消息表 + /// + public virtual DbSet T_Sys_Message { get; set; } + /// /// 位置大小类型列表 /// @@ -173,6 +178,11 @@ public partial class CloudGamingPhoneContext : MultiTenantDbContext//DbContext /// public virtual DbSet T_User_GameList { get; set; } + /// + /// 用户消息表 + /// + public virtual DbSet T_User_Messages { get; set; } + /// /// 用户游玩时间表,总表,一个游戏一条数据 /// @@ -1028,6 +1038,27 @@ public partial class CloudGamingPhoneContext : MultiTenantDbContext//DbContext } }); + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__T_Sys_Me__3214EC073AAC025D"); + + entity.ToTable(tb => tb.HasComment("系统消息表")); + + entity.Property(e => e.Content).HasComment("消息内容"); + entity.Property(e => e.CreatedAt) + .HasComment("消息创建时间") + .HasColumnType("datetime"); + entity.Property(e => e.TenantId).HasComment("租户"); + entity.Property(e => e.Title) + .HasMaxLength(50) + .HasComment("标题"); + //添加全局筛选器 + if (this.TenantInfo != null) + { + entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId); + } + }); + modelBuilder.Entity(entity => { entity.HasKey(e => e.Id).HasName("PK_T_UITYPES"); @@ -1131,6 +1162,40 @@ public partial class CloudGamingPhoneContext : MultiTenantDbContext//DbContext } }); + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__T_User_M__3214EC07ECFD5286"); + + entity.ToTable(tb => tb.HasComment("用户消息表")); + + entity.Property(e => e.Id).HasComment("主键"); + entity.Property(e => e.Content).HasComment("消息内容"); + entity.Property(e => e.CreateAt) + .HasComment("创建时间") + .HasColumnType("datetime"); + entity.Property(e => e.IsRead).HasComment("是否已读"); + entity.Property(e => e.MessageType) + .HasMaxLength(10) + .HasComment("消息类型"); + entity.Property(e => e.ReadAt) + .HasComment("已读时间") + .HasColumnType("datetime"); + entity.Property(e => e.SendAt) + .HasComment("消息发送时间") + .HasColumnType("datetime"); + entity.Property(e => e.SystemId).HasComment("系统消息Id"); + entity.Property(e => e.TenantId).HasComment("租户"); + entity.Property(e => e.Title) + .HasMaxLength(100) + .HasComment("消息标题"); + entity.Property(e => e.UserId).HasComment("对应用户的Id"); + //添加全局筛选器 + if (this.TenantInfo != null) + { + entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId); + } + }); + modelBuilder.Entity(entity => { entity.HasKey(e => e.Id).HasName("PK__T_User_P__3214EC07D35C08FA"); diff --git a/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_Phone/T_Sys_Message.cs b/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_Phone/T_Sys_Message.cs new file mode 100644 index 0000000..7c46517 --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_Phone/T_Sys_Message.cs @@ -0,0 +1,33 @@ +using System; + +namespace CloudGaming.Model.DbSqlServer.Db_Phone; + +/// +/// 系统消息表 +/// +public partial class T_Sys_Message: MultiTenantEntity +{ + public T_Sys_Message() { } + + public virtual int Id { get; set; } + + /// + /// 标题 + /// + public virtual string Title { get; set; } = null!; + + /// + /// 消息内容 + /// + public virtual string Content { get; set; } = null!; + + /// + /// 消息创建时间 + /// + public virtual DateTime CreatedAt { get; set; } + + /// + /// 所属租户 + /// + public override Guid TenantId { get; set; } + } diff --git a/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_Phone/T_User_Messages.cs b/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_Phone/T_User_Messages.cs new file mode 100644 index 0000000..ca5ad90 --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.Model/DbSqlServer/Db_Phone/T_User_Messages.cs @@ -0,0 +1,66 @@ +using System; + +namespace CloudGaming.Model.DbSqlServer.Db_Phone; + +/// +/// 用户消息表 +/// +public partial class T_User_Messages: MultiTenantEntity +{ + public T_User_Messages() { } + + /// + /// 主键 + /// + public virtual int Id { get; set; } + + /// + /// 对应用户的Id + /// + public virtual int UserId { get; set; } + + /// + /// 所属租户 + /// + public override Guid TenantId { get; set; } + + /// + /// 消息类型 + /// + public virtual string MessageType { get; set; } = null!; + + /// + /// 消息标题 + /// + public virtual string Title { get; set; } = null!; + + /// + /// 消息内容 + /// + public virtual string Content { get; set; } = null!; + + /// + /// 是否已读 + /// + public virtual bool IsRead { get; set; } + + /// + /// 已读时间 + /// + public virtual DateTime? ReadAt { get; set; } + + /// + /// 创建时间 + /// + public virtual DateTime CreateAt { get; set; } + + /// + /// 系统消息Id + /// + public virtual int SystemId { get; set; } + + /// + /// 消息发送时间 + /// + public virtual DateTime SendAt { get; set; } +}