f
This commit is contained in:
137
internal/domains/article/entities/announcement.go
Normal file
137
internal/domains/article/entities/announcement.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// AnnouncementStatus 公告状态枚举
|
||||
type AnnouncementStatus string
|
||||
|
||||
const (
|
||||
AnnouncementStatusDraft AnnouncementStatus = "draft" // 草稿
|
||||
AnnouncementStatusPublished AnnouncementStatus = "published" // 已发布
|
||||
AnnouncementStatusArchived AnnouncementStatus = "archived" // 已归档
|
||||
)
|
||||
|
||||
// Announcement 公告聚合根
|
||||
// 用于对系统公告进行管理,支持发布、撤回、定时发布等功能
|
||||
type Announcement struct {
|
||||
// 基础标识
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"公告唯一标识"`
|
||||
Title string `gorm:"type:varchar(200);not null;index" json:"title" comment:"公告标题"`
|
||||
Content string `gorm:"type:text;not null" json:"content" comment:"公告内容"`
|
||||
Status AnnouncementStatus `gorm:"type:varchar(20);not null;default:'draft';index" json:"status" comment:"公告状态"`
|
||||
ScheduledAt *time.Time `gorm:"index" json:"scheduled_at" comment:"定时发布时间"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime;index" json:"created_at" comment:"创建时间"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at" comment:"更新时间"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-" comment:"软删除时间"`
|
||||
}
|
||||
|
||||
// TableName 指定表名
|
||||
func (Announcement) TableName() string {
|
||||
return "announcements"
|
||||
}
|
||||
|
||||
// BeforeCreate GORM钩子:创建前自动生成UUID
|
||||
func (a *Announcement) BeforeCreate(tx *gorm.DB) error {
|
||||
if a.ID == "" {
|
||||
a.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 实现 Entity 接口 - 提供统一的实体管理接口
|
||||
// GetID 获取实体唯一标识
|
||||
func (a *Announcement) GetID() string {
|
||||
return a.ID
|
||||
}
|
||||
|
||||
// GetCreatedAt 获取创建时间
|
||||
func (a *Announcement) GetCreatedAt() time.Time {
|
||||
return a.CreatedAt
|
||||
}
|
||||
|
||||
// GetUpdatedAt 获取更新时间
|
||||
func (a *Announcement) GetUpdatedAt() time.Time {
|
||||
return a.UpdatedAt
|
||||
}
|
||||
|
||||
// 验证公告信息
|
||||
func (a *Announcement) Validate() error {
|
||||
if a.Title == "" {
|
||||
return NewValidationError("公告标题不能为空")
|
||||
}
|
||||
if a.Content == "" {
|
||||
return NewValidationError("公告内容不能为空")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 发布公告
|
||||
func (a *Announcement) Publish() error {
|
||||
if a.Status == AnnouncementStatusPublished {
|
||||
return NewValidationError("公告已经是发布状态")
|
||||
}
|
||||
a.Status = AnnouncementStatusPublished
|
||||
now := time.Now()
|
||||
a.CreatedAt = now
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 撤回公告
|
||||
func (a *Announcement) Withdraw() error {
|
||||
if a.Status == AnnouncementStatusDraft {
|
||||
return NewValidationError("公告已经是草稿状态")
|
||||
}
|
||||
a.Status = AnnouncementStatusDraft
|
||||
now := time.Now()
|
||||
a.CreatedAt = now
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 定时发布公告
|
||||
func (a *Announcement) SchedulePublish(scheduledTime time.Time) error {
|
||||
if a.Status == AnnouncementStatusPublished {
|
||||
return NewValidationError("公告已经是发布状态")
|
||||
}
|
||||
a.Status = AnnouncementStatusDraft // 保持草稿状态,等待定时发布
|
||||
a.ScheduledAt = &scheduledTime
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 更新定时发布时间
|
||||
func (a *Announcement) UpdateSchedulePublish(scheduledTime time.Time) error {
|
||||
if a.Status == AnnouncementStatusPublished {
|
||||
return NewValidationError("公告已经是发布状态")
|
||||
}
|
||||
if scheduledTime.Before(time.Now()) {
|
||||
return NewValidationError("定时发布时间不能早于当前时间")
|
||||
}
|
||||
a.ScheduledAt = &scheduledTime
|
||||
return nil
|
||||
}
|
||||
|
||||
// CancelSchedulePublish 取消定时发布
|
||||
func (a *Announcement) CancelSchedulePublish() error {
|
||||
if a.Status == AnnouncementStatusPublished {
|
||||
return NewValidationError("公告已经是发布状态")
|
||||
}
|
||||
a.ScheduledAt = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsScheduled 判断是否已设置定时发布
|
||||
func (a *Announcement) IsScheduled() bool {
|
||||
return a.ScheduledAt != nil && a.Status == AnnouncementStatusDraft
|
||||
}
|
||||
|
||||
// GetScheduledTime 获取定时发布时间
|
||||
func (a *Announcement) GetScheduledTime() *time.Time {
|
||||
return a.ScheduledAt
|
||||
}
|
||||
221
internal/domains/article/entities/article.go
Normal file
221
internal/domains/article/entities/article.go
Normal file
@@ -0,0 +1,221 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ArticleStatus 文章状态枚举
|
||||
type ArticleStatus string
|
||||
|
||||
const (
|
||||
ArticleStatusDraft ArticleStatus = "draft" // 草稿
|
||||
ArticleStatusPublished ArticleStatus = "published" // 已发布
|
||||
ArticleStatusArchived ArticleStatus = "archived" // 已归档
|
||||
)
|
||||
|
||||
// Article 文章聚合根
|
||||
// 系统的核心内容实体,提供文章的完整生命周期管理
|
||||
// 支持草稿、发布、归档状态,实现Entity接口便于统一管理
|
||||
type Article struct {
|
||||
// 基础标识
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"文章唯一标识"`
|
||||
Title string `gorm:"type:varchar(200);not null" json:"title" comment:"文章标题"`
|
||||
Content string `gorm:"type:text;not null" json:"content" comment:"文章内容"`
|
||||
Summary string `gorm:"type:varchar(500)" json:"summary" comment:"文章摘要"`
|
||||
CoverImage string `gorm:"type:varchar(500)" json:"cover_image" comment:"封面图片"`
|
||||
|
||||
// 分类
|
||||
CategoryID string `gorm:"type:varchar(36)" json:"category_id" comment:"分类ID"`
|
||||
|
||||
// 状态管理
|
||||
Status ArticleStatus `gorm:"type:varchar(20);not null;default:'draft'" json:"status" comment:"文章状态"`
|
||||
IsFeatured bool `gorm:"default:false" json:"is_featured" comment:"是否推荐"`
|
||||
PublishedAt *time.Time `json:"published_at" comment:"发布时间"`
|
||||
ScheduledAt *time.Time `json:"scheduled_at" comment:"定时发布时间"`
|
||||
|
||||
// 统计信息
|
||||
ViewCount int `gorm:"default:0" json:"view_count" comment:"阅读量"`
|
||||
|
||||
// 时间戳字段
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at" comment:"创建时间"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at" comment:"更新时间"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-" comment:"软删除时间"`
|
||||
|
||||
// 关联关系
|
||||
Category *Category `gorm:"foreignKey:CategoryID" json:"category,omitempty" comment:"分类信息"`
|
||||
Tags []Tag `gorm:"many2many:article_tag_relations;" json:"tags,omitempty" comment:"标签列表"`
|
||||
|
||||
// 领域事件 (不持久化)
|
||||
domainEvents []interface{} `gorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
// TableName 指定表名
|
||||
func (Article) TableName() string {
|
||||
return "articles"
|
||||
}
|
||||
|
||||
// BeforeCreate GORM钩子:创建前自动生成UUID
|
||||
func (a *Article) BeforeCreate(tx *gorm.DB) error {
|
||||
if a.ID == "" {
|
||||
a.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 实现 Entity 接口 - 提供统一的实体管理接口
|
||||
// GetID 获取实体唯一标识
|
||||
func (a *Article) GetID() string {
|
||||
return a.ID
|
||||
}
|
||||
|
||||
// GetCreatedAt 获取创建时间
|
||||
func (a *Article) GetCreatedAt() time.Time {
|
||||
return a.CreatedAt
|
||||
}
|
||||
|
||||
// GetUpdatedAt 获取更新时间
|
||||
func (a *Article) GetUpdatedAt() time.Time {
|
||||
return a.UpdatedAt
|
||||
}
|
||||
|
||||
// Validate 验证文章信息
|
||||
// 检查文章必填字段是否完整,确保数据的有效性
|
||||
func (a *Article) Validate() error {
|
||||
if a.Title == "" {
|
||||
return NewValidationError("文章标题不能为空")
|
||||
}
|
||||
if a.Content == "" {
|
||||
return NewValidationError("文章内容不能为空")
|
||||
}
|
||||
|
||||
// 验证标题长度
|
||||
if len(a.Title) > 200 {
|
||||
return NewValidationError("文章标题不能超过200个字符")
|
||||
}
|
||||
|
||||
// 验证摘要长度
|
||||
if a.Summary != "" && len(a.Summary) > 500 {
|
||||
return NewValidationError("文章摘要不能超过500个字符")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Publish 发布文章
|
||||
func (a *Article) Publish() error {
|
||||
if a.Status == ArticleStatusPublished {
|
||||
return NewValidationError("文章已经是发布状态")
|
||||
}
|
||||
|
||||
a.Status = ArticleStatusPublished
|
||||
now := time.Now()
|
||||
a.PublishedAt = &now
|
||||
a.ScheduledAt = nil // 清除定时发布时间
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SchedulePublish 定时发布文章
|
||||
func (a *Article) SchedulePublish(scheduledTime time.Time) error {
|
||||
if a.Status == ArticleStatusPublished {
|
||||
return NewValidationError("文章已经是发布状态")
|
||||
}
|
||||
|
||||
if scheduledTime.Before(time.Now()) {
|
||||
return NewValidationError("定时发布时间不能早于当前时间")
|
||||
}
|
||||
|
||||
a.Status = ArticleStatusDraft // 保持草稿状态,等待定时发布
|
||||
a.ScheduledAt = &scheduledTime
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateSchedulePublish 更新定时发布时间
|
||||
func (a *Article) UpdateSchedulePublish(scheduledTime time.Time) error {
|
||||
if a.Status == ArticleStatusPublished {
|
||||
return NewValidationError("文章已经是发布状态")
|
||||
}
|
||||
|
||||
if scheduledTime.Before(time.Now()) {
|
||||
return NewValidationError("定时发布时间不能早于当前时间")
|
||||
}
|
||||
|
||||
a.ScheduledAt = &scheduledTime
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CancelSchedulePublish 取消定时发布
|
||||
func (a *Article) CancelSchedulePublish() error {
|
||||
if a.Status == ArticleStatusPublished {
|
||||
return NewValidationError("文章已经是发布状态")
|
||||
}
|
||||
|
||||
a.ScheduledAt = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsScheduled 判断是否已设置定时发布
|
||||
func (a *Article) IsScheduled() bool {
|
||||
return a.ScheduledAt != nil && a.Status == ArticleStatusDraft
|
||||
}
|
||||
|
||||
// GetScheduledTime 获取定时发布时间
|
||||
func (a *Article) GetScheduledTime() *time.Time {
|
||||
return a.ScheduledAt
|
||||
}
|
||||
|
||||
// Archive 归档文章
|
||||
func (a *Article) Archive() error {
|
||||
if a.Status == ArticleStatusArchived {
|
||||
return NewValidationError("文章已经是归档状态")
|
||||
}
|
||||
|
||||
a.Status = ArticleStatusArchived
|
||||
return nil
|
||||
}
|
||||
|
||||
// IncrementViewCount 增加阅读量
|
||||
func (a *Article) IncrementViewCount() {
|
||||
a.ViewCount++
|
||||
}
|
||||
|
||||
// SetFeatured 设置推荐状态
|
||||
func (a *Article) SetFeatured(featured bool) {
|
||||
a.IsFeatured = featured
|
||||
}
|
||||
|
||||
// IsPublished 判断是否已发布
|
||||
func (a *Article) IsPublished() bool {
|
||||
return a.Status == ArticleStatusPublished
|
||||
}
|
||||
|
||||
// IsDraft 判断是否为草稿
|
||||
func (a *Article) IsDraft() bool {
|
||||
return a.Status == ArticleStatusDraft
|
||||
}
|
||||
|
||||
// IsArchived 判断是否已归档
|
||||
func (a *Article) IsArchived() bool {
|
||||
return a.Status == ArticleStatusArchived
|
||||
}
|
||||
|
||||
// CanEdit 判断是否可以编辑
|
||||
func (a *Article) CanEdit() bool {
|
||||
return a.Status == ArticleStatusDraft
|
||||
}
|
||||
|
||||
// CanPublish 判断是否可以发布
|
||||
func (a *Article) CanPublish() bool {
|
||||
return a.Status == ArticleStatusDraft
|
||||
}
|
||||
|
||||
// CanArchive 判断是否可以归档
|
||||
func (a *Article) CanArchive() bool {
|
||||
return a.Status == ArticleStatusPublished
|
||||
}
|
||||
78
internal/domains/article/entities/category.go
Normal file
78
internal/domains/article/entities/category.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Category 文章分类实体
|
||||
// 用于对文章进行分类管理,支持层级结构和排序
|
||||
type Category struct {
|
||||
// 基础标识
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"分类唯一标识"`
|
||||
Name string `gorm:"type:varchar(100);not null" json:"name" comment:"分类名称"`
|
||||
Description string `gorm:"type:text" json:"description" comment:"分类描述"`
|
||||
SortOrder int `gorm:"default:0" json:"sort_order" comment:"排序"`
|
||||
|
||||
// 时间戳字段
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at" comment:"创建时间"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at" comment:"更新时间"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-" comment:"软删除时间"`
|
||||
|
||||
// 关联关系
|
||||
Articles []Article `gorm:"foreignKey:CategoryID" json:"articles,omitempty" comment:"分类下的文章"`
|
||||
|
||||
// 领域事件 (不持久化)
|
||||
domainEvents []interface{} `gorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
// TableName 指定表名
|
||||
func (Category) TableName() string {
|
||||
return "article_categories"
|
||||
}
|
||||
|
||||
// BeforeCreate GORM钩子:创建前自动生成UUID
|
||||
func (c *Category) BeforeCreate(tx *gorm.DB) error {
|
||||
if c.ID == "" {
|
||||
c.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 实现 Entity 接口 - 提供统一的实体管理接口
|
||||
// GetID 获取实体唯一标识
|
||||
func (c *Category) GetID() string {
|
||||
return c.ID
|
||||
}
|
||||
|
||||
// GetCreatedAt 获取创建时间
|
||||
func (c *Category) GetCreatedAt() time.Time {
|
||||
return c.CreatedAt
|
||||
}
|
||||
|
||||
// GetUpdatedAt 获取更新时间
|
||||
func (c *Category) GetUpdatedAt() time.Time {
|
||||
return c.UpdatedAt
|
||||
}
|
||||
|
||||
// Validate 验证分类信息
|
||||
// 检查分类必填字段是否完整,确保数据的有效性
|
||||
func (c *Category) Validate() error {
|
||||
if c.Name == "" {
|
||||
return NewValidationError("分类名称不能为空")
|
||||
}
|
||||
|
||||
// 验证名称长度
|
||||
if len(c.Name) > 100 {
|
||||
return NewValidationError("分类名称不能超过100个字符")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetSortOrder 设置排序
|
||||
func (c *Category) SetSortOrder(order int) {
|
||||
c.SortOrder = order
|
||||
}
|
||||
21
internal/domains/article/entities/errors.go
Normal file
21
internal/domains/article/entities/errors.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package entities
|
||||
|
||||
// ValidationError 验证错误
|
||||
type ValidationError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *ValidationError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
// NewValidationError 创建验证错误
|
||||
func NewValidationError(message string) *ValidationError {
|
||||
return &ValidationError{Message: message}
|
||||
}
|
||||
|
||||
// IsValidationError 判断是否为验证错误
|
||||
func IsValidationError(err error) bool {
|
||||
_, ok := err.(*ValidationError)
|
||||
return ok
|
||||
}
|
||||
113
internal/domains/article/entities/scheduled_task.go
Normal file
113
internal/domains/article/entities/scheduled_task.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// TaskStatus 任务状态枚举
|
||||
type TaskStatus string
|
||||
|
||||
const (
|
||||
TaskStatusPending TaskStatus = "pending" // 等待执行
|
||||
TaskStatusRunning TaskStatus = "running" // 正在执行
|
||||
TaskStatusCompleted TaskStatus = "completed" // 已完成
|
||||
TaskStatusFailed TaskStatus = "failed" // 执行失败
|
||||
TaskStatusCancelled TaskStatus = "cancelled" // 已取消
|
||||
)
|
||||
|
||||
// ScheduledTask 定时任务状态管理实体
|
||||
type ScheduledTask struct {
|
||||
// 基础标识
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"任务唯一标识"`
|
||||
TaskID string `gorm:"type:varchar(100);not null;uniqueIndex" json:"task_id" comment:"Asynq任务ID"`
|
||||
TaskType string `gorm:"type:varchar(50);not null" json:"task_type" comment:"任务类型"`
|
||||
|
||||
// 关联信息
|
||||
ArticleID string `gorm:"type:varchar(36);not null;index" json:"article_id" comment:"关联的文章ID"`
|
||||
|
||||
// 任务状态
|
||||
Status TaskStatus `gorm:"type:varchar(20);not null;default:'pending'" json:"status" comment:"任务状态"`
|
||||
|
||||
// 时间信息
|
||||
ScheduledAt time.Time `gorm:"not null" json:"scheduled_at" comment:"计划执行时间"`
|
||||
StartedAt *time.Time `json:"started_at" comment:"开始执行时间"`
|
||||
CompletedAt *time.Time `json:"completed_at" comment:"完成时间"`
|
||||
|
||||
// 执行结果
|
||||
Error string `gorm:"type:text" json:"error" comment:"错误信息"`
|
||||
RetryCount int `gorm:"default:0" json:"retry_count" comment:"重试次数"`
|
||||
|
||||
// 时间戳字段
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at" comment:"创建时间"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at" comment:"更新时间"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-" comment:"软删除时间"`
|
||||
|
||||
// 关联关系
|
||||
Article *Article `gorm:"foreignKey:ArticleID" json:"article,omitempty" comment:"关联的文章"`
|
||||
}
|
||||
|
||||
// TableName 指定表名
|
||||
func (ScheduledTask) TableName() string {
|
||||
return "scheduled_tasks"
|
||||
}
|
||||
|
||||
// BeforeCreate GORM钩子:创建前自动生成UUID
|
||||
func (st *ScheduledTask) BeforeCreate(tx *gorm.DB) error {
|
||||
if st.ID == "" {
|
||||
st.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarkAsRunning 标记任务为正在执行
|
||||
func (st *ScheduledTask) MarkAsRunning() {
|
||||
st.Status = TaskStatusRunning
|
||||
now := time.Now()
|
||||
st.StartedAt = &now
|
||||
}
|
||||
|
||||
// MarkAsCompleted 标记任务为已完成
|
||||
func (st *ScheduledTask) MarkAsCompleted() {
|
||||
st.Status = TaskStatusCompleted
|
||||
now := time.Now()
|
||||
st.CompletedAt = &now
|
||||
}
|
||||
|
||||
// MarkAsFailed 标记任务为执行失败
|
||||
func (st *ScheduledTask) MarkAsFailed(errorMsg string) {
|
||||
st.Status = TaskStatusFailed
|
||||
now := time.Now()
|
||||
st.CompletedAt = &now
|
||||
st.Error = errorMsg
|
||||
st.RetryCount++
|
||||
}
|
||||
|
||||
// MarkAsCancelled 标记任务为已取消
|
||||
func (st *ScheduledTask) MarkAsCancelled() {
|
||||
st.Status = TaskStatusCancelled
|
||||
now := time.Now()
|
||||
st.CompletedAt = &now
|
||||
}
|
||||
|
||||
// IsActive 判断任务是否处于活动状态
|
||||
func (st *ScheduledTask) IsActive() bool {
|
||||
return st.Status == TaskStatusPending || st.Status == TaskStatusRunning
|
||||
}
|
||||
|
||||
// IsCancelled 判断任务是否已取消
|
||||
func (st *ScheduledTask) IsCancelled() bool {
|
||||
return st.Status == TaskStatusCancelled
|
||||
}
|
||||
|
||||
// IsCompleted 判断任务是否已完成
|
||||
func (st *ScheduledTask) IsCompleted() bool {
|
||||
return st.Status == TaskStatusCompleted
|
||||
}
|
||||
|
||||
// IsFailed 判断任务是否执行失败
|
||||
func (st *ScheduledTask) IsFailed() bool {
|
||||
return st.Status == TaskStatusFailed
|
||||
}
|
||||
102
internal/domains/article/entities/tag.go
Normal file
102
internal/domains/article/entities/tag.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Tag 文章标签实体
|
||||
// 用于对文章进行标签化管理,支持颜色配置
|
||||
type Tag struct {
|
||||
// 基础标识
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"标签唯一标识"`
|
||||
Name string `gorm:"type:varchar(50);not null" json:"name" comment:"标签名称"`
|
||||
Color string `gorm:"type:varchar(20);default:'#1890ff'" json:"color" comment:"标签颜色"`
|
||||
|
||||
// 时间戳字段
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at" comment:"创建时间"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at" comment:"更新时间"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-" comment:"软删除时间"`
|
||||
|
||||
// 关联关系
|
||||
Articles []Article `gorm:"many2many:article_tag_relations;" json:"articles,omitempty" comment:"标签下的文章"`
|
||||
|
||||
// 领域事件 (不持久化)
|
||||
domainEvents []interface{} `gorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
// TableName 指定表名
|
||||
func (Tag) TableName() string {
|
||||
return "article_tags"
|
||||
}
|
||||
|
||||
// BeforeCreate GORM钩子:创建前自动生成UUID
|
||||
func (t *Tag) BeforeCreate(tx *gorm.DB) error {
|
||||
if t.ID == "" {
|
||||
t.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 实现 Entity 接口 - 提供统一的实体管理接口
|
||||
// GetID 获取实体唯一标识
|
||||
func (t *Tag) GetID() string {
|
||||
return t.ID
|
||||
}
|
||||
|
||||
// GetCreatedAt 获取创建时间
|
||||
func (t *Tag) GetCreatedAt() time.Time {
|
||||
return t.CreatedAt
|
||||
}
|
||||
|
||||
// GetUpdatedAt 获取更新时间
|
||||
func (t *Tag) GetUpdatedAt() time.Time {
|
||||
return t.UpdatedAt
|
||||
}
|
||||
|
||||
// Validate 验证标签信息
|
||||
// 检查标签必填字段是否完整,确保数据的有效性
|
||||
func (t *Tag) Validate() error {
|
||||
if t.Name == "" {
|
||||
return NewValidationError("标签名称不能为空")
|
||||
}
|
||||
|
||||
// 验证名称长度
|
||||
if len(t.Name) > 50 {
|
||||
return NewValidationError("标签名称不能超过50个字符")
|
||||
}
|
||||
|
||||
// 验证颜色格式
|
||||
if t.Color != "" && !isValidColor(t.Color) {
|
||||
return NewValidationError("标签颜色格式无效")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetColor 设置标签颜色
|
||||
func (t *Tag) SetColor(color string) error {
|
||||
if color != "" && !isValidColor(color) {
|
||||
return NewValidationError("标签颜色格式无效")
|
||||
}
|
||||
t.Color = color
|
||||
return nil
|
||||
}
|
||||
|
||||
// isValidColor 验证颜色格式
|
||||
func isValidColor(color string) bool {
|
||||
// 简单的颜色格式验证,支持 #RRGGBB 格式
|
||||
if len(color) == 7 && color[0] == '#' {
|
||||
for i := 1; i < 7; i++ {
|
||||
if !((color[i] >= '0' && color[i] <= '9') ||
|
||||
(color[i] >= 'a' && color[i] <= 'f') ||
|
||||
(color[i] >= 'A' && color[i] <= 'F')) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user