live-forum/server/webapi/需求文件/消息.md
2026-03-24 11:27:37 +08:00

24 KiB
Raw Blame History

消息业务逻辑文档

一、消息系统概述

消息系统用于处理用户之间的互动消息和系统通知,主要包括四种消息类型:

  • MessageType = 1: 评论回复消息
  • MessageType = 2: 点赞消息
  • MessageType = 3: 关注消息
  • MessageType = 4: 系统通知

二、数据模型

2.1 T_Messages消息表

字段 类型 说明
Id long 消息ID主键自增
ReceiverId long 接收消息的用户ID
SenderId long? 发送消息的用户ID系统消息时为NULL
MessageType int 消息类型1-评论回复2-点赞3-关注4-系统通知
MessageContent string 消息内容文本最大500字符
ContentType int 内容类型1-帖子2-评论
ContentId long? 关联的内容ID帖子ID或评论ID
IsRead bool 是否已读默认false
ReadAt DateTime? 消息阅读时间
CreatedAt DateTime 消息创建时间

2.2 T_SystemNotifications系统通知表

字段 类型 说明
Id long 通知ID主键自增
Title string 通知标题最大100字符
Content string 通知正文内容
IsActive bool 是否启用该通知默认true
PublishTime DateTime? 通知发布时间
ExpireTime DateTime? 通知过期时间
CreatedAt DateTime 通知创建时间
UpdatedAt DateTime 通知更新时间

三、核心业务逻辑

3.1 GetMessages - 获取消息列表(通用方法)

功能描述:获取当前用户的消息列表,支持按消息类型和已读状态过滤。

