调整 Controller

This commit is contained in:
2025-09-30 00:18:21 +08:00
parent 56dbb680a7
commit ab9842dc10

View File

@@ -34,37 +34,36 @@ func NewController(repo repository.DeviceRepository, logger *logs.Logger) *Contr
// CreateDeviceRequest 定义了创建设备时需要传入的参数 // CreateDeviceRequest 定义了创建设备时需要传入的参数
type CreateDeviceRequest struct { type CreateDeviceRequest struct {
Name string `json:"name" binding:"required"` Name string `json:"name" binding:"required"`
Type models.DeviceType `json:"type" binding:"required"` DeviceTemplateID uint `json:"device_template_id" binding:"required"`
SubType models.DeviceSubType `json:"sub_type,omitempty"` AreaControllerID uint `json:"area_controller_id" binding:"required"`
ParentID *uint `json:"parent_id,omitempty"` Location string `json:"location,omitempty"`
Location string `json:"location,omitempty"` Properties map[string]interface{} `json:"properties,omitempty"`
Properties map[string]interface{} `json:"properties,omitempty"`
} }
// UpdateDeviceRequest 定义了更新设备时需要传入的参数 // UpdateDeviceRequest 定义了更新设备时需要传入的参数
type UpdateDeviceRequest struct { type UpdateDeviceRequest struct {
Name string `json:"name" binding:"required"` Name string `json:"name" binding:"required"`
Type models.DeviceType `json:"type" binding:"required"` DeviceTemplateID uint `json:"device_template_id" binding:"required"`
SubType models.DeviceSubType `json:"sub_type,omitempty"` AreaControllerID uint `json:"area_controller_id" binding:"required"`
ParentID *uint `json:"parent_id,omitempty"` Location string `json:"location,omitempty"`
Location string `json:"location,omitempty"` Properties map[string]interface{} `json:"properties,omitempty"`
Properties map[string]interface{} `json:"properties,omitempty"`
} }
// --- Response DTOs --- // --- Response DTOs ---
// DeviceResponse 定义了返回给客户端的单个设备信息的结构 // DeviceResponse 定义了返回给客户端的单个设备信息的结构
type DeviceResponse struct { type DeviceResponse struct {
ID uint `json:"id"` ID uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Type models.DeviceType `json:"type"` DeviceTemplateID uint `json:"device_template_id"`
SubType models.DeviceSubType `json:"sub_type"` DeviceTemplateName string `json:"device_template_name"`
ParentID *uint `json:"parent_id"` AreaControllerID uint `json:"area_controller_id"`
Location string `json:"location"` AreaControllerName string `json:"area_controller_name"`
Properties map[string]interface{} `json:"properties"` Location string `json:"location"`
CreatedAt string `json:"created_at"` Properties map[string]interface{} `json:"properties"`
UpdatedAt string `json:"updated_at"` CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
} }
// --- DTO 转换函数 --- // --- 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{ return &DeviceResponse{
ID: device.ID, ID: device.ID,
Name: device.Name, Name: device.Name,
Type: device.Type, DeviceTemplateID: device.DeviceTemplateID,
SubType: device.SubType, DeviceTemplateName: deviceTemplateName,
ParentID: device.ParentID, AreaControllerID: device.AreaControllerID,
Location: device.Location, AreaControllerName: areaControllerName,
Properties: props, Location: device.Location,
CreatedAt: device.CreatedAt.Format(time.RFC3339), Properties: props,
UpdatedAt: device.UpdatedAt.Format(time.RFC3339), CreatedAt: device.CreatedAt.Format(time.RFC3339),
UpdatedAt: device.UpdatedAt.Format(time.RFC3339),
}, nil }, nil
} }
@@ -136,18 +147,21 @@ func (c *Controller) CreateDevice(ctx *gin.Context) {
} }
device := &models.Device{ device := &models.Device{
Name: req.Name, Name: req.Name,
Type: req.Type, DeviceTemplateID: req.DeviceTemplateID,
SubType: req.SubType, AreaControllerID: req.AreaControllerID,
ParentID: req.ParentID, Location: req.Location,
Location: req.Location, Properties: propertiesJSON,
Properties: propertiesJSON,
} }
// 在创建设备前进行自检 // 在创建设备前进行自检
if !device.SelfCheck() { // 注意:这里的 SelfCheck 依赖于 DeviceTemplate 和 AreaController 字段,
c.logger.Errorf("%s: 设备属性自检失败: %v", actionType, device) // 但在创建时这些关联对象可能尚未完全加载。如果 SelfCheck 内部需要这些关联对象,
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求", actionType, "设备属性自检失败", device) // 则需要在调用 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 return
} }
@@ -157,10 +171,18 @@ func (c *Controller) CreateDevice(ctx *gin.Context) {
return 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 { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v", actionType, err) c.logger.Errorf("%s: 序列化响应失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但响应生成失败", actionType, "响应序列化失败", device) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但响应生成失败", actionType, "响应序列化失败", createdDevice)
return return
} }
@@ -186,6 +208,7 @@ func (c *Controller) GetDevice(ctx *gin.Context) {
return return
} }
// 假设 FindByIDString 方法会预加载 DeviceTemplate 和 AreaController
device, err := c.repo.FindByIDString(deviceID) device, err := c.repo.FindByIDString(deviceID)
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
@@ -223,6 +246,7 @@ func (c *Controller) GetDevice(ctx *gin.Context) {
// @Router /api/v1/devices [get] // @Router /api/v1/devices [get]
func (c *Controller) ListDevices(ctx *gin.Context) { func (c *Controller) ListDevices(ctx *gin.Context) {
const actionType = "获取设备列表" const actionType = "获取设备列表"
// 假设 ListAll 方法会预加载 DeviceTemplate 和 AreaController
devices, err := c.repo.ListAll() devices, err := c.repo.ListAll()
if err != nil { if err != nil {
c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err) c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err)
@@ -256,6 +280,7 @@ func (c *Controller) UpdateDevice(ctx *gin.Context) {
deviceID := ctx.Param("id") deviceID := ctx.Param("id")
// 1. 检查设备是否存在 // 1. 检查设备是否存在
// 假设 FindByIDString 方法会预加载 DeviceTemplate 和 AreaController
existingDevice, err := c.repo.FindByIDString(deviceID) existingDevice, err := c.repo.FindByIDString(deviceID)
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
@@ -290,16 +315,19 @@ func (c *Controller) UpdateDevice(ctx *gin.Context) {
// 3. 更新从数据库中查出的现有设备对象的字段 // 3. 更新从数据库中查出的现有设备对象的字段
existingDevice.Name = req.Name existingDevice.Name = req.Name
existingDevice.Type = req.Type existingDevice.DeviceTemplateID = req.DeviceTemplateID
existingDevice.SubType = req.SubType existingDevice.AreaControllerID = req.AreaControllerID
existingDevice.ParentID = req.ParentID
existingDevice.Location = req.Location existingDevice.Location = req.Location
existingDevice.Properties = propertiesJSON existingDevice.Properties = propertiesJSON
// 在更新设备前进行自检 // 在更新设备前进行自检
if !existingDevice.SelfCheck() { // 注意:这里的 SelfCheck 依赖于 DeviceTemplate 和 AreaController 字段,
c.logger.Errorf("%s: 设备属性自检失败: %v", actionType, existingDevice) // 但在更新时这些关联对象可能尚未完全加载。如果 SelfCheck 内部需要这些关联对象,
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求", actionType, "设备属性自检失败", existingDevice) // 则需要在调用 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 return
} }
@@ -310,10 +338,18 @@ func (c *Controller) UpdateDevice(ctx *gin.Context) {
return return
} }
resp, err := newDeviceResponse(existingDevice) // 为了在响应中包含 DeviceTemplateName 和 AreaControllerName需要重新从数据库加载设备并预加载关联。
updatedDevice, err := c.repo.FindByID(existingDevice.ID)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, Device: %+v", actionType, err, existingDevice) c.logger.Errorf("%s: 重新加载更新的设备失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备更新成功,但响应生成失败", actionType, "响应序列化失败", existingDevice) 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 return
} }
@@ -346,7 +382,7 @@ func (c *Controller) DeleteDevice(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID) c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备不存在", actionType, "设备不存在", deviceID) controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID)
return return
} }
c.logger.Errorf("%s: 查找设备失败: %v, ID: %s", actionType, err, deviceID) c.logger.Errorf("%s: 查找设备失败: %v, ID: %s", actionType, err, deviceID)