重构部分枚举, 让models包不依赖其他项目中的包

This commit is contained in:
2025-11-07 21:39:24 +08:00
parent 375af57afe
commit 2796d9bad7
17 changed files with 188 additions and 148 deletions

View File

@@ -10,14 +10,14 @@ import (
// 活跃告警会被更新(如确认状态),因此保留 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 string `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"`
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"`
}
@@ -32,16 +32,16 @@ func (ActiveAlarm) TableName() string {
// ID 和 CreatedAt 共同构成联合主键,以满足 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 string `gorm:"comment:告警级别" json:"alarm_level,omitempty"`
AlarmContent string `gorm:"comment:告警内容描述" json:"alarm_content,omitempty"`
TriggerTime time.Time `gorm:"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"`
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"`
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"`
}

View File

@@ -5,12 +5,41 @@ import (
"errors"
"fmt"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/utils/command_generater"
"gorm.io/datatypes"
"gorm.io/gorm"
)
// ModbusFunctionCode 定义Modbus功能码的枚举类型
type ModbusFunctionCode byte
// 定义常用的Modbus功能码常量及其应用场景
const (
// ReadCoils 读取线圈状态 (0x01)
// 场景: 用于读取数字量输出DO或内部标志位的当前状态这些状态通常是开关量。
ReadCoils ModbusFunctionCode = 0x01
// ReadDiscreteInputs 读取离散输入状态 (0x02)
// 场景: 用于读取数字量输入DI的当前状态这些状态通常是外部传感器的开关量信号。
ReadDiscreteInputs ModbusFunctionCode = 0x02
// ReadHoldingRegisters 读取保持寄存器 (0x03)
// 场景: 用于读取设备内部可读写的参数或数据,例如温度设定值、电机速度等模拟量或配置数据。
ReadHoldingRegisters ModbusFunctionCode = 0x03
// ReadInputRegisters 读取输入寄存器 (0x04)
// 场景: 用于读取设备的模拟量输入AI数据这些数据通常是只读的例如当前温度、压力、电压等实时测量值。
ReadInputRegisters ModbusFunctionCode = 0x04
// WriteSingleCoil 写入单个线圈 (0x05)
// 场景: 用于控制单个数字量输出DO例如打开或关闭一个继电器、指示灯等。
WriteSingleCoil ModbusFunctionCode = 0x05
// WriteSingleRegister 写入单个保持寄存器 (0x06)
// 场景: 用于修改设备内部的单个可写参数,例如设置一个温度控制器的目标温度、调整一个阀门的开度等。
WriteSingleRegister ModbusFunctionCode = 0x06
// WriteMultipleCoils 写入多个线圈 (0x0F)
// 场景: 用于批量控制多个数字量输出DO例如同时打开或关闭一组继电器。
WriteMultipleCoils ModbusFunctionCode = 0x0F
// WriteMultipleRegisters 写入多个保持寄存器 (0x10)
// 场景: 用于批量修改设备内部的多个可写参数,例如一次性更新多个配置参数或模拟量输出值。
WriteMultipleRegisters ModbusFunctionCode = 0x10
)
// DeviceCategory 定义了设备模板的宽泛类别
type DeviceCategory string
@@ -51,7 +80,7 @@ func (sc *SwitchCommands) SelfCheck() error {
// SensorCommands 定义了传感器读取指令所需的Modbus参数
type SensorCommands struct {
// ModbusFunctionCode 记录Modbus功能码例如 ReadHoldingRegisters。(一般是第二字节)
ModbusFunctionCode command_generater.ModbusFunctionCode `json:"modbus_function_code"`
ModbusFunctionCode ModbusFunctionCode `json:"modbus_function_code"`
// ModbusStartAddress 记录Modbus寄存器的起始地址用于生成指令。(一般是第三到四字节)
ModbusStartAddress uint16 `json:"modbus_start_address"`
// ModbusQuantity 记录Modbus寄存器的数量用于生成指令。(一般是五到六字节)
@@ -62,7 +91,7 @@ type SensorCommands struct {
func (sc *SensorCommands) SelfCheck() error {
// 校验ModbusFunctionCode是否为读取类型
switch sc.ModbusFunctionCode {
case command_generater.ReadCoils, command_generater.ReadDiscreteInputs, command_generater.ReadHoldingRegisters, command_generater.ReadInputRegisters:
case ReadCoils, ReadDiscreteInputs, ReadHoldingRegisters, ReadInputRegisters:
// 支持的读取功能码
default:
return fmt.Errorf("'sensor' 指令集 ModbusFunctionCode %X 无效或不是读取类型", sc.ModbusFunctionCode)

View File

@@ -154,7 +154,6 @@ func (PendingCollection) TableName() string {
}
// --- 用户审计日志 ---
// TODO 这些变量放这个包合适吗?
// --- 审计日志状态常量 ---
type AuditStatus string

View File

@@ -6,6 +6,8 @@ import (
"fmt"
"strconv"
"strings"
"go.uber.org/zap/zapcore"
)
// GetAllModels 返回一个包含所有数据库模型实例的切片。
@@ -129,3 +131,68 @@ func (a *UintArray) Scan(src interface{}) error {
*a = arr
return nil
}
// SeverityLevel 定义了系统中告警、通知、日志的统一级别枚举。
// 它以中文形式存储在数据库中,提高了可读性。
type SeverityLevel string
const (
// DebugLevel 调试级别,用于开发和诊断问题。
DebugLevel SeverityLevel = "Debug"
// InfoLevel 信息级别,用于记录常规操作。
InfoLevel SeverityLevel = "Info"
// WarnLevel 警告级别,表示出现潜在问题,需要关注。
WarnLevel SeverityLevel = "Warn"
// ErrorLevel 错误级别,表示发生了需要处理的错误。
ErrorLevel SeverityLevel = "Error"
// DPanicLevel 开发时崩溃级别,在开发模式下会触发 panic。
DPanicLevel SeverityLevel = "DPanic"
// PanicLevel 崩溃级别,记录日志后会立即触发 panic。
PanicLevel SeverityLevel = "Panic"
// FatalLevel 致命级别,记录日志后会调用 os.Exit(1) 退出程序。
FatalLevel SeverityLevel = "Fatal"
)
// ToZapLevel 将我们的自定义级别转换为 zapcore.Level以便与日志记录器兼容。
func (al SeverityLevel) ToZapLevel() zapcore.Level {
switch al {
case DebugLevel:
return zapcore.DebugLevel
case InfoLevel:
return zapcore.InfoLevel
case WarnLevel:
return zapcore.WarnLevel
case ErrorLevel:
return zapcore.ErrorLevel
case DPanicLevel:
return zapcore.DPanicLevel
case PanicLevel:
return zapcore.PanicLevel
case FatalLevel:
return zapcore.FatalLevel
default:
// 默认情况下返回 Info 级别,保证程序健壮性
return zapcore.InfoLevel
}
}
// Scan 实现了 sql.Scanner 接口GORM 在从数据库读取数据时会调用此方法。
func (al *SeverityLevel) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
// 尝试处理其他可能的类型,例如字符串
s, ok := value.(string)
if !ok {
return fmt.Errorf("无法将值 %v (类型 %T) 扫描为 SeverityLevel", value, value)
}
*al = SeverityLevel(s)
return nil
}
*al = SeverityLevel(bytes)
return nil
}
// Value 实现了 driver.Valuer 接口GORM 在将数据写入数据库时会调用此方法。
func (al SeverityLevel) Value() (driver.Value, error) {
return string(al), nil
}

View File

@@ -1,15 +1,25 @@
package models
import (
"database/sql/driver"
"errors"
"time"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/notify"
"go.uber.org/zap/zapcore"
"gorm.io/gorm"
)
// NotifierType 定义了通知器的类型。
type NotifierType string
const (
// NotifierTypeSMTP 表示 SMTP 邮件通知器。
NotifierTypeSMTP NotifierType = "邮件"
// NotifierTypeWeChat 表示企业微信通知器。
NotifierTypeWeChat NotifierType = "企业微信"
// NotifierTypeLark 表示飞书通知器。
NotifierTypeLark NotifierType = "飞书"
// NotifierTypeLog 表示日志通知器,作为最终的告警记录渠道。
NotifierTypeLog NotifierType = "日志"
)
// NotificationStatus 定义了通知发送尝试的状态枚举。
type NotificationStatus string
@@ -19,40 +29,12 @@ const (
NotificationStatusSkipped NotificationStatus = "已跳过" // 通知因某些原因被跳过(例如:用户未配置联系方式)
)
// LogLevel is a custom type for zapcore.Level to handle database scanning and valuing.
type LogLevel zapcore.Level
// Scan implements the sql.Scanner interface.
func (l *LogLevel) Scan(value interface{}) error {
var s string
switch v := value.(type) {
case []byte:
s = string(v)
case string:
s = v
default:
return errors.New("LogLevel的类型无效")
}
var zl zapcore.Level
if err := zl.UnmarshalText([]byte(s)); err != nil {
return err
}
*l = LogLevel(zl)
return nil
}
// Value implements the driver.Valuer interface.
func (l LogLevel) Value() (driver.Value, error) {
return (zapcore.Level)(l).String(), nil
}
// Notification 表示已发送或尝试发送的通知记录。
type Notification struct {
gorm.Model
// NotifierType 通知器类型 (例如:"邮件", "企业微信", "飞书", "日志")
NotifierType notify.NotifierType `gorm:"type:varchar(20);not null;index" json:"notifier_type"`
NotifierType NotifierType `gorm:"type:varchar(20);not null;index" json:"notifier_type"`
// UserID 接收通知的用户ID用于追溯通知记录到特定用户
UserID uint `gorm:"index" json:"user_id"` // 增加 UserID 字段,并添加索引
// Title 通知标题
@@ -60,7 +42,7 @@ type Notification struct {
// Message 通知内容
Message string `gorm:"type:text;not null" json:"message"`
// Level 通知级别 (例如INFO, WARN, ERROR)
Level LogLevel `gorm:"type:varchar(10);not null" json:"level"`
Level SeverityLevel `gorm:"type:varchar(10);not null" json:"level"`
// AlarmTimestamp 通知内容生成时的时间戳,与 ID 构成复合主键
AlarmTimestamp time.Time `gorm:"primaryKey;not null" json:"alarm_timestamp"`
// ToAddress 接收地址 (例如:邮箱地址, 企业微信ID, 日志标识符)