feat: add announcement data models
Add announcement and read-tracking models with active/unread query helpers for the operations announcement system.
This commit is contained in:
parent
1de1cdb14f
commit
6a409b7724
92
model/announcement.go
Normal file
92
model/announcement.go
Normal file
@ -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)
|
||||
}
|
||||
33
model/announcement_read.go
Normal file
33
model/announcement_read.go
Normal file
@ -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"`
|
||||
}
|
||||
@ -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))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user