From ab9842dc106ee4fe0afd790d6e5f6431b8c57825 Mon Sep 17 00:00:00 2001 From: huang <1724659546@qq.com> Date: Tue, 30 Sep 2025 00:18:21 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=20Controller?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/device/device_controller.go | 138 +++++++++++------- 1 file changed, 87 insertions(+), 51 deletions(-) diff --git a/internal/app/controller/device/device_controller.go b/internal/app/controller/device/device_controller.go index 41ac035..4661298 100644 --- a/internal/app/controller/device/device_controller.go +++ b/internal/app/controller/device/device_controller.go @@ -34,37 +34,36 @@ func NewController(repo repository.DeviceRepository, logger *logs.Logger) *Contr // CreateDeviceRequest 定义了创建设备时需要传入的参数 type CreateDeviceRequest struct { - Name string `json:"name" binding:"required"` - Type models.DeviceType `json:"type" binding:"required"` - SubType models.DeviceSubType `json:"sub_type,omitempty"` - ParentID *uint `json:"parent_id,omitempty"` - Location string `json:"location,omitempty"` - Properties map[string]interface{} `json:"properties,omitempty"` + Name string `json:"name" binding:"required"` + DeviceTemplateID uint `json:"device_template_id" binding:"required"` + AreaControllerID uint `json:"area_controller_id" binding:"required"` + Location string `json:"location,omitempty"` + Properties map[string]interface{} `json:"properties,omitempty"` } // UpdateDeviceRequest 定义了更新设备时需要传入的参数 type UpdateDeviceRequest struct { - Name string `json:"name" binding:"required"` - Type models.DeviceType `json:"type" binding:"required"` - SubType models.DeviceSubType `json:"sub_type,omitempty"` - ParentID *uint `json:"parent_id,omitempty"` - Location string `json:"location,omitempty"` - Properties map[string]interface{} `json:"properties,omitempty"` + Name string `json:"name" binding:"required"` + DeviceTemplateID uint `json:"device_template_id" binding:"required"` + AreaControllerID uint `json:"area_controller_id" binding:"required"` + Location string `json:"location,omitempty"` + Properties map[string]interface{} `json:"properties,omitempty"` } // --- Response DTOs --- // DeviceResponse 定义了返回给客户端的单个设备信息的结构 type DeviceResponse struct { - ID uint `json:"id"` - Name string `json:"name"` - Type models.DeviceType `json:"type"` - SubType models.DeviceSubType `json:"sub_type"` - ParentID *uint `json:"parent_id"` - Location string `json:"location"` - Properties map[string]interface{} `json:"properties"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` + ID uint `json:"id"` + Name string `json:"name"` + DeviceTemplateID uint `json:"device_template_id"` + DeviceTemplateName string `json:"device_template_name"` + AreaControllerID uint `json:"area_controller_id"` + AreaControllerName string `json:"area_controller_name"` + Location string `json:"location"` + Properties map[string]interface{} `json:"properties"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` } // --- DTO 转换函数 --- @@ -82,16 +81,28 @@ func newDeviceResponse(device *models.Device) (*DeviceResponse, error) { } } + // 确保 DeviceTemplate 和 AreaController 已预加载 + deviceTemplateName := "" + if device.DeviceTemplate.ID != 0 { + deviceTemplateName = device.DeviceTemplate.Name + } + + areaControllerName := "" + if device.AreaController.ID != 0 { + areaControllerName = device.AreaController.Name + } + return &DeviceResponse{ - ID: device.ID, - Name: device.Name, - Type: device.Type, - SubType: device.SubType, - ParentID: device.ParentID, - Location: device.Location, - Properties: props, - CreatedAt: device.CreatedAt.Format(time.RFC3339), - UpdatedAt: device.UpdatedAt.Format(time.RFC3339), + ID: device.ID, + Name: device.Name, + DeviceTemplateID: device.DeviceTemplateID, + DeviceTemplateName: deviceTemplateName, + AreaControllerID: device.AreaControllerID, + AreaControllerName: areaControllerName, + Location: device.Location, + Properties: props, + CreatedAt: device.CreatedAt.Format(time.RFC3339), + UpdatedAt: device.UpdatedAt.Format(time.RFC3339), }, nil } @@ -136,18 +147,21 @@ func (c *Controller) CreateDevice(ctx *gin.Context) { } device := &models.Device{ - Name: req.Name, - Type: req.Type, - SubType: req.SubType, - ParentID: req.ParentID, - Location: req.Location, - Properties: propertiesJSON, + Name: req.Name, + DeviceTemplateID: req.DeviceTemplateID, + AreaControllerID: req.AreaControllerID, + Location: req.Location, + Properties: propertiesJSON, } // 在创建设备前进行自检 - if !device.SelfCheck() { - c.logger.Errorf("%s: 设备属性自检失败: %v", actionType, device) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求", actionType, "设备属性自检失败", device) + // 注意:这里的 SelfCheck 依赖于 DeviceTemplate 和 AreaController 字段, + // 但在创建时这些关联对象可能尚未完全加载。如果 SelfCheck 内部需要这些关联对象, + // 则需要在调用 SelfCheck 之前手动加载或调整 SelfCheck 逻辑。 + // 目前假设 SelfCheck 仅检查 ID 和 Properties。 + if err := device.SelfCheck(); err != nil { + c.logger.Errorf("%s: 设备属性自检失败: %v", actionType, err) + controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求: "+err.Error(), actionType, "设备属性自检失败", device) return } @@ -157,10 +171,18 @@ func (c *Controller) CreateDevice(ctx *gin.Context) { return } - resp, err := newDeviceResponse(device) + // 为了在响应中包含 DeviceTemplateName 和 AreaControllerName,需要重新从数据库加载设备,并预加载关联。 + createdDevice, err := c.repo.FindByID(device.ID) + if err != nil { + c.logger.Errorf("%s: 重新加载创建的设备失败: %v", actionType, err) + controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但重新加载设备失败", actionType, "重新加载设备失败", device) + return + } + + resp, err := newDeviceResponse(createdDevice) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但响应生成失败", actionType, "响应序列化失败", device) + controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但响应生成失败", actionType, "响应序列化失败", createdDevice) return } @@ -186,6 +208,7 @@ func (c *Controller) GetDevice(ctx *gin.Context) { return } + // 假设 FindByIDString 方法会预加载 DeviceTemplate 和 AreaController device, err := c.repo.FindByIDString(deviceID) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { @@ -223,6 +246,7 @@ func (c *Controller) GetDevice(ctx *gin.Context) { // @Router /api/v1/devices [get] func (c *Controller) ListDevices(ctx *gin.Context) { const actionType = "获取设备列表" + // 假设 ListAll 方法会预加载 DeviceTemplate 和 AreaController devices, err := c.repo.ListAll() if err != nil { c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err) @@ -256,6 +280,7 @@ func (c *Controller) UpdateDevice(ctx *gin.Context) { deviceID := ctx.Param("id") // 1. 检查设备是否存在 + // 假设 FindByIDString 方法会预加载 DeviceTemplate 和 AreaController existingDevice, err := c.repo.FindByIDString(deviceID) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { @@ -290,16 +315,19 @@ func (c *Controller) UpdateDevice(ctx *gin.Context) { // 3. 更新从数据库中查出的现有设备对象的字段 existingDevice.Name = req.Name - existingDevice.Type = req.Type - existingDevice.SubType = req.SubType - existingDevice.ParentID = req.ParentID + existingDevice.DeviceTemplateID = req.DeviceTemplateID + existingDevice.AreaControllerID = req.AreaControllerID existingDevice.Location = req.Location existingDevice.Properties = propertiesJSON // 在更新设备前进行自检 - if !existingDevice.SelfCheck() { - c.logger.Errorf("%s: 设备属性自检失败: %v", actionType, existingDevice) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求", actionType, "设备属性自检失败", existingDevice) + // 注意:这里的 SelfCheck 依赖于 DeviceTemplate 和 AreaController 字段, + // 但在更新时这些关联对象可能尚未完全加载。如果 SelfCheck 内部需要这些关联对象, + // 则需要在调用 SelfCheck 之前手动加载或调整 SelfCheck 逻辑。 + // 目前假设 SelfCheck 仅检查 ID 和 Properties。 + if err := existingDevice.SelfCheck(); err != nil { + c.logger.Errorf("%s: 设备属性自检失败: %v", actionType, err) + controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求: "+err.Error(), actionType, "设备属性自检失败", existingDevice) return } @@ -310,10 +338,18 @@ func (c *Controller) UpdateDevice(ctx *gin.Context) { return } - resp, err := newDeviceResponse(existingDevice) + // 为了在响应中包含 DeviceTemplateName 和 AreaControllerName,需要重新从数据库加载设备,并预加载关联。 + updatedDevice, err := c.repo.FindByID(existingDevice.ID) if err != nil { - c.logger.Errorf("%s: 序列化响应失败: %v, Device: %+v", actionType, err, existingDevice) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备更新成功,但响应生成失败", actionType, "响应序列化失败", existingDevice) + c.logger.Errorf("%s: 重新加载更新的设备失败: %v", actionType, err) + controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备更新成功,但重新加载设备失败", actionType, "重新加载设备失败", existingDevice) + return + } + + resp, err := newDeviceResponse(updatedDevice) + if err != nil { + c.logger.Errorf("%s: 序列化响应失败: %v, Device: %+v", actionType, err, updatedDevice) + controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备更新成功,但响应生成失败", actionType, "响应序列化失败", updatedDevice) return } @@ -346,7 +382,7 @@ func (c *Controller) DeleteDevice(ctx *gin.Context) { if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备不存在", actionType, "设备不存在", deviceID) + controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID) return } c.logger.Errorf("%s: 查找设备失败: %v, ID: %s", actionType, err, deviceID)