new
This commit is contained in:
434
internal/domains/statistics/entities/statistics_dashboard.go
Normal file
434
internal/domains/statistics/entities/statistics_dashboard.go
Normal file
@@ -0,0 +1,434 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// StatisticsDashboard 仪表板配置实体
|
||||
// 用于存储仪表板的配置信息
|
||||
type StatisticsDashboard 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:"仪表板描述"`
|
||||
UserRole string `gorm:"type:varchar(20);not null;index" json:"user_role" comment:"用户角色"`
|
||||
IsDefault bool `gorm:"default:false" json:"is_default" comment:"是否为默认仪表板"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active" comment:"是否激活"`
|
||||
|
||||
// 仪表板配置
|
||||
Layout string `gorm:"type:json" json:"layout" comment:"布局配置"`
|
||||
Widgets string `gorm:"type:json" json:"widgets" comment:"组件配置"`
|
||||
Settings string `gorm:"type:json" json:"settings" comment:"设置配置"`
|
||||
RefreshInterval int `gorm:"default:300" json:"refresh_interval" comment:"刷新间隔(秒)"`
|
||||
|
||||
// 权限和访问控制
|
||||
CreatedBy string `gorm:"type:varchar(36);not null" json:"created_by" comment:"创建者ID"`
|
||||
AccessLevel string `gorm:"type:varchar(20);default:'private'" json:"access_level" 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 (StatisticsDashboard) TableName() string {
|
||||
return "statistics_dashboards"
|
||||
}
|
||||
|
||||
// BeforeCreate GORM钩子:创建前自动生成UUID
|
||||
func (s *StatisticsDashboard) BeforeCreate(tx *gorm.DB) error {
|
||||
if s.ID == "" {
|
||||
s.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 实现 Entity 接口 - 提供统一的实体管理接口
|
||||
// GetID 获取实体唯一标识
|
||||
func (s *StatisticsDashboard) GetID() string {
|
||||
return s.ID
|
||||
}
|
||||
|
||||
// GetCreatedAt 获取创建时间
|
||||
func (s *StatisticsDashboard) GetCreatedAt() time.Time {
|
||||
return s.CreatedAt
|
||||
}
|
||||
|
||||
// GetUpdatedAt 获取更新时间
|
||||
func (s *StatisticsDashboard) GetUpdatedAt() time.Time {
|
||||
return s.UpdatedAt
|
||||
}
|
||||
|
||||
// Validate 验证仪表板配置信息
|
||||
// 检查仪表板必填字段是否完整,确保数据的有效性
|
||||
func (s *StatisticsDashboard) Validate() error {
|
||||
if s.Name == "" {
|
||||
return NewValidationError("仪表板名称不能为空")
|
||||
}
|
||||
if s.UserRole == "" {
|
||||
return NewValidationError("用户角色不能为空")
|
||||
}
|
||||
if s.CreatedBy == "" {
|
||||
return NewValidationError("创建者ID不能为空")
|
||||
}
|
||||
|
||||
// 验证用户角色
|
||||
if !s.IsValidUserRole() {
|
||||
return NewValidationError("无效的用户角色")
|
||||
}
|
||||
|
||||
// 验证访问级别
|
||||
if !s.IsValidAccessLevel() {
|
||||
return NewValidationError("无效的访问级别")
|
||||
}
|
||||
|
||||
// 验证刷新间隔
|
||||
if s.RefreshInterval < 30 {
|
||||
return NewValidationError("刷新间隔不能少于30秒")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValidUserRole 检查用户角色是否有效
|
||||
func (s *StatisticsDashboard) IsValidUserRole() bool {
|
||||
validRoles := []string{
|
||||
"admin", // 管理员
|
||||
"user", // 普通用户
|
||||
"manager", // 经理
|
||||
"analyst", // 分析师
|
||||
}
|
||||
|
||||
for _, validRole := range validRoles {
|
||||
if s.UserRole == validRole {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsValidAccessLevel 检查访问级别是否有效
|
||||
func (s *StatisticsDashboard) IsValidAccessLevel() bool {
|
||||
validLevels := []string{
|
||||
"private", // 私有
|
||||
"public", // 公开
|
||||
"shared", // 共享
|
||||
}
|
||||
|
||||
for _, validLevel := range validLevels {
|
||||
if s.AccessLevel == validLevel {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetUserRoleName 获取用户角色的中文名称
|
||||
func (s *StatisticsDashboard) GetUserRoleName() string {
|
||||
roleNames := map[string]string{
|
||||
"admin": "管理员",
|
||||
"user": "普通用户",
|
||||
"manager": "经理",
|
||||
"analyst": "分析师",
|
||||
}
|
||||
|
||||
if name, exists := roleNames[s.UserRole]; exists {
|
||||
return name
|
||||
}
|
||||
return s.UserRole
|
||||
}
|
||||
|
||||
// GetAccessLevelName 获取访问级别的中文名称
|
||||
func (s *StatisticsDashboard) GetAccessLevelName() string {
|
||||
levelNames := map[string]string{
|
||||
"private": "私有",
|
||||
"public": "公开",
|
||||
"shared": "共享",
|
||||
}
|
||||
|
||||
if name, exists := levelNames[s.AccessLevel]; exists {
|
||||
return name
|
||||
}
|
||||
return s.AccessLevel
|
||||
}
|
||||
|
||||
// NewStatisticsDashboard 工厂方法 - 创建仪表板配置
|
||||
func NewStatisticsDashboard(name, description, userRole, createdBy string) (*StatisticsDashboard, error) {
|
||||
if name == "" {
|
||||
return nil, errors.New("仪表板名称不能为空")
|
||||
}
|
||||
if userRole == "" {
|
||||
return nil, errors.New("用户角色不能为空")
|
||||
}
|
||||
if createdBy == "" {
|
||||
return nil, errors.New("创建者ID不能为空")
|
||||
}
|
||||
|
||||
dashboard := &StatisticsDashboard{
|
||||
Name: name,
|
||||
Description: description,
|
||||
UserRole: userRole,
|
||||
CreatedBy: createdBy,
|
||||
IsDefault: false,
|
||||
IsActive: true,
|
||||
AccessLevel: "private",
|
||||
RefreshInterval: 300, // 默认5分钟
|
||||
domainEvents: make([]interface{}, 0),
|
||||
}
|
||||
|
||||
// 验证仪表板
|
||||
if err := dashboard.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 添加领域事件
|
||||
dashboard.addDomainEvent(&StatisticsDashboardCreatedEvent{
|
||||
DashboardID: dashboard.ID,
|
||||
Name: name,
|
||||
UserRole: userRole,
|
||||
CreatedBy: createdBy,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
return dashboard, nil
|
||||
}
|
||||
|
||||
// SetAsDefault 设置为默认仪表板
|
||||
func (s *StatisticsDashboard) SetAsDefault() error {
|
||||
if !s.IsActive {
|
||||
return NewValidationError("只有激活状态的仪表板才能设置为默认")
|
||||
}
|
||||
|
||||
s.IsDefault = true
|
||||
|
||||
// 添加领域事件
|
||||
s.addDomainEvent(&StatisticsDashboardSetAsDefaultEvent{
|
||||
DashboardID: s.ID,
|
||||
SetAt: time.Now(),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveAsDefault 取消默认状态
|
||||
func (s *StatisticsDashboard) RemoveAsDefault() error {
|
||||
if !s.IsDefault {
|
||||
return NewValidationError("当前仪表板不是默认仪表板")
|
||||
}
|
||||
|
||||
s.IsDefault = false
|
||||
|
||||
// 添加领域事件
|
||||
s.addDomainEvent(&StatisticsDashboardRemovedAsDefaultEvent{
|
||||
DashboardID: s.ID,
|
||||
RemovedAt: time.Now(),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Activate 激活仪表板
|
||||
func (s *StatisticsDashboard) Activate() error {
|
||||
if s.IsActive {
|
||||
return NewValidationError("仪表板已经是激活状态")
|
||||
}
|
||||
|
||||
s.IsActive = true
|
||||
|
||||
// 添加领域事件
|
||||
s.addDomainEvent(&StatisticsDashboardActivatedEvent{
|
||||
DashboardID: s.ID,
|
||||
ActivatedAt: time.Now(),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deactivate 停用仪表板
|
||||
func (s *StatisticsDashboard) Deactivate() error {
|
||||
if !s.IsActive {
|
||||
return NewValidationError("仪表板已经是停用状态")
|
||||
}
|
||||
|
||||
s.IsActive = false
|
||||
|
||||
// 如果是默认仪表板,需要先取消默认状态
|
||||
if s.IsDefault {
|
||||
s.IsDefault = false
|
||||
}
|
||||
|
||||
// 添加领域事件
|
||||
s.addDomainEvent(&StatisticsDashboardDeactivatedEvent{
|
||||
DashboardID: s.ID,
|
||||
DeactivatedAt: time.Now(),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateLayout 更新布局配置
|
||||
func (s *StatisticsDashboard) UpdateLayout(layout string) error {
|
||||
if layout == "" {
|
||||
return NewValidationError("布局配置不能为空")
|
||||
}
|
||||
|
||||
s.Layout = layout
|
||||
|
||||
// 添加领域事件
|
||||
s.addDomainEvent(&StatisticsDashboardLayoutUpdatedEvent{
|
||||
DashboardID: s.ID,
|
||||
UpdatedAt: time.Now(),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateWidgets 更新组件配置
|
||||
func (s *StatisticsDashboard) UpdateWidgets(widgets string) error {
|
||||
if widgets == "" {
|
||||
return NewValidationError("组件配置不能为空")
|
||||
}
|
||||
|
||||
s.Widgets = widgets
|
||||
|
||||
// 添加领域事件
|
||||
s.addDomainEvent(&StatisticsDashboardWidgetsUpdatedEvent{
|
||||
DashboardID: s.ID,
|
||||
UpdatedAt: time.Now(),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateSettings 更新设置配置
|
||||
func (s *StatisticsDashboard) UpdateSettings(settings string) error {
|
||||
s.Settings = settings
|
||||
|
||||
// 添加领域事件
|
||||
s.addDomainEvent(&StatisticsDashboardSettingsUpdatedEvent{
|
||||
DashboardID: s.ID,
|
||||
UpdatedAt: time.Now(),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateRefreshInterval 更新刷新间隔
|
||||
func (s *StatisticsDashboard) UpdateRefreshInterval(interval int) error {
|
||||
if interval < 30 {
|
||||
return NewValidationError("刷新间隔不能少于30秒")
|
||||
}
|
||||
|
||||
oldInterval := s.RefreshInterval
|
||||
s.RefreshInterval = interval
|
||||
|
||||
// 添加领域事件
|
||||
s.addDomainEvent(&StatisticsDashboardRefreshIntervalUpdatedEvent{
|
||||
DashboardID: s.ID,
|
||||
OldInterval: oldInterval,
|
||||
NewInterval: interval,
|
||||
UpdatedAt: time.Now(),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CanBeModified 检查仪表板是否可以被修改
|
||||
func (s *StatisticsDashboard) CanBeModified() bool {
|
||||
return s.IsActive
|
||||
}
|
||||
|
||||
// CanBeDeleted 检查仪表板是否可以被删除
|
||||
func (s *StatisticsDashboard) CanBeDeleted() bool {
|
||||
return !s.IsDefault && s.IsActive
|
||||
}
|
||||
|
||||
// ================ 领域事件管理 ================
|
||||
|
||||
// addDomainEvent 添加领域事件
|
||||
func (s *StatisticsDashboard) addDomainEvent(event interface{}) {
|
||||
if s.domainEvents == nil {
|
||||
s.domainEvents = make([]interface{}, 0)
|
||||
}
|
||||
s.domainEvents = append(s.domainEvents, event)
|
||||
}
|
||||
|
||||
// GetDomainEvents 获取领域事件
|
||||
func (s *StatisticsDashboard) GetDomainEvents() []interface{} {
|
||||
return s.domainEvents
|
||||
}
|
||||
|
||||
// ClearDomainEvents 清除领域事件
|
||||
func (s *StatisticsDashboard) ClearDomainEvents() {
|
||||
s.domainEvents = make([]interface{}, 0)
|
||||
}
|
||||
|
||||
// ================ 领域事件定义 ================
|
||||
|
||||
// StatisticsDashboardCreatedEvent 仪表板创建事件
|
||||
type StatisticsDashboardCreatedEvent struct {
|
||||
DashboardID string `json:"dashboard_id"`
|
||||
Name string `json:"name"`
|
||||
UserRole string `json:"user_role"`
|
||||
CreatedBy string `json:"created_by"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// StatisticsDashboardSetAsDefaultEvent 仪表板设置为默认事件
|
||||
type StatisticsDashboardSetAsDefaultEvent struct {
|
||||
DashboardID string `json:"dashboard_id"`
|
||||
SetAt time.Time `json:"set_at"`
|
||||
}
|
||||
|
||||
// StatisticsDashboardRemovedAsDefaultEvent 仪表板取消默认事件
|
||||
type StatisticsDashboardRemovedAsDefaultEvent struct {
|
||||
DashboardID string `json:"dashboard_id"`
|
||||
RemovedAt time.Time `json:"removed_at"`
|
||||
}
|
||||
|
||||
// StatisticsDashboardActivatedEvent 仪表板激活事件
|
||||
type StatisticsDashboardActivatedEvent struct {
|
||||
DashboardID string `json:"dashboard_id"`
|
||||
ActivatedAt time.Time `json:"activated_at"`
|
||||
}
|
||||
|
||||
// StatisticsDashboardDeactivatedEvent 仪表板停用事件
|
||||
type StatisticsDashboardDeactivatedEvent struct {
|
||||
DashboardID string `json:"dashboard_id"`
|
||||
DeactivatedAt time.Time `json:"deactivated_at"`
|
||||
}
|
||||
|
||||
// StatisticsDashboardLayoutUpdatedEvent 仪表板布局更新事件
|
||||
type StatisticsDashboardLayoutUpdatedEvent struct {
|
||||
DashboardID string `json:"dashboard_id"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// StatisticsDashboardWidgetsUpdatedEvent 仪表板组件更新事件
|
||||
type StatisticsDashboardWidgetsUpdatedEvent struct {
|
||||
DashboardID string `json:"dashboard_id"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// StatisticsDashboardSettingsUpdatedEvent 仪表板设置更新事件
|
||||
type StatisticsDashboardSettingsUpdatedEvent struct {
|
||||
DashboardID string `json:"dashboard_id"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// StatisticsDashboardRefreshIntervalUpdatedEvent 仪表板刷新间隔更新事件
|
||||
type StatisticsDashboardRefreshIntervalUpdatedEvent struct {
|
||||
DashboardID string `json:"dashboard_id"`
|
||||
OldInterval int `json:"old_interval"`
|
||||
NewInterval int `json:"new_interval"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
244
internal/domains/statistics/entities/statistics_metric.go
Normal file
244
internal/domains/statistics/entities/statistics_metric.go
Normal file
@@ -0,0 +1,244 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// StatisticsMetric 统计指标实体
|
||||
// 用于存储各种统计指标数据,支持多维度统计
|
||||
type StatisticsMetric struct {
|
||||
// 基础标识
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"统计指标唯一标识"`
|
||||
MetricType string `gorm:"type:varchar(50);not null;index" json:"metric_type" comment:"指标类型"`
|
||||
MetricName string `gorm:"type:varchar(100);not null" json:"metric_name" comment:"指标名称"`
|
||||
Dimension string `gorm:"type:varchar(50)" json:"dimension" comment:"统计维度"`
|
||||
Value float64 `gorm:"type:decimal(20,4);not null" json:"value" comment:"指标值"`
|
||||
Metadata string `gorm:"type:json" json:"metadata" comment:"额外维度信息"`
|
||||
Date time.Time `gorm:"type:date;index" json:"date" 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 (StatisticsMetric) TableName() string {
|
||||
return "statistics_metrics"
|
||||
}
|
||||
|
||||
// BeforeCreate GORM钩子:创建前自动生成UUID
|
||||
func (s *StatisticsMetric) BeforeCreate(tx *gorm.DB) error {
|
||||
if s.ID == "" {
|
||||
s.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 实现 Entity 接口 - 提供统一的实体管理接口
|
||||
// GetID 获取实体唯一标识
|
||||
func (s *StatisticsMetric) GetID() string {
|
||||
return s.ID
|
||||
}
|
||||
|
||||
// GetCreatedAt 获取创建时间
|
||||
func (s *StatisticsMetric) GetCreatedAt() time.Time {
|
||||
return s.CreatedAt
|
||||
}
|
||||
|
||||
// GetUpdatedAt 获取更新时间
|
||||
func (s *StatisticsMetric) GetUpdatedAt() time.Time {
|
||||
return s.UpdatedAt
|
||||
}
|
||||
|
||||
// Validate 验证统计指标信息
|
||||
// 检查统计指标必填字段是否完整,确保数据的有效性
|
||||
func (s *StatisticsMetric) Validate() error {
|
||||
if s.MetricType == "" {
|
||||
return NewValidationError("指标类型不能为空")
|
||||
}
|
||||
if s.MetricName == "" {
|
||||
return NewValidationError("指标名称不能为空")
|
||||
}
|
||||
if s.Value < 0 {
|
||||
return NewValidationError("指标值不能为负数")
|
||||
}
|
||||
if s.Date.IsZero() {
|
||||
return NewValidationError("统计日期不能为空")
|
||||
}
|
||||
|
||||
// 验证指标类型
|
||||
if !s.IsValidMetricType() {
|
||||
return NewValidationError("无效的指标类型")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValidMetricType 检查指标类型是否有效
|
||||
func (s *StatisticsMetric) IsValidMetricType() bool {
|
||||
validTypes := []string{
|
||||
"api_calls", // API调用统计
|
||||
"users", // 用户统计
|
||||
"finance", // 财务统计
|
||||
"products", // 产品统计
|
||||
"certification", // 认证统计
|
||||
}
|
||||
|
||||
for _, validType := range validTypes {
|
||||
if s.MetricType == validType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetMetricTypeName 获取指标类型的中文名称
|
||||
func (s *StatisticsMetric) GetMetricTypeName() string {
|
||||
typeNames := map[string]string{
|
||||
"api_calls": "API调用统计",
|
||||
"users": "用户统计",
|
||||
"finance": "财务统计",
|
||||
"products": "产品统计",
|
||||
"certification": "认证统计",
|
||||
}
|
||||
|
||||
if name, exists := typeNames[s.MetricType]; exists {
|
||||
return name
|
||||
}
|
||||
return s.MetricType
|
||||
}
|
||||
|
||||
// GetFormattedValue 获取格式化的指标值
|
||||
func (s *StatisticsMetric) GetFormattedValue() string {
|
||||
// 根据指标类型格式化数值
|
||||
switch s.MetricType {
|
||||
case "api_calls", "users":
|
||||
return fmt.Sprintf("%.0f", s.Value)
|
||||
case "finance":
|
||||
return fmt.Sprintf("%.2f", s.Value)
|
||||
default:
|
||||
return fmt.Sprintf("%.4f", s.Value)
|
||||
}
|
||||
}
|
||||
|
||||
// NewStatisticsMetric 工厂方法 - 创建统计指标
|
||||
func NewStatisticsMetric(metricType, metricName, dimension string, value float64, date time.Time) (*StatisticsMetric, error) {
|
||||
if metricType == "" {
|
||||
return nil, errors.New("指标类型不能为空")
|
||||
}
|
||||
if metricName == "" {
|
||||
return nil, errors.New("指标名称不能为空")
|
||||
}
|
||||
if value < 0 {
|
||||
return nil, errors.New("指标值不能为负数")
|
||||
}
|
||||
if date.IsZero() {
|
||||
return nil, errors.New("统计日期不能为空")
|
||||
}
|
||||
|
||||
metric := &StatisticsMetric{
|
||||
MetricType: metricType,
|
||||
MetricName: metricName,
|
||||
Dimension: dimension,
|
||||
Value: value,
|
||||
Date: date,
|
||||
domainEvents: make([]interface{}, 0),
|
||||
}
|
||||
|
||||
// 验证指标
|
||||
if err := metric.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 添加领域事件
|
||||
metric.addDomainEvent(&StatisticsMetricCreatedEvent{
|
||||
MetricID: metric.ID,
|
||||
MetricType: metricType,
|
||||
MetricName: metricName,
|
||||
Value: value,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
|
||||
return metric, nil
|
||||
}
|
||||
|
||||
// UpdateValue 更新指标值
|
||||
func (s *StatisticsMetric) UpdateValue(newValue float64) error {
|
||||
if newValue < 0 {
|
||||
return NewValidationError("指标值不能为负数")
|
||||
}
|
||||
|
||||
oldValue := s.Value
|
||||
s.Value = newValue
|
||||
|
||||
// 添加领域事件
|
||||
s.addDomainEvent(&StatisticsMetricUpdatedEvent{
|
||||
MetricID: s.ID,
|
||||
OldValue: oldValue,
|
||||
NewValue: newValue,
|
||||
UpdatedAt: time.Now(),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ================ 领域事件管理 ================
|
||||
|
||||
// addDomainEvent 添加领域事件
|
||||
func (s *StatisticsMetric) addDomainEvent(event interface{}) {
|
||||
if s.domainEvents == nil {
|
||||
s.domainEvents = make([]interface{}, 0)
|
||||
}
|
||||
s.domainEvents = append(s.domainEvents, event)
|
||||
}
|
||||
|
||||
// GetDomainEvents 获取领域事件
|
||||
func (s *StatisticsMetric) GetDomainEvents() []interface{} {
|
||||
return s.domainEvents
|
||||
}
|
||||
|
||||
// ClearDomainEvents 清除领域事件
|
||||
func (s *StatisticsMetric) ClearDomainEvents() {
|
||||
s.domainEvents = make([]interface{}, 0)
|
||||
}
|
||||
|
||||
// ================ 领域事件定义 ================
|
||||
|
||||
// StatisticsMetricCreatedEvent 统计指标创建事件
|
||||
type StatisticsMetricCreatedEvent struct {
|
||||
MetricID string `json:"metric_id"`
|
||||
MetricType string `json:"metric_type"`
|
||||
MetricName string `json:"metric_name"`
|
||||
Value float64 `json:"value"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// StatisticsMetricUpdatedEvent 统计指标更新事件
|
||||
type StatisticsMetricUpdatedEvent struct {
|
||||
MetricID string `json:"metric_id"`
|
||||
OldValue float64 `json:"old_value"`
|
||||
NewValue float64 `json:"new_value"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// ValidationError 验证错误
|
||||
type ValidationError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *ValidationError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func NewValidationError(message string) *ValidationError {
|
||||
return &ValidationError{Message: message}
|
||||
}
|
||||
343
internal/domains/statistics/entities/statistics_report.go
Normal file
343
internal/domains/statistics/entities/statistics_report.go
Normal file
@@ -0,0 +1,343 @@
|
||||
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"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user