diff --git a/model/announcement.go b/model/announcement.go new file mode 100644 index 00000000..62b1dc2d --- /dev/null +++ b/model/announcement.go @@ -0,0 +1,92 @@ +package model + +import ( + "time" + + "gorm.io/gorm" +) + +type Announcement struct { + Id int `json:"id" gorm:"primaryKey;autoIncrement"` + Title string `json:"title" gorm:"type:varchar(255);not null"` + Content string `json:"content" gorm:"type:text;not null"` + ContentHtml string `json:"content_html" gorm:"type:text"` + Status string `json:"status" gorm:"type:varchar(16);not null;default:'draft';index"` + NotifyMode string `json:"notify_mode" gorm:"type:varchar(16);not null;default:'silent'"` + JsonRules string `json:"json_rules" gorm:"type:text"` + StartsAt *time.Time `json:"starts_at" gorm:"index"` + EndsAt *time.Time `json:"ends_at" gorm:"index"` + CreatedBy int `json:"created_by" gorm:"not null;default:0"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +func (Announcement) TableName() string { + return "announcements" +} + +func (a *Announcement) Insert() error { + return DB.Create(a).Error +} + +func (a *Announcement) Update() error { + return DB.Save(a).Error +} + +func GetAnnouncementByID(id int) (*Announcement, error) { + var announcement Announcement + err := DB.First(&announcement, "id = ?", id).Error + return &announcement, err +} + +func GetAnnouncements(page int, pageSize int, status string) ([]Announcement, int64, error) { + var announcements []Announcement + var total int64 + query := DB.Model(&Announcement{}) + if status != "" { + query = query.Where("status = ?", status) + } + if err := query.Count(&total).Error; err != nil { + return nil, 0, err + } + if page < 1 { + page = 1 + } + if pageSize < 1 { + pageSize = 20 + } + err := query.Order("id DESC").Offset((page - 1) * pageSize).Limit(pageSize).Find(&announcements).Error + return announcements, total, err +} + +func GetActiveAnnouncements() ([]Announcement, error) { + var announcements []Announcement + err := activeAnnouncementQuery(). + Order("id DESC"). + Find(&announcements).Error + return announcements, err +} + +func GetUnreadAnnouncements(userId int) ([]Announcement, error) { + var announcements []Announcement + readSubQuery := DB.Model(&AnnouncementRead{}). + Select("announcement_id"). + Where("user_id = ?", userId) + err := activeAnnouncementQuery(). + Where("id NOT IN (?)", readSubQuery). + Order("id DESC"). + Find(&announcements).Error + return announcements, err +} + +func DeleteAnnouncementByID(id int) error { + return DB.Delete(&Announcement{}, id).Error +} + +func activeAnnouncementQuery() *gorm.DB { + now := time.Now() + return DB.Model(&Announcement{}). + Where("status = ?", "active"). + Where("(starts_at IS NULL OR starts_at <= ?)", now). + Where("(ends_at IS NULL OR ends_at >= ?)", now) +} diff --git a/model/announcement_read.go b/model/announcement_read.go new file mode 100644 index 00000000..b7e2037c --- /dev/null +++ b/model/announcement_read.go @@ -0,0 +1,33 @@ +package model + +import "time" + +type AnnouncementRead struct { + Id int `json:"id" gorm:"primaryKey;autoIncrement"` + AnnouncementId int `json:"announcement_id" gorm:"not null;index:idx_announcement_read_user,unique"` + UserId int `json:"user_id" gorm:"not null;index:idx_announcement_read_user,unique"` + ReadAt time.Time `json:"read_at" gorm:"not null"` +} + +func (AnnouncementRead) TableName() string { + return "announcement_reads" +} + +func (r *AnnouncementRead) Insert() error { + return DB.Create(r).Error +} + +func IsAnnouncementRead(announcementId int, userId int) (bool, error) { + var count int64 + err := DB.Model(&AnnouncementRead{}). + Where("announcement_id = ? AND user_id = ?", announcementId, userId). + Count(&count).Error + return count > 0, err +} + +type AnnouncementReadStatus struct { + UserId int `json:"user_id"` + Username string `json:"username"` + ReadAt *time.Time `json:"read_at"` + IsRead bool `json:"is_read"` +} diff --git a/model/main.go b/model/main.go index 815e1bff..2e554302 100644 --- a/model/main.go +++ b/model/main.go @@ -283,6 +283,8 @@ func migrateDB() error { &PerfMetric{}, &PromoCode{}, &PromoCodeUsage{}, + &Announcement{}, + &AnnouncementRead{}, ) if err != nil { return err @@ -334,6 +336,8 @@ func migrateDBFast() error { {&PerfMetric{}, "PerfMetric"}, {&PromoCode{}, "PromoCode"}, {&PromoCodeUsage{}, "PromoCodeUsage"}, + {&Announcement{}, "Announcement"}, + {&AnnouncementRead{}, "AnnouncementRead"}, } // 动态计算migration数量,确保errChan缓冲区足够大 errChan := make(chan error, len(migrations))