package model import ( "encoding/json" "time" "gorm.io/gorm" ) // User 用户表 type User struct { ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"` Username string `gorm:"unique" json:"username"` Email string `gorm:"unique" json:"email"` PasswordHash string `gorm:"column:password_hash" json:"passwordHash"` FullName *string `gorm:"column:full_name" json:"fullName,omitempty"` Role string `gorm:"default:user" json:"role"` Active bool `gorm:"default:true" json:"active"` CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"` UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"` } func (User) TableName() string { return "users" } // Room 房间表 type Room struct { ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"` Name string `json:"name"` Code *string `json:"code,omitempty"` Location *string `json:"location,omitempty"` Description *string `json:"description,omitempty"` Capacity *int `gorm:"type:int" json:"capacity,omitempty"` Stage *string `gorm:"size:32" json:"stage,omitempty"` Status string `gorm:"default:active" json:"status"` CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"` UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"` } func (Room) TableName() string { return "rooms" } // Device 设备表 type Device struct { ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"` DeviceKey string `gorm:"column:device_key;unique" json:"deviceKey"` Name string `json:"name"` Kind string `gorm:"default:sensor" json:"kind"` Model *string `json:"model,omitempty"` Firmware *string `json:"firmware,omitempty"` OnlineStatus string `gorm:"column:online_status;default:online" json:"onlineStatus"` LastSeen *time.Time `gorm:"column:last_seen;type:timestamptz" json:"lastSeen,omitempty"` RoomID string `gorm:"column:room_id;type:uuid;index" json:"roomId"` Topic *string `gorm:"column:topic" json:"topic,omitempty"` // 设备上行主题(持久化,防止后端重启丢失) CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"` UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"` } func (Device) TableName() string { return "devices" } // Sensor 传感器表 type Sensor struct { ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"` Name string `json:"name"` Metric string `json:"metric"` Unit *string `json:"unit,omitempty"` DataType *string `gorm:"column:data_type" json:"dataType,omitempty"` DeviceID string `gorm:"column:device_id;type:uuid;index" json:"deviceId"` CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"` } func (Sensor) TableName() string { return "sensors" } // Threshold 阈值表 type Threshold struct { ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"` Name *string `json:"name,omitempty"` MinValue float64 `gorm:"column:min_value;type:float" json:"minValue"` MaxValue float64 `gorm:"column:max_value;type:float" json:"maxValue"` DebounceSeconds int `gorm:"column:debounce_seconds;type:int;default:5" json:"debounceSeconds"` Severity int `gorm:"type:int;default:3" json:"severity"` Enabled bool `gorm:"default:true" json:"enabled"` SensorID string `gorm:"column:sensor_id;type:uuid;index" json:"sensorId"` CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"` UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"` } func (Threshold) TableName() string { return "thresholds" } // Alarm 告警表 type Alarm struct { ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"` Code *string `json:"code,omitempty"` Title *string `json:"title,omitempty"` Message *string `json:"message,omitempty"` Severity *string `json:"severity,omitempty"` Open bool `gorm:"default:true;index:idx_alarms_device_open_triggered,priority:2" json:"open"` Acknowledged bool `gorm:"default:false" json:"acknowledged"` AcknowledgedAt *time.Time `gorm:"column:acknowledged_at;type:timestamptz" json:"acknowledgedAt,omitempty"` TriggeredAt time.Time `gorm:"column:triggered_at;type:timestamptz;index:idx_alarms_device_open_triggered,priority:3" json:"triggeredAt"` ResolvedAt *time.Time `gorm:"column:resolved_at;type:timestamptz" json:"resolvedAt,omitempty"` DeviceKey *string `gorm:"column:device_key;index:idx_alarms_device_open_triggered,priority:1" json:"deviceKey,omitempty"` Metric *string `json:"metric,omitempty"` Value *float64 `gorm:"type:float" json:"value,omitempty"` ThresholdMin *float64 `gorm:"column:threshold_min;type:float" json:"thresholdMin,omitempty"` ThresholdMax *float64 `gorm:"column:threshold_max;type:float" json:"thresholdMax,omitempty"` } func (Alarm) TableName() string { return "alarms" } // Camera 摄像头表 type Camera struct { ID uint `gorm:"primaryKey;autoIncrement" json:"id"` RoomID *string `gorm:"column:room_id;index" json:"roomId,omitempty"` Code string `gorm:"size:64" json:"code"` Name string `gorm:"size:128" json:"name"` RtspURL *string `gorm:"column:rtsp_url;size:512" json:"rtspUrl,omitempty"` HTTPURL *string `gorm:"column:http_url;size:512" json:"httpUrl,omitempty"` Username *string `gorm:"size:64" json:"username,omitempty"` PasswordEnc *string `gorm:"column:password_enc;size:255" json:"passwordEnc,omitempty"` Position *string `gorm:"size:255" json:"position,omitempty"` Resolution *string `gorm:"size:32" json:"resolution,omitempty"` FPS *int `gorm:"type:int" json:"fps,omitempty"` IsOnline bool `gorm:"column:is_online;default:true" json:"isOnline"` GbDeviceID *string `gorm:"column:gb_device_id;size:20" json:"gbDeviceId,omitempty"` GbChannelID *string `gorm:"column:gb_channel_id;size:20" json:"gbChannelId,omitempty"` GbAuthID *string `gorm:"column:gb_auth_id;size:20" json:"gbAuthId,omitempty"` GbAuthPassword *string `gorm:"column:gb_auth_password;size:255" json:"gbAuthPassword,omitempty"` GbStreamType *string `gorm:"column:gb_stream_type;size:10" json:"gbStreamType,omitempty"` GbTransport *string `gorm:"column:gb_transport;size:10" json:"gbTransport,omitempty"` GbAlarmChannelID *string `gorm:"column:gb_alarm_channel_id;size:20" json:"gbAlarmChannelId,omitempty"` GbVoiceChannelID *string `gorm:"column:gb_voice_channel_id;size:20" json:"gbVoiceChannelId,omitempty"` GbManufacturer *string `gorm:"column:gb_manufacturer;size:64" json:"gbManufacturer,omitempty"` ManufacturerID *string `gorm:"column:manufacturer_id;size:64" json:"manufacturerId,omitempty"` // 以下字段不在数据库中,运行时通过 WVP API 填充 StreamURL *string `gorm:"-" json:"streamUrl,omitempty"` HlsURL *string `gorm:"-" json:"hlsUrl,omitempty"` FlvURL *string `gorm:"-" json:"flvUrl,omitempty"` WebrtcURL *string `gorm:"-" json:"webrtcUrl,omitempty"` SnapshotURL *string `gorm:"-" json:"snapshotUrl,omitempty"` Online bool `gorm:"-" json:"online"` Enabled bool `gorm:"default:true" json:"enabled"` CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"` UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"` } func (Camera) TableName() string { return "cameras" } // AfterFind 查询后同步 IsOnline → Online func (c *Camera) AfterFind(tx *gorm.DB) error { c.Online = c.IsOnline return nil } // VideoClip 视频片段表 type VideoClip struct { ID uint `gorm:"primaryKey;autoIncrement" json:"id"` Trigger string `gorm:"default:alarm" json:"trigger"` FilePath *string `gorm:"column:file_path" json:"filePath,omitempty"` DurationSec float64 `gorm:"column:duration_sec;type:real;default:0" json:"durationSec"` StartAt time.Time `gorm:"column:start_at;type:timestamptz" json:"startAt"` EndAt *time.Time `gorm:"column:end_at;type:timestamptz" json:"endAt,omitempty"` Resolution *string `json:"resolution,omitempty"` SizeBytes *int64 `gorm:"column:size_bytes;type:bigint" json:"sizeBytes,omitempty"` Notes *string `json:"notes,omitempty"` CameraID string `gorm:"column:camera_id;index" json:"cameraId"` RoomID *string `gorm:"column:room_id;index" json:"roomId,omitempty"` AlarmID *string `gorm:"column:alarm_id;index" json:"alarmId,omitempty"` CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"` UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"` S3Bucket *string `gorm:"column:s3_bucket" json:"s3Bucket,omitempty"` S3Key *string `gorm:"column:s3_key" json:"s3Key,omitempty"` // 以下字段不在数据库中,运行时填充 PlaybackURL *string `gorm:"-" json:"playbackUrl,omitempty"` Format string `gorm:"-" json:"format"` } func (VideoClip) TableName() string { return "video_clips" } // AuditLog 审计日志表 type AuditLog struct { ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"` UserID *string `gorm:"column:user_id;type:uuid;index:idx_audit_logs_user_created,priority:1" json:"userId,omitempty"` Username *string `json:"username,omitempty"` Action string `gorm:"index:idx_audit_logs_action_created,priority:1" json:"action"` Resource *string `gorm:"index:idx_audit_logs_resource_target,priority:1" json:"resource,omitempty"` TargetID *string `gorm:"column:target_id;index:idx_audit_logs_resource_target,priority:2" json:"targetId,omitempty"` Description *string `json:"description,omitempty"` IPAddress *string `gorm:"column:ip_address" json:"ipAddress,omitempty"` UserAgent *string `gorm:"column:user_agent" json:"userAgent,omitempty"` Metadata json.RawMessage `gorm:"column:metadata;type:jsonb" json:"metadata,omitempty"` CreatedAt time.Time `gorm:"type:timestamptz;index:idx_audit_logs_user_created,priority:2;index:idx_audit_logs_action_created,priority:2" json:"createdAt"` } func (AuditLog) TableName() string { return "audit_logs" } // Telemetry 遥测数据表 type Telemetry struct { ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"` DeviceKey string `gorm:"column:device_key;index:idx_telemetry_device_timestamp,priority:1" json:"deviceKey"` Metric string `json:"metric"` Value float64 `gorm:"type:float" json:"value"` Timestamp time.Time `gorm:"type:timestamptz;index:idx_telemetry_device_timestamp,priority:2" json:"timestamp"` } func (Telemetry) TableName() string { return "telemetry" }