344 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			344 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package entities
 | ||
| 
 | ||
| import (
 | ||
| 	"errors"
 | ||
| 	"time"
 | ||
| 
 | ||
| 	"github.com/google/uuid"
 | ||
| 	"gorm.io/gorm"
 | ||
| )
 | ||
| 
 | ||
| // StatisticsReport 统计报告实体
 | ||
| // 用于存储生成的统计报告数据
 | ||
| type StatisticsReport struct {
 | ||
| 	// 基础标识
 | ||
| 	ID         string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"报告唯一标识"`
 | ||
| 	ReportType string `gorm:"type:varchar(50);not null;index" json:"report_type" comment:"报告类型"`
 | ||
| 	Title      string `gorm:"type:varchar(200);not null" json:"title" comment:"报告标题"`
 | ||
| 	Content    string `gorm:"type:json" json:"content" comment:"报告内容"`
 | ||
| 	Period     string `gorm:"type:varchar(20)" json:"period" comment:"统计周期"`
 | ||
| 	UserRole   string `gorm:"type:varchar(20)" json:"user_role" comment:"用户角色"`
 | ||
| 	Status     string `gorm:"type:varchar(20);default:'draft'" json:"status" comment:"报告状态"`
 | ||
| 
 | ||
| 	// 报告元数据
 | ||
| 	GeneratedBy string     `gorm:"type:varchar(36)" json:"generated_by" comment:"生成者ID"`
 | ||
| 	GeneratedAt *time.Time `json:"generated_at" comment:"生成时间"`
 | ||
| 	ExpiresAt   *time.Time `json:"expires_at" 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:"软删除时间"`
 | ||
| 
 | ||
| 	// 领域事件 (不持久化)
 | ||
| 	domainEvents []interface{} `gorm:"-" json:"-"`
 | ||
| }
 | ||
| 
 | ||
| // TableName 指定数据库表名
 | ||
| func (StatisticsReport) TableName() string {
 | ||
| 	return "statistics_reports"
 | ||
| }
 | ||
| 
 | ||
| // BeforeCreate GORM钩子:创建前自动生成UUID
 | ||
| func (s *StatisticsReport) BeforeCreate(tx *gorm.DB) error {
 | ||
| 	if s.ID == "" {
 | ||
| 		s.ID = uuid.New().String()
 | ||
| 	}
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // 实现 Entity 接口 - 提供统一的实体管理接口
 | ||
| // GetID 获取实体唯一标识
 | ||
| func (s *StatisticsReport) GetID() string {
 | ||
| 	return s.ID
 | ||
| }
 | ||
| 
 | ||
| // GetCreatedAt 获取创建时间
 | ||
| func (s *StatisticsReport) GetCreatedAt() time.Time {
 | ||
| 	return s.CreatedAt
 | ||
| }
 | ||
| 
 | ||
| // GetUpdatedAt 获取更新时间
 | ||
| func (s *StatisticsReport) GetUpdatedAt() time.Time {
 | ||
| 	return s.UpdatedAt
 | ||
| }
 | ||
| 
 | ||
| // Validate 验证统计报告信息
 | ||
| // 检查统计报告必填字段是否完整,确保数据的有效性
 | ||
| func (s *StatisticsReport) Validate() error {
 | ||
| 	if s.ReportType == "" {
 | ||
| 		return NewValidationError("报告类型不能为空")
 | ||
| 	}
 | ||
| 	if s.Title == "" {
 | ||
| 		return NewValidationError("报告标题不能为空")
 | ||
| 	}
 | ||
| 	if s.Period == "" {
 | ||
| 		return NewValidationError("统计周期不能为空")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 验证报告类型
 | ||
| 	if !s.IsValidReportType() {
 | ||
| 		return NewValidationError("无效的报告类型")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 验证报告状态
 | ||
| 	if !s.IsValidStatus() {
 | ||
| 		return NewValidationError("无效的报告状态")
 | ||
| 	}
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // IsValidReportType 检查报告类型是否有效
 | ||
| func (s *StatisticsReport) IsValidReportType() bool {
 | ||
| 	validTypes := []string{
 | ||
| 		"dashboard",  // 仪表板报告
 | ||
| 		"summary",    // 汇总报告
 | ||
| 		"detailed",   // 详细报告
 | ||
| 		"custom",     // 自定义报告
 | ||
| 	}
 | ||
| 
 | ||
| 	for _, validType := range validTypes {
 | ||
| 		if s.ReportType == validType {
 | ||
| 			return true
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return false
 | ||
| }
 | ||
| 
 | ||
| // IsValidStatus 检查报告状态是否有效
 | ||
| func (s *StatisticsReport) IsValidStatus() bool {
 | ||
| 	validStatuses := []string{
 | ||
| 		"draft",     // 草稿
 | ||
| 		"generating", // 生成中
 | ||
| 		"completed", // 已完成
 | ||
| 		"failed",    // 生成失败
 | ||
| 		"expired",   // 已过期
 | ||
| 	}
 | ||
| 
 | ||
| 	for _, validStatus := range validStatuses {
 | ||
| 		if s.Status == validStatus {
 | ||
| 			return true
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return false
 | ||
| }
 | ||
| 
 | ||
| // GetReportTypeName 获取报告类型的中文名称
 | ||
| func (s *StatisticsReport) GetReportTypeName() string {
 | ||
| 	typeNames := map[string]string{
 | ||
| 		"dashboard": "仪表板报告",
 | ||
| 		"summary":   "汇总报告",
 | ||
| 		"detailed":  "详细报告",
 | ||
| 		"custom":    "自定义报告",
 | ||
| 	}
 | ||
| 
 | ||
| 	if name, exists := typeNames[s.ReportType]; exists {
 | ||
| 		return name
 | ||
| 	}
 | ||
| 	return s.ReportType
 | ||
| }
 | ||
| 
 | ||
| // GetStatusName 获取报告状态的中文名称
 | ||
| func (s *StatisticsReport) GetStatusName() string {
 | ||
| 	statusNames := map[string]string{
 | ||
| 		"draft":      "草稿",
 | ||
| 		"generating": "生成中",
 | ||
| 		"completed":  "已完成",
 | ||
| 		"failed":     "生成失败",
 | ||
| 		"expired":    "已过期",
 | ||
| 	}
 | ||
| 
 | ||
| 	if name, exists := statusNames[s.Status]; exists {
 | ||
| 		return name
 | ||
| 	}
 | ||
| 	return s.Status
 | ||
| }
 | ||
| 
 | ||
| // NewStatisticsReport 工厂方法 - 创建统计报告
 | ||
| func NewStatisticsReport(reportType, title, period, userRole string) (*StatisticsReport, error) {
 | ||
| 	if reportType == "" {
 | ||
| 		return nil, errors.New("报告类型不能为空")
 | ||
| 	}
 | ||
| 	if title == "" {
 | ||
| 		return nil, errors.New("报告标题不能为空")
 | ||
| 	}
 | ||
| 	if period == "" {
 | ||
| 		return nil, errors.New("统计周期不能为空")
 | ||
| 	}
 | ||
| 
 | ||
| 	report := &StatisticsReport{
 | ||
| 		ReportType: reportType,
 | ||
| 		Title:      title,
 | ||
| 		Period:     period,
 | ||
| 		UserRole:   userRole,
 | ||
| 		Status:     "draft",
 | ||
| 		domainEvents: make([]interface{}, 0),
 | ||
| 	}
 | ||
| 
 | ||
| 	// 验证报告
 | ||
| 	if err := report.Validate(); err != nil {
 | ||
| 		return nil, err
 | ||
| 	}
 | ||
| 
 | ||
| 	// 添加领域事件
 | ||
| 	report.addDomainEvent(&StatisticsReportCreatedEvent{
 | ||
| 		ReportID:   report.ID,
 | ||
| 		ReportType: reportType,
 | ||
| 		Title:      title,
 | ||
| 		Period:     period,
 | ||
| 		CreatedAt:  time.Now(),
 | ||
| 	})
 | ||
| 
 | ||
| 	return report, nil
 | ||
| }
 | ||
| 
 | ||
| // StartGeneration 开始生成报告
 | ||
| func (s *StatisticsReport) StartGeneration(generatedBy string) error {
 | ||
| 	if s.Status != "draft" {
 | ||
| 		return NewValidationError("只有草稿状态的报告才能开始生成")
 | ||
| 	}
 | ||
| 
 | ||
| 	s.Status = "generating"
 | ||
| 	s.GeneratedBy = generatedBy
 | ||
| 	now := time.Now()
 | ||
| 	s.GeneratedAt = &now
 | ||
| 
 | ||
| 	// 添加领域事件
 | ||
| 	s.addDomainEvent(&StatisticsReportGenerationStartedEvent{
 | ||
| 		ReportID:     s.ID,
 | ||
| 		GeneratedBy:  generatedBy,
 | ||
| 		StartedAt:    now,
 | ||
| 	})
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // CompleteGeneration 完成报告生成
 | ||
| func (s *StatisticsReport) CompleteGeneration(content string) error {
 | ||
| 	if s.Status != "generating" {
 | ||
| 		return NewValidationError("只有生成中状态的报告才能完成生成")
 | ||
| 	}
 | ||
| 
 | ||
| 	s.Status = "completed"
 | ||
| 	s.Content = content
 | ||
| 
 | ||
| 	// 设置过期时间(默认7天)
 | ||
| 	expiresAt := time.Now().Add(7 * 24 * time.Hour)
 | ||
| 	s.ExpiresAt = &expiresAt
 | ||
| 
 | ||
| 	// 添加领域事件
 | ||
| 	s.addDomainEvent(&StatisticsReportCompletedEvent{
 | ||
| 		ReportID:    s.ID,
 | ||
| 		CompletedAt: time.Now(),
 | ||
| 	})
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // FailGeneration 报告生成失败
 | ||
| func (s *StatisticsReport) FailGeneration(reason string) error {
 | ||
| 	if s.Status != "generating" {
 | ||
| 		return NewValidationError("只有生成中状态的报告才能标记为失败")
 | ||
| 	}
 | ||
| 
 | ||
| 	s.Status = "failed"
 | ||
| 
 | ||
| 	// 添加领域事件
 | ||
| 	s.addDomainEvent(&StatisticsReportFailedEvent{
 | ||
| 		ReportID:   s.ID,
 | ||
| 		Reason:     reason,
 | ||
| 		FailedAt:   time.Now(),
 | ||
| 	})
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // IsExpired 检查报告是否已过期
 | ||
| func (s *StatisticsReport) IsExpired() bool {
 | ||
| 	if s.ExpiresAt == nil {
 | ||
| 		return false
 | ||
| 	}
 | ||
| 	return time.Now().After(*s.ExpiresAt)
 | ||
| }
 | ||
| 
 | ||
| // MarkAsExpired 标记报告为过期
 | ||
| func (s *StatisticsReport) MarkAsExpired() error {
 | ||
| 	if s.Status != "completed" {
 | ||
| 		return NewValidationError("只有已完成状态的报告才能标记为过期")
 | ||
| 	}
 | ||
| 
 | ||
| 	s.Status = "expired"
 | ||
| 
 | ||
| 	// 添加领域事件
 | ||
| 	s.addDomainEvent(&StatisticsReportExpiredEvent{
 | ||
| 		ReportID:  s.ID,
 | ||
| 		ExpiredAt: time.Now(),
 | ||
| 	})
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // CanBeRegenerated 检查报告是否可以重新生成
 | ||
| func (s *StatisticsReport) CanBeRegenerated() bool {
 | ||
| 	return s.Status == "failed" || s.Status == "expired"
 | ||
| }
 | ||
| 
 | ||
| // ================ 领域事件管理 ================
 | ||
| 
 | ||
| // addDomainEvent 添加领域事件
 | ||
| func (s *StatisticsReport) addDomainEvent(event interface{}) {
 | ||
| 	if s.domainEvents == nil {
 | ||
| 		s.domainEvents = make([]interface{}, 0)
 | ||
| 	}
 | ||
| 	s.domainEvents = append(s.domainEvents, event)
 | ||
| }
 | ||
| 
 | ||
| // GetDomainEvents 获取领域事件
 | ||
| func (s *StatisticsReport) GetDomainEvents() []interface{} {
 | ||
| 	return s.domainEvents
 | ||
| }
 | ||
| 
 | ||
| // ClearDomainEvents 清除领域事件
 | ||
| func (s *StatisticsReport) ClearDomainEvents() {
 | ||
| 	s.domainEvents = make([]interface{}, 0)
 | ||
| }
 | ||
| 
 | ||
| // ================ 领域事件定义 ================
 | ||
| 
 | ||
| // StatisticsReportCreatedEvent 统计报告创建事件
 | ||
| type StatisticsReportCreatedEvent struct {
 | ||
| 	ReportID   string    `json:"report_id"`
 | ||
| 	ReportType string    `json:"report_type"`
 | ||
| 	Title      string    `json:"title"`
 | ||
| 	Period     string    `json:"period"`
 | ||
| 	CreatedAt  time.Time `json:"created_at"`
 | ||
| }
 | ||
| 
 | ||
| // StatisticsReportGenerationStartedEvent 统计报告生成开始事件
 | ||
| type StatisticsReportGenerationStartedEvent struct {
 | ||
| 	ReportID    string    `json:"report_id"`
 | ||
| 	GeneratedBy string    `json:"generated_by"`
 | ||
| 	StartedAt   time.Time `json:"started_at"`
 | ||
| }
 | ||
| 
 | ||
| // StatisticsReportCompletedEvent 统计报告完成事件
 | ||
| type StatisticsReportCompletedEvent struct {
 | ||
| 	ReportID    string    `json:"report_id"`
 | ||
| 	CompletedAt time.Time `json:"completed_at"`
 | ||
| }
 | ||
| 
 | ||
| // StatisticsReportFailedEvent 统计报告失败事件
 | ||
| type StatisticsReportFailedEvent struct {
 | ||
| 	ReportID string    `json:"report_id"`
 | ||
| 	Reason   string    `json:"reason"`
 | ||
| 	FailedAt time.Time `json:"failed_at"`
 | ||
| }
 | ||
| 
 | ||
| // StatisticsReportExpiredEvent 统计报告过期事件
 | ||
| type StatisticsReportExpiredEvent struct {
 | ||
| 	ReportID  string    `json:"report_id"`
 | ||
| 	ExpiredAt time.Time `json:"expired_at"`
 | ||
| }
 | ||
| 
 |