message_repository.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package repository
  2. import (
  3. "errors"
  4. "time"
  5. "github.com/2930134478/AI-CS/backend/models"
  6. "gorm.io/gorm"
  7. )
  8. // MessageRepository 封装与消息相关的数据库操作。
  9. type MessageRepository struct {
  10. db *gorm.DB
  11. }
  12. // NewMessageRepository 创建消息仓库实例。
  13. func NewMessageRepository(db *gorm.DB) *MessageRepository {
  14. return &MessageRepository{db: db}
  15. }
  16. // Create 新建一条消息记录。
  17. func (r *MessageRepository) Create(message *models.Message) error {
  18. return r.db.Create(message).Error
  19. }
  20. // ListByConversationID 按时间顺序查询会话中的全部消息。
  21. func (r *MessageRepository) ListByConversationID(conversationID uint) ([]models.Message, error) {
  22. var messages []models.Message
  23. if err := r.db.Where("conversation_id = ?", conversationID).Order("created_at asc").Find(&messages).Error; err != nil {
  24. return nil, err
  25. }
  26. return messages, nil
  27. }
  28. // LatestByConversationID 查询会话中最新的一条消息。
  29. func (r *MessageRepository) LatestByConversationID(conversationID uint) (*models.Message, error) {
  30. var message models.Message
  31. if err := r.db.Where("conversation_id = ?", conversationID).
  32. Order("created_at desc").
  33. First(&message).Error; err != nil {
  34. if errors.Is(err, gorm.ErrRecordNotFound) {
  35. return nil, nil
  36. }
  37. return nil, err
  38. }
  39. return &message, nil
  40. }
  41. // GetByID 根据 ID 获取单条消息
  42. func (r *MessageRepository) GetByID(id uint) (*models.Message, error) {
  43. var message models.Message
  44. if err := r.db.First(&message, id).Error; err != nil {
  45. if errors.Is(err, gorm.ErrRecordNotFound) {
  46. return nil, nil
  47. }
  48. return nil, err
  49. }
  50. return &message, nil
  51. }
  52. // CountUnreadBySender 统计指定发送方的未读消息数量。
  53. func (r *MessageRepository) CountUnreadBySender(conversationID uint, senderIsAgent bool) (int64, error) {
  54. var count int64
  55. if err := r.db.Model(&models.Message{}).
  56. Where("conversation_id = ? AND sender_is_agent = ? AND is_read = ?", conversationID, senderIsAgent, false).
  57. Count(&count).Error; err != nil {
  58. return 0, err
  59. }
  60. return count, nil
  61. }
  62. // FindConversationIDsByContent 根据关键字查询包含该内容的会话 ID。
  63. func (r *MessageRepository) FindConversationIDsByContent(keyword string) ([]uint, error) {
  64. var ids []uint
  65. if err := r.db.Model(&models.Message{}).
  66. Where("content LIKE ?", keyword).
  67. Pluck("conversation_id", &ids).Error; err != nil {
  68. return nil, err
  69. }
  70. return ids, nil
  71. }
  72. // MarkMessagesRead 将指定发送方的未读消息标记为已读,并返回受影响的消息 ID 及时间。
  73. func (r *MessageRepository) MarkMessagesRead(conversationID uint, senderIsAgent bool) ([]uint, int64, time.Time, error) {
  74. var messageIDs []uint
  75. if err := r.db.Model(&models.Message{}).
  76. Where("conversation_id = ? AND sender_is_agent = ? AND is_read = ?", conversationID, senderIsAgent, false).
  77. Pluck("id", &messageIDs).Error; err != nil {
  78. return nil, 0, time.Time{}, err
  79. }
  80. if len(messageIDs) == 0 {
  81. return []uint{}, 0, time.Time{}, nil
  82. }
  83. now := time.Now()
  84. if err := r.db.Model(&models.Message{}).
  85. Where("id IN ?", messageIDs).
  86. Updates(map[string]interface{}{
  87. "is_read": true,
  88. "read_at": now,
  89. }).Error; err != nil {
  90. return nil, 0, time.Time{}, err
  91. }
  92. remaining, err := r.CountUnreadBySender(conversationID, senderIsAgent)
  93. if err != nil {
  94. return nil, 0, time.Time{}, nil
  95. }
  96. return messageIDs, remaining, now, nil
  97. }
  98. // HasAgentJoinMessage 检查该对话中是否已经存在该客服的加入消息。
  99. // 用于避免重复创建"xxx加入了会话"的系统消息。
  100. func (r *MessageRepository) HasAgentJoinMessage(conversationID uint, agentID uint, agentName string) (bool, error) {
  101. var count int64
  102. joinMessageContent := agentName + "加入了会话"
  103. if err := r.db.Model(&models.Message{}).
  104. Where("conversation_id = ? AND sender_id = ? AND sender_is_agent = ? AND message_type = ? AND content = ?",
  105. conversationID, agentID, true, "system_message", joinMessageContent).
  106. Count(&count).Error; err != nil {
  107. return false, err
  108. }
  109. return count > 0, nil
  110. }
  111. // HasVisitorMessageInHumanMode 检查对话中是否有访客在人工模式下发送的消息。
  112. // 用于判断对话是否应该显示在客服列表中。
  113. // 只有当 ChatMode == "human" 且存在访客发送的消息时,才应该显示。
  114. func (r *MessageRepository) HasVisitorMessageInHumanMode(conversationID uint) (bool, error) {
  115. var count int64
  116. // 查询是否有访客发送的消息(sender_is_agent = false)
  117. // 注意:这里不检查 ChatMode,因为 ChatMode 在 Conversation 表中
  118. // 这个方法只检查消息是否存在,ChatMode 的检查在 Service 层
  119. if err := r.db.Model(&models.Message{}).
  120. Where("conversation_id = ? AND sender_is_agent = ?", conversationID, false).
  121. Count(&count).Error; err != nil {
  122. return false, err
  123. }
  124. return count > 0, nil
  125. }
  126. // HasAgentParticipated 检查指定客服是否在指定会话中发送过消息。
  127. // 用于判断该会话是否应该出现在该客服的"My chats"列表中。
  128. func (r *MessageRepository) HasAgentParticipated(conversationID uint, agentID uint) (bool, error) {
  129. var count int64
  130. // 查询是否有该客服发送的消息(sender_is_agent = true AND sender_id = agentID)
  131. // 注意:系统消息(message_type = 'system_message')也应该算作参与
  132. // 所以不限制 message_type,包括所有类型的消息
  133. if err := r.db.Model(&models.Message{}).
  134. Where("conversation_id = ? AND sender_is_agent = ? AND sender_id = ?", conversationID, true, agentID).
  135. Count(&count).Error; err != nil {
  136. return false, err
  137. }
  138. return count > 0, nil
  139. }