diff --git a/internal/app/controller/device/device_controller.go b/internal/app/controller/device/device_controller.go index df5a8c5..ba6510a 100644 --- a/internal/app/controller/device/device_controller.go +++ b/internal/app/controller/device/device_controller.go @@ -12,7 +12,7 @@ import ( "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" - "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" "gorm.io/gorm" ) @@ -54,20 +54,18 @@ func NewController( // @Param device body dto.CreateDeviceRequest true "设备信息" // @Success 200 {object} controller.Response{data=dto.DeviceResponse} // @Router /api/v1/devices [post] -func (c *Controller) CreateDevice(ctx *gin.Context) { +func (c *Controller) CreateDevice(ctx echo.Context) error { const actionType = "创建设备" var req dto.CreateDeviceRequest - if err := ctx.ShouldBindJSON(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) } propertiesJSON, err := json.Marshal(req.Properties) if err != nil { c.logger.Errorf("%s: 序列化属性失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties) } device := &models.Device{ @@ -80,32 +78,28 @@ func (c *Controller) CreateDevice(ctx *gin.Context) { if err := device.SelfCheck(); err != nil { c.logger.Errorf("%s: 设备属性自检失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求: "+err.Error(), actionType, "设备属性自检失败", device) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求: "+err.Error(), actionType, "设备属性自检失败", device) } if err := c.deviceRepo.Create(device); err != nil { c.logger.Errorf("%s: 数据库操作失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建设备失败: "+err.Error(), actionType, "数据库创建失败", device) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建设备失败: "+err.Error(), actionType, "数据库创建失败", device) } createdDevice, err := c.deviceRepo.FindByID(device.ID) if err != nil { c.logger.Errorf("%s: 重新加载创建的设备失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但重新加载设备失败", actionType, "重新加载设备失败", device) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但重新加载设备失败", actionType, "重新加载设备失败", device) } resp, err := dto.NewDeviceResponse(createdDevice) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, Device: %+v", actionType, err, createdDevice) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但响应生成失败", actionType, "响应序列化失败", createdDevice) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但响应生成失败", actionType, "响应序列化失败", createdDevice) } c.logger.Infof("%s: 设备创建成功, ID: %d", actionType, device.ID) - controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "设备创建成功", resp, actionType, "设备创建成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "设备创建成功", resp, actionType, "设备创建成功", resp) } // GetDevice godoc @@ -117,42 +111,37 @@ func (c *Controller) CreateDevice(ctx *gin.Context) { // @Param id path string true "设备ID" // @Success 200 {object} controller.Response{data=dto.DeviceResponse} // @Router /api/v1/devices/{id} [get] -func (c *Controller) GetDevice(ctx *gin.Context) { +func (c *Controller) GetDevice(ctx echo.Context) error { const actionType = "获取设备" deviceID := ctx.Param("id") if deviceID == "" { c.logger.Errorf("%s: 设备ID为空", actionType) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备ID不能为空", actionType, "设备ID为空", nil) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备ID不能为空", actionType, "设备ID为空", nil) } device, err := c.deviceRepo.FindByIDString(deviceID) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID) } if strings.Contains(err.Error(), "无效的设备ID格式") { c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID) } c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备信息失败: "+err.Error(), actionType, "数据库查询失败", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备信息失败: "+err.Error(), actionType, "数据库查询失败", deviceID) } resp, err := dto.NewDeviceResponse(device) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, Device: %+v", actionType, err, device) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备信息失败: 内部数据格式错误", actionType, "响应序列化失败", device) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备信息失败: 内部数据格式错误", actionType, "响应序列化失败", device) } c.logger.Infof("%s: 获取设备信息成功, ID: %d", actionType, device.ID) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备信息成功", resp, actionType, "获取设备信息成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备信息成功", resp, actionType, "获取设备信息成功", resp) } // ListDevices godoc @@ -163,24 +152,22 @@ func (c *Controller) GetDevice(ctx *gin.Context) { // @Produce json // @Success 200 {object} controller.Response{data=[]dto.DeviceResponse} // @Router /api/v1/devices [get] -func (c *Controller) ListDevices(ctx *gin.Context) { +func (c *Controller) ListDevices(ctx echo.Context) error { const actionType = "获取设备列表" devices, err := c.deviceRepo.ListAll() if err != nil { c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备列表失败: "+err.Error(), actionType, "数据库查询失败", nil) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备列表失败: "+err.Error(), actionType, "数据库查询失败", nil) } resp, err := dto.NewListDeviceResponse(devices) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, Devices: %+v", actionType, err, devices) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备列表失败: 内部数据格式错误", actionType, "响应序列化失败", devices) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备列表失败: 内部数据格式错误", actionType, "响应序列化失败", devices) } c.logger.Infof("%s: 获取设备列表成功, 数量: %d", actionType, len(devices)) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备列表成功", resp, actionType, "获取设备列表成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备列表成功", resp, actionType, "获取设备列表成功", resp) } // UpdateDevice godoc @@ -194,7 +181,7 @@ func (c *Controller) ListDevices(ctx *gin.Context) { // @Param device body dto.UpdateDeviceRequest true "要更新的设备信息" // @Success 200 {object} controller.Response{data=dto.DeviceResponse} // @Router /api/v1/devices/{id} [put] -func (c *Controller) UpdateDevice(ctx *gin.Context) { +func (c *Controller) UpdateDevice(ctx echo.Context) error { const actionType = "更新设备" deviceID := ctx.Param("id") @@ -202,31 +189,26 @@ func (c *Controller) UpdateDevice(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) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID) } if strings.Contains(err.Error(), "无效的设备ID格式") { c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID) } c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备失败: "+err.Error(), actionType, "数据库查询失败", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备失败: "+err.Error(), actionType, "数据库查询失败", deviceID) } var req dto.UpdateDeviceRequest - if err := ctx.ShouldBindJSON(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) } propertiesJSON, err := json.Marshal(req.Properties) if err != nil { c.logger.Errorf("%s: 序列化属性失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties) } existingDevice.Name = req.Name @@ -237,32 +219,28 @@ func (c *Controller) UpdateDevice(ctx *gin.Context) { if err := existingDevice.SelfCheck(); err != nil { c.logger.Errorf("%s: 设备属性自检失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求: "+err.Error(), actionType, "设备属性自检失败", existingDevice) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求: "+err.Error(), actionType, "设备属性自检失败", existingDevice) } if err := c.deviceRepo.Update(existingDevice); err != nil { c.logger.Errorf("%s: 数据库更新失败: %v, Device: %+v", actionType, err, existingDevice) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备失败: "+err.Error(), actionType, "数据库更新失败", existingDevice) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备失败: "+err.Error(), actionType, "数据库更新失败", deviceID) } updatedDevice, err := c.deviceRepo.FindByID(existingDevice.ID) if err != nil { c.logger.Errorf("%s: 重新加载更新的设备失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备更新成功,但重新加载设备失败", actionType, "重新加载设备失败", existingDevice) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备更新成功,但重新加载设备失败", actionType, "重新加载设备失败", existingDevice) } resp, err := dto.NewDeviceResponse(updatedDevice) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, Device: %+v", actionType, err, updatedDevice) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备更新成功,但响应生成失败", actionType, "响应序列化失败", updatedDevice) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备更新成功,但响应生成失败", actionType, "响应序列化失败", updatedDevice) } c.logger.Infof("%s: 设备更新成功, ID: %d", actionType, existingDevice.ID) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备更新成功", resp, actionType, "设备更新成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备更新成功", resp, actionType, "设备更新成功", resp) } // DeleteDevice godoc @@ -274,37 +252,33 @@ func (c *Controller) UpdateDevice(ctx *gin.Context) { // @Param id path string true "设备ID" // @Success 200 {object} controller.Response // @Router /api/v1/devices/{id} [delete] -func (c *Controller) DeleteDevice(ctx *gin.Context) { +func (c *Controller) DeleteDevice(ctx echo.Context) error { const actionType = "删除设备" deviceID := ctx.Param("id") idUint, err := strconv.ParseUint(deviceID, 10, 64) if err != nil { c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备ID格式", actionType, "设备ID格式错误", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备ID格式", actionType, "设备ID格式错误", deviceID) } _, err = c.deviceRepo.FindByIDString(deviceID) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID) } c.logger.Errorf("%s: 查找设备失败: %v, ID: %s", actionType, err, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备失败: 查找设备时发生内部错误", actionType, "数据库查询失败", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备失败: 查找设备时发生内部错误", actionType, "数据库查询失败", deviceID) } if err := c.deviceRepo.Delete(uint(idUint)); err != nil { c.logger.Errorf("%s: 数据库删除失败: %v, ID: %d", actionType, err, idUint) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备失败: "+err.Error(), actionType, "数据库删除失败", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备失败: "+err.Error(), actionType, "数据库删除失败", deviceID) } c.logger.Infof("%s: 设备删除成功, ID: %d", actionType, idUint) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备删除成功", nil, actionType, "设备删除成功", deviceID) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备删除成功", nil, actionType, "设备删除成功", deviceID) } // ManualControl godoc @@ -318,32 +292,28 @@ func (c *Controller) DeleteDevice(ctx *gin.Context) { // @Param manualControl body dto.ManualControlDeviceRequest true "手动控制指令" // @Success 200 {object} controller.Response // @Router /api/v1/devices/manual-control/{id} [post] -func (c *Controller) ManualControl(ctx *gin.Context) { +func (c *Controller) ManualControl(ctx echo.Context) error { const actionType = "手动控制设备" deviceID := ctx.Param("id") var req dto.ManualControlDeviceRequest - if err := ctx.ShouldBindJSON(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) } dev, err := c.deviceRepo.FindByIDString(deviceID) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID) } if strings.Contains(err.Error(), "无效的设备ID格式") { c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID) } c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "手动控制失败: "+err.Error(), actionType, "数据库查询失败", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "手动控制失败: "+err.Error(), actionType, "数据库查询失败", deviceID) } c.logger.Infof("%s: 接收到指令, 设备ID: %s, 动作: %s", actionType, deviceID, req.Action) @@ -351,7 +321,7 @@ func (c *Controller) ManualControl(ctx *gin.Context) { err = c.deviceService.Collect(dev.AreaControllerID, []*models.Device{dev}) if err != nil { c.logger.Errorf("%s: 获取设备状态失败: %v, 设备ID: %s", actionType, err, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备状态失败: "+err.Error(), actionType, "获取设备状态失败", deviceID) + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备状态失败: "+err.Error(), actionType, "获取设备状态失败", deviceID) } } else { action := device.DeviceActionStart @@ -361,17 +331,16 @@ func (c *Controller) ManualControl(ctx *gin.Context) { case "on": default: c.logger.Errorf("%s: 无效的动作: %s, 设备ID: %s", actionType, *req.Action, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的动作: "+*req.Action, actionType, "无效的动作", req.Action) + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的动作: "+*req.Action, actionType, "无效的动作", req.Action) } err = c.deviceService.Switch(dev, action) if err != nil { c.logger.Errorf("%s: 设备控制失败: %v, 设备ID: %s", actionType, err, deviceID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备控制失败: "+err.Error(), actionType, "设备控制失败", deviceID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备控制失败: "+err.Error(), actionType, "设备控制失败", deviceID) } } - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "指令已发送", map[string]interface{}{"device_id": deviceID}, actionType, "指令发送成功", gin.H{"device_id": deviceID, "action": req.Action}) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "指令已发送", map[string]interface{}{"device_id": deviceID}, actionType, "指令发送成功", map[string]interface{}{"device_id": deviceID, "action": req.Action}) } // --- Controller Methods: Area Controllers --- @@ -386,20 +355,18 @@ func (c *Controller) ManualControl(ctx *gin.Context) { // @Param areaController body dto.CreateAreaControllerRequest true "区域主控信息" // @Success 200 {object} controller.Response{data=dto.AreaControllerResponse} // @Router /api/v1/area-controllers [post] -func (c *Controller) CreateAreaController(ctx *gin.Context) { +func (c *Controller) CreateAreaController(ctx echo.Context) error { const actionType = "创建区域主控" var req dto.CreateAreaControllerRequest - if err := ctx.ShouldBindJSON(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) } propertiesJSON, err := json.Marshal(req.Properties) if err != nil { c.logger.Errorf("%s: 序列化属性失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties) } ac := &models.AreaController{ @@ -411,25 +378,22 @@ func (c *Controller) CreateAreaController(ctx *gin.Context) { if err := ac.SelfCheck(); err != nil { c.logger.Errorf("%s: 区域主控自检失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "区域主控参数不符合要求: "+err.Error(), actionType, "区域主控自检失败", ac) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "区域主控参数不符合要求: "+err.Error(), actionType, "区域主控自检失败", ac) } if err := c.areaControllerRepo.Create(ac); err != nil { c.logger.Errorf("%s: 数据库操作失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建区域主控失败: "+err.Error(), actionType, "数据库创建失败", ac) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建区域主控失败: "+err.Error(), actionType, "数据库创建失败", ac) } resp, err := dto.NewAreaControllerResponse(ac) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "区域主控创建成功,但响应生成失败", actionType, "响应序列化失败", ac) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "区域主控创建成功,但响应生成失败", actionType, "响应序列化失败", ac) } c.logger.Infof("%s: 区域主控创建成功, ID: %d", actionType, ac.ID) - controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "区域主控创建成功", resp, actionType, "区域主控创建成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "区域主控创建成功", resp, actionType, "区域主控创建成功", resp) } // GetAreaController godoc @@ -441,38 +405,34 @@ func (c *Controller) CreateAreaController(ctx *gin.Context) { // @Param id path string true "区域主控ID" // @Success 200 {object} controller.Response{data=dto.AreaControllerResponse} // @Router /api/v1/area-controllers/{id} [get] -func (c *Controller) GetAreaController(ctx *gin.Context) { +func (c *Controller) GetAreaController(ctx echo.Context) error { const actionType = "获取区域主控" acID := ctx.Param("id") idUint, err := strconv.ParseUint(acID, 10, 64) if err != nil { c.logger.Errorf("%s: 区域主控ID格式错误: %v, ID: %s", actionType, err, acID) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的区域主控ID格式", actionType, "ID格式错误", acID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的区域主控ID格式", actionType, "ID格式错误", acID) } ac, err := c.areaControllerRepo.FindByID(uint(idUint)) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID) } c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, acID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控信息失败: "+err.Error(), actionType, "数据库查询失败", acID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控信息失败: "+err.Error(), actionType, "数据库查询失败", acID) } resp, err := dto.NewAreaControllerResponse(ac) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, AreaController: %+v", actionType, err, ac) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控信息失败: 内部数据格式错误", actionType, "响应序列化失败", ac) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控信息失败: 内部数据格式错误", actionType, "响应序列化失败", ac) } c.logger.Infof("%s: 获取区域主控信息成功, ID: %d", actionType, ac.ID) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取区域主控信息成功", resp, actionType, "获取区域主控信息成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取区域主控信息成功", resp, actionType, "获取区域主控信息成功", resp) } // ListAreaControllers godoc @@ -483,24 +443,22 @@ func (c *Controller) GetAreaController(ctx *gin.Context) { // @Produce json // @Success 200 {object} controller.Response{data=[]dto.AreaControllerResponse} // @Router /api/v1/area-controllers [get] -func (c *Controller) ListAreaControllers(ctx *gin.Context) { +func (c *Controller) ListAreaControllers(ctx echo.Context) error { const actionType = "获取区域主控列表" acs, err := c.areaControllerRepo.ListAll() if err != nil { c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控列表失败: "+err.Error(), actionType, "数据库查询失败", nil) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控列表失败: "+err.Error(), actionType, "数据库查询失败", nil) } resp, err := dto.NewListAreaControllerResponse(acs) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, AreaControllers: %+v", actionType, err, acs) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控列表失败: 内部数据格式错误", actionType, "响应序列化失败", acs) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控列表失败: 内部数据格式错误", actionType, "响应序列化失败", acs) } c.logger.Infof("%s: 获取区域主控列表成功, 数量: %d", actionType, len(acs)) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取区域主控列表成功", resp, actionType, "获取区域主控列表成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取区域主控列表成功", resp, actionType, "获取区域主控列表成功", resp) } // UpdateAreaController godoc @@ -514,41 +472,36 @@ func (c *Controller) ListAreaControllers(ctx *gin.Context) { // @Param areaController body dto.UpdateAreaControllerRequest true "要更新的区域主控信息" // @Success 200 {object} controller.Response{data=dto.AreaControllerResponse} // @Router /api/v1/area-controllers/{id} [put] -func (c *Controller) UpdateAreaController(ctx *gin.Context) { +func (c *Controller) UpdateAreaController(ctx echo.Context) error { const actionType = "更新区域主控" acID := ctx.Param("id") idUint, err := strconv.ParseUint(acID, 10, 64) if err != nil { c.logger.Errorf("%s: 区域主控ID格式错误: %v, ID: %s", actionType, err, acID) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的区域主控ID格式", actionType, "ID格式错误", acID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的区域主控ID格式", actionType, "ID格式错误", acID) } existingAC, err := c.areaControllerRepo.FindByID(uint(idUint)) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID) } c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, acID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新区域主控失败: "+err.Error(), actionType, "数据库查询失败", acID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新区域主控失败: "+err.Error(), actionType, "数据库查询失败", acID) } var req dto.UpdateAreaControllerRequest - if err := ctx.ShouldBindJSON(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) } propertiesJSON, err := json.Marshal(req.Properties) if err != nil { c.logger.Errorf("%s: 序列化属性失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties) } existingAC.Name = req.Name @@ -558,25 +511,22 @@ func (c *Controller) UpdateAreaController(ctx *gin.Context) { if err := existingAC.SelfCheck(); err != nil { c.logger.Errorf("%s: 区域主控自检失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "区域主控参数不符合要求: "+err.Error(), actionType, "区域主控自检失败", existingAC) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "区域主控参数不符合要求: "+err.Error(), actionType, "区域主控自检失败", existingAC) } if err := c.areaControllerRepo.Update(existingAC); err != nil { c.logger.Errorf("%s: 数据库更新失败: %v, AreaController: %+v", actionType, err, existingAC) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新区域主控失败: "+err.Error(), actionType, "数据库更新失败", existingAC) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新区域主控失败: "+err.Error(), actionType, "数据库更新失败", acID) } resp, err := dto.NewAreaControllerResponse(existingAC) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, AreaController: %+v", actionType, err, existingAC) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "区域主控更新成功,但响应生成失败", actionType, "响应序列化失败", existingAC) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "区域主控更新成功,但响应生成失败", actionType, "响应序列化失败", existingAC) } c.logger.Infof("%s: 区域主控更新成功, ID: %d", actionType, existingAC.ID) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "区域主控更新成功", resp, actionType, "区域主控更新成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "区域主控更新成功", resp, actionType, "区域主控更新成功", resp) } // DeleteAreaController godoc @@ -588,37 +538,33 @@ func (c *Controller) UpdateAreaController(ctx *gin.Context) { // @Param id path string true "区域主控ID" // @Success 200 {object} controller.Response // @Router /api/v1/area-controllers/{id} [delete] -func (c *Controller) DeleteAreaController(ctx *gin.Context) { +func (c *Controller) DeleteAreaController(ctx echo.Context) error { const actionType = "删除区域主控" acID := ctx.Param("id") idUint, err := strconv.ParseUint(acID, 10, 64) if err != nil { c.logger.Errorf("%s: 区域主控ID格式错误: %v, ID: %s", actionType, err, acID) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的区域主控ID格式", actionType, "ID格式错误", acID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的区域主控ID格式", actionType, "ID格式错误", acID) } _, err = c.areaControllerRepo.FindByID(uint(idUint)) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID) } c.logger.Errorf("%s: 查找区域主控失败: %v, ID: %s", actionType, err, acID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除区域主控失败: 查找时发生内部错误", actionType, "数据库查询失败", acID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除区域主控失败: 查找时发生内部错误", actionType, "数据库查询失败", acID) } if err := c.areaControllerRepo.Delete(uint(idUint)); err != nil { c.logger.Errorf("%s: 数据库删除失败: %v, ID: %d", actionType, err, idUint) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除区域主控失败: "+err.Error(), actionType, "数据库删除失败", acID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除区域主控失败: "+err.Error(), actionType, "数据库删除失败", acID) } c.logger.Infof("%s: 区域主控删除成功, ID: %d", actionType, idUint) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "区域主控删除成功", nil, actionType, "区域主控删除成功", acID) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "区域主控删除成功", nil, actionType, "区域主控删除成功", acID) } // --- Controller Methods: Device Templates --- @@ -633,27 +579,24 @@ func (c *Controller) DeleteAreaController(ctx *gin.Context) { // @Param deviceTemplate body dto.CreateDeviceTemplateRequest true "设备模板信息" // @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse} // @Router /api/v1/device-templates [post] -func (c *Controller) CreateDeviceTemplate(ctx *gin.Context) { +func (c *Controller) CreateDeviceTemplate(ctx echo.Context) error { const actionType = "创建设备模板" var req dto.CreateDeviceTemplateRequest - if err := ctx.ShouldBindJSON(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) } commandsJSON, err := json.Marshal(req.Commands) if err != nil { c.logger.Errorf("%s: 序列化命令失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "命令字段格式错误", actionType, "命令序列化失败", req.Commands) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "命令字段格式错误", actionType, "命令序列化失败", req.Commands) } valuesJSON, err := json.Marshal(req.Values) if err != nil { c.logger.Errorf("%s: 序列化值描述符失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "值描述符字段格式错误", actionType, "值描述符序列化失败", req.Values) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "值描述符字段格式错误", actionType, "值描述符序列化失败", req.Values) } deviceTemplate := &models.DeviceTemplate{ @@ -667,25 +610,22 @@ func (c *Controller) CreateDeviceTemplate(ctx *gin.Context) { if err := deviceTemplate.SelfCheck(); err != nil { c.logger.Errorf("%s: 设备模板自检失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备模板参数不符合要求: "+err.Error(), actionType, "设备模板自检失败", deviceTemplate) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备模板参数不符合要求: "+err.Error(), actionType, "设备模板自检失败", deviceTemplate) } if err := c.deviceTemplateRepo.Create(deviceTemplate); err != nil { c.logger.Errorf("%s: 数据库操作失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建设备模板失败: "+err.Error(), actionType, "数据库创建失败", deviceTemplate) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建设备模板失败: "+err.Error(), actionType, "数据库创建失败", deviceTemplate) } resp, err := dto.NewDeviceTemplateResponse(deviceTemplate) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备模板创建成功,但响应生成失败", actionType, "响应序列化失败", deviceTemplate) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备模板创建成功,但响应生成失败", actionType, "响应序列化失败", deviceTemplate) } c.logger.Infof("%s: 设备模板创建成功, ID: %d", actionType, deviceTemplate.ID) - controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "设备模板创建成功", resp, actionType, "设备模板创建成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "设备模板创建成功", resp, actionType, "设备模板创建成功", resp) } // GetDeviceTemplate godoc @@ -697,38 +637,34 @@ func (c *Controller) CreateDeviceTemplate(ctx *gin.Context) { // @Param id path string true "设备模板ID" // @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse} // @Router /api/v1/device-templates/{id} [get] -func (c *Controller) GetDeviceTemplate(ctx *gin.Context) { +func (c *Controller) GetDeviceTemplate(ctx echo.Context) error { const actionType = "获取设备模板" dtID := ctx.Param("id") idUint, err := strconv.ParseUint(dtID, 10, 64) if err != nil { c.logger.Errorf("%s: 设备模板ID格式错误: %v, ID: %s", actionType, err, dtID) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备模板ID格式", actionType, "ID格式错误", dtID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备模板ID格式", actionType, "ID格式错误", dtID) } deviceTemplate, err := c.deviceTemplateRepo.FindByID(uint(idUint)) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID) } c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, dtID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板信息失败: "+err.Error(), actionType, "数据库查询失败", dtID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板信息失败: "+err.Error(), actionType, "数据库查询失败", dtID) } resp, err := dto.NewDeviceTemplateResponse(deviceTemplate) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, DeviceTemplate: %+v", actionType, err, deviceTemplate) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板信息失败: 内部数据格式错误", actionType, "响应序列化失败", deviceTemplate) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板信息失败: 内部数据格式错误", actionType, "响应序列化失败", deviceTemplate) } c.logger.Infof("%s: 获取设备模板信息成功, ID: %d", actionType, deviceTemplate.ID) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备模板信息成功", resp, actionType, "获取设备模板信息成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备模板信息成功", resp, actionType, "获取设备模板信息成功", resp) } // ListDeviceTemplates godoc @@ -739,24 +675,22 @@ func (c *Controller) GetDeviceTemplate(ctx *gin.Context) { // @Produce json // @Success 200 {object} controller.Response{data=[]dto.DeviceTemplateResponse} // @Router /api/v1/device-templates [get] -func (c *Controller) ListDeviceTemplates(ctx *gin.Context) { +func (c *Controller) ListDeviceTemplates(ctx echo.Context) error { const actionType = "获取设备模板列表" deviceTemplates, err := c.deviceTemplateRepo.ListAll() if err != nil { c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板列表失败: "+err.Error(), actionType, "数据库查询失败", nil) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板列表失败: "+err.Error(), actionType, "数据库查询失败", nil) } resp, err := dto.NewListDeviceTemplateResponse(deviceTemplates) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, DeviceTemplates: %+v", actionType, err, deviceTemplates) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板列表失败: 内部数据格式错误", actionType, "响应序列化失败", deviceTemplates) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板列表失败: 内部数据格式错误", actionType, "响应序列化失败", deviceTemplates) } c.logger.Infof("%s: 获取设备模板列表成功, 数量: %d", actionType, len(deviceTemplates)) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备模板列表成功", resp, actionType, "获取设备模板列表成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备模板列表成功", resp, actionType, "获取设备模板列表成功", resp) } // UpdateDeviceTemplate godoc @@ -770,48 +704,42 @@ func (c *Controller) ListDeviceTemplates(ctx *gin.Context) { // @Param deviceTemplate body dto.UpdateDeviceTemplateRequest true "要更新的设备模板信息" // @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse} // @Router /api/v1/device-templates/{id} [put] -func (c *Controller) UpdateDeviceTemplate(ctx *gin.Context) { +func (c *Controller) UpdateDeviceTemplate(ctx echo.Context) error { const actionType = "更新设备模板" dtID := ctx.Param("id") idUint, err := strconv.ParseUint(dtID, 10, 64) if err != nil { c.logger.Errorf("%s: 设备模板ID格式错误: %v, ID: %s", actionType, err, dtID) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备模板ID格式", actionType, "ID格式错误", dtID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备模板ID格式", actionType, "ID格式错误", dtID) } existingDeviceTemplate, err := c.deviceTemplateRepo.FindByID(uint(idUint)) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID) } c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, dtID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备模板失败: "+err.Error(), actionType, "数据库查询失败", dtID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备模板失败: "+err.Error(), actionType, "数据库查询失败", dtID) } var req dto.UpdateDeviceTemplateRequest - if err := ctx.ShouldBindJSON(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) } commandsJSON, err := json.Marshal(req.Commands) if err != nil { c.logger.Errorf("%s: 序列化命令失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "命令字段格式错误", actionType, "命令序列化失败", req.Commands) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "命令字段格式错误", actionType, "命令序列化失败", req.Commands) } valuesJSON, err := json.Marshal(req.Values) if err != nil { c.logger.Errorf("%s: 序列化值描述符失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "值描述符字段格式错误", actionType, "值描述符序列化失败", req.Values) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "值描述符字段格式错误", actionType, "值描述符序列化失败", req.Values) } existingDeviceTemplate.Name = req.Name @@ -823,25 +751,22 @@ func (c *Controller) UpdateDeviceTemplate(ctx *gin.Context) { if err := existingDeviceTemplate.SelfCheck(); err != nil { c.logger.Errorf("%s: 设备模板自检失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备模板参数不符合要求: "+err.Error(), actionType, "设备模板自检失败", existingDeviceTemplate) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备模板参数不符合要求: "+err.Error(), actionType, "设备模板自检失败", existingDeviceTemplate) } if err := c.deviceTemplateRepo.Update(existingDeviceTemplate); err != nil { c.logger.Errorf("%s: 数据库更新失败: %v, DeviceTemplate: %+v", actionType, err, existingDeviceTemplate) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备模板失败: "+err.Error(), actionType, "数据库更新失败", existingDeviceTemplate) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备模板失败: "+err.Error(), actionType, "数据库更新失败", dtID) } resp, err := dto.NewDeviceTemplateResponse(existingDeviceTemplate) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, DeviceTemplate: %+v", actionType, err, existingDeviceTemplate) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备模板更新成功,但响应生成失败", actionType, "响应序列化失败", existingDeviceTemplate) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备模板更新成功,但响应生成失败", actionType, "响应序列化失败", existingDeviceTemplate) } c.logger.Infof("%s: 设备模板更新成功, ID: %d", actionType, existingDeviceTemplate.ID) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备模板更新成功", resp, actionType, "设备模板更新成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备模板更新成功", resp, actionType, "设备模板更新成功", resp) } // DeleteDeviceTemplate godoc @@ -853,15 +778,14 @@ func (c *Controller) UpdateDeviceTemplate(ctx *gin.Context) { // @Param id path string true "设备模板ID" // @Success 200 {object} controller.Response // @Router /api/v1/device-templates/{id} [delete] -func (c *Controller) DeleteDeviceTemplate(ctx *gin.Context) { +func (c *Controller) DeleteDeviceTemplate(ctx echo.Context) error { const actionType = "删除设备模板" dtID := ctx.Param("id") idUint, err := strconv.ParseUint(dtID, 10, 64) if err != nil { c.logger.Errorf("%s: 设备模板ID格式错误: %v, ID: %s", actionType, err, dtID) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备模板ID格式", actionType, "ID格式错误", dtID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备模板ID格式", actionType, "ID格式错误", dtID) } // 在尝试删除之前,先检查设备模板是否存在 @@ -869,12 +793,10 @@ func (c *Controller) DeleteDeviceTemplate(ctx *gin.Context) { if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID) } c.logger.Errorf("%s: 查找设备模板失败: %v, ID: %s", actionType, err, dtID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备模板失败: 查找时发生内部错误", actionType, "数据库查询失败", dtID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备模板失败: 查找时发生内部错误", actionType, "数据库查询失败", dtID) } // 调用仓库层的删除方法,该方法会检查模板是否被使用 @@ -882,14 +804,13 @@ func (c *Controller) DeleteDeviceTemplate(ctx *gin.Context) { c.logger.Errorf("%s: 数据库删除失败: %v, ID: %d", actionType, err, idUint) // 如果错误信息包含“设备模板正在被设备使用,无法删除”,则返回特定的错误码 if strings.Contains(err.Error(), "设备模板正在被设备使用,无法删除") { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备模板正在使用", dtID) + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备模板正在使用", dtID) } else { // 其他数据库错误 - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备模板失败: "+err.Error(), actionType, "数据库删除失败", dtID) + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备模板失败: "+err.Error(), actionType, "数据库删除失败", dtID) } - return } c.logger.Infof("%s: 设备模板删除成功, ID: %d", actionType, idUint) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备模板删除成功", nil, actionType, "设备模板删除成功", dtID) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备模板删除成功", nil, actionType, "设备模板删除成功", dtID) } diff --git a/internal/app/controller/management/controller_helpers.go b/internal/app/controller/management/controller_helpers.go index e4bc122..97cec5b 100644 --- a/internal/app/controller/management/controller_helpers.go +++ b/internal/app/controller/management/controller_helpers.go @@ -7,39 +7,39 @@ import ( "git.huangwc.com/pig/pig-farm-controller/internal/app/controller" "git.huangwc.com/pig/pig-farm-controller/internal/app/service" - "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" ) // mapAndSendError 统一映射服务层错误并发送响应。 // 这个函数将服务层返回的错误转换为控制器层应返回的HTTP状态码和审计信息。 -func mapAndSendError(c *PigBatchController, ctx *gin.Context, action string, err error, id uint) { +func mapAndSendError(c *PigBatchController, ctx echo.Context, action string, err error, id uint) error { if errors.Is(err, service.ErrPigBatchNotFound) || errors.Is(err, service.ErrPenNotFound) || errors.Is(err, service.ErrPenNotAssociatedWithBatch) { - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), id) + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), id) } else if errors.Is(err, service.ErrInvalidOperation) || errors.Is(err, service.ErrPigBatchActive) || errors.Is(err, service.ErrPigBatchNotActive) || errors.Is(err, service.ErrPenOccupiedByOtherBatch) || errors.Is(err, service.ErrPenStatusInvalidForAllocation) || errors.Is(err, service.ErrPenNotEmpty) { - controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) + return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) } else { c.logger.Errorf("操作[%s]业务逻辑失败: %v", action, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, fmt.Sprintf("操作失败: %v", err), action, err.Error(), id) + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, fmt.Sprintf("操作失败: %v", err), action, err.Error(), id) } } -// idExtractorFunc 定义了一个函数类型,用于从gin.Context中提取主ID。 -type idExtractorFunc func(ctx *gin.Context) (uint, error) +// idExtractorFunc 定义了一个函数类型,用于从echo.Context中提取主ID。 +type idExtractorFunc func(ctx echo.Context) (uint, error) -// extractOperatorAndPrimaryID 封装了从gin.Context中提取操作员ID和主ID的通用逻辑。 +// extractOperatorAndPrimaryID 封装了从echo.Context中提取操作员ID和主ID的通用逻辑。 // 它负责处理ID提取过程中的错误,并发送相应的HTTP响应。 // // 参数: // // c: *PigBatchController - 控制器实例,用于访问其日志。 -// ctx: *gin.Context - Gin上下文。 +// ctx: echo.Context - Echo上下文。 // action: string - 当前操作的描述,用于日志和审计。 // idExtractor: idExtractorFunc - 可选函数,用于从ctx中提取主ID。如果为nil,则尝试从":id"路径参数中提取。 // @@ -47,26 +47,24 @@ type idExtractorFunc func(ctx *gin.Context) (uint, error) // // operatorID: uint - 提取到的操作员ID。 // primaryID: uint - 提取到的主ID。 -// ok: bool - 如果ID提取成功且没有发送错误响应,则为true。 +// err: error - 如果ID提取失败或发送错误响应,则返回错误。 func extractOperatorAndPrimaryID( c *PigBatchController, - ctx *gin.Context, + ctx echo.Context, action string, idExtractor idExtractorFunc, -) (operatorID uint, primaryID uint, ok bool) { +) (operatorID uint, primaryID uint, err error) { // 1. 获取操作员ID - operatorID, err := controller.GetOperatorIDFromContext(ctx) + operatorID, err = controller.GetOperatorIDFromContext(ctx) if err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeUnauthorized, "未授权", action, "无法获取操作员ID", nil) - return 0, 0, false + return 0, 0, controller.SendErrorWithAudit(ctx, controller.CodeUnauthorized, "未授权", action, "无法获取操作员ID", nil) } // 2. 提取主ID if idExtractor != nil { primaryID, err = idExtractor(ctx) if err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", err.Error()) - return 0, 0, false + return 0, 0, controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", err.Error()) } } else { // 默认从 ":id" 路径参数提取 idParam := ctx.Param("id") @@ -75,165 +73,155 @@ func extractOperatorAndPrimaryID( } else { parsedID, err := strconv.ParseUint(idParam, 10, 32) if err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", idParam) - return 0, 0, false + return 0, 0, controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", idParam) } primaryID = uint(parsedID) } } - return operatorID, primaryID, true + return operatorID, primaryID, nil } // handleAPIRequest 封装了控制器中处理带有请求体和路径参数的API请求的通用逻辑。 // 它负责请求体绑定、操作员ID获取、服务层调用、错误映射和响应发送。 func handleAPIRequest[Req any]( c *PigBatchController, - ctx *gin.Context, + ctx echo.Context, action string, reqDTO Req, - serviceExecutor func(ctx *gin.Context, operatorID uint, primaryID uint, req Req) error, + serviceExecutor func(ctx echo.Context, operatorID uint, primaryID uint, req Req) error, successMsg string, idExtractor idExtractorFunc, -) { +) error { // 1. 绑定请求体 - if err := ctx.ShouldBindJSON(&reqDTO); err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", reqDTO) - return + if err := ctx.Bind(&reqDTO); err != nil { + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", reqDTO) } // 2. 提取操作员ID和主ID - operatorID, primaryID, ok := extractOperatorAndPrimaryID(c, ctx, action, idExtractor) - if !ok { - return // 错误已在 extractOperatorAndPrimaryID 中处理 + operatorID, primaryID, err := extractOperatorAndPrimaryID(c, ctx, action, idExtractor) + if err != nil { + return err // 错误已在 extractOperatorAndPrimaryID 中处理 } // 3. 执行服务层逻辑 - err := serviceExecutor(ctx, operatorID, primaryID, reqDTO) + err = serviceExecutor(ctx, operatorID, primaryID, reqDTO) if err != nil { - mapAndSendError(c, ctx, action, err, primaryID) - return + return mapAndSendError(c, ctx, action, err, primaryID) } // 4. 发送成功响应 - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, successMsg, nil, action, successMsg, primaryID) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, successMsg, nil, action, successMsg, primaryID) } // handleNoBodyAPIRequest 封装了处理不带请求体,但有路径参数和操作员ID的API请求的通用逻辑。 func handleNoBodyAPIRequest( c *PigBatchController, - ctx *gin.Context, + ctx echo.Context, action string, - serviceExecutor func(ctx *gin.Context, operatorID uint, primaryID uint) error, + serviceExecutor func(ctx echo.Context, operatorID uint, primaryID uint) error, successMsg string, idExtractor idExtractorFunc, -) { +) error { // 1. 提取操作员ID和主ID - operatorID, primaryID, ok := extractOperatorAndPrimaryID(c, ctx, action, idExtractor) - if !ok { - return // 错误已在 extractOperatorAndPrimaryID 中处理 + operatorID, primaryID, err := extractOperatorAndPrimaryID(c, ctx, action, idExtractor) + if err != nil { + return err // 错误已在 extractOperatorAndPrimaryID 中处理 } // 2. 执行服务层逻辑 - err := serviceExecutor(ctx, operatorID, primaryID) + err = serviceExecutor(ctx, operatorID, primaryID) if err != nil { - mapAndSendError(c, ctx, action, err, primaryID) - return + return mapAndSendError(c, ctx, action, err, primaryID) } // 3. 发送成功响应 - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, successMsg, nil, action, successMsg, primaryID) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, successMsg, nil, action, successMsg, primaryID) } // handleAPIRequestWithResponse 封装了控制器中处理带有请求体、路径参数并返回响应DTO的API请求的通用逻辑。 func handleAPIRequestWithResponse[Req any, Resp any]( c *PigBatchController, - ctx *gin.Context, + ctx echo.Context, action string, reqDTO Req, - serviceExecutor func(ctx *gin.Context, operatorID uint, primaryID uint, req Req) (Resp, error), // serviceExecutor现在返回Resp + serviceExecutor func(ctx echo.Context, operatorID uint, primaryID uint, req Req) (Resp, error), // serviceExecutor现在返回Resp successMsg string, idExtractor idExtractorFunc, -) { +) error { // 1. 绑定请求体 - if err := ctx.ShouldBindJSON(&reqDTO); err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, fmt.Sprintf("无效的请求体: %v", err), action, fmt.Sprintf("请求体绑定失败: %v", err), reqDTO) - return + if err := ctx.Bind(&reqDTO); err != nil { + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, fmt.Sprintf("无效的请求体: %v", err), action, fmt.Sprintf("请求体绑定失败: %v", err), reqDTO) } // 2. 提取操作员ID和主ID - operatorID, primaryID, ok := extractOperatorAndPrimaryID(c, ctx, action, idExtractor) - if !ok { - return // 错误已在 extractOperatorAndPrimaryID 中处理 + operatorID, primaryID, err := extractOperatorAndPrimaryID(c, ctx, action, idExtractor) + if err != nil { + return err // 错误已在 extractOperatorAndPrimaryID 中处理 } // 3. 执行服务层逻辑 respDTO, err := serviceExecutor(ctx, operatorID, primaryID, reqDTO) if err != nil { - mapAndSendError(c, ctx, action, err, primaryID) - return + return mapAndSendError(c, ctx, action, err, primaryID) } // 4. 发送成功响应 - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, successMsg, respDTO, action, successMsg, primaryID) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, successMsg, respDTO, action, successMsg, primaryID) } // handleNoBodyAPIRequestWithResponse 封装了处理不带请求体,但有路径参数和操作员ID,并返回响应DTO的API请求的通用逻辑。 func handleNoBodyAPIRequestWithResponse[Resp any]( c *PigBatchController, - ctx *gin.Context, + ctx echo.Context, action string, - serviceExecutor func(ctx *gin.Context, operatorID uint, primaryID uint) (Resp, error), // serviceExecutor现在返回Resp + serviceExecutor func(ctx echo.Context, operatorID uint, primaryID uint) (Resp, error), // serviceExecutor现在返回Resp successMsg string, idExtractor idExtractorFunc, -) { +) error { // 1. 提取操作员ID和主ID - operatorID, primaryID, ok := extractOperatorAndPrimaryID(c, ctx, action, idExtractor) - if !ok { - return // 错误已在 extractOperatorAndPrimaryID 中处理 + operatorID, primaryID, err := extractOperatorAndPrimaryID(c, ctx, action, idExtractor) + if err != nil { + return err // 错误已在 extractOperatorAndPrimaryID 中处理 } // 2. 执行服务层逻辑 respDTO, err := serviceExecutor(ctx, operatorID, primaryID) if err != nil { - mapAndSendError(c, ctx, action, err, primaryID) - return + return mapAndSendError(c, ctx, action, err, primaryID) } // 3. 发送成功响应 - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, successMsg, respDTO, action, successMsg, primaryID) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, successMsg, respDTO, action, successMsg, primaryID) } // handleQueryAPIRequestWithResponse 封装了处理带有查询参数并返回响应DTO的API请求的通用逻辑。 func handleQueryAPIRequestWithResponse[Query any, Resp any]( c *PigBatchController, - ctx *gin.Context, + ctx echo.Context, action string, queryDTO Query, - serviceExecutor func(ctx *gin.Context, operatorID uint, query Query) (Resp, error), // serviceExecutor现在接收queryDTO + serviceExecutor func(ctx echo.Context, operatorID uint, query Query) (Resp, error), // serviceExecutor现在接收queryDTO successMsg string, -) { +) error { // 1. 绑定查询参数 - if err := ctx.ShouldBindQuery(&queryDTO); err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数", action, "查询参数绑定失败", queryDTO) - return + if err := ctx.Bind(&queryDTO); err != nil { + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数", action, "查询参数绑定失败", queryDTO) } // 2. 获取操作员ID operatorID, err := controller.GetOperatorIDFromContext(ctx) if err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeUnauthorized, "未授权", action, "无法获取操作员ID", nil) - return + return controller.SendErrorWithAudit(ctx, controller.CodeUnauthorized, "未授权", action, "无法获取操作员ID", nil) } // 3. 执行服务层逻辑 respDTO, err := serviceExecutor(ctx, operatorID, queryDTO) if err != nil { // 对于列表查询,通常没有primaryID,所以传递0 - mapAndSendError(c, ctx, action, err, 0) - return + return mapAndSendError(c, ctx, action, err, 0) } // 4. 发送成功响应 - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, successMsg, respDTO, action, successMsg, nil) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, successMsg, respDTO, action, successMsg, nil) } diff --git a/internal/app/controller/management/pig_batch_controller.go b/internal/app/controller/management/pig_batch_controller.go index 7f24b13..0d7a17d 100644 --- a/internal/app/controller/management/pig_batch_controller.go +++ b/internal/app/controller/management/pig_batch_controller.go @@ -7,7 +7,7 @@ import ( "git.huangwc.com/pig/pig-farm-controller/internal/app/service" "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" - "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" ) // PigBatchController 负责处理猪批次相关的API请求 @@ -34,13 +34,13 @@ func NewPigBatchController(logger *logs.Logger, service service.PigBatchService) // @Param body body dto.PigBatchCreateDTO true "猪批次信息" // @Success 201 {object} controller.Response{data=dto.PigBatchResponseDTO} "创建成功" // @Router /api/v1/pig-batches [post] -func (c *PigBatchController) CreatePigBatch(ctx *gin.Context) { +func (c *PigBatchController) CreatePigBatch(ctx echo.Context) error { const action = "创建猪批次" var req dto.PigBatchCreateDTO - handleAPIRequestWithResponse( + return handleAPIRequestWithResponse( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error) { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error) { // 对于创建操作,primaryID通常不从路径中获取,而是由服务层生成 return c.service.CreatePigBatch(operatorID, req) }, @@ -58,12 +58,12 @@ func (c *PigBatchController) CreatePigBatch(ctx *gin.Context) { // @Param id path int true "猪批次ID" // @Success 200 {object} controller.Response{data=dto.PigBatchResponseDTO} "获取成功" // @Router /api/v1/pig-batches/{id} [get] -func (c *PigBatchController) GetPigBatch(ctx *gin.Context) { +func (c *PigBatchController) GetPigBatch(ctx echo.Context) error { const action = "获取猪批次" - handleNoBodyAPIRequestWithResponse( + return handleNoBodyAPIRequestWithResponse( c, ctx, action, - func(ctx *gin.Context, operatorID uint, primaryID uint) (*dto.PigBatchResponseDTO, error) { + func(ctx echo.Context, operatorID uint, primaryID uint) (*dto.PigBatchResponseDTO, error) { return c.service.GetPigBatch(primaryID) }, "获取成功", @@ -82,13 +82,13 @@ func (c *PigBatchController) GetPigBatch(ctx *gin.Context) { // @Param body body dto.PigBatchUpdateDTO true "猪批次信息" // @Success 200 {object} controller.Response{data=dto.PigBatchResponseDTO} "更新成功" // @Router /api/v1/pig-batches/{id} [put] -func (c *PigBatchController) UpdatePigBatch(ctx *gin.Context) { +func (c *PigBatchController) UpdatePigBatch(ctx echo.Context) error { const action = "更新猪批次" var req dto.PigBatchUpdateDTO - handleAPIRequestWithResponse( + return handleAPIRequestWithResponse( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error) { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error) { return c.service.UpdatePigBatch(primaryID, req) }, "更新成功", @@ -105,12 +105,12 @@ func (c *PigBatchController) UpdatePigBatch(ctx *gin.Context) { // @Param id path int true "猪批次ID" // @Success 200 {object} controller.Response "删除成功" // @Router /api/v1/pig-batches/{id} [delete] -func (c *PigBatchController) DeletePigBatch(ctx *gin.Context) { +func (c *PigBatchController) DeletePigBatch(ctx echo.Context) error { const action = "删除猪批次" - handleNoBodyAPIRequest( + return handleNoBodyAPIRequest( c, ctx, action, - func(ctx *gin.Context, operatorID uint, primaryID uint) error { + func(ctx echo.Context, operatorID uint, primaryID uint) error { return c.service.DeletePigBatch(primaryID) }, "删除成功", @@ -127,13 +127,13 @@ func (c *PigBatchController) DeletePigBatch(ctx *gin.Context) { // @Param is_active query bool false "是否活跃 (true/false)" // @Success 200 {object} controller.Response{data=[]dto.PigBatchResponseDTO} "获取成功" // @Router /api/v1/pig-batches [get] -func (c *PigBatchController) ListPigBatches(ctx *gin.Context) { +func (c *PigBatchController) ListPigBatches(ctx echo.Context) error { const action = "获取猪批次列表" var query dto.PigBatchQueryDTO - handleQueryAPIRequestWithResponse( + return handleQueryAPIRequestWithResponse( c, ctx, action, &query, - func(ctx *gin.Context, operatorID uint, query *dto.PigBatchQueryDTO) ([]*dto.PigBatchResponseDTO, error) { + func(ctx echo.Context, operatorID uint, query *dto.PigBatchQueryDTO) ([]*dto.PigBatchResponseDTO, error) { return c.service.ListPigBatches(query.IsActive) }, "获取成功", @@ -151,13 +151,13 @@ func (c *PigBatchController) ListPigBatches(ctx *gin.Context) { // @Param body body dto.AssignEmptyPensToBatchRequest true "待分配的猪栏ID列表" // @Success 200 {object} controller.Response "分配成功" // @Router /api/v1/pig-batches/assign-pens/{id} [post] -func (c *PigBatchController) AssignEmptyPensToBatch(ctx *gin.Context) { +func (c *PigBatchController) AssignEmptyPensToBatch(ctx echo.Context) error { const action = "为猪批次分配空栏" var req dto.AssignEmptyPensToBatchRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.AssignEmptyPensToBatchRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.AssignEmptyPensToBatchRequest) error { return c.service.AssignEmptyPensToBatch(primaryID, req.PenIDs, operatorID) }, "分配成功", @@ -176,18 +176,18 @@ func (c *PigBatchController) AssignEmptyPensToBatch(ctx *gin.Context) { // @Param body body dto.ReclassifyPenToNewBatchRequest true "划拨请求信息 (包含目标批次ID、猪栏ID和备注)" // @Success 200 {object} controller.Response "划拨成功" // @Router /api/v1/pig-batches/reclassify-pen/{fromBatchID} [post] -func (c *PigBatchController) ReclassifyPenToNewBatch(ctx *gin.Context) { +func (c *PigBatchController) ReclassifyPenToNewBatch(ctx echo.Context) error { const action = "划拨猪栏到新批次" var req dto.ReclassifyPenToNewBatchRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.ReclassifyPenToNewBatchRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.ReclassifyPenToNewBatchRequest) error { // primaryID 在这里是 fromBatchID return c.service.ReclassifyPenToNewBatch(primaryID, req.ToBatchID, req.PenID, operatorID, req.Remarks) }, "划拨成功", - func(ctx *gin.Context) (uint, error) { // 自定义ID提取器,从 ":fromBatchID" 路径参数提取 + func(ctx echo.Context) (uint, error) { // 自定义ID提取器,从 ":fromBatchID" 路径参数提取 idParam := ctx.Param("fromBatchID") parsedID, err := strconv.ParseUint(idParam, 10, 32) if err != nil { @@ -208,22 +208,22 @@ func (c *PigBatchController) ReclassifyPenToNewBatch(ctx *gin.Context) { // @Param penID path int true "待移除的猪栏ID" // @Success 200 {object} controller.Response "移除成功" // @Router /api/v1/pig-batches/remove-pen/{penID}/{batchID} [delete] -func (c *PigBatchController) RemoveEmptyPenFromBatch(ctx *gin.Context) { +func (c *PigBatchController) RemoveEmptyPenFromBatch(ctx echo.Context) error { const action = "从猪批次移除空栏" - handleNoBodyAPIRequest( + return handleNoBodyAPIRequest( c, ctx, action, - func(ctx *gin.Context, operatorID uint, primaryID uint) error { + func(ctx echo.Context, operatorID uint, primaryID uint) error { // primaryID 在这里是 batchID penIDParam := ctx.Param("penID") - penID, err := strconv.ParseUint(penIDParam, 10, 32) + parsedPenID, err := strconv.ParseUint(penIDParam, 10, 32) if err != nil { return err // 返回错误,因为 penID 格式无效 } - return c.service.RemoveEmptyPenFromBatch(primaryID, uint(penID)) + return c.service.RemoveEmptyPenFromBatch(primaryID, uint(parsedPenID)) }, "移除成功", - func(ctx *gin.Context) (uint, error) { // 自定义ID提取器,从 ":batchID" 路径参数提取 + func(ctx echo.Context) (uint, error) { // 自定义ID提取器,从 ":batchID" 路径参数提取 idParam := ctx.Param("batchID") parsedID, err := strconv.ParseUint(idParam, 10, 32) if err != nil { @@ -245,13 +245,13 @@ func (c *PigBatchController) RemoveEmptyPenFromBatch(ctx *gin.Context) { // @Param body body dto.MovePigsIntoPenRequest true "移入猪只请求信息 (包含目标猪栏ID、数量和备注)" // @Success 200 {object} controller.Response "移入成功" // @Router /api/v1/pig-batches/move-pigs-into-pen/{id} [post] -func (c *PigBatchController) MovePigsIntoPen(ctx *gin.Context) { +func (c *PigBatchController) MovePigsIntoPen(ctx echo.Context) error { const action = "将猪只移入猪栏" var req dto.MovePigsIntoPenRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.MovePigsIntoPenRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.MovePigsIntoPenRequest) error { return c.service.MovePigsIntoPen(primaryID, req.ToPenID, req.Quantity, operatorID, req.Remarks) }, "移入成功", diff --git a/internal/app/controller/management/pig_batch_health_controller.go b/internal/app/controller/management/pig_batch_health_controller.go index 828c5a3..00d51ff 100644 --- a/internal/app/controller/management/pig_batch_health_controller.go +++ b/internal/app/controller/management/pig_batch_health_controller.go @@ -2,7 +2,7 @@ package management import ( "git.huangwc.com/pig/pig-farm-controller/internal/app/dto" - "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" ) // RecordSickPigs godoc @@ -16,13 +16,13 @@ import ( // @Param body body dto.RecordSickPigsRequest true "记录病猪请求信息" // @Success 200 {object} controller.Response "记录成功" // @Router /api/v1/pig-batches/record-sick-pigs/{id} [post] -func (c *PigBatchController) RecordSickPigs(ctx *gin.Context) { +func (c *PigBatchController) RecordSickPigs(ctx echo.Context) error { const action = "记录新增病猪事件" var req dto.RecordSickPigsRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigsRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigsRequest) error { return c.service.RecordSickPigs(operatorID, primaryID, req.PenID, req.Quantity, req.TreatmentLocation, req.HappenedAt, req.Remarks) }, "记录成功", @@ -41,13 +41,13 @@ func (c *PigBatchController) RecordSickPigs(ctx *gin.Context) { // @Param body body dto.RecordSickPigRecoveryRequest true "记录病猪康复请求信息" // @Success 200 {object} controller.Response "记录成功" // @Router /api/v1/pig-batches/record-sick-pig-recovery/{id} [post] -func (c *PigBatchController) RecordSickPigRecovery(ctx *gin.Context) { +func (c *PigBatchController) RecordSickPigRecovery(ctx echo.Context) error { const action = "记录病猪康复事件" var req dto.RecordSickPigRecoveryRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigRecoveryRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigRecoveryRequest) error { return c.service.RecordSickPigRecovery(operatorID, primaryID, req.PenID, req.Quantity, req.TreatmentLocation, req.HappenedAt, req.Remarks) }, "记录成功", @@ -66,13 +66,13 @@ func (c *PigBatchController) RecordSickPigRecovery(ctx *gin.Context) { // @Param body body dto.RecordSickPigDeathRequest true "记录病猪死亡请求信息" // @Success 200 {object} controller.Response "记录成功" // @Router /api/v1/pig-batches/record-sick-pig-death/{id} [post] -func (c *PigBatchController) RecordSickPigDeath(ctx *gin.Context) { +func (c *PigBatchController) RecordSickPigDeath(ctx echo.Context) error { const action = "记录病猪死亡事件" var req dto.RecordSickPigDeathRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigDeathRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigDeathRequest) error { return c.service.RecordSickPigDeath(operatorID, primaryID, req.PenID, req.Quantity, req.TreatmentLocation, req.HappenedAt, req.Remarks) }, "记录成功", @@ -91,13 +91,13 @@ func (c *PigBatchController) RecordSickPigDeath(ctx *gin.Context) { // @Param body body dto.RecordSickPigCullRequest true "记录病猪淘汰请求信息" // @Success 200 {object} controller.Response "记录成功" // @Router /api/v1/pig-batches/record-sick-pig-cull/{id} [post] -func (c *PigBatchController) RecordSickPigCull(ctx *gin.Context) { +func (c *PigBatchController) RecordSickPigCull(ctx echo.Context) error { const action = "记录病猪淘汰事件" var req dto.RecordSickPigCullRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigCullRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigCullRequest) error { return c.service.RecordSickPigCull(operatorID, primaryID, req.PenID, req.Quantity, req.TreatmentLocation, req.HappenedAt, req.Remarks) }, "记录成功", @@ -116,13 +116,13 @@ func (c *PigBatchController) RecordSickPigCull(ctx *gin.Context) { // @Param body body dto.RecordDeathRequest true "记录正常猪只死亡请求信息" // @Success 200 {object} controller.Response "记录成功" // @Router /api/v1/pig-batches/record-death/{id} [post] -func (c *PigBatchController) RecordDeath(ctx *gin.Context) { +func (c *PigBatchController) RecordDeath(ctx echo.Context) error { const action = "记录正常猪只死亡事件" var req dto.RecordDeathRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.RecordDeathRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordDeathRequest) error { return c.service.RecordDeath(operatorID, primaryID, req.PenID, req.Quantity, req.HappenedAt, req.Remarks) }, "记录成功", @@ -141,13 +141,13 @@ func (c *PigBatchController) RecordDeath(ctx *gin.Context) { // @Param body body dto.RecordCullRequest true "记录正常猪只淘汰请求信息" // @Success 200 {object} controller.Response "记录成功" // @Router /api/v1/pig-batches/record-cull/{id} [post] -func (c *PigBatchController) RecordCull(ctx *gin.Context) { +func (c *PigBatchController) RecordCull(ctx echo.Context) error { const action = "记录正常猪只淘汰事件" var req dto.RecordCullRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.RecordCullRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordCullRequest) error { return c.service.RecordCull(operatorID, primaryID, req.PenID, req.Quantity, req.HappenedAt, req.Remarks) }, "记录成功", diff --git a/internal/app/controller/management/pig_batch_trade_controller.go b/internal/app/controller/management/pig_batch_trade_controller.go index de79498..37ad5dd 100644 --- a/internal/app/controller/management/pig_batch_trade_controller.go +++ b/internal/app/controller/management/pig_batch_trade_controller.go @@ -2,7 +2,7 @@ package management import ( "git.huangwc.com/pig/pig-farm-controller/internal/app/dto" - "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" ) // SellPigs godoc @@ -16,13 +16,13 @@ import ( // @Param body body dto.SellPigsRequest true "卖猪请求信息" // @Success 200 {object} controller.Response "卖猪成功" // @Router /api/v1/pig-batches/sell-pigs/{id} [post] -func (c *PigBatchController) SellPigs(ctx *gin.Context) { +func (c *PigBatchController) SellPigs(ctx echo.Context) error { const action = "卖猪" var req dto.SellPigsRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.SellPigsRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.SellPigsRequest) error { return c.service.SellPigs(primaryID, req.PenID, req.Quantity, req.UnitPrice, req.TotalPrice, req.TraderName, req.TradeDate, req.Remarks, operatorID) }, "卖猪成功", @@ -41,13 +41,13 @@ func (c *PigBatchController) SellPigs(ctx *gin.Context) { // @Param body body dto.BuyPigsRequest true "买猪请求信息" // @Success 200 {object} controller.Response "买猪成功" // @Router /api/v1/pig-batches/buy-pigs/{id} [post] -func (c *PigBatchController) BuyPigs(ctx *gin.Context) { +func (c *PigBatchController) BuyPigs(ctx echo.Context) error { const action = "买猪" var req dto.BuyPigsRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.BuyPigsRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.BuyPigsRequest) error { return c.service.BuyPigs(primaryID, req.PenID, req.Quantity, req.UnitPrice, req.TotalPrice, req.TraderName, req.TradeDate, req.Remarks, operatorID) }, "买猪成功", diff --git a/internal/app/controller/management/pig_batch_transfer_controller.go b/internal/app/controller/management/pig_batch_transfer_controller.go index 715cb61..e57a45a 100644 --- a/internal/app/controller/management/pig_batch_transfer_controller.go +++ b/internal/app/controller/management/pig_batch_transfer_controller.go @@ -4,7 +4,7 @@ import ( "strconv" "git.huangwc.com/pig/pig-farm-controller/internal/app/dto" - "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" ) // TransferPigsAcrossBatches godoc @@ -18,18 +18,18 @@ import ( // @Param body body dto.TransferPigsAcrossBatchesRequest true "跨群调栏请求信息" // @Success 200 {object} controller.Response "调栏成功" // @Router /api/v1/pig-batches/transfer-across-batches/{sourceBatchID} [post] -func (c *PigBatchController) TransferPigsAcrossBatches(ctx *gin.Context) { +func (c *PigBatchController) TransferPigsAcrossBatches(ctx echo.Context) error { const action = "跨猪群调栏" var req dto.TransferPigsAcrossBatchesRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.TransferPigsAcrossBatchesRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.TransferPigsAcrossBatchesRequest) error { // primaryID 在这里是 sourceBatchID return c.service.TransferPigsAcrossBatches(primaryID, req.DestBatchID, req.FromPenID, req.ToPenID, req.Quantity, operatorID, req.Remarks) }, "调栏成功", - func(ctx *gin.Context) (uint, error) { // 自定义ID提取器,从 ":sourceBatchID" 路径参数提取 + func(ctx echo.Context) (uint, error) { // 自定义ID提取器,从 ":sourceBatchID" 路径参数提取 idParam := ctx.Param("sourceBatchID") parsedID, err := strconv.ParseUint(idParam, 10, 32) if err != nil { @@ -51,13 +51,13 @@ func (c *PigBatchController) TransferPigsAcrossBatches(ctx *gin.Context) { // @Param body body dto.TransferPigsWithinBatchRequest true "群内调栏请求信息" // @Success 200 {object} controller.Response "调栏成功" // @Router /api/v1/pig-batches/transfer-within-batch/{id} [post] -func (c *PigBatchController) TransferPigsWithinBatch(ctx *gin.Context) { +func (c *PigBatchController) TransferPigsWithinBatch(ctx echo.Context) error { const action = "群内调栏" var req dto.TransferPigsWithinBatchRequest - handleAPIRequest( + return handleAPIRequest( c, ctx, action, &req, - func(ctx *gin.Context, operatorID uint, primaryID uint, req *dto.TransferPigsWithinBatchRequest) error { + func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.TransferPigsWithinBatchRequest) error { // primaryID 在这里是 batchID return c.service.TransferPigsWithinBatch(primaryID, req.FromPenID, req.ToPenID, req.Quantity, operatorID, req.Remarks) }, diff --git a/internal/app/controller/management/pig_farm_controller.go b/internal/app/controller/management/pig_farm_controller.go index f0a005e..0d78048 100644 --- a/internal/app/controller/management/pig_farm_controller.go +++ b/internal/app/controller/management/pig_farm_controller.go @@ -8,7 +8,7 @@ import ( "git.huangwc.com/pig/pig-farm-controller/internal/app/dto" "git.huangwc.com/pig/pig-farm-controller/internal/app/service" "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" - "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" ) // --- 控制器定义 --- @@ -31,7 +31,7 @@ func NewPigFarmController(logger *logs.Logger, service service.PigFarmService) * // CreatePigHouse godoc // @Summary 创建猪舍 -// @Description 创建一个新的猪舍 +// @Description 根据提供的信息创建一个新猪舍 // @Tags 猪场管理 // @Security BearerAuth // @Accept json @@ -39,19 +39,18 @@ func NewPigFarmController(logger *logs.Logger, service service.PigFarmService) * // @Param body body dto.CreatePigHouseRequest true "猪舍信息" // @Success 201 {object} controller.Response{data=dto.PigHouseResponse} "创建成功" // @Router /api/v1/pig-houses [post] -func (c *PigFarmController) CreatePigHouse(ctx *gin.Context) { +func (c *PigFarmController) CreatePigHouse(ctx echo.Context) error { const action = "创建猪舍" var req dto.CreatePigHouseRequest - if err := ctx.ShouldBindJSON(&req); err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) - return + if err := ctx.Bind(&req); err != nil { + c.logger.Errorf("%s: 参数绑定失败: %v", action, err) + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) } house, err := c.service.CreatePigHouse(req.Name, req.Description) if err != nil { c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪舍失败", action, "业务逻辑失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪舍失败", action, "业务逻辑失败", req) } resp := dto.PigHouseResponse{ @@ -59,7 +58,7 @@ func (c *PigFarmController) CreatePigHouse(ctx *gin.Context) { Name: house.Name, Description: house.Description, } - controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp) } // GetPigHouse godoc @@ -71,23 +70,20 @@ func (c *PigFarmController) CreatePigHouse(ctx *gin.Context) { // @Param id path int true "猪舍ID" // @Success 200 {object} controller.Response{data=dto.PigHouseResponse} "获取成功" // @Router /api/v1/pig-houses/{id} [get] -func (c *PigFarmController) GetPigHouse(ctx *gin.Context) { +func (c *PigFarmController) GetPigHouse(ctx echo.Context) error { const action = "获取猪舍" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) } house, err := c.service.GetPigHouseByID(uint(id)) if err != nil { if errors.Is(err, service.ErrHouseNotFound) { - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id) } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪舍失败", action, "业务逻辑失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪舍失败", action, "业务逻辑失败", id) } resp := dto.PigHouseResponse{ @@ -95,7 +91,7 @@ func (c *PigFarmController) GetPigHouse(ctx *gin.Context) { Name: house.Name, Description: house.Description, } - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp) } // ListPigHouses godoc @@ -106,13 +102,12 @@ func (c *PigFarmController) GetPigHouse(ctx *gin.Context) { // @Produce json // @Success 200 {object} controller.Response{data=[]dto.PigHouseResponse} "获取成功" // @Router /api/v1/pig-houses [get] -func (c *PigFarmController) ListPigHouses(ctx *gin.Context) { +func (c *PigFarmController) ListPigHouses(ctx echo.Context) error { const action = "获取猪舍列表" houses, err := c.service.ListPigHouses() if err != nil { c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil) } var resp []dto.PigHouseResponse @@ -124,7 +119,7 @@ func (c *PigFarmController) ListPigHouses(ctx *gin.Context) { }) } - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp) } // UpdatePigHouse godoc @@ -138,29 +133,25 @@ func (c *PigFarmController) ListPigHouses(ctx *gin.Context) { // @Param body body dto.UpdatePigHouseRequest true "猪舍信息" // @Success 200 {object} controller.Response{data=dto.PigHouseResponse} "更新成功" // @Router /api/v1/pig-houses/{id} [put] -func (c *PigFarmController) UpdatePigHouse(ctx *gin.Context) { +func (c *PigFarmController) UpdatePigHouse(ctx echo.Context) error { const action = "更新猪舍" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) } var req dto.UpdatePigHouseRequest - if err := ctx.ShouldBindJSON(&req); err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) - return + if err := ctx.Bind(&req); err != nil { + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) } house, err := c.service.UpdatePigHouse(uint(id), req.Name, req.Description) if err != nil { if errors.Is(err, service.ErrHouseNotFound) { - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id) } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req) } resp := dto.PigHouseResponse{ @@ -168,7 +159,7 @@ func (c *PigFarmController) UpdatePigHouse(ctx *gin.Context) { Name: house.Name, Description: house.Description, } - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) } // DeletePigHouse godoc @@ -180,30 +171,26 @@ func (c *PigFarmController) UpdatePigHouse(ctx *gin.Context) { // @Param id path int true "猪舍ID" // @Success 200 {object} controller.Response "删除成功" // @Router /api/v1/pig-houses/{id} [delete] -func (c *PigFarmController) DeletePigHouse(ctx *gin.Context) { +func (c *PigFarmController) DeletePigHouse(ctx echo.Context) error { const action = "删除猪舍" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) } if err := c.service.DeletePigHouse(uint(id)); err != nil { if errors.Is(err, service.ErrHouseNotFound) { - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id) } // 检查是否是业务逻辑错误 if errors.Is(err, service.ErrHouseContainsPens) { - controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除失败", action, "业务逻辑失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除失败", action, "业务逻辑失败", id) } - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "删除成功", nil, action, "删除成功", id) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "删除成功", nil, action, "删除成功", id) } // --- 猪栏 (Pen) API 实现 --- @@ -218,24 +205,21 @@ func (c *PigFarmController) DeletePigHouse(ctx *gin.Context) { // @Param body body dto.CreatePenRequest true "猪栏信息" // @Success 201 {object} controller.Response{data=dto.PenResponse} "创建成功" // @Router /api/v1/pens [post] -func (c *PigFarmController) CreatePen(ctx *gin.Context) { +func (c *PigFarmController) CreatePen(ctx echo.Context) error { const action = "创建猪栏" var req dto.CreatePenRequest - if err := ctx.ShouldBindJSON(&req); err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) - return + if err := ctx.Bind(&req); err != nil { + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) } pen, err := c.service.CreatePen(req.PenNumber, req.HouseID, req.Capacity) if err != nil { // 检查是否是业务逻辑错误 if errors.Is(err, service.ErrHouseNotFound) { - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), req) } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪栏失败", action, "业务逻辑失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪栏失败", action, "业务逻辑失败", req) } resp := dto.PenResponse{ @@ -245,7 +229,7 @@ func (c *PigFarmController) CreatePen(ctx *gin.Context) { Capacity: pen.Capacity, Status: pen.Status, } - controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp) } // GetPen godoc @@ -257,26 +241,23 @@ func (c *PigFarmController) CreatePen(ctx *gin.Context) { // @Param id path int true "猪栏ID" // @Success 200 {object} controller.Response{data=dto.PenResponse} "获取成功" // @Router /api/v1/pens/{id} [get] -func (c *PigFarmController) GetPen(ctx *gin.Context) { +func (c *PigFarmController) GetPen(ctx echo.Context) error { const action = "获取猪栏" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) } pen, err := c.service.GetPenByID(uint(id)) if err != nil { if errors.Is(err, service.ErrPenNotFound) { - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id) } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪栏失败", action, "业务逻辑失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪栏失败", action, "业务逻辑失败", id) } - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", pen, action, "获取成功", pen) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", pen, action, "获取成功", pen) } // ListPens godoc @@ -287,16 +268,15 @@ func (c *PigFarmController) GetPen(ctx *gin.Context) { // @Produce json // @Success 200 {object} controller.Response{data=[]dto.PenResponse} "获取成功" // @Router /api/v1/pens [get] -func (c *PigFarmController) ListPens(ctx *gin.Context) { +func (c *PigFarmController) ListPens(ctx echo.Context) error { const action = "获取猪栏列表" pens, err := c.service.ListPens() if err != nil { c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil) } - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", pens, action, "获取成功", pens) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", pens, action, "获取成功", pens) } // UpdatePen godoc @@ -310,30 +290,26 @@ func (c *PigFarmController) ListPens(ctx *gin.Context) { // @Param body body dto.UpdatePenRequest true "猪栏信息" // @Success 200 {object} controller.Response{data=dto.PenResponse} "更新成功" // @Router /api/v1/pens/{id} [put] -func (c *PigFarmController) UpdatePen(ctx *gin.Context) { +func (c *PigFarmController) UpdatePen(ctx echo.Context) error { const action = "更新猪栏" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) } var req dto.UpdatePenRequest - if err := ctx.ShouldBindJSON(&req); err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) - return + if err := ctx.Bind(&req); err != nil { + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) } pen, err := c.service.UpdatePen(uint(id), req.PenNumber, req.HouseID, req.Capacity, req.Status) if err != nil { if errors.Is(err, service.ErrPenNotFound) { - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id) } // 其他业务逻辑错误可以在这里添加处理 c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req) } resp := dto.PenResponse{ @@ -344,7 +320,7 @@ func (c *PigFarmController) UpdatePen(ctx *gin.Context) { Status: pen.Status, PigBatchID: pen.PigBatchID, } - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) } // DeletePen godoc @@ -356,30 +332,26 @@ func (c *PigFarmController) UpdatePen(ctx *gin.Context) { // @Param id path int true "猪栏ID" // @Success 200 {object} controller.Response "删除成功" // @Router /api/v1/pens/{id} [delete] -func (c *PigFarmController) DeletePen(ctx *gin.Context) { +func (c *PigFarmController) DeletePen(ctx echo.Context) error { const action = "删除猪栏" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) } if err := c.service.DeletePen(uint(id)); err != nil { if errors.Is(err, service.ErrPenNotFound) { - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id) } // 检查是否是业务逻辑错误 if errors.Is(err, service.ErrPenInUse) { - controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除失败", action, "业务逻辑失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除失败", action, "业务逻辑失败", id) } - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "删除成功", nil, action, "删除成功", id) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "删除成功", nil, action, "删除成功", id) } // UpdatePenStatus godoc @@ -393,32 +365,27 @@ func (c *PigFarmController) DeletePen(ctx *gin.Context) { // @Param body body dto.UpdatePenStatusRequest true "新的猪栏状态" // @Success 200 {object} controller.Response{data=dto.PenResponse} "更新成功" // @Router /api/v1/pens/{id}/status [put] -func (c *PigFarmController) UpdatePenStatus(ctx *gin.Context) { +func (c *PigFarmController) UpdatePenStatus(ctx echo.Context) error { const action = "更新猪栏状态" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) } var req dto.UpdatePenStatusRequest - if err := ctx.ShouldBindJSON(&req); err != nil { - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) - return + if err := ctx.Bind(&req); err != nil { + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) } pen, err := c.service.UpdatePenStatus(uint(id), req.Status) if err != nil { if errors.Is(err, service.ErrPenNotFound) { - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), id) } else if errors.Is(err, service.ErrPenStatusInvalidForOccupiedPen) || errors.Is(err, service.ErrPenStatusInvalidForUnoccupiedPen) { - controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新猪栏状态失败", action, err.Error(), id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新猪栏状态失败", action, err.Error(), id) } resp := dto.PenResponse{ @@ -429,5 +396,5 @@ func (c *PigFarmController) UpdatePenStatus(ctx *gin.Context) { Status: pen.Status, PigBatchID: pen.PigBatchID, } - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) } diff --git a/internal/app/controller/monitor/monitor_controller.go b/internal/app/controller/monitor/monitor_controller.go index c5836ad..b12d781 100644 --- a/internal/app/controller/monitor/monitor_controller.go +++ b/internal/app/controller/monitor/monitor_controller.go @@ -9,7 +9,7 @@ import ( "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" - "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" ) // Controller 监控控制器,封装了所有与数据监控相关的业务逻辑 @@ -35,14 +35,13 @@ func NewController(monitorService service.MonitorService, logger *logs.Logger) * // @Param query query dto.ListSensorDataRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListSensorDataResponse} // @Router /api/v1/monitor/sensor-data [get] -func (c *Controller) ListSensorData(ctx *gin.Context) { +func (c *Controller) ListSensorData(ctx echo.Context) error { const actionType = "获取传感器数据列表" var req dto.ListSensorDataRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.SensorDataListOptions{ @@ -60,18 +59,16 @@ func (c *Controller) ListSensorData(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取传感器数据失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取传感器数据失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListSensorDataResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取传感器数据成功", resp, actionType, "获取传感器数据成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取传感器数据成功", resp, actionType, "获取传感器数据成功", req) } // ListDeviceCommandLogs godoc @@ -83,14 +80,13 @@ func (c *Controller) ListSensorData(ctx *gin.Context) { // @Param query query dto.ListDeviceCommandLogRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListDeviceCommandLogResponse} // @Router /api/v1/monitor/device-command-logs [get] -func (c *Controller) ListDeviceCommandLogs(ctx *gin.Context) { +func (c *Controller) ListDeviceCommandLogs(ctx echo.Context) error { const actionType = "获取设备命令日志列表" var req dto.ListDeviceCommandLogRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.DeviceCommandLogListOptions{ @@ -105,18 +101,16 @@ func (c *Controller) ListDeviceCommandLogs(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备命令日志失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备命令日志失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListDeviceCommandLogResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备命令日志成功", resp, actionType, "获取设备命令日志成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备命令日志成功", resp, actionType, "获取设备命令日志成功", req) } // ListPlanExecutionLogs godoc @@ -128,14 +122,13 @@ func (c *Controller) ListDeviceCommandLogs(ctx *gin.Context) { // @Param query query dto.ListPlanExecutionLogRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListPlanExecutionLogResponse} // @Router /api/v1/monitor/plan-execution-logs [get] -func (c *Controller) ListPlanExecutionLogs(ctx *gin.Context) { +func (c *Controller) ListPlanExecutionLogs(ctx echo.Context) error { const actionType = "获取计划执行日志列表" var req dto.ListPlanExecutionLogRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.PlanExecutionLogListOptions{ @@ -153,18 +146,16 @@ func (c *Controller) ListPlanExecutionLogs(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划执行日志失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划执行日志失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListPlanExecutionLogResponse(planLogs, plans, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(planLogs), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取计划执行日志成功", resp, actionType, "获取计划执行日志成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取计划执行日志成功", resp, actionType, "获取计划执行日志成功", req) } // ListTaskExecutionLogs godoc @@ -176,14 +167,13 @@ func (c *Controller) ListPlanExecutionLogs(ctx *gin.Context) { // @Param query query dto.ListTaskExecutionLogRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListTaskExecutionLogResponse} // @Router /api/v1/monitor/task-execution-logs [get] -func (c *Controller) ListTaskExecutionLogs(ctx *gin.Context) { +func (c *Controller) ListTaskExecutionLogs(ctx echo.Context) error { const actionType = "获取任务执行日志列表" var req dto.ListTaskExecutionLogRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.TaskExecutionLogListOptions{ @@ -202,18 +192,16 @@ func (c *Controller) ListTaskExecutionLogs(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取任务执行日志失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取任务执行日志失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListTaskExecutionLogResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取任务执行日志成功", resp, actionType, "获取任务执行日志成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取任务执行日志成功", resp, actionType, "获取任务执行日志成功", req) } // ListPendingCollections godoc @@ -225,14 +213,13 @@ func (c *Controller) ListTaskExecutionLogs(ctx *gin.Context) { // @Param query query dto.ListPendingCollectionRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListPendingCollectionResponse} // @Router /api/v1/monitor/pending-collections [get] -func (c *Controller) ListPendingCollections(ctx *gin.Context) { +func (c *Controller) ListPendingCollections(ctx echo.Context) error { const actionType = "获取待采集请求列表" var req dto.ListPendingCollectionRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.PendingCollectionListOptions{ @@ -250,18 +237,16 @@ func (c *Controller) ListPendingCollections(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取待采集请求失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取待采集请求失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListPendingCollectionResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取待采集请求成功", resp, actionType, "获取待采集请求成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取待采集请求成功", resp, actionType, "获取待采集请求成功", req) } // ListUserActionLogs godoc @@ -273,14 +258,13 @@ func (c *Controller) ListPendingCollections(ctx *gin.Context) { // @Param query query dto.ListUserActionLogRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListUserActionLogResponse} // @Router /api/v1/monitor/user-action-logs [get] -func (c *Controller) ListUserActionLogs(ctx *gin.Context) { +func (c *Controller) ListUserActionLogs(ctx echo.Context) error { const actionType = "获取用户操作日志列表" var req dto.ListUserActionLogRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.UserActionLogListOptions{ @@ -300,18 +284,16 @@ func (c *Controller) ListUserActionLogs(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取用户操作日志失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取用户操作日志失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListUserActionLogResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取用户操作日志成功", resp, actionType, "获取用户操作日志成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取用户操作日志成功", resp, actionType, "获取用户操作日志成功", req) } // ListRawMaterialPurchases godoc @@ -323,14 +305,13 @@ func (c *Controller) ListUserActionLogs(ctx *gin.Context) { // @Param query query dto.ListRawMaterialPurchaseRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListRawMaterialPurchaseResponse} // @Router /api/v1/monitor/raw-material-purchases [get] -func (c *Controller) ListRawMaterialPurchases(ctx *gin.Context) { +func (c *Controller) ListRawMaterialPurchases(ctx echo.Context) error { const actionType = "获取原料采购记录列表" var req dto.ListRawMaterialPurchaseRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.RawMaterialPurchaseListOptions{ @@ -345,18 +326,16 @@ func (c *Controller) ListRawMaterialPurchases(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取原料采购记录失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取原料采购记录失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListRawMaterialPurchaseResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取原料采购记录成功", resp, actionType, "获取原料采购记录成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取原料采购记录成功", resp, actionType, "获取原料采购记录成功", req) } // ListRawMaterialStockLogs godoc @@ -368,14 +347,13 @@ func (c *Controller) ListRawMaterialPurchases(ctx *gin.Context) { // @Param query query dto.ListRawMaterialStockLogRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListRawMaterialStockLogResponse} // @Router /api/v1/monitor/raw-material-stock-logs [get] -func (c *Controller) ListRawMaterialStockLogs(ctx *gin.Context) { +func (c *Controller) ListRawMaterialStockLogs(ctx echo.Context) error { const actionType = "获取原料库存日志列表" var req dto.ListRawMaterialStockLogRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.RawMaterialStockLogListOptions{ @@ -394,18 +372,16 @@ func (c *Controller) ListRawMaterialStockLogs(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取原料库存日志失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取原料库存日志失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListRawMaterialStockLogResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取原料库存日志成功", resp, actionType, "获取原料库存日志成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取原料库存日志成功", resp, actionType, "获取原料库存日志成功", req) } // ListFeedUsageRecords godoc @@ -417,14 +393,13 @@ func (c *Controller) ListRawMaterialStockLogs(ctx *gin.Context) { // @Param query query dto.ListFeedUsageRecordRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListFeedUsageRecordResponse} // @Router /api/v1/monitor/feed-usage-records [get] -func (c *Controller) ListFeedUsageRecords(ctx *gin.Context) { +func (c *Controller) ListFeedUsageRecords(ctx echo.Context) error { const actionType = "获取饲料使用记录列表" var req dto.ListFeedUsageRecordRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.FeedUsageRecordListOptions{ @@ -440,18 +415,16 @@ func (c *Controller) ListFeedUsageRecords(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取饲料使用记录失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取饲料使用记录失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListFeedUsageRecordResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取饲料使用记录成功", resp, actionType, "获取饲料使用记录成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取饲料使用记录成功", resp, actionType, "获取饲料使用记录成功", req) } // ListMedicationLogs godoc @@ -463,14 +436,13 @@ func (c *Controller) ListFeedUsageRecords(ctx *gin.Context) { // @Param query query dto.ListMedicationLogRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListMedicationLogResponse} // @Router /api/v1/monitor/medication-logs [get] -func (c *Controller) ListMedicationLogs(ctx *gin.Context) { +func (c *Controller) ListMedicationLogs(ctx echo.Context) error { const actionType = "获取用药记录列表" var req dto.ListMedicationLogRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.MedicationLogListOptions{ @@ -490,18 +462,16 @@ func (c *Controller) ListMedicationLogs(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取用药记录失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取用药记录失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListMedicationLogResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取用药记录成功", resp, actionType, "获取用药记录成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取用药记录成功", resp, actionType, "获取用药记录成功", req) } // ListPigBatchLogs godoc @@ -513,14 +483,13 @@ func (c *Controller) ListMedicationLogs(ctx *gin.Context) { // @Param query query dto.ListPigBatchLogRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListPigBatchLogResponse} // @Router /api/v1/monitor/pig-batch-logs [get] -func (c *Controller) ListPigBatchLogs(ctx *gin.Context) { +func (c *Controller) ListPigBatchLogs(ctx echo.Context) error { const actionType = "获取猪批次日志列表" var req dto.ListPigBatchLogRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.PigBatchLogListOptions{ @@ -539,18 +508,16 @@ func (c *Controller) ListPigBatchLogs(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪批次日志失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪批次日志失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListPigBatchLogResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取猪批次日志成功", resp, actionType, "获取猪批次日志成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取猪批次日志成功", resp, actionType, "获取猪批次日志成功", req) } // ListWeighingBatches godoc @@ -562,14 +529,13 @@ func (c *Controller) ListPigBatchLogs(ctx *gin.Context) { // @Param query query dto.ListWeighingBatchRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListWeighingBatchResponse} // @Router /api/v1/monitor/weighing-batches [get] -func (c *Controller) ListWeighingBatches(ctx *gin.Context) { +func (c *Controller) ListWeighingBatches(ctx echo.Context) error { const actionType = "获取批次称重记录列表" var req dto.ListWeighingBatchRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.WeighingBatchListOptions{ @@ -583,18 +549,16 @@ func (c *Controller) ListWeighingBatches(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取批次称重记录失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取批次称重记录失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListWeighingBatchResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取批次称重记录成功", resp, actionType, "获取批次称重记录成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取批次称重记录成功", resp, actionType, "获取批次称重记录成功", req) } // ListWeighingRecords godoc @@ -606,14 +570,13 @@ func (c *Controller) ListWeighingBatches(ctx *gin.Context) { // @Param query query dto.ListWeighingRecordRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListWeighingRecordResponse} // @Router /api/v1/monitor/weighing-records [get] -func (c *Controller) ListWeighingRecords(ctx *gin.Context) { +func (c *Controller) ListWeighingRecords(ctx echo.Context) error { const actionType = "获取单次称重记录列表" var req dto.ListWeighingRecordRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.WeighingRecordListOptions{ @@ -629,18 +592,16 @@ func (c *Controller) ListWeighingRecords(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取单次称重记录失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取单次称重记录失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListWeighingRecordResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取单次称重记录成功", resp, actionType, "获取单次称重记录成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取单次称重记录成功", resp, actionType, "获取单次称重记录成功", req) } // ListPigTransferLogs godoc @@ -652,14 +613,13 @@ func (c *Controller) ListWeighingRecords(ctx *gin.Context) { // @Param query query dto.ListPigTransferLogRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListPigTransferLogResponse} // @Router /api/v1/monitor/pig-transfer-logs [get] -func (c *Controller) ListPigTransferLogs(ctx *gin.Context) { +func (c *Controller) ListPigTransferLogs(ctx echo.Context) error { const actionType = "获取猪只迁移日志列表" var req dto.ListPigTransferLogRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.PigTransferLogListOptions{ @@ -680,18 +640,16 @@ func (c *Controller) ListPigTransferLogs(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪只迁移日志失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪只迁移日志失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListPigTransferLogResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取猪只迁移日志成功", resp, actionType, "获取猪只迁移日志成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取猪只迁移日志成功", resp, actionType, "获取猪只迁移日志成功", req) } // ListPigSickLogs godoc @@ -703,14 +661,13 @@ func (c *Controller) ListPigTransferLogs(ctx *gin.Context) { // @Param query query dto.ListPigSickLogRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListPigSickLogResponse} // @Router /api/v1/monitor/pig-sick-logs [get] -func (c *Controller) ListPigSickLogs(ctx *gin.Context) { +func (c *Controller) ListPigSickLogs(ctx echo.Context) error { const actionType = "获取病猪日志列表" var req dto.ListPigSickLogRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.PigSickLogListOptions{ @@ -734,18 +691,16 @@ func (c *Controller) ListPigSickLogs(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取病猪日志失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取病猪日志失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListPigSickLogResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取病猪日志成功", resp, actionType, "获取病猪日志成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取病猪日志成功", resp, actionType, "获取病猪日志成功", req) } // ListPigPurchases godoc @@ -757,14 +712,13 @@ func (c *Controller) ListPigSickLogs(ctx *gin.Context) { // @Param query query dto.ListPigPurchaseRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListPigPurchaseResponse} // @Router /api/v1/monitor/pig-purchases [get] -func (c *Controller) ListPigPurchases(ctx *gin.Context) { +func (c *Controller) ListPigPurchases(ctx echo.Context) error { const actionType = "获取猪只采购记录列表" var req dto.ListPigPurchaseRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.PigPurchaseListOptions{ @@ -780,18 +734,16 @@ func (c *Controller) ListPigPurchases(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪只采购记录失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪只采购记录失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListPigPurchaseResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取猪只采购记录成功", resp, actionType, "获取猪只采购记录成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取猪只采购记录成功", resp, actionType, "获取猪只采购记录成功", req) } // ListPigSales godoc @@ -803,14 +755,13 @@ func (c *Controller) ListPigPurchases(ctx *gin.Context) { // @Param query query dto.ListPigSaleRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListPigSaleResponse} // @Router /api/v1/monitor/pig-sales [get] -func (c *Controller) ListPigSales(ctx *gin.Context) { +func (c *Controller) ListPigSales(ctx echo.Context) error { const actionType = "获取猪只售卖记录列表" var req dto.ListPigSaleRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.PigSaleListOptions{ @@ -826,18 +777,16 @@ func (c *Controller) ListPigSales(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪只售卖记录失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪只售卖记录失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListPigSaleResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取猪只售卖记录成功", resp, actionType, "获取猪只售卖记录成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取猪只售卖记录成功", resp, actionType, "获取猪只售卖记录成功", req) } // ListNotifications godoc @@ -849,14 +798,13 @@ func (c *Controller) ListPigSales(ctx *gin.Context) { // @Param query query dto.ListNotificationRequest true "查询参数" // @Success 200 {object} controller.Response{data=dto.ListNotificationResponse} // @Router /api/v1/monitor/notifications [get] -func (c *Controller) ListNotifications(ctx *gin.Context) { +func (c *Controller) ListNotifications(ctx echo.Context) error { const actionType = "批量查询通知" var req dto.ListNotificationRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } opts := repository.NotificationListOptions{ @@ -873,16 +821,14 @@ func (c *Controller) ListNotifications(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "批量查询通知失败: "+err.Error(), actionType, "服务层查询失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "批量查询通知失败: "+err.Error(), actionType, "服务层查询失败", req) } resp := dto.NewListNotificationResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "批量查询通知成功", resp, actionType, "批量查询通知成功", req) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "批量查询通知成功", resp, actionType, "批量查询通知成功", req) } diff --git a/internal/app/controller/plan/plan_controller.go b/internal/app/controller/plan/plan_controller.go index b682227..a7ebd9c 100644 --- a/internal/app/controller/plan/plan_controller.go +++ b/internal/app/controller/plan/plan_controller.go @@ -10,11 +10,11 @@ import ( "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" - "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" "gorm.io/gorm" ) -// --- Controller 定义 --- +// --- 控制器定义 --- // Controller 定义了计划相关的控制器 type Controller struct { @@ -44,21 +44,19 @@ func NewController(logger *logs.Logger, planRepo repository.PlanRepository, anal // @Param plan body dto.CreatePlanRequest true "计划信息" // @Success 200 {object} controller.Response{data=dto.PlanResponse} "业务码为201代表创建成功" // @Router /api/v1/plans [post] -func (c *Controller) CreatePlan(ctx *gin.Context) { +func (c *Controller) CreatePlan(ctx echo.Context) error { var req dto.CreatePlanRequest const actionType = "创建计划" - if err := ctx.ShouldBindJSON(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) } // 使用已有的转换函数,它已经包含了验证和重排逻辑 planToCreate, err := dto.NewPlanFromCreateRequest(&req) if err != nil { c.logger.Errorf("%s: 计划数据校验失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划数据校验失败: "+err.Error(), actionType, "计划数据校验失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划数据校验失败: "+err.Error(), actionType, "计划数据校验失败", req) } // --- 业务规则处理 --- @@ -76,8 +74,7 @@ func (c *Controller) CreatePlan(ctx *gin.Context) { // 调用仓库方法创建计划 if err := c.planRepo.CreatePlan(planToCreate); err != nil { c.logger.Errorf("%s: 数据库创建计划失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建计划失败: "+err.Error(), actionType, "数据库创建计划失败", planToCreate) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建计划失败: "+err.Error(), actionType, "数据库创建计划失败", planToCreate) } // 创建成功后,调用 manager 确保触发器任务定义存在,但不立即加入待执行队列 @@ -89,14 +86,13 @@ func (c *Controller) CreatePlan(ctx *gin.Context) { // 使用已有的转换函数将创建后的模型转换为响应对象 resp, err := dto.NewPlanToResponse(planToCreate) if err != nil { - c.logger.Errorf("%s: 序列化响应失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "计划创建成功,但响应生成失败", actionType, "响应序列化失败", planToCreate) - return + c.logger.Errorf("%s: 序列化响应失败: %v, Plan: %+v", actionType, err, planToCreate) + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "计划创建成功,但响应生成失败", actionType, "响应序列化失败", planToCreate) } // 使用统一的成功响应函数 c.logger.Infof("%s: 计划创建成功, ID: %d", actionType, planToCreate.ID) - controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "计划创建成功", resp, actionType, "计划创建成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "计划创建成功", resp, actionType, "计划创建成功", resp) } // GetPlan godoc @@ -108,15 +104,14 @@ func (c *Controller) CreatePlan(ctx *gin.Context) { // @Param id path int true "计划ID" // @Success 200 {object} controller.Response{data=dto.PlanResponse} "业务码为200代表成功获取" // @Router /api/v1/plans/{id} [get] -func (c *Controller) GetPlan(ctx *gin.Context) { +func (c *Controller) GetPlan(ctx echo.Context) error { const actionType = "获取计划详情" // 1. 从 URL 路径中获取 ID idStr := ctx.Param("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) } // 2. 调用仓库层获取计划详情 @@ -125,26 +120,23 @@ func (c *Controller) GetPlan(ctx *gin.Context) { // 判断是否为“未找到”错误 if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) } // 其他数据库错误视为内部错误 c.logger.Errorf("%s: 数据库查询失败: %v, ID: %d", actionType, err, id) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划详情时发生内部错误", actionType, "数据库查询失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划详情时发生内部错误", actionType, "数据库查询失败", id) } // 3. 将模型转换为响应 DTO resp, err := dto.NewPlanToResponse(plan) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, Plan: %+v", actionType, err, plan) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划详情失败: 内部数据格式错误", actionType, "响应序列化失败", plan) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划详情失败: 内部数据格式错误", actionType, "响应序列化失败", plan) } // 4. 发送成功响应 c.logger.Infof("%s: 获取计划详情成功, ID: %d", actionType, id) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取计划详情成功", resp, actionType, "获取计划详情成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取计划详情成功", resp, actionType, "获取计划详情成功", resp) } // ListPlans godoc @@ -156,13 +148,12 @@ func (c *Controller) GetPlan(ctx *gin.Context) { // @Param query query dto.ListPlansQuery false "查询参数" // @Success 200 {object} controller.Response{data=dto.ListPlansResponse} "业务码为200代表成功获取列表" // @Router /api/v1/plans [get] -func (c *Controller) ListPlans(ctx *gin.Context) { +func (c *Controller) ListPlans(ctx echo.Context) error { const actionType = "获取计划列表" var query dto.ListPlansQuery - if err := ctx.ShouldBindQuery(&query); err != nil { + if err := ctx.Bind(&query); err != nil { c.logger.Errorf("%s: 查询参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", query) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", query) } // 1. 调用仓库层获取所有计划 @@ -170,8 +161,7 @@ func (c *Controller) ListPlans(ctx *gin.Context) { plans, total, err := c.planRepo.ListPlans(opts, query.Page, query.PageSize) if err != nil { c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划列表时发生内部错误", actionType, "数据库查询失败", nil) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划列表时发生内部错误", actionType, "数据库查询失败", nil) } // 2. 将模型转换为响应 DTO @@ -180,8 +170,7 @@ func (c *Controller) ListPlans(ctx *gin.Context) { resp, err := dto.NewPlanToResponse(&p) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, Plan: %+v", actionType, err, p) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划列表失败: 内部数据格式错误", actionType, "响应序列化失败", p) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划列表失败: 内部数据格式错误", actionType, "响应序列化失败", p) } planResponses = append(planResponses, *resp) } @@ -192,7 +181,7 @@ func (c *Controller) ListPlans(ctx *gin.Context) { Total: total, } c.logger.Infof("%s: 获取计划列表成功, 数量: %d", actionType, len(planResponses)) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取计划列表成功", resp, actionType, "获取计划列表成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取计划列表成功", resp, actionType, "获取计划列表成功", resp) } // UpdatePlan godoc @@ -206,23 +195,21 @@ func (c *Controller) ListPlans(ctx *gin.Context) { // @Param plan body dto.UpdatePlanRequest true "更新后的计划信息" // @Success 200 {object} controller.Response{data=dto.PlanResponse} "业务码为200代表更新成功" // @Router /api/v1/plans/{id} [put] -func (c *Controller) UpdatePlan(ctx *gin.Context) { +func (c *Controller) UpdatePlan(ctx echo.Context) error { const actionType = "更新计划" // 1. 从 URL 路径中获取 ID idStr := ctx.Param("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) } // 2. 绑定请求体 var req dto.UpdatePlanRequest - if err := ctx.ShouldBindJSON(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) } // 3. 检查计划是否存在 @@ -230,27 +217,23 @@ func (c *Controller) UpdatePlan(ctx *gin.Context) { if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) } c.logger.Errorf("%s: 获取计划信息失败: %v, ID: %d", actionType, err, id) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id) } // 4. 业务规则:系统计划不允许修改 if existingPlan.PlanType == models.PlanTypeSystem { c.logger.Warnf("%s: 尝试修改系统计划, ID: %d", actionType, id) - controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许修改", actionType, "尝试修改系统计划", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许修改", actionType, "尝试修改系统计划", id) } // 5. 将请求转换为模型(转换函数带校验) planToUpdate, err := dto.NewPlanFromUpdateRequest(&req) if err != nil { c.logger.Errorf("%s: 计划数据校验失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划数据校验失败: "+err.Error(), actionType, "计划数据校验失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划数据校验失败: "+err.Error(), actionType, "计划数据校验失败", req) } planToUpdate.ID = uint(id) // 确保ID被设置 @@ -269,8 +252,7 @@ func (c *Controller) UpdatePlan(ctx *gin.Context) { if err := c.planRepo.UpdatePlan(planToUpdate); err != nil { c.logger.Errorf("%s: 数据库更新计划失败: %v, Plan: %+v", actionType, err, planToUpdate) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新计划失败: "+err.Error(), actionType, "数据库更新计划失败", planToUpdate) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新计划失败: "+err.Error(), actionType, "数据库更新计划失败", planToUpdate) } // 更新成功后,调用 manager 确保触发器任务定义存在 @@ -283,21 +265,19 @@ func (c *Controller) UpdatePlan(ctx *gin.Context) { updatedPlan, err := c.planRepo.GetPlanByID(uint(id)) if err != nil { c.logger.Errorf("%s: 获取更新后计划详情失败: %v, ID: %d", actionType, err, id) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取更新后计划详情时发生内部错误", actionType, "获取更新后计划详情失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取更新后计划详情时发生内部错误", actionType, "获取更新后计划详情失败", id) } // 8. 将模型转换为响应 DTO resp, err := dto.NewPlanToResponse(updatedPlan) if err != nil { c.logger.Errorf("%s: 序列化响应失败: %v, Updated Plan: %+v", actionType, err, updatedPlan) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "计划更新成功,但响应生成失败", actionType, "响应序列化失败", updatedPlan) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "计划更新成功,但响应生成失败", actionType, "响应序列化失败", updatedPlan) } // 9. 发送成功响应 c.logger.Infof("%s: 计划更新成功, ID: %d", actionType, updatedPlan.ID) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "计划更新成功", resp, actionType, "计划更新成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "计划更新成功", resp, actionType, "计划更新成功", resp) } // DeletePlan godoc @@ -309,15 +289,14 @@ func (c *Controller) UpdatePlan(ctx *gin.Context) { // @Param id path int true "计划ID" // @Success 200 {object} controller.Response "业务码为200代表删除成功" // @Router /api/v1/plans/{id} [delete] -func (c *Controller) DeletePlan(ctx *gin.Context) { +func (c *Controller) DeletePlan(ctx echo.Context) error { const actionType = "删除计划" // 1. 从 URL 路径中获取 ID idStr := ctx.Param("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) } // 2. 检查计划是否存在 @@ -325,40 +304,35 @@ func (c *Controller) DeletePlan(ctx *gin.Context) { if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) } c.logger.Errorf("%s: 获取计划信息失败: %v, ID: %d", actionType, err, id) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id) } // 3. 业务规则:系统计划不允许删除 if plan.PlanType == models.PlanTypeSystem { c.logger.Warnf("%s: 尝试删除系统计划, ID: %d", actionType, id) - controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许删除", actionType, "尝试删除系统计划", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许删除", actionType, "尝试删除系统计划", id) } // 4. 停止这个计划 if plan.Status == models.PlanStatusEnabled { if err := c.planRepo.StopPlanTransactionally(uint(id)); err != nil { c.logger.Errorf("%s: 停止计划失败: %v, ID: %d", actionType, err, id) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "停止计划时发生内部错误: "+err.Error(), actionType, "停止计划失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "停止计划时发生内部错误: "+err.Error(), actionType, "停止计划失败", id) } } // 5. 调用仓库层删除计划 if err := c.planRepo.DeletePlan(uint(id)); err != nil { c.logger.Errorf("%s: 数据库删除失败: %v, ID: %d", actionType, err, id) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除计划时发生内部错误", actionType, "数据库删除失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除计划时发生内部错误", actionType, "数据库删除失败", id) } // 6. 发送成功响应 c.logger.Infof("%s: 计划删除成功, ID: %d", actionType, id) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "计划删除成功", nil, actionType, "计划删除成功", id) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "计划删除成功", nil, actionType, "计划删除成功", id) } // StartPlan godoc @@ -370,15 +344,14 @@ func (c *Controller) DeletePlan(ctx *gin.Context) { // @Param id path int true "计划ID" // @Success 200 {object} controller.Response "业务码为200代表成功启动计划" // @Router /api/v1/plans/{id}/start [post] -func (c *Controller) StartPlan(ctx *gin.Context) { +func (c *Controller) StartPlan(ctx echo.Context) error { const actionType = "启动计划" // 1. 从 URL 路径中获取 ID idStr := ctx.Param("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) } // 2. 检查计划是否存在 @@ -386,24 +359,20 @@ func (c *Controller) StartPlan(ctx *gin.Context) { if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) } c.logger.Errorf("%s: 获取计划信息失败: %v, ID: %d", actionType, err, id) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id) } // 3. 业务规则检查 if plan.PlanType == models.PlanTypeSystem { c.logger.Warnf("%s: 尝试手动启动系统计划, ID: %d", actionType, id) - controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许手动启动", actionType, "尝试手动启动系统计划", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许手动启动", actionType, "尝试手动启动系统计划", id) } if plan.Status == models.PlanStatusEnabled { c.logger.Warnf("%s: 计划已处于启动状态,无需重复操作, ID: %d", actionType, id) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划已处于启动状态,无需重复操作", actionType, "计划已处于启动状态", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划已处于启动状态,无需重复操作", actionType, "计划已处于启动状态", id) } // 4. 检查并重置执行计数器,然后更新计划状态为“已启动” @@ -413,8 +382,7 @@ func (c *Controller) StartPlan(ctx *gin.Context) { if plan.ExecuteCount > 0 { if err := c.planRepo.UpdateExecuteCount(plan.ID, 0); err != nil { c.logger.Errorf("%s: 重置计划执行计数失败: %v, ID: %d", actionType, err, plan.ID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "重置计划执行计数失败", actionType, "重置执行计数失败", plan.ID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "重置计划执行计数失败", actionType, "重置执行计数失败", plan.ID) } c.logger.Infof("计划 #%d 的执行计数器已重置为 0。", plan.ID) } @@ -422,28 +390,25 @@ func (c *Controller) StartPlan(ctx *gin.Context) { // 更新计划状态为“已启动” if err := c.planRepo.UpdatePlanStatus(plan.ID, models.PlanStatusEnabled); err != nil { c.logger.Errorf("%s: 更新计划状态失败: %v, ID: %d", actionType, err, plan.ID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新计划状态失败", actionType, "更新计划状态失败", plan.ID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新计划状态失败", actionType, "更新计划状态失败", plan.ID) } c.logger.Infof("已成功更新计划 #%d 的状态为 '已启动'。", plan.ID) } else { // 如果计划已经处于 Enabled 状态,则无需更新 c.logger.Infof("计划 #%d 已处于启动状态,无需重复操作。", plan.ID) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划已处于启动状态,无需重复操作", actionType, "计划已处于启动状态", plan.ID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划已处于启动状态,无需重复操作", actionType, "计划已处于启动状态", plan.ID) } // 5. 为计划创建或更新触发器 if err := c.analysisPlanTaskManager.CreateOrUpdateTrigger(plan.ID); err != nil { // 此处错误不回滚状态,因为状态更新已成功,但需要明确告知用户触发器创建失败 c.logger.Errorf("%s: 创建或更新触发器失败: %v, ID: %d", actionType, err, plan.ID) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "计划状态已更新,但创建执行触发器失败,请检查计划配置或稍后重试", actionType, "创建执行触发器失败", plan.ID) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "计划状态已更新,但创建执行触发器失败,请检查计划配置或稍后重试", actionType, "创建执行触发器失败", plan.ID) } // 6. 发送成功响应 c.logger.Infof("%s: 计划已成功启动, ID: %d", actionType, id) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "计划已成功启动", nil, actionType, "计划已成功启动", id) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "计划已成功启动", nil, actionType, "计划已成功启动", id) } // StopPlan godoc @@ -455,15 +420,14 @@ func (c *Controller) StartPlan(ctx *gin.Context) { // @Param id path int true "计划ID" // @Success 200 {object} controller.Response "业务码为200代表成功停止计划" // @Router /api/v1/plans/{id}/stop [post] -func (c *Controller) StopPlan(ctx *gin.Context) { +func (c *Controller) StopPlan(ctx echo.Context) error { const actionType = "停止计划" // 1. 从 URL 路径中获取 ID idStr := ctx.Param("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) } // 2. 检查计划是否存在 @@ -471,36 +435,31 @@ func (c *Controller) StopPlan(ctx *gin.Context) { if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id) - controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) } c.logger.Errorf("%s: 获取计划信息失败: %v, ID: %d", actionType, err, id) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id) } // 3. 业务规则:系统计划不允许停止 if plan.PlanType == models.PlanTypeSystem { c.logger.Warnf("%s: 尝试停止系统计划, ID: %d", actionType, id) - controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许停止", actionType, "尝试停止系统计划", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许停止", actionType, "尝试停止系统计划", id) } // 4. 检查计划当前状态 if plan.Status != models.PlanStatusEnabled { c.logger.Warnf("%s: 计划当前不是启用状态, ID: %d, Status: %s", actionType, id, plan.Status) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划当前不是启用状态", actionType, "计划未启用", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划当前不是启用状态", actionType, "计划未启用", id) } // 5. 调用仓库层方法,该方法内部处理事务 if err := c.planRepo.StopPlanTransactionally(uint(id)); err != nil { c.logger.Errorf("%s: 停止计划失败: %v, ID: %d", actionType, err, id) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "停止计划时发生内部错误: "+err.Error(), actionType, "停止计划失败", id) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "停止计划时发生内部错误: "+err.Error(), actionType, "停止计划失败", id) } // 6. 发送成功响应 c.logger.Infof("%s: 计划已成功停止, ID: %d", actionType, id) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "计划已成功停止", nil, actionType, "计划已成功停止", id) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "计划已成功停止", nil, actionType, "计划已成功停止", id) } diff --git a/internal/app/controller/user/user_controller.go b/internal/app/controller/user/user_controller.go index 6ddd6d9..03a9016 100644 --- a/internal/app/controller/user/user_controller.go +++ b/internal/app/controller/user/user_controller.go @@ -12,7 +12,7 @@ import ( "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" - "github.com/gin-gonic/gin" + "github.com/labstack/echo/v4" "gorm.io/gorm" ) @@ -53,12 +53,11 @@ func NewController( // @Param user body dto.CreateUserRequest true "用户信息" // @Success 200 {object} controller.Response{data=dto.CreateUserResponse} "业务码为201代表创建成功" // @Router /api/v1/users [post] -func (c *Controller) CreateUser(ctx *gin.Context) { +func (c *Controller) CreateUser(ctx echo.Context) error { var req dto.CreateUserRequest - if err := ctx.ShouldBindJSON(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("创建用户: 参数绑定失败: %v", err) - controller.SendErrorResponse(ctx, controller.CodeBadRequest, err.Error()) - return + return controller.SendErrorResponse(ctx, controller.CodeBadRequest, err.Error()) } user := &models.User{ @@ -72,16 +71,14 @@ func (c *Controller) CreateUser(ctx *gin.Context) { // 尝试查询用户,以判断是否是用户名重复导致的错误 _, findErr := c.userRepo.FindByUsername(req.Username) if findErr == nil { // 如果能找到用户,说明是用户名重复 - controller.SendErrorResponse(ctx, controller.CodeConflict, "用户名已存在") - return + return controller.SendErrorResponse(ctx, controller.CodeConflict, "用户名已存在") } // 其他创建失败的情况 - controller.SendErrorResponse(ctx, controller.CodeInternalError, "创建用户失败") - return + return controller.SendErrorResponse(ctx, controller.CodeInternalError, "创建用户失败") } - controller.SendResponse(ctx, controller.CodeCreated, "用户创建成功", dto.CreateUserResponse{ + return controller.SendResponse(ctx, controller.CodeCreated, "用户创建成功", dto.CreateUserResponse{ Username: user.Username, ID: user.ID, }) @@ -96,40 +93,35 @@ func (c *Controller) CreateUser(ctx *gin.Context) { // @Param credentials body dto.LoginRequest true "登录凭证" // @Success 200 {object} controller.Response{data=dto.LoginResponse} "业务码为200代表登录成功" // @Router /api/v1/users/login [post] -func (c *Controller) Login(ctx *gin.Context) { +func (c *Controller) Login(ctx echo.Context) error { var req dto.LoginRequest - if err := ctx.ShouldBindJSON(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("登录: 参数绑定失败: %v", err) - controller.SendErrorResponse(ctx, controller.CodeBadRequest, err.Error()) - return + return controller.SendErrorResponse(ctx, controller.CodeBadRequest, err.Error()) } // 使用新的方法,通过唯一标识符(用户名、邮箱等)查找用户 user, err := c.userRepo.FindUserForLogin(req.Identifier) if err != nil { if err == gorm.ErrRecordNotFound { - controller.SendErrorResponse(ctx, controller.CodeUnauthorized, "登录凭证不正确") - return + return controller.SendErrorResponse(ctx, controller.CodeUnauthorized, "登录凭证不正确") } c.logger.Errorf("登录: 查询用户失败: %v", err) - controller.SendErrorResponse(ctx, controller.CodeInternalError, "登录失败") - return + return controller.SendErrorResponse(ctx, controller.CodeInternalError, "登录失败") } if !user.CheckPassword(req.Password) { - controller.SendErrorResponse(ctx, controller.CodeUnauthorized, "登录凭证不正确") - return + return controller.SendErrorResponse(ctx, controller.CodeUnauthorized, "登录凭证不正确") } // 登录成功,生成 JWT token tokenString, err := c.tokenService.GenerateToken(user.ID) if err != nil { c.logger.Errorf("登录: 生成令牌失败: %v", err) - controller.SendErrorResponse(ctx, controller.CodeInternalError, "登录失败,无法生成认证信息") - return + return controller.SendErrorResponse(ctx, controller.CodeInternalError, "登录失败,无法生成认证信息") } - controller.SendResponse(ctx, controller.CodeSuccess, "登录成功", dto.LoginResponse{ + return controller.SendResponse(ctx, controller.CodeSuccess, "登录成功", dto.LoginResponse{ Username: user.Username, ID: user.ID, Token: tokenString, @@ -146,7 +138,7 @@ func (c *Controller) Login(ctx *gin.Context) { // @Param query query dto.ListUserActionLogRequest false "查询参数 (除了 user_id,它被路径中的ID覆盖)" // @Success 200 {object} controller.Response{data=dto.ListUserActionLogResponse} "业务码为200代表成功获取" // @Router /api/v1/users/{id}/history [get] -func (c *Controller) ListUserHistory(ctx *gin.Context) { +func (c *Controller) ListUserHistory(ctx echo.Context) error { const actionType = "获取用户操作历史" // 1. 解析路径中的用户ID,它的优先级最高 @@ -154,16 +146,14 @@ func (c *Controller) ListUserHistory(ctx *gin.Context) { userID, err := strconv.ParseUint(userIDStr, 10, 64) if err != nil { c.logger.Errorf("%s: 无效的用户ID格式: %v, ID: %s", actionType, err, userIDStr) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的用户ID格式", actionType, "无效的用户ID格式", userIDStr) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的用户ID格式", actionType, "无效的用户ID格式", userIDStr) } // 2. 绑定通用的查询请求 DTO var req dto.ListUserActionLogRequest - if err := ctx.ShouldBindQuery(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) } // 3. 准备 Service 调用参数,并强制使用路径中的 UserID @@ -188,18 +178,16 @@ func (c *Controller) ListUserHistory(ctx *gin.Context) { if err != nil { if errors.Is(err, repository.ErrInvalidPagination) { c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", opts) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", opts) } c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取用户历史记录失败", actionType, "服务层查询失败", opts) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取用户历史记录失败", actionType, "服务层查询失败", opts) } // 5. 使用复用的 DTO 构建并发送成功响应 resp := dto.NewListUserActionLogResponse(data, total, req.Page, req.PageSize) c.logger.Infof("%s: 成功获取用户 %d 的操作历史, 数量: %d", actionType, userID, len(data)) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取用户操作历史成功", resp, actionType, "获取用户操作历史成功", opts) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取用户操作历史成功", resp, actionType, "获取用户操作历史成功", opts) } // SendTestNotification godoc @@ -213,34 +201,31 @@ func (c *Controller) ListUserHistory(ctx *gin.Context) { // @Param body body dto.SendTestNotificationRequest true "请求体" // @Success 200 {object} controller.Response{data=string} "成功响应" // @Router /api/v1/users/{id}/notifications/test [post] -func (c *Controller) SendTestNotification(ctx *gin.Context) { +func (c *Controller) SendTestNotification(ctx echo.Context) error { const actionType = "发送测试通知" // 1. 从 URL 中获取用户 ID userID, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { c.logger.Errorf("%s: 无效的用户ID格式: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的用户ID格式", actionType, "无效的用户ID格式", ctx.Param("id")) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的用户ID格式", actionType, "无效的用户ID格式", ctx.Param("id")) } // 2. 从请求体 (JSON Body) 中获取要测试的通知类型 var req dto.SendTestNotificationRequest - if err := ctx.ShouldBindJSON(&req); err != nil { + if err := ctx.Bind(&req); err != nil { c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "请求体格式错误或缺少 'type' 字段: "+err.Error(), actionType, "请求体绑定失败", req) - return + return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "请求体格式错误或缺少 'type' 字段: "+err.Error(), actionType, "请求体绑定失败", req) } // 3. 调用领域服务 err = c.notifyService.SendTestMessage(uint(userID), req.Type) if err != nil { c.logger.Errorf("%s: 服务层调用失败: %v", actionType, err) - controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "发送测试消息失败: "+err.Error(), actionType, "服务层调用失败", gin.H{"userID": userID, "type": req.Type}) - return + return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "发送测试消息失败: "+err.Error(), actionType, "服务层调用失败", map[string]interface{}{"userID": userID, "type": req.Type}) } // 4. 返回成功响应 c.logger.Infof("%s: 成功为用户 %d 发送类型为 %s 的测试消息", actionType, userID, req.Type) - controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "测试消息已发送,请检查您的接收端。", nil, actionType, "测试消息发送成功", gin.H{"userID": userID, "type": req.Type}) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "测试消息已发送,请检查您的接收端。", nil, actionType, "测试消息发送成功", map[string]interface{}{"userID": userID, "type": req.Type}) } diff --git a/openspec/changes/refactor-migrate-gin-to-echo/tasks.md b/openspec/changes/refactor-migrate-gin-to-echo/tasks.md index e6d2e79..6c62c13 100644 --- a/openspec/changes/refactor-migrate-gin-to-echo/tasks.md +++ b/openspec/changes/refactor-migrate-gin-to-echo/tasks.md @@ -26,27 +26,27 @@ - [x] **移除所有响应体捕获和解析的逻辑** (`bodyLogWriter`, `auditResponse` 等)。 - [x] 在 `next(c)` 调用后,**直接从 `echo.Context` 中获取**由 `response.go` 设置好的最终审计状态和结果详情。 -- [ ] **4. 控制器 (`internal/app/controller/...`)** - - [ ] **通用修改**:对所有控制器文件执行以下操作: - - [ ] 将 `import "github.com/gin-gonic/gin"` 替换为 `import "github.com/labstack/echo/v4"`。 - - [ ] 将所有处理函数签名从 `func(c *gin.Context)` 修改为 `func(c echo.Context) error`。 - - [ ] 将 `c.ShouldBindJSON(&req)` 或 `c.ShouldBindQuery(&req)` 替换为 +- [x] **4. 控制器 (`internal/app/controller/...`)** + - [x] **通用修改**:对所有控制器文件执行以下操作: + - [x] 将 `import "github.com/gin-gonic/gin"` 替换为 `import "github.com/labstack/echo/v4"`。 + - [x] 将所有处理函数签名从 `func(c *gin.Context)` 修改为 `func(c echo.Context) error`。 + - [x] 将 `c.ShouldBindJSON(&req)` 或 `c.ShouldBindQuery(&req)` 替换为 `if err := c.Bind(&req); err != nil { ... }`。 - - [ ] 将 `c.Param("id")` 替换为 `c.Param("id")` (用法相同,检查返回值即可)。 - - [ ] 将 `controller.SendResponse(c, ...)` 和 `controller.SendErrorResponse(c, ...)` 调用修改为 + - [x] 将 `c.Param("id")` 替换为 `c.Param("id")` (用法相同,检查返回值即可)。 + - [x] 将 `controller.SendResponse(c, ...)` 和 `controller.SendErrorResponse(c, ...)` 调用修改为 `return controller.SendResponse(c, ...)` 和 `return controller.SendErrorResponse(c, ...)`。 - - [ ] **文件清单** (按依赖顺序建议): - - [ ] `internal/app/controller/management/controller_helpers.go` (注意:其中的泛型辅助函数也需要修改为返回 + - [x] **文件清单** (按依赖顺序建议): + - [x] `internal/app/controller/management/controller_helpers.go` (注意:其中的泛型辅助函数也需要修改为返回 `error`) - - [ ] `internal/app/controller/device/device_controller.go` - - [ ] `internal/app/controller/management/pig_farm_controller.go` - - [ ] `internal/app/controller/management/pig_batch_controller.go` - - [ ] `internal/app/controller/management/pig_batch_health_controller.go` - - [ ] `internal/app/controller/management/pig_batch_trade_controller.go` - - [ ] `internal/app/controller/management/pig_batch_transfer_controller.go` - - [ ] `internal/app/controller/monitor/monitor_controller.go` - - [ ] `internal/app/controller/plan/plan_controller.go` - - [ ] `internal/app/controller/user/user_controller.go` + - [x] `internal/app/controller/device/device_controller.go` + - [x] `internal/app/controller/management/pig_farm_controller.go` + - [x] `internal/app/controller/management/pig_batch_controller.go` + - [x] `internal/app/controller/management/pig_batch_health_controller.go` + - [x] `internal/app/controller/management/pig_batch_trade_controller.go` + - [x] `internal/app/controller/management/pig_batch_transfer_controller.go` + - [x] `internal/app/controller/monitor/monitor_controller.go` + - [x] `internal/app/controller/plan/plan_controller.go` + - [x] `internal/app/controller/user/user_controller.go` - [ ] **5. 核心 API 层 (`internal/app/api`)** - [ ] **`router.go`**