Files
tyapi-server/internal/domains/statistics/entities/statistics_report.go
2025-09-12 01:15:09 +08:00

344 lines
8.8 KiB
Go
Raw 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 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"`
}