重构 #4
							
								
								
									
										5
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								go.mod
									
									
									
									
									
								
							| @@ -10,12 +10,14 @@ require ( | ||||
| 	golang.org/x/crypto v0.31.0 | ||||
| 	gopkg.in/natefinch/lumberjack.v2 v2.2.1 | ||||
| 	gopkg.in/yaml.v2 v2.4.0 | ||||
| 	gorm.io/datatypes v1.2.6 | ||||
| 	gorm.io/driver/postgres v1.6.0 | ||||
| 	gorm.io/driver/sqlite v1.6.0 | ||||
| 	gorm.io/gorm v1.30.5 | ||||
| ) | ||||
|  | ||||
| require ( | ||||
| 	filippo.io/edwards25519 v1.1.0 // indirect | ||||
| 	github.com/bytedance/sonic v1.11.6 // indirect | ||||
| 	github.com/bytedance/sonic/loader v0.1.1 // indirect | ||||
| 	github.com/cloudwego/base64x v0.1.4 // indirect | ||||
| @@ -26,7 +28,9 @@ require ( | ||||
| 	github.com/go-playground/locales v0.14.1 // indirect | ||||
| 	github.com/go-playground/universal-translator v0.18.1 // indirect | ||||
| 	github.com/go-playground/validator/v10 v10.20.0 // indirect | ||||
| 	github.com/go-sql-driver/mysql v1.8.1 // indirect | ||||
| 	github.com/goccy/go-json v0.10.2 // indirect | ||||
| 	github.com/google/uuid v1.6.0 // indirect | ||||
| 	github.com/jackc/pgpassfile v1.0.0 // indirect | ||||
| 	github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect | ||||
| 	github.com/jackc/pgx/v5 v5.6.0 // indirect | ||||
| @@ -54,4 +58,5 @@ require ( | ||||
| 	golang.org/x/text v0.21.0 // indirect | ||||
| 	google.golang.org/protobuf v1.34.1 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| 	gorm.io/driver/mysql v1.5.6 // indirect | ||||
| ) | ||||
|   | ||||
							
								
								
									
										20
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								go.sum
									
									
									
									
									
								
							| @@ -1,3 +1,5 @@ | ||||
| filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= | ||||
| filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= | ||||
| github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= | ||||
| github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= | ||||
| github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= | ||||
| @@ -23,13 +25,22 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn | ||||
| github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= | ||||
| github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= | ||||
| github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= | ||||
| github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= | ||||
| github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= | ||||
| github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= | ||||
| github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= | ||||
| github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= | ||||
| github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= | ||||
| github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= | ||||
| github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= | ||||
| github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= | ||||
| github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= | ||||
| github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= | ||||
| github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= | ||||
| github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | ||||
| github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= | ||||
| github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||
| github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= | ||||
| github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= | ||||
| github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= | ||||
| @@ -58,6 +69,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE | ||||
| github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | ||||
| github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= | ||||
| github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= | ||||
| github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA= | ||||
| github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= | ||||
| github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= | ||||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||||
| @@ -122,10 +135,17 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | ||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gorm.io/datatypes v1.2.6 h1:KafLdXvFUhzNeL2ncm03Gl3eTLONQfNKZ+wJ+9Y4Nck= | ||||
| gorm.io/datatypes v1.2.6/go.mod h1:M2iO+6S3hhi4nAyYe444Pcb0dcIiOMJ7QHaUXxyiNZY= | ||||
| gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8= | ||||
| gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= | ||||
| gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4= | ||||
| gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo= | ||||
| gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= | ||||
| gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= | ||||
| gorm.io/driver/sqlserver v1.6.0 h1:VZOBQVsVhkHU/NzNhRJKoANt5pZGQAS1Bwc6m6dgfnc= | ||||
| gorm.io/driver/sqlserver v1.6.0/go.mod h1:WQzt4IJo/WHKnckU9jXBLMJIVNMVeTu25dnOzehntWw= | ||||
| gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= | ||||
| gorm.io/gorm v1.30.5 h1:dvEfYwxL+i+xgCNSGGBT1lDjCzfELK8fHZxL3Ee9X0s= | ||||
| gorm.io/gorm v1.30.5/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= | ||||
| nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= | ||||
|   | ||||
| @@ -119,7 +119,7 @@ func initStorage(cfg config.DatabaseConfig, logger *logs.Logger) (database.Stora | ||||
|  | ||||
| 	// 执行数据库迁移 | ||||
| 	// 这里需要添加所有需要自动迁移的模型 | ||||
| 	var dbModels = []interface{}{&models.User{}} | ||||
| 	var dbModels = []interface{}{&models.User{}, &models.Device{}} | ||||
| 	if err := storage.Migrate(dbModels...); err != nil { | ||||
| 		return nil, fmt.Errorf("数据库迁移失败: %w", err) | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										100
									
								
								internal/infra/models/device.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								internal/infra/models/device.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| package models | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
|  | ||||
| 	"gorm.io/datatypes" | ||||
| 	"gorm.io/gorm" | ||||
| ) | ||||
|  | ||||
| // DeviceType 定义了设备的高级类别 | ||||
| type DeviceType string | ||||
|  | ||||
| const ( | ||||
| 	// DeviceTypeAreaController 区域主控,负责管理一个片区的设备 | ||||
| 	DeviceTypeAreaController DeviceType = "area_controller" | ||||
| 	// DeviceTypeDevice 普通设备,如传感器、阀门等 | ||||
| 	DeviceTypeDevice DeviceType = "device" | ||||
| ) | ||||
|  | ||||
| // DeviceSubType 定义了普通设备的具体子类别 | ||||
| type DeviceSubType string | ||||
|  | ||||
| const ( | ||||
| 	// SubTypeNone 未指定或不适用的子类型 | ||||
| 	SubTypeNone DeviceSubType = "" | ||||
| 	// SubTypeSensorTemp 温度传感器 | ||||
| 	SubTypeSensorTemp DeviceSubType = "temperature" | ||||
| 	// SubTypeSensorHumidity 湿度传感器 | ||||
| 	SubTypeSensorHumidity DeviceSubType = "humidity" | ||||
| 	// SubTypeSensorAmmonia 氨气传感器 | ||||
| 	SubTypeSensorAmmonia DeviceSubType = "ammonia" | ||||
|  | ||||
| 	// SubTypeValveFeed 下料阀门 | ||||
| 	SubTypeValveFeed DeviceSubType = "feed_valve" | ||||
| 	// SubTypeFan 风机 | ||||
| 	SubTypeFan DeviceSubType = "fan" | ||||
| 	// SubTypeWaterCurtain 水帘 | ||||
| 	SubTypeWaterCurtain DeviceSubType = "water_curtain" | ||||
| ) | ||||
|  | ||||
| // --- Properties 结构体定义 --- | ||||
|  | ||||
| // LoraProperties 定义了区域主控的特有属性 | ||||
| type LoraProperties struct { | ||||
| 	LoraAddress string `json:"lora_address"` // LoRa 地址 | ||||
| } | ||||
|  | ||||
| // BusProperties 定义了总线设备的特有属性 | ||||
| type BusProperties struct { | ||||
| 	BusID      int `json:"bus_id"`      // 485 总线号 | ||||
| 	BusAddress int `json:"bus_address"` // 485 总线地址 | ||||
| } | ||||
|  | ||||
| // Device 代表系统中的所有设备 | ||||
| type Device struct { | ||||
| 	// gorm.Model 内嵌了标准模型字段 (ID, CreatedAt, UpdatedAt, DeletedAt) | ||||
| 	gorm.Model | ||||
|  | ||||
| 	// Name 是设备的业务名称,应清晰可读,例如 "1号猪舍温度传感器" 或 "做料车间主控" | ||||
| 	Name string `gorm:"not null" json:"name"` | ||||
|  | ||||
| 	// DeviceCode 是设备的唯一出厂编码或序列号,用于在系统中唯一标识一个物理设备 | ||||
| 	DeviceCode string `gorm:"unique;not null" json:"device_code"` | ||||
|  | ||||
| 	// Type 是设备的高级类别,用于区分区域主控和普通设备。建立索引以优化按类型查询。 | ||||
| 	Type DeviceType `gorm:"not null;index" json:"type"` | ||||
|  | ||||
| 	// SubType 是设备的子类别,用于描述普通设备的具体功能,例如 "temperature", "fan" 等。建立索引以优化按子类型查询。 | ||||
| 	SubType DeviceSubType `gorm:"index" json:"sub_type"` | ||||
|  | ||||
| 	// ParentID 指向其父级设备的ID。对于顶层设备(如区域主控),此值为 NULL。 | ||||
| 	// 使用指针类型 *uint 来允许 NULL 值,从而清晰地表示“无父级”,避免了使用 0 作为魔术数字的歧义。建立索引以优化层级查询。 | ||||
| 	ParentID *uint `gorm:"index" json:"parent_id"` | ||||
|  | ||||
| 	// Location 描述了设备的物理安装位置,例如 "1号猪舍东侧",方便运维。建立索引以优化按位置查询。 | ||||
| 	Location string `gorm:"index" json:"location"` | ||||
|  | ||||
| 	// Properties 用于存储特定类型设备的独有属性,采用JSON格式。 | ||||
| 	// 建议在应用层为不同子类型的设备定义专用的属性结构体(如 LoraProperties, BusProperties),以保证数据一致性。 | ||||
| 	Properties datatypes.JSON `json:"properties"` | ||||
| } | ||||
|  | ||||
| // TableName 自定义 GORM 使用的数据库表名 | ||||
| func (Device) TableName() string { | ||||
| 	return "devices" | ||||
| } | ||||
|  | ||||
| // ParseProperties 解析 JSON 属性到一个具体的结构体中。 | ||||
| // 调用方需要传入一个指向目标结构体实例的指针。 | ||||
| // 示例: | ||||
| // | ||||
| //	var props LoraProperties | ||||
| //	if err := device.ParseProperties(&props); err != nil { ... } | ||||
| func (d *Device) ParseProperties(v interface{}) error { | ||||
| 	if d.Properties == nil { | ||||
| 		return errors.New("设备属性为空,无法解析") | ||||
| 	} | ||||
| 	return json.Unmarshal(d.Properties, v) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user