Files
backend/internal/model/message.go
lan 4d8f2ec997 Initial backend repository commit.
Set up project files and add .gitignore to exclude local build/runtime artifacts.

Made-with: Cursor
2026-03-09 21:28:58 +08:00

206 lines
6.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"database/sql/driver"
"encoding/json"
"errors"
"strconv"
"time"
"gorm.io/gorm"
"carrot_bbs/internal/pkg/utils"
)
// 系统消息相关常量
const (
// SystemSenderID 系统消息发送者ID (类似QQ 10000)
SystemSenderID int64 = 10000
// SystemSenderIDStr 系统消息发送者ID字符串版本
SystemSenderIDStr string = "10000"
// SystemConversationID 系统通知会话ID (string类型)
SystemConversationID string = "9999999999"
)
// ContentType 消息内容类型
type ContentType string
const (
ContentTypeText ContentType = "text"
ContentTypeImage ContentType = "image"
ContentTypeVideo ContentType = "video"
ContentTypeAudio ContentType = "audio"
ContentTypeFile ContentType = "file"
)
// MessageStatus 消息状态
type MessageStatus string
const (
MessageStatusNormal MessageStatus = "normal" // 正常
MessageStatusRecalled MessageStatus = "recalled" // 已撤回
MessageStatusDeleted MessageStatus = "deleted" // 已删除
)
// MessageCategory 消息类别
type MessageCategory string
const (
CategoryChat MessageCategory = "chat" // 普通聊天
CategoryNotification MessageCategory = "notification" // 通知类消息
CategoryAnnouncement MessageCategory = "announcement" // 系统公告
CategoryMarketing MessageCategory = "marketing" // 营销消息
)
// SystemMessageType 系统消息类型 (对应原NotificationType)
type SystemMessageType string
const (
// 互动通知
SystemTypeLikePost SystemMessageType = "like_post" // 点赞帖子
SystemTypeLikeComment SystemMessageType = "like_comment" // 点赞评论
SystemTypeComment SystemMessageType = "comment" // 评论
SystemTypeReply SystemMessageType = "reply" // 回复
SystemTypeFollow SystemMessageType = "follow" // 关注
SystemTypeMention SystemMessageType = "mention" // @提及
// 系统消息
SystemTypeSystem SystemMessageType = "system" // 系统通知
SystemTypeAnnounce SystemMessageType = "announce" // 系统公告
)
// ExtraData 消息额外数据,用于存储系统消息的相关信息
type ExtraData struct {
// 操作者信息
ActorID int64 `json:"actor_id,omitempty"` // 操作者ID (数字格式,兼容旧数据)
ActorIDStr string `json:"actor_id_str,omitempty"` // 操作者ID (UUID字符串格式)
ActorName string `json:"actor_name,omitempty"` // 操作者名称
AvatarURL string `json:"avatar_url,omitempty"` // 操作者头像
// 目标信息
TargetID int64 `json:"target_id,omitempty"` // 目标ID帖子ID、评论ID等
TargetTitle string `json:"target_title,omitempty"` // 目标标题
TargetType string `json:"target_type,omitempty"` // 目标类型post/comment等
// 其他信息
ActionURL string `json:"action_url,omitempty"` // 跳转链接
ActionTime string `json:"action_time,omitempty"` // 操作时间
}
// Value 实现driver.Valuer接口用于数据库存储
func (e ExtraData) Value() (driver.Value, error) {
return json.Marshal(e)
}
// Scan 实现sql.Scanner接口用于数据库读取
func (e *ExtraData) Scan(value interface{}) error {
if value == nil {
return nil
}
bytes, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed")
}
return json.Unmarshal(bytes, e)
}
// MessageSegmentData 单个消息段的数据
type MessageSegmentData map[string]interface{}
// MessageSegment 消息段
type MessageSegment struct {
Type string `json:"type"`
Data MessageSegmentData `json:"data"`
}
// MessageSegments 消息链类型
type MessageSegments []MessageSegment
// Value 实现driver.Valuer接口用于数据库存储
func (s MessageSegments) Value() (driver.Value, error) {
return json.Marshal(s)
}
// Scan 实现sql.Scanner接口用于数据库读取
func (s *MessageSegments) Scan(value interface{}) error {
if value == nil {
*s = nil
return nil
}
bytes, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed")
}
return json.Unmarshal(bytes, s)
}
// Message 消息实体
// 使用雪花算法IDstring类型和seq机制实现消息排序和增量同步
type Message struct {
ID string `gorm:"primaryKey;size:20" json:"id"` // 雪花算法IDstring类型
ConversationID string `gorm:"not null;size:20;index:idx_msg_conversation_seq,priority:1" json:"conversation_id"` // 会话IDstring类型
SenderID string `gorm:"column:sender_id;type:varchar(50);index;not null" json:"sender_id"` // 发送者ID (UUID格式)
Seq int64 `gorm:"not null;index:idx_msg_conversation_seq,priority:2" json:"seq"` // 会话内序号,用于排序和增量同步
Segments MessageSegments `gorm:"type:json" json:"segments"` // 消息链(结构体数组)
ReplyToID *string `json:"reply_to_id,omitempty"` // 回复的消息IDstring类型
Status MessageStatus `gorm:"type:varchar(20);default:'normal'" json:"status"` // 消息状态
// 新增字段:消息分类和系统消息类型
Category MessageCategory `gorm:"type:varchar(20);default:'chat'" json:"category"` // 消息分类
SystemType SystemMessageType `gorm:"type:varchar(30)" json:"system_type,omitempty"` // 系统消息类型
ExtraData *ExtraData `gorm:"type:json" json:"extra_data,omitempty"` // 额外数据JSON格式
// @相关字段
MentionUsers string `gorm:"type:text" json:"mention_users"` // @的用户ID列表JSON数组
MentionAll bool `gorm:"default:false" json:"mention_all"` // 是否@所有人
// 软删除
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
// 时间戳
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
}
// SenderIDStr 返回发送者ID字符串保持兼容性
func (m *Message) SenderIDStr() string {
return m.SenderID
}
// BeforeCreate 创建前生成雪花算法ID
func (m *Message) BeforeCreate(tx *gorm.DB) error {
if m.ID == "" {
id, err := utils.GetSnowflake().GenerateID()
if err != nil {
return err
}
m.ID = strconv.FormatInt(id, 10)
}
return nil
}
func (Message) TableName() string {
return "messages"
}
// IsSystemMessage 判断是否为系统消息
func (m *Message) IsSystemMessage() bool {
return m.SenderID == SystemSenderIDStr || m.Category == CategoryNotification || m.Category == CategoryAnnouncement
}
// IsInteractionNotification 判断是否为互动通知
func (m *Message) IsInteractionNotification() bool {
if m.Category != CategoryNotification {
return false
}
switch m.SystemType {
case SystemTypeLikePost, SystemTypeLikeComment, SystemTypeComment,
SystemTypeReply, SystemTypeFollow, SystemTypeMention:
return true
default:
return false
}
}