diff --git a/internal/infra/database/postgres.go b/internal/infra/database/postgres.go index 7b29ebd..d86d578 100644 --- a/internal/infra/database/postgres.go +++ b/internal/infra/database/postgres.go @@ -179,6 +179,7 @@ func (ps *PostgresStorage) creatingHyperTable(ctx context.Context) error { {models.PigPurchase{}, "purchase_date"}, {models.PigSale{}, "sale_date"}, {models.Notification{}, "alarm_timestamp"}, + {models.HistoricalAlarm{}, "trigger_time"}, } for _, table := range tablesToConvert { @@ -221,6 +222,7 @@ func (ps *PostgresStorage) applyCompressionPolicies(ctx context.Context) error { {models.PigPurchase{}, "pig_batch_id"}, {models.PigSale{}, "pig_batch_id"}, {models.Notification{}, "user_id"}, + {models.HistoricalAlarm{}, "source_id"}, } for _, policy := range policies { diff --git a/internal/infra/models/alarm.go b/internal/infra/models/alarm.go index 33a3425..53a40be 100644 --- a/internal/infra/models/alarm.go +++ b/internal/infra/models/alarm.go @@ -6,20 +6,37 @@ import ( "gorm.io/gorm" ) +// AlarmSourceType 定义了告警的来源类型 +type AlarmSourceType string + +const ( + AlarmSourceTypeDevice AlarmSourceType = "普通设备" + AlarmSourceTypeAreaController AlarmSourceType = "区域主控" + AlarmSourceTypeSystem AlarmSourceType = "系统" +) + // ActiveAlarm 活跃告警 -// 活跃告警会被更新(如确认状态),因此保留 gorm.Model 以包含所有标准字段。 +// 活跃告警会被更新(如忽略状态),因此保留 gorm.Model 以包含所有标准字段。 type ActiveAlarm struct { gorm.Model - FarmID uint `gorm:"not null;comment:猪场ID" json:"farm_id,omitempty"` - DeviceID uint `gorm:"not null;comment:设备ID" json:"device_id,omitempty"` - AlarmType string `gorm:"comment:告警类型" json:"alarm_type,omitempty"` - AlarmLevel SeverityLevel `gorm:"comment:告警级别" json:"alarm_level,omitempty"` - AlarmContent string `gorm:"comment:告警内容描述" json:"alarm_content,omitempty"` - TriggerTime time.Time `gorm:"not null;comment:告警触发时间" json:"trigger_time"` - IsAcknowledged bool `gorm:"default:false;comment:是否已确认" json:"is_acknowledged,omitempty"` - AcknowledgedBy string `gorm:"comment:确认人" json:"acknowledged_by,omitempty"` - // 使用指针类型 *time.Time 来表示可为空的确认时间 - AcknowledgedTime *time.Time `gorm:"comment:确认时间" json:"acknowledged_time,omitempty"` + + SourceType AlarmSourceType `gorm:"type:varchar(50);not null;index;comment:告警来源类型" json:"source_type"` + // SourceID 告警来源ID,其具体含义取决于 SourceType 字段 (例如:设备ID, 区域主控ID, 猪栏ID)。 + SourceID uint `gorm:"not null;index;comment:告警来源ID" json:"source_id"` + + AlarmSummary string `gorm:"comment:告警简述" json:"alarm_summary"` + Level SeverityLevel `gorm:"type:varchar(10);not null;comment:严重性等级" json:"level"` + AlarmDetails string `gorm:"comment:告警详细内容" json:"alarm_details"` + TriggerTime time.Time `gorm:"not null;comment:告警触发时间" json:"trigger_time"` + + // IsIgnored 是否被手动忽略 (Snooze) + IsIgnored bool `gorm:"default:false;comment:是否被手动忽略" json:"is_ignored"` + // IgnoredUntil 忽略截止时间。在此时间之前,即使告警持续,也不会发送通知。 + // 使用指针类型 *time.Time 来表示可为空的时间。 + IgnoredUntil *time.Time `gorm:"comment:忽略截止时间" json:"ignored_until"` + + // LastNotifiedAt 上次发送通知的时间。用于控制重复通知的频率。 + LastNotifiedAt *time.Time `gorm:"comment:上次发送通知时间" json:"last_notified_at"` } // TableName 指定 ActiveAlarm 结构体对应的数据库表名 @@ -29,21 +46,24 @@ func (ActiveAlarm) TableName() string { // HistoricalAlarm 历史告警 // 历史告警是不可变归档数据,我们移除 gorm.Model,并手动定义字段。 -// ID 和 CreatedAt 共同构成联合主键,以满足 TimescaleDB 超表的要求。 +// ID 和 TriggerTime 共同构成联合主键,以满足 TimescaleDB 超表的要求。 type HistoricalAlarm struct { // 手动定义主键,ID 仍然自增 - ID uint `gorm:"primaryKey;autoIncrement;comment:主键ID" json:"id,omitempty"` - FarmID uint `gorm:"not null;comment:猪场ID" json:"farm_id,omitempty"` - DeviceID uint `gorm:"not null;comment:设备ID" json:"device_id,omitempty"` - AlarmType string `gorm:"comment:告警类型" json:"alarm_type,omitempty"` - AlarmLevel SeverityLevel `gorm:"comment:告警级别" json:"alarm_level,omitempty"` - AlarmContent string `gorm:"comment:告警内容描述" json:"alarm_content,omitempty"` - TriggerTime time.Time `gorm:"not null;comment:告警触发时间" json:"trigger_time"` + ID uint `gorm:"primaryKey;autoIncrement;comment:主键ID" json:"id"` + + SourceType AlarmSourceType `gorm:"type:varchar(50);not null;index;comment:告警来源类型" json:"source_type"` + // SourceID 告警来源ID,其具体含义取决于 SourceType 字段 (例如:设备ID, 区域主控ID, 猪栏ID)。 + SourceID uint `gorm:"not null;index;comment:告警来源ID" json:"source_id"` + + AlarmSummary string `gorm:"comment:告警简述" json:"alarm_summary"` + Level SeverityLevel `gorm:"type:varchar(10);not null;comment:严重性等级" json:"level"` + AlarmDetails string `gorm:"comment:告警详细内容" json:"alarm_details"` + TriggerTime time.Time `gorm:"primaryKey;not null;comment:告警触发时间" json:"trigger_time"` ResolveTime time.Time `gorm:"not null;comment:告警解决时间" json:"resolve_time"` - ResolveMethod string `gorm:"comment:告警解决方式" json:"resolve_method,omitempty"` - ResolvedBy string `gorm:"comment:告警解决人" json:"resolved_by,omitempty"` - // 将 CreatedAt 作为联合主键的一部分,用于 TimescaleDB 分区 - CreatedAt time.Time `gorm:"primaryKey;comment:创建时间" json:"created_at"` + ResolveMethod string `gorm:"comment:告警解决方式" json:"resolve_method"` + + // ResolvedBy 使用指针类型 *uint 来表示可为空解决人, 当字段为空时表示系统自动解决的 + ResolvedBy *uint `gorm:"comment:告警解决人" json:"resolved_by"` } // TableName 指定 HistoricalAlarm 结构体对应的数据库表名 diff --git a/internal/infra/models/models.go b/internal/infra/models/models.go index 13c5418..9fbb914 100644 --- a/internal/infra/models/models.go +++ b/internal/infra/models/models.go @@ -63,6 +63,10 @@ func GetAllModels() []interface{} { &Medication{}, &MedicationLog{}, + // Alarm Models + &ActiveAlarm{}, + &HistoricalAlarm{}, + // Notification Models &Notification{}, }