业务逻辑流程

  1. 基础查询构建

    • 查询条件:ReceiverId == currentUserId
    • 根据请求参数过滤消息类型(MessageType
    • 根据请求参数过滤已读状态(IsRead
  2. 系统通知特殊处理(当 MessageType == 4 时)

    • 查询未创建消息记录的系统通知:
      SELECT n.* FROM T_SystemNotifications n
      LEFT JOIN T_Messages m ON n.Id = m.SenderId 
          AND m.MessageType = 4 
          AND m.ReceiverId = currentUserId
      WHERE m.Id IS NULL 
        AND (n.ExpireTime > NOW() OR n.ExpireTime IS NULL)
        AND n.PublishTime <= NOW()
      
    • 如果存在未创建消息的系统通知,自动为它们创建消息记录:
      • ReceiverId = 当前用户ID
      • SenderId = 通知ID使用通知ID作为SenderId
      • MessageType = 4
      • MessageContent = "{通知标题}: {通知内容}"
      • IsRead = false
      • CreatedAt = 当前时间
  3. 排序与分页

    • 按创建时间倒序排列(OrderByDescending(x => x.CreatedAt)
    • 支持分页查询(PageIndex, PageSize
  4. 关联数据查询

    • 用户信息:查询发送者信息(排除系统通知类型)
      • T_Users 表获取发送者详细信息昵称、头像、VIP状态、认证状态等
    • 帖子信息:当 ContentType == 1 时,查询关联的帖子信息
    • 评论信息:当 ContentType == 2 时,查询关联的评论信息
      • 如果评论关联了帖子,同时获取帖子信息
  5. 数据组装

    • 构建 MessageListItemDto 对象,包含:
      • 消息基本信息ID、类型、内容、创建时间、已读状态
      • 发送者信息(MessageSenderDto,系统通知时为空对象)
      • 关联内容信息(MessageRelatedContentDto,包含帖子标题、评论内容等)
  6. 返回结果

    • 总记录数(Total
    • 总页数(TotalPages
    • 未读消息数量(UnreadCount
    • 消息列表(Items

3.2 GetSystemNotifications - 获取系统通知列表

功能描述:获取系统通知列表(从 T_SystemNotifications 表查询,非消息表)。

业务逻辑流程

  1. 查询条件

    • IsActive == true
    • ExpireTime == null OR ExpireTime > 当前时间
    • PublishTime == null OR PublishTime <= 当前时间
  2. 排序

    • 按发布时间倒序(OrderByDescending(x => x.PublishTime ?? x.CreatedAt)
  3. 分页查询

    • 支持分页参数
  4. 返回结果

    • 系统通知列表(不包含未读数量统计)

3.3 ReadMessage - 标记单条消息已读

功能描述:将指定消息标记为已读。

业务逻辑流程

  1. 权限验证

    • 验证消息是否存在
    • 验证消息是否属于当前用户(ReceiverId == currentUserId
  2. 更新消息状态

    • IsRead = true
    • ReadAt = 当前时间
  3. 返回结果

    • 消息ID、已读状态、阅读时间

3.4 ReadBatchMessages - 批量标记消息已读

功能描述:批量将多条消息标记为已读。

业务逻辑流程

  1. 参数验证

    • 消息ID列表不能为空
    • 批量操作数量限制最多100条
  2. 批量更新

    • 使用批量更新操作,更新条件:
      • ReceiverId == currentUserId
      • Id IN (消息ID列表)
    • 设置 IsRead = trueReadAt = 当前时间
  3. 返回结果

    • 成功更新的数量(SuccessCount
    • 阅读时间(ReadAt

3.5 ReadAllMessages - 标记所有消息已读

功能描述:将当前用户的所有未读消息(或指定类型的未读消息)标记为已读。

业务逻辑流程

  1. 查询未读消息

    • 基础条件:ReceiverId == currentUserId AND IsRead == false
    • 如果指定了 MessageType,则按类型过滤
  2. 批量更新

    • 遍历所有未读消息,设置 IsRead = trueReadAt = 当前时间
    • 批量更新到数据库
  3. 返回结果

    • 成功更新的数量(SuccessCount
    • 阅读时间(ReadAt

3.6 DeleteMessage - 删除消息

功能描述:删除指定消息。

业务逻辑流程

  1. 权限验证

    • 验证消息是否存在
    • 验证消息是否属于当前用户(ReceiverId == currentUserId
  2. 删除操作

    • 物理删除消息记录
  3. 返回结果

    • 操作成功标识

3.7 GetUnreadCount - 获取未读消息数量

功能描述:获取当前用户各类消息的未读数量统计。

业务逻辑流程

  1. 查询未读消息

    • 查询条件:ReceiverId == currentUserId AND IsRead == false
    • 按消息类型分组统计
  2. 统计结果

    • TotalUnread:总未读数量
    • CommentReplyUnread评论回复未读数量MessageType == 1
    • LikeUnread点赞未读数量MessageType == 2
    • FollowUnread关注未读数量MessageType == 3
    • SystemUnread系统通知未读数量MessageType == 4

3.8 GetCommentRepliesMessages - 获取评论回复消息

功能描述:专门获取评论回复类型的消息列表。

业务逻辑流程

  1. 查询构建

    • 固定条件:ReceiverId == currentUserId AND MessageType == 1
    • 可选过滤:按已读状态过滤
  2. 关联数据查询

    • 发送者信息:查询回复评论的用户信息
    • 评论信息:查询被回复的评论内容
    • 帖子信息:查询评论所属的帖子信息
    • 我的评论信息:查询当前用户被回复的原始评论(通过 ParentCommentId 关联)
  3. 数据组装

    • 构建 CommentReplyMessageDto 对象,包含:
      • 消息基本信息
      • 发送者信息
      • 回复的评论信息(CommentInfoDto
      • 我的原始评论信息(MyCommentInfoDto

3.9 GetLikesMessages - 获取点赞消息

功能描述:专门获取点赞类型的消息列表。

业务逻辑流程

  1. 查询构建

    • 固定条件:ReceiverId == currentUserId AND MessageType == 2
    • 可选过滤:按已读状态过滤
  2. 关联数据查询

    • 发送者信息:查询点赞的用户信息
    • 帖子信息:当 ContentType == 1 时,查询被点赞的帖子信息
    • 评论信息:当 ContentType == 2 时,查询被点赞的评论信息
      • 如果评论关联了帖子,同时获取帖子信息
  3. 数据组装

    • 构建 LikeMessageDto 对象,包含:
      • 消息基本信息
      • 发送者信息
      • 被点赞的内容信息(LikedContentDto包含内容类型、ID、帖子标题、评论内容等

3.10 GetFollowsMessages - 获取关注消息

功能描述:专门获取关注类型的消息列表。

业务逻辑流程

  1. 查询构建

    • 固定条件:ReceiverId == currentUserId AND MessageType == 3
    • 可选过滤:按已读状态过滤
  2. 关联数据查询

    • 关注者信息:查询关注当前用户的用户信息
  3. 数据组装

    • 构建 FollowMessageDto 对象,包含:
      • 消息基本信息
      • 关注者信息(FollowerInfoDto包含用户ID、昵称、头像、VIP状态、认证状态、个性签名等

四、系统通知的特殊机制

4.1 系统通知的双表设计

系统通知采用双表设计:

  • T_SystemNotifications:存储系统通知的原始数据(标题、内容、发布时间、过期时间等)
  • T_Messages:存储用户级别的消息记录(用于已读/未读状态管理)

4.2 系统通知的自动创建机制

当用户查询系统通知类型的消息时(MessageType == 4),系统会:

  1. 检查是否存在未创建消息记录的系统通知
  2. 查询条件:
    • 系统通知已发布(PublishTime <= 当前时间
    • 系统通知未过期(ExpireTime > 当前时间 OR ExpireTime IS NULL
    • 该用户尚未收到该通知的消息记录(通过 LEFT JOIN 判断)
  3. 自动为符合条件的系统通知创建消息记录
  4. 使用通知ID作为消息的 SenderId,便于关联

4.3 系统通知的查询方式

系统提供两种查询系统通知的方式:

  • GetSystemNotifications:从 T_SystemNotifications 表查询,返回所有系统通知(不区分用户)
  • GetMessages(MessageType=4):从 T_Messages 表查询,返回当前用户收到的系统通知(包含已读/未读状态)

五、消息类型与内容类型的关系

5.1 消息类型MessageType

类型值 类型名称 说明 SenderId ContentId
1 评论回复 用户回复了评论 回复者用户ID 评论ID
2 点赞 用户点赞了内容 点赞者用户ID 帖子ID或评论ID
3 关注 用户关注了当前用户 关注者用户ID
4 系统通知 系统发送的通知 通知ID或NULL 可选

5.2 内容类型ContentType

类型值 类型名称 说明 使用场景
1 帖子 关联的是帖子 点赞帖子、系统通知关联帖子
2 评论 关联的是评论 评论回复、点赞评论

5.3 消息类型与内容类型的组合

  • 评论回复MessageType=1ContentType=2ContentId=评论ID
  • 点赞MessageType=2ContentType=1或2ContentId=帖子ID或评论ID
  • 关注MessageType=3ContentType=0ContentId=null
  • 系统通知MessageType=4ContentType=0或1或2ContentId=可选

六、数据查询优化

6.1 批量查询优化

在获取消息列表时,采用批量查询优化:

  1. 先查询消息记录
  2. 收集所有需要关联的ID发送者ID、帖子ID、评论ID
  3. 批量查询关联数据
  4. 使用字典Dictionary存储提高查找效率
  5. 最后组装返回数据

6.2 分页查询

所有列表查询方法都支持分页:

  • PageIndex页码从1开始
  • PageSize:每页数量
  • 返回 Total(总记录数)和 TotalPages(总页数)

七、注意事项

  1. 系统通知的特殊性

    • 系统通知的 SenderId 可能为通知ID也可能为NULL
    • 查询系统通知时,不会查询发送者信息(用户信息)
  2. 已读状态管理

    • 所有消息默认 IsRead = false
    • 标记已读时会同时更新 ReadAt 时间戳
  3. 权限控制

    • 所有消息操作都验证 ReceiverId == currentUserId
    • 确保用户只能操作自己的消息
  4. 系统通知的时效性

    • 系统通知有发布时间(PublishTime)和过期时间(ExpireTime
    • 只有已发布且未过期的通知才会被自动创建消息记录
  5. 批量操作限制

    • 批量标记已读操作限制最多100条消息

八、待改造点

根据当前业务逻辑,以下方面可能需要改造:

  1. 系统消息扩展
    • 可向指定用户/类型用户发送站内信如节假日向认证用户发送。用户点击按钮在弹窗中填写收货地址并提交视为参与该活动此类活动有结束时间到期后按钮处于灰色不可点击状态。弹窗只展示联系方式和收获地址。用户表中有CertifiedType认证类型
    • 这个需求我们需要讨论一下,要怎么修改表结构。先把前面两个需求做了。

九、系统消息扩展需求分析

9.1 需求概述

系统需要支持活动类型的系统消息,具备以下特性:

  • 定向发送:可向指定用户或按用户类型(如认证类型)批量发送
  • 活动参与:用户可通过点击按钮参与活动,填写收货地址等信息
  • 时效控制:活动有结束时间,到期后用户无法参与
  • 数据展示:后台可查看用户的参与信息(联系方式、收货地址)

9.2 业务场景示例

场景:节假日向认证用户发送活动通知

  • 系统创建活动通知,设置目标用户类型为"认证用户"CertifiedType = 1 或 2
  • 符合条件的用户收到系统消息
  • 用户点击"参与活动"按钮,弹出表单
  • 用户填写收货地址、联系方式等信息并提交
  • 活动结束后,按钮变为灰色不可点击状态
  • 后台管理员可查看所有参与用户的收货信息

9.3 表结构设计分析

9.3.1 T_SystemNotifications 表扩展

需要在现有系统通知表基础上新增字段:

字段名 类型 说明 是否必填
NotificationType int 通知类型1-普通通知2-活动通知
TargetUserType int? 目标用户类型null-所有用户1-指定用户列表2-按认证类型筛选
TargetCertifiedType int? 目标认证类型1-SK认证2-其他认证当TargetUserType=2时使用
TargetUserIds string 目标用户ID列表JSON格式当TargetUserType=1时使用
ActivityEndTime DateTime? 活动结束时间当NotificationType=2时使用
IsActivity bool 是否为活动类型通知(是否需要用户参与) 默认false
ActivityButtonText string 活动按钮文本(如"参与活动"、"立即领取"等)

说明

  • NotificationType:区分普通通知和活动通知
  • TargetUserType:支持三种发送方式
    • null 或 0所有用户
    • 1指定用户列表通过TargetUserIds存储
    • 2按用户类型筛选通过TargetCertifiedType指定
  • IsActivity:标识是否为活动类型,决定是否显示参与按钮
  • ActivityEndTime:活动结束时间,用于前端判断按钮是否可点击

9.3.2 新建表T_SystemNotificationParticipants系统通知参与记录表

用于存储用户参与活动的信息:

字段名 类型 说明
Id long 主键,自增
NotificationId long 系统通知ID外键关联T_SystemNotifications
UserId long 用户ID外键关联T_Users
ContactInfo string 联系方式(电话/微信等)
ShippingAddress string 收货地址
ParticipantName string 收货人姓名(可选)
ParticipantPhone string 收货人电话(可选)
Status int 参与状态1-已提交2-已处理3-已发货等
SubmittedAt DateTime 提交时间
CreatedAt DateTime 创建时间
UpdatedAt DateTime 更新时间

说明

  • 一个用户对一个活动只能参与一次(通过 NotificationId + UserId 唯一约束)
  • 支持扩展参与状态,便于后续流程管理
  • 联系方式、收货地址等字段长度需要根据实际需求设定

9.4 业务逻辑流程

9.4.1 创建活动通知流程

  1. 管理员创建活动通知

    • 填写通知标题、内容
    • 选择通知类型为"活动通知"NotificationType = 2
    • 设置 IsActivity = true
    • 选择发送范围:
      • 所有用户TargetUserType = null
      • 指定用户TargetUserType = 1填写 TargetUserIdsJSON数组
      • 按类型筛选TargetUserType = 2选择 TargetCertifiedType
    • 设置活动结束时间ActivityEndTime
    • 设置活动按钮文本ActivityButtonText
    • 设置发布时间PublishTime
  2. 系统发送通知

    • 根据 TargetUserType 和 TargetCertifiedType 筛选目标用户
    • 为每个目标用户创建 T_Messages 记录MessageType = 4
    • 使用通知ID作为 SenderId

9.4.2 用户查看活动通知流程

  1. 用户查看消息列表

    • 调用 GetMessages(MessageType=4) 获取系统通知
    • 系统自动创建未创建的系统通知消息记录
  2. 前端展示判断

    • 检查通知的 IsActivity 字段
    • 如果为 true显示活动按钮
    • 检查 ActivityEndTime 是否已过期
    • 如果已过期,按钮置灰不可点击
    • 如果未过期,按钮可点击
  3. 检查用户是否已参与

    • 前端调用接口检查当前用户是否已参与该活动
    • 如果已参与,按钮显示"已参与"或隐藏按钮
    • 如果未参与且未过期,显示参与按钮

9.4.3 用户参与活动流程

  1. 用户点击参与按钮

    • 前端弹出表单(弹窗)
    • 表单字段:
      • 联系方式ContactInfo
      • 收货地址ShippingAddress
      • 提交按钮
  2. 用户提交表单

    • 前端调用参与活动接口
    • 后端验证:
      • 活动是否存在且有效
      • 活动是否已过期ActivityEndTime
      • 用户是否已参与过(防止重复提交)
      • 必填字段是否完整
  3. 保存参与记录

    • 在 T_SystemNotificationParticipants 表中创建记录
    • Status = 1已提交
    • 记录提交时间
  4. 返回结果

    • 成功:返回参与成功信息
    • 失败:返回具体错误原因

9.5 接口设计思路

9.5.1 创建活动通知接口(后台管理)暂不需要,后台有后台的项目,不在这个项目中处理

接口POST /api/SystemNotifications/CreateActivityNotification

请求参数

public class CreateActivityNotificationReq
{
    public string Title { get; set; }           // 通知标题
    public string Content { get; set; }         // 通知内容
    public int TargetUserType { get; set; }      // 目标用户类型0-所有1-指定用户2-按认证类型
    public int? TargetCertifiedType { get; set; } // 目标认证类型当TargetUserType=2时
    public List<long>? TargetUserIds { get; set; } // 目标用户ID列表当TargetUserType=1时
    public DateTime? PublishTime { get; set; }   // 发布时间
    public DateTime ActivityEndTime { get; set; } // 活动结束时间
    public string ActivityButtonText { get; set; } // 按钮文本
}

9.5.2 检查用户参与状态接口(用户参与状态应该是在系统消息接口返回的时候就应该带上这个状态的,因为没有消息详情,所以列表中就是全部消息内容)

接口GET /api/Messages/CheckActivityParticipated

请求参数

public class CheckActivityParticipatedReq
{
    public long NotificationId { get; set; }     // 通知ID
}

返回结果

public class CheckActivityParticipatedResp
{
    public bool IsParticipated { get; set; }      // 是否已参与
    public DateTime? SubmittedAt { get; set; }   // 参与时间(如果已参与)
}

9.5.3 参与活动接口

接口POST /api/Messages/ParticipateActivity

请求参数

public class ParticipateActivityReq
{
    public long NotificationId { get; set; }       // 通知ID
    public string ContactInfo { get; set; }       // 联系方式
    public string ShippingAddress { get; set; }   // 收货地址
}

9.6 前端展示逻辑

9.6.1 消息列表展示

  • 普通系统通知:正常显示标题、内容、时间
  • 活动通知:额外显示活动按钮(如果未过期且未参与)

9.6.2 活动按钮状态

  1. 可参与状态(绿色/正常)

    • 条件:IsActivity == true && ActivityEndTime > 当前时间 && 用户未参与
    • 显示:活动按钮文本(如"参与活动"
  2. 已过期状态(灰色/禁用)

    • 条件:ActivityEndTime <= 当前时间
    • 显示:按钮置灰,不可点击
  3. 已参与状态(隐藏或显示"已参与"

    • 条件:用户已参与该活动
    • 显示:隐藏按钮或显示"已参与"文字

9.6.3 参与表单弹窗

  • 表单字段:
    • 联系方式(必填)
    • 收货地址(必填)
  • 提交后:关闭弹窗,更新按钮状态

9.7 数据查询优化

9.7.1 系统通知创建时的用户筛选

EnsureSystemNotificationsCreated 方法中,需要根据通知的 TargetUserTypeTargetCertifiedType 筛选用户:

// 伪代码逻辑
if (notification.TargetUserType == 1) // 指定用户
{
    var userIds = JsonConvert.DeserializeObject<List<long>>(notification.TargetUserIds);
    // 只为这些用户创建消息
}
else if (notification.TargetUserType == 2) // 按认证类型
{
    // 查询符合认证类型的用户
    var users = _usersRepository.Select
        .Where(u => u.CertifiedType == notification.TargetCertifiedType)
        .ToList();
    // 为这些用户创建消息
}
else // 所有用户
{
    // 为所有用户创建消息
}

9.7.2 参与记录查询优化

  • 使用索引NotificationId + UserId 联合索引
  • 支持按状态筛选、按时间排序
  • 支持分页查询

9.8 注意事项

  1. 数据一致性

    • 确保活动通知创建时,目标用户的消息记录正确创建
    • 确保用户参与记录的唯一性(一个用户一个活动只能参与一次)
  2. 性能考虑

    • 如果目标用户数量很大(如所有用户),需要考虑批量创建消息的性能,所以我们采用被动式触发创建系统消息。当用户去访问了未读数量,或者系统消息列表接口时候,我们去查询处理一下新的消息接口。
  3. 安全性

    • 参与活动接口需要验证用户身份
    • 防止用户重复提交(通过数据库唯一约束)
    • 验证活动是否有效(未过期、已发布)
  4. 扩展性

    • 参与状态字段支持后续扩展(已处理、已发货等)暂不需要
    • 可以考虑支持更多筛选条件如VIP用户、等级用户等暂不需要

9.9 待确认问题

  1. 发送范围扩展

    • 是否支持更多筛选条件如VIP用户、等级范围等暂不需要
    • 是否支持组合条件?(如"SK认证且VIP用户")暂不需要
  2. 参与表单字段

    • 联系方式、收货地址的字段长度限制联系方式字符串限制100收获地址限制500
    • 是否需要其他字段?(如邮编、备注等)不需要
  3. 活动类型扩展

    • 是否只支持"填写收货地址"这一种活动类型?
    • 未来是否需要支持其他类型的活动?(如问卷调查、投票等)以后再扩展。
  4. 消息创建时机

    • 活动通知是否采用延迟创建机制,和正常系统通知一样。