完成任务4

This commit is contained in:
2025-10-30 17:15:14 +08:00
parent f0982839e0
commit d235130d11
11 changed files with 531 additions and 765 deletions

View File

@@ -12,7 +12,7 @@ import (
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "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/models"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
"github.com/gin-gonic/gin" "github.com/labstack/echo/v4"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -54,20 +54,18 @@ func NewController(
// @Param device body dto.CreateDeviceRequest true "设备信息" // @Param device body dto.CreateDeviceRequest true "设备信息"
// @Success 200 {object} controller.Response{data=dto.DeviceResponse} // @Success 200 {object} controller.Response{data=dto.DeviceResponse}
// @Router /api/v1/devices [post] // @Router /api/v1/devices [post]
func (c *Controller) CreateDevice(ctx *gin.Context) { func (c *Controller) CreateDevice(ctx echo.Context) error {
const actionType = "创建设备" const actionType = "创建设备"
var req dto.CreateDeviceRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
return
} }
propertiesJSON, err := json.Marshal(req.Properties) propertiesJSON, err := json.Marshal(req.Properties)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化属性失败: %v", actionType, err) c.logger.Errorf("%s: 序列化属性失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties)
return
} }
device := &models.Device{ device := &models.Device{
@@ -80,32 +78,28 @@ func (c *Controller) CreateDevice(ctx *gin.Context) {
if err := device.SelfCheck(); err != nil { if err := device.SelfCheck(); err != nil {
c.logger.Errorf("%s: 设备属性自检失败: %v", actionType, err) c.logger.Errorf("%s: 设备属性自检失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求: "+err.Error(), actionType, "设备属性自检失败", device) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求: "+err.Error(), actionType, "设备属性自检失败", device)
return
} }
if err := c.deviceRepo.Create(device); err != nil { if err := c.deviceRepo.Create(device); err != nil {
c.logger.Errorf("%s: 数据库操作失败: %v", actionType, err) c.logger.Errorf("%s: 数据库操作失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建设备失败: "+err.Error(), actionType, "数据库创建失败", device) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建设备失败: "+err.Error(), actionType, "数据库创建失败", device)
return
} }
createdDevice, err := c.deviceRepo.FindByID(device.ID) createdDevice, err := c.deviceRepo.FindByID(device.ID)
if err != nil { if err != nil {
c.logger.Errorf("%s: 重新加载创建的设备失败: %v", actionType, err) c.logger.Errorf("%s: 重新加载创建的设备失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但重新加载设备失败", actionType, "重新加载设备失败", device) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但重新加载设备失败", actionType, "重新加载设备失败", device)
return
} }
resp, err := dto.NewDeviceResponse(createdDevice) resp, err := dto.NewDeviceResponse(createdDevice)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, Device: %+v", actionType, err, createdDevice) c.logger.Errorf("%s: 序列化响应失败: %v, Device: %+v", actionType, err, createdDevice)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但响应生成失败", actionType, "响应序列化失败", createdDevice) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备创建成功,但响应生成失败", actionType, "响应序列化失败", createdDevice)
return
} }
c.logger.Infof("%s: 设备创建成功, ID: %d", actionType, device.ID) 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 // GetDevice godoc
@@ -117,42 +111,37 @@ func (c *Controller) CreateDevice(ctx *gin.Context) {
// @Param id path string true "设备ID" // @Param id path string true "设备ID"
// @Success 200 {object} controller.Response{data=dto.DeviceResponse} // @Success 200 {object} controller.Response{data=dto.DeviceResponse}
// @Router /api/v1/devices/{id} [get] // @Router /api/v1/devices/{id} [get]
func (c *Controller) GetDevice(ctx *gin.Context) { func (c *Controller) GetDevice(ctx echo.Context) error {
const actionType = "获取设备" const actionType = "获取设备"
deviceID := ctx.Param("id") deviceID := ctx.Param("id")
if deviceID == "" { if deviceID == "" {
c.logger.Errorf("%s: 设备ID为空", actionType) c.logger.Errorf("%s: 设备ID为空", actionType)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备ID不能为空", actionType, "设备ID为空", nil) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备ID不能为空", actionType, "设备ID为空", nil)
return
} }
device, err := c.deviceRepo.FindByIDString(deviceID) device, err := c.deviceRepo.FindByIDString(deviceID)
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID) c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID)
return
} }
if strings.Contains(err.Error(), "无效的设备ID格式") { if strings.Contains(err.Error(), "无效的设备ID格式") {
c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID) c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID)
return
} }
c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, deviceID) 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)
return
} }
resp, err := dto.NewDeviceResponse(device) resp, err := dto.NewDeviceResponse(device)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, Device: %+v", actionType, err, device) c.logger.Errorf("%s: 序列化响应失败: %v, Device: %+v", actionType, err, device)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备信息失败: 内部数据格式错误", actionType, "响应序列化失败", device) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备信息失败: 内部数据格式错误", actionType, "响应序列化失败", device)
return
} }
c.logger.Infof("%s: 获取设备信息成功, ID: %d", actionType, device.ID) 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 // ListDevices godoc
@@ -163,24 +152,22 @@ func (c *Controller) GetDevice(ctx *gin.Context) {
// @Produce json // @Produce json
// @Success 200 {object} controller.Response{data=[]dto.DeviceResponse} // @Success 200 {object} controller.Response{data=[]dto.DeviceResponse}
// @Router /api/v1/devices [get] // @Router /api/v1/devices [get]
func (c *Controller) ListDevices(ctx *gin.Context) { func (c *Controller) ListDevices(ctx echo.Context) error {
const actionType = "获取设备列表" const actionType = "获取设备列表"
devices, err := c.deviceRepo.ListAll() devices, err := c.deviceRepo.ListAll()
if err != nil { if err != nil {
c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err) c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备列表失败: "+err.Error(), actionType, "数据库查询失败", nil) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备列表失败: "+err.Error(), actionType, "数据库查询失败", nil)
return
} }
resp, err := dto.NewListDeviceResponse(devices) resp, err := dto.NewListDeviceResponse(devices)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, Devices: %+v", actionType, err, devices) c.logger.Errorf("%s: 序列化响应失败: %v, Devices: %+v", actionType, err, devices)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备列表失败: 内部数据格式错误", actionType, "响应序列化失败", devices) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备列表失败: 内部数据格式错误", actionType, "响应序列化失败", devices)
return
} }
c.logger.Infof("%s: 获取设备列表成功, 数量: %d", actionType, len(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 // UpdateDevice godoc
@@ -194,7 +181,7 @@ func (c *Controller) ListDevices(ctx *gin.Context) {
// @Param device body dto.UpdateDeviceRequest true "要更新的设备信息" // @Param device body dto.UpdateDeviceRequest true "要更新的设备信息"
// @Success 200 {object} controller.Response{data=dto.DeviceResponse} // @Success 200 {object} controller.Response{data=dto.DeviceResponse}
// @Router /api/v1/devices/{id} [put] // @Router /api/v1/devices/{id} [put]
func (c *Controller) UpdateDevice(ctx *gin.Context) { func (c *Controller) UpdateDevice(ctx echo.Context) error {
const actionType = "更新设备" const actionType = "更新设备"
deviceID := ctx.Param("id") deviceID := ctx.Param("id")
@@ -202,31 +189,26 @@ func (c *Controller) UpdateDevice(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID) c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID)
return
} }
if strings.Contains(err.Error(), "无效的设备ID格式") { if strings.Contains(err.Error(), "无效的设备ID格式") {
c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID) c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID)
return
} }
c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, deviceID) 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)
return
} }
var req dto.UpdateDeviceRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
return
} }
propertiesJSON, err := json.Marshal(req.Properties) propertiesJSON, err := json.Marshal(req.Properties)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化属性失败: %v", actionType, err) c.logger.Errorf("%s: 序列化属性失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties)
return
} }
existingDevice.Name = req.Name existingDevice.Name = req.Name
@@ -237,32 +219,28 @@ func (c *Controller) UpdateDevice(ctx *gin.Context) {
if err := existingDevice.SelfCheck(); err != nil { if err := existingDevice.SelfCheck(); err != nil {
c.logger.Errorf("%s: 设备属性自检失败: %v", actionType, err) c.logger.Errorf("%s: 设备属性自检失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求: "+err.Error(), actionType, "设备属性自检失败", existingDevice) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备属性不符合要求: "+err.Error(), actionType, "设备属性自检失败", existingDevice)
return
} }
if err := c.deviceRepo.Update(existingDevice); err != nil { if err := c.deviceRepo.Update(existingDevice); err != nil {
c.logger.Errorf("%s: 数据库更新失败: %v, Device: %+v", actionType, err, existingDevice) c.logger.Errorf("%s: 数据库更新失败: %v, Device: %+v", actionType, err, existingDevice)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备失败: "+err.Error(), actionType, "数据库更新失败", existingDevice) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备失败: "+err.Error(), actionType, "数据库更新失败", deviceID)
return
} }
updatedDevice, err := c.deviceRepo.FindByID(existingDevice.ID) updatedDevice, err := c.deviceRepo.FindByID(existingDevice.ID)
if err != nil { if err != nil {
c.logger.Errorf("%s: 重新加载更新的设备失败: %v", actionType, err) c.logger.Errorf("%s: 重新加载更新的设备失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备更新成功,但重新加载设备失败", actionType, "重新加载设备失败", existingDevice) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备更新成功,但重新加载设备失败", actionType, "重新加载设备失败", existingDevice)
return
} }
resp, err := dto.NewDeviceResponse(updatedDevice) resp, err := dto.NewDeviceResponse(updatedDevice)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, Device: %+v", actionType, err, updatedDevice) c.logger.Errorf("%s: 序列化响应失败: %v, Device: %+v", actionType, err, updatedDevice)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备更新成功,但响应生成失败", actionType, "响应序列化失败", updatedDevice) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备更新成功,但响应生成失败", actionType, "响应序列化失败", updatedDevice)
return
} }
c.logger.Infof("%s: 设备更新成功, ID: %d", actionType, existingDevice.ID) 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 // DeleteDevice godoc
@@ -274,37 +252,33 @@ func (c *Controller) UpdateDevice(ctx *gin.Context) {
// @Param id path string true "设备ID" // @Param id path string true "设备ID"
// @Success 200 {object} controller.Response // @Success 200 {object} controller.Response
// @Router /api/v1/devices/{id} [delete] // @Router /api/v1/devices/{id} [delete]
func (c *Controller) DeleteDevice(ctx *gin.Context) { func (c *Controller) DeleteDevice(ctx echo.Context) error {
const actionType = "删除设备" const actionType = "删除设备"
deviceID := ctx.Param("id") deviceID := ctx.Param("id")
idUint, err := strconv.ParseUint(deviceID, 10, 64) idUint, err := strconv.ParseUint(deviceID, 10, 64)
if err != nil { if err != nil {
c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID) c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备ID格式", actionType, "设备ID格式错误", deviceID) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备ID格式", actionType, "设备ID格式错误", deviceID)
return
} }
_, err = c.deviceRepo.FindByIDString(deviceID) _, err = c.deviceRepo.FindByIDString(deviceID)
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID) c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID)
return
} }
c.logger.Errorf("%s: 查找设备失败: %v, ID: %s", actionType, err, deviceID) c.logger.Errorf("%s: 查找设备失败: %v, ID: %s", actionType, err, deviceID)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备失败: 查找设备时发生内部错误", actionType, "数据库查询失败", deviceID) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备失败: 查找设备时发生内部错误", actionType, "数据库查询失败", deviceID)
return
} }
if err := c.deviceRepo.Delete(uint(idUint)); err != nil { if err := c.deviceRepo.Delete(uint(idUint)); err != nil {
c.logger.Errorf("%s: 数据库删除失败: %v, ID: %d", actionType, err, idUint) c.logger.Errorf("%s: 数据库删除失败: %v, ID: %d", actionType, err, idUint)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备失败: "+err.Error(), actionType, "数据库删除失败", deviceID) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备失败: "+err.Error(), actionType, "数据库删除失败", deviceID)
return
} }
c.logger.Infof("%s: 设备删除成功, ID: %d", actionType, idUint) 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 // ManualControl godoc
@@ -318,32 +292,28 @@ func (c *Controller) DeleteDevice(ctx *gin.Context) {
// @Param manualControl body dto.ManualControlDeviceRequest true "手动控制指令" // @Param manualControl body dto.ManualControlDeviceRequest true "手动控制指令"
// @Success 200 {object} controller.Response // @Success 200 {object} controller.Response
// @Router /api/v1/devices/manual-control/{id} [post] // @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 = "手动控制设备" const actionType = "手动控制设备"
deviceID := ctx.Param("id") deviceID := ctx.Param("id")
var req dto.ManualControlDeviceRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
return
} }
dev, err := c.deviceRepo.FindByIDString(deviceID) dev, err := c.deviceRepo.FindByIDString(deviceID)
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID) c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID)
return
} }
if strings.Contains(err.Error(), "无效的设备ID格式") { if strings.Contains(err.Error(), "无效的设备ID格式") {
c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID) c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID)
return
} }
c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, deviceID) 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)
return
} }
c.logger.Infof("%s: 接收到指令, 设备ID: %s, 动作: %s", actionType, deviceID, req.Action) 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}) err = c.deviceService.Collect(dev.AreaControllerID, []*models.Device{dev})
if err != nil { if err != nil {
c.logger.Errorf("%s: 获取设备状态失败: %v, 设备ID: %s", actionType, err, deviceID) 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 { } else {
action := device.DeviceActionStart action := device.DeviceActionStart
@@ -361,17 +331,16 @@ func (c *Controller) ManualControl(ctx *gin.Context) {
case "on": case "on":
default: default:
c.logger.Errorf("%s: 无效的动作: %s, 设备ID: %s", actionType, *req.Action, deviceID) 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) err = c.deviceService.Switch(dev, action)
if err != nil { if err != nil {
c.logger.Errorf("%s: 设备控制失败: %v, 设备ID: %s", actionType, err, deviceID) 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)
return
} }
} }
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 --- // --- Controller Methods: Area Controllers ---
@@ -386,20 +355,18 @@ func (c *Controller) ManualControl(ctx *gin.Context) {
// @Param areaController body dto.CreateAreaControllerRequest true "区域主控信息" // @Param areaController body dto.CreateAreaControllerRequest true "区域主控信息"
// @Success 200 {object} controller.Response{data=dto.AreaControllerResponse} // @Success 200 {object} controller.Response{data=dto.AreaControllerResponse}
// @Router /api/v1/area-controllers [post] // @Router /api/v1/area-controllers [post]
func (c *Controller) CreateAreaController(ctx *gin.Context) { func (c *Controller) CreateAreaController(ctx echo.Context) error {
const actionType = "创建区域主控" const actionType = "创建区域主控"
var req dto.CreateAreaControllerRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
return
} }
propertiesJSON, err := json.Marshal(req.Properties) propertiesJSON, err := json.Marshal(req.Properties)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化属性失败: %v", actionType, err) c.logger.Errorf("%s: 序列化属性失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties)
return
} }
ac := &models.AreaController{ ac := &models.AreaController{
@@ -411,25 +378,22 @@ func (c *Controller) CreateAreaController(ctx *gin.Context) {
if err := ac.SelfCheck(); err != nil { if err := ac.SelfCheck(); err != nil {
c.logger.Errorf("%s: 区域主控自检失败: %v", actionType, err) c.logger.Errorf("%s: 区域主控自检失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "区域主控参数不符合要求: "+err.Error(), actionType, "区域主控自检失败", ac) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "区域主控参数不符合要求: "+err.Error(), actionType, "区域主控自检失败", ac)
return
} }
if err := c.areaControllerRepo.Create(ac); err != nil { if err := c.areaControllerRepo.Create(ac); err != nil {
c.logger.Errorf("%s: 数据库操作失败: %v", actionType, err) c.logger.Errorf("%s: 数据库操作失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建区域主控失败: "+err.Error(), actionType, "数据库创建失败", ac) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建区域主控失败: "+err.Error(), actionType, "数据库创建失败", ac)
return
} }
resp, err := dto.NewAreaControllerResponse(ac) resp, err := dto.NewAreaControllerResponse(ac)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v", actionType, err) c.logger.Errorf("%s: 序列化响应失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "区域主控创建成功,但响应生成失败", actionType, "响应序列化失败", ac) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "区域主控创建成功,但响应生成失败", actionType, "响应序列化失败", ac)
return
} }
c.logger.Infof("%s: 区域主控创建成功, ID: %d", actionType, ac.ID) 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 // GetAreaController godoc
@@ -441,38 +405,34 @@ func (c *Controller) CreateAreaController(ctx *gin.Context) {
// @Param id path string true "区域主控ID" // @Param id path string true "区域主控ID"
// @Success 200 {object} controller.Response{data=dto.AreaControllerResponse} // @Success 200 {object} controller.Response{data=dto.AreaControllerResponse}
// @Router /api/v1/area-controllers/{id} [get] // @Router /api/v1/area-controllers/{id} [get]
func (c *Controller) GetAreaController(ctx *gin.Context) { func (c *Controller) GetAreaController(ctx echo.Context) error {
const actionType = "获取区域主控" const actionType = "获取区域主控"
acID := ctx.Param("id") acID := ctx.Param("id")
idUint, err := strconv.ParseUint(acID, 10, 64) idUint, err := strconv.ParseUint(acID, 10, 64)
if err != nil { if err != nil {
c.logger.Errorf("%s: 区域主控ID格式错误: %v, ID: %s", actionType, err, acID) c.logger.Errorf("%s: 区域主控ID格式错误: %v, ID: %s", actionType, err, acID)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的区域主控ID格式", actionType, "ID格式错误", acID) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的区域主控ID格式", actionType, "ID格式错误", acID)
return
} }
ac, err := c.areaControllerRepo.FindByID(uint(idUint)) ac, err := c.areaControllerRepo.FindByID(uint(idUint))
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID) c.logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID)
return
} }
c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, acID) c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, acID)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控信息失败: "+err.Error(), actionType, "数据库查询失败", acID) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控信息失败: "+err.Error(), actionType, "数据库查询失败", acID)
return
} }
resp, err := dto.NewAreaControllerResponse(ac) resp, err := dto.NewAreaControllerResponse(ac)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, AreaController: %+v", actionType, err, ac) c.logger.Errorf("%s: 序列化响应失败: %v, AreaController: %+v", actionType, err, ac)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控信息失败: 内部数据格式错误", actionType, "响应序列化失败", ac) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控信息失败: 内部数据格式错误", actionType, "响应序列化失败", ac)
return
} }
c.logger.Infof("%s: 获取区域主控信息成功, ID: %d", actionType, ac.ID) 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 // ListAreaControllers godoc
@@ -483,24 +443,22 @@ func (c *Controller) GetAreaController(ctx *gin.Context) {
// @Produce json // @Produce json
// @Success 200 {object} controller.Response{data=[]dto.AreaControllerResponse} // @Success 200 {object} controller.Response{data=[]dto.AreaControllerResponse}
// @Router /api/v1/area-controllers [get] // @Router /api/v1/area-controllers [get]
func (c *Controller) ListAreaControllers(ctx *gin.Context) { func (c *Controller) ListAreaControllers(ctx echo.Context) error {
const actionType = "获取区域主控列表" const actionType = "获取区域主控列表"
acs, err := c.areaControllerRepo.ListAll() acs, err := c.areaControllerRepo.ListAll()
if err != nil { if err != nil {
c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err) c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控列表失败: "+err.Error(), actionType, "数据库查询失败", nil) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控列表失败: "+err.Error(), actionType, "数据库查询失败", nil)
return
} }
resp, err := dto.NewListAreaControllerResponse(acs) resp, err := dto.NewListAreaControllerResponse(acs)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, AreaControllers: %+v", actionType, err, acs) c.logger.Errorf("%s: 序列化响应失败: %v, AreaControllers: %+v", actionType, err, acs)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控列表失败: 内部数据格式错误", actionType, "响应序列化失败", acs) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控列表失败: 内部数据格式错误", actionType, "响应序列化失败", acs)
return
} }
c.logger.Infof("%s: 获取区域主控列表成功, 数量: %d", actionType, len(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 // UpdateAreaController godoc
@@ -514,41 +472,36 @@ func (c *Controller) ListAreaControllers(ctx *gin.Context) {
// @Param areaController body dto.UpdateAreaControllerRequest true "要更新的区域主控信息" // @Param areaController body dto.UpdateAreaControllerRequest true "要更新的区域主控信息"
// @Success 200 {object} controller.Response{data=dto.AreaControllerResponse} // @Success 200 {object} controller.Response{data=dto.AreaControllerResponse}
// @Router /api/v1/area-controllers/{id} [put] // @Router /api/v1/area-controllers/{id} [put]
func (c *Controller) UpdateAreaController(ctx *gin.Context) { func (c *Controller) UpdateAreaController(ctx echo.Context) error {
const actionType = "更新区域主控" const actionType = "更新区域主控"
acID := ctx.Param("id") acID := ctx.Param("id")
idUint, err := strconv.ParseUint(acID, 10, 64) idUint, err := strconv.ParseUint(acID, 10, 64)
if err != nil { if err != nil {
c.logger.Errorf("%s: 区域主控ID格式错误: %v, ID: %s", actionType, err, acID) c.logger.Errorf("%s: 区域主控ID格式错误: %v, ID: %s", actionType, err, acID)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的区域主控ID格式", actionType, "ID格式错误", acID) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的区域主控ID格式", actionType, "ID格式错误", acID)
return
} }
existingAC, err := c.areaControllerRepo.FindByID(uint(idUint)) existingAC, err := c.areaControllerRepo.FindByID(uint(idUint))
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID) c.logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID)
return
} }
c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, acID) c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, acID)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新区域主控失败: "+err.Error(), actionType, "数据库查询失败", acID) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新区域主控失败: "+err.Error(), actionType, "数据库查询失败", acID)
return
} }
var req dto.UpdateAreaControllerRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
return
} }
propertiesJSON, err := json.Marshal(req.Properties) propertiesJSON, err := json.Marshal(req.Properties)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化属性失败: %v", actionType, err) c.logger.Errorf("%s: 序列化属性失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "属性字段格式错误", actionType, "属性序列化失败", req.Properties)
return
} }
existingAC.Name = req.Name existingAC.Name = req.Name
@@ -558,25 +511,22 @@ func (c *Controller) UpdateAreaController(ctx *gin.Context) {
if err := existingAC.SelfCheck(); err != nil { if err := existingAC.SelfCheck(); err != nil {
c.logger.Errorf("%s: 区域主控自检失败: %v", actionType, err) c.logger.Errorf("%s: 区域主控自检失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "区域主控参数不符合要求: "+err.Error(), actionType, "区域主控自检失败", existingAC) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "区域主控参数不符合要求: "+err.Error(), actionType, "区域主控自检失败", existingAC)
return
} }
if err := c.areaControllerRepo.Update(existingAC); err != nil { if err := c.areaControllerRepo.Update(existingAC); err != nil {
c.logger.Errorf("%s: 数据库更新失败: %v, AreaController: %+v", actionType, err, existingAC) c.logger.Errorf("%s: 数据库更新失败: %v, AreaController: %+v", actionType, err, existingAC)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新区域主控失败: "+err.Error(), actionType, "数据库更新失败", existingAC) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新区域主控失败: "+err.Error(), actionType, "数据库更新失败", acID)
return
} }
resp, err := dto.NewAreaControllerResponse(existingAC) resp, err := dto.NewAreaControllerResponse(existingAC)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, AreaController: %+v", actionType, err, existingAC) c.logger.Errorf("%s: 序列化响应失败: %v, AreaController: %+v", actionType, err, existingAC)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "区域主控更新成功,但响应生成失败", actionType, "响应序列化失败", existingAC) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "区域主控更新成功,但响应生成失败", actionType, "响应序列化失败", existingAC)
return
} }
c.logger.Infof("%s: 区域主控更新成功, ID: %d", actionType, existingAC.ID) 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 // DeleteAreaController godoc
@@ -588,37 +538,33 @@ func (c *Controller) UpdateAreaController(ctx *gin.Context) {
// @Param id path string true "区域主控ID" // @Param id path string true "区域主控ID"
// @Success 200 {object} controller.Response // @Success 200 {object} controller.Response
// @Router /api/v1/area-controllers/{id} [delete] // @Router /api/v1/area-controllers/{id} [delete]
func (c *Controller) DeleteAreaController(ctx *gin.Context) { func (c *Controller) DeleteAreaController(ctx echo.Context) error {
const actionType = "删除区域主控" const actionType = "删除区域主控"
acID := ctx.Param("id") acID := ctx.Param("id")
idUint, err := strconv.ParseUint(acID, 10, 64) idUint, err := strconv.ParseUint(acID, 10, 64)
if err != nil { if err != nil {
c.logger.Errorf("%s: 区域主控ID格式错误: %v, ID: %s", actionType, err, acID) c.logger.Errorf("%s: 区域主控ID格式错误: %v, ID: %s", actionType, err, acID)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的区域主控ID格式", actionType, "ID格式错误", acID) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的区域主控ID格式", actionType, "ID格式错误", acID)
return
} }
_, err = c.areaControllerRepo.FindByID(uint(idUint)) _, err = c.areaControllerRepo.FindByID(uint(idUint))
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID) c.logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID)
return
} }
c.logger.Errorf("%s: 查找区域主控失败: %v, ID: %s", actionType, err, acID) c.logger.Errorf("%s: 查找区域主控失败: %v, ID: %s", actionType, err, acID)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除区域主控失败: 查找时发生内部错误", actionType, "数据库查询失败", acID) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除区域主控失败: 查找时发生内部错误", actionType, "数据库查询失败", acID)
return
} }
if err := c.areaControllerRepo.Delete(uint(idUint)); err != nil { if err := c.areaControllerRepo.Delete(uint(idUint)); err != nil {
c.logger.Errorf("%s: 数据库删除失败: %v, ID: %d", actionType, err, idUint) c.logger.Errorf("%s: 数据库删除失败: %v, ID: %d", actionType, err, idUint)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除区域主控失败: "+err.Error(), actionType, "数据库删除失败", acID) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除区域主控失败: "+err.Error(), actionType, "数据库删除失败", acID)
return
} }
c.logger.Infof("%s: 区域主控删除成功, ID: %d", actionType, idUint) 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 --- // --- Controller Methods: Device Templates ---
@@ -633,27 +579,24 @@ func (c *Controller) DeleteAreaController(ctx *gin.Context) {
// @Param deviceTemplate body dto.CreateDeviceTemplateRequest true "设备模板信息" // @Param deviceTemplate body dto.CreateDeviceTemplateRequest true "设备模板信息"
// @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse} // @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse}
// @Router /api/v1/device-templates [post] // @Router /api/v1/device-templates [post]
func (c *Controller) CreateDeviceTemplate(ctx *gin.Context) { func (c *Controller) CreateDeviceTemplate(ctx echo.Context) error {
const actionType = "创建设备模板" const actionType = "创建设备模板"
var req dto.CreateDeviceTemplateRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
return
} }
commandsJSON, err := json.Marshal(req.Commands) commandsJSON, err := json.Marshal(req.Commands)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化命令失败: %v", actionType, err) c.logger.Errorf("%s: 序列化命令失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "命令字段格式错误", actionType, "命令序列化失败", req.Commands) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "命令字段格式错误", actionType, "命令序列化失败", req.Commands)
return
} }
valuesJSON, err := json.Marshal(req.Values) valuesJSON, err := json.Marshal(req.Values)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化值描述符失败: %v", actionType, err) c.logger.Errorf("%s: 序列化值描述符失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "值描述符字段格式错误", actionType, "值描述符序列化失败", req.Values) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "值描述符字段格式错误", actionType, "值描述符序列化失败", req.Values)
return
} }
deviceTemplate := &models.DeviceTemplate{ deviceTemplate := &models.DeviceTemplate{
@@ -667,25 +610,22 @@ func (c *Controller) CreateDeviceTemplate(ctx *gin.Context) {
if err := deviceTemplate.SelfCheck(); err != nil { if err := deviceTemplate.SelfCheck(); err != nil {
c.logger.Errorf("%s: 设备模板自检失败: %v", actionType, err) c.logger.Errorf("%s: 设备模板自检失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备模板参数不符合要求: "+err.Error(), actionType, "设备模板自检失败", deviceTemplate) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备模板参数不符合要求: "+err.Error(), actionType, "设备模板自检失败", deviceTemplate)
return
} }
if err := c.deviceTemplateRepo.Create(deviceTemplate); err != nil { if err := c.deviceTemplateRepo.Create(deviceTemplate); err != nil {
c.logger.Errorf("%s: 数据库操作失败: %v", actionType, err) c.logger.Errorf("%s: 数据库操作失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建设备模板失败: "+err.Error(), actionType, "数据库创建失败", deviceTemplate) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建设备模板失败: "+err.Error(), actionType, "数据库创建失败", deviceTemplate)
return
} }
resp, err := dto.NewDeviceTemplateResponse(deviceTemplate) resp, err := dto.NewDeviceTemplateResponse(deviceTemplate)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v", actionType, err) c.logger.Errorf("%s: 序列化响应失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备模板创建成功,但响应生成失败", actionType, "响应序列化失败", deviceTemplate) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备模板创建成功,但响应生成失败", actionType, "响应序列化失败", deviceTemplate)
return
} }
c.logger.Infof("%s: 设备模板创建成功, ID: %d", actionType, deviceTemplate.ID) 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 // GetDeviceTemplate godoc
@@ -697,38 +637,34 @@ func (c *Controller) CreateDeviceTemplate(ctx *gin.Context) {
// @Param id path string true "设备模板ID" // @Param id path string true "设备模板ID"
// @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse} // @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse}
// @Router /api/v1/device-templates/{id} [get] // @Router /api/v1/device-templates/{id} [get]
func (c *Controller) GetDeviceTemplate(ctx *gin.Context) { func (c *Controller) GetDeviceTemplate(ctx echo.Context) error {
const actionType = "获取设备模板" const actionType = "获取设备模板"
dtID := ctx.Param("id") dtID := ctx.Param("id")
idUint, err := strconv.ParseUint(dtID, 10, 64) idUint, err := strconv.ParseUint(dtID, 10, 64)
if err != nil { if err != nil {
c.logger.Errorf("%s: 设备模板ID格式错误: %v, ID: %s", actionType, err, dtID) c.logger.Errorf("%s: 设备模板ID格式错误: %v, ID: %s", actionType, err, dtID)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备模板ID格式", actionType, "ID格式错误", dtID) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备模板ID格式", actionType, "ID格式错误", dtID)
return
} }
deviceTemplate, err := c.deviceTemplateRepo.FindByID(uint(idUint)) deviceTemplate, err := c.deviceTemplateRepo.FindByID(uint(idUint))
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID) c.logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID)
return
} }
c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, dtID) c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, dtID)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板信息失败: "+err.Error(), actionType, "数据库查询失败", dtID) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板信息失败: "+err.Error(), actionType, "数据库查询失败", dtID)
return
} }
resp, err := dto.NewDeviceTemplateResponse(deviceTemplate) resp, err := dto.NewDeviceTemplateResponse(deviceTemplate)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, DeviceTemplate: %+v", actionType, err, deviceTemplate) c.logger.Errorf("%s: 序列化响应失败: %v, DeviceTemplate: %+v", actionType, err, deviceTemplate)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板信息失败: 内部数据格式错误", actionType, "响应序列化失败", deviceTemplate) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板信息失败: 内部数据格式错误", actionType, "响应序列化失败", deviceTemplate)
return
} }
c.logger.Infof("%s: 获取设备模板信息成功, ID: %d", actionType, deviceTemplate.ID) 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 // ListDeviceTemplates godoc
@@ -739,24 +675,22 @@ func (c *Controller) GetDeviceTemplate(ctx *gin.Context) {
// @Produce json // @Produce json
// @Success 200 {object} controller.Response{data=[]dto.DeviceTemplateResponse} // @Success 200 {object} controller.Response{data=[]dto.DeviceTemplateResponse}
// @Router /api/v1/device-templates [get] // @Router /api/v1/device-templates [get]
func (c *Controller) ListDeviceTemplates(ctx *gin.Context) { func (c *Controller) ListDeviceTemplates(ctx echo.Context) error {
const actionType = "获取设备模板列表" const actionType = "获取设备模板列表"
deviceTemplates, err := c.deviceTemplateRepo.ListAll() deviceTemplates, err := c.deviceTemplateRepo.ListAll()
if err != nil { if err != nil {
c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err) c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板列表失败: "+err.Error(), actionType, "数据库查询失败", nil) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板列表失败: "+err.Error(), actionType, "数据库查询失败", nil)
return
} }
resp, err := dto.NewListDeviceTemplateResponse(deviceTemplates) resp, err := dto.NewListDeviceTemplateResponse(deviceTemplates)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, DeviceTemplates: %+v", actionType, err, deviceTemplates) c.logger.Errorf("%s: 序列化响应失败: %v, DeviceTemplates: %+v", actionType, err, deviceTemplates)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板列表失败: 内部数据格式错误", actionType, "响应序列化失败", deviceTemplates) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板列表失败: 内部数据格式错误", actionType, "响应序列化失败", deviceTemplates)
return
} }
c.logger.Infof("%s: 获取设备模板列表成功, 数量: %d", actionType, len(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 // UpdateDeviceTemplate godoc
@@ -770,48 +704,42 @@ func (c *Controller) ListDeviceTemplates(ctx *gin.Context) {
// @Param deviceTemplate body dto.UpdateDeviceTemplateRequest true "要更新的设备模板信息" // @Param deviceTemplate body dto.UpdateDeviceTemplateRequest true "要更新的设备模板信息"
// @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse} // @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse}
// @Router /api/v1/device-templates/{id} [put] // @Router /api/v1/device-templates/{id} [put]
func (c *Controller) UpdateDeviceTemplate(ctx *gin.Context) { func (c *Controller) UpdateDeviceTemplate(ctx echo.Context) error {
const actionType = "更新设备模板" const actionType = "更新设备模板"
dtID := ctx.Param("id") dtID := ctx.Param("id")
idUint, err := strconv.ParseUint(dtID, 10, 64) idUint, err := strconv.ParseUint(dtID, 10, 64)
if err != nil { if err != nil {
c.logger.Errorf("%s: 设备模板ID格式错误: %v, ID: %s", actionType, err, dtID) c.logger.Errorf("%s: 设备模板ID格式错误: %v, ID: %s", actionType, err, dtID)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备模板ID格式", actionType, "ID格式错误", dtID) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备模板ID格式", actionType, "ID格式错误", dtID)
return
} }
existingDeviceTemplate, err := c.deviceTemplateRepo.FindByID(uint(idUint)) existingDeviceTemplate, err := c.deviceTemplateRepo.FindByID(uint(idUint))
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID) c.logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID)
return
} }
c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, dtID) c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, dtID)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备模板失败: "+err.Error(), actionType, "数据库查询失败", dtID) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备模板失败: "+err.Error(), actionType, "数据库查询失败", dtID)
return
} }
var req dto.UpdateDeviceTemplateRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
return
} }
commandsJSON, err := json.Marshal(req.Commands) commandsJSON, err := json.Marshal(req.Commands)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化命令失败: %v", actionType, err) c.logger.Errorf("%s: 序列化命令失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "命令字段格式错误", actionType, "命令序列化失败", req.Commands) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "命令字段格式错误", actionType, "命令序列化失败", req.Commands)
return
} }
valuesJSON, err := json.Marshal(req.Values) valuesJSON, err := json.Marshal(req.Values)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化值描述符失败: %v", actionType, err) c.logger.Errorf("%s: 序列化值描述符失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "值描述符字段格式错误", actionType, "值描述符序列化失败", req.Values) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "值描述符字段格式错误", actionType, "值描述符序列化失败", req.Values)
return
} }
existingDeviceTemplate.Name = req.Name existingDeviceTemplate.Name = req.Name
@@ -823,25 +751,22 @@ func (c *Controller) UpdateDeviceTemplate(ctx *gin.Context) {
if err := existingDeviceTemplate.SelfCheck(); err != nil { if err := existingDeviceTemplate.SelfCheck(); err != nil {
c.logger.Errorf("%s: 设备模板自检失败: %v", actionType, err) c.logger.Errorf("%s: 设备模板自检失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备模板参数不符合要求: "+err.Error(), actionType, "设备模板自检失败", existingDeviceTemplate) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "设备模板参数不符合要求: "+err.Error(), actionType, "设备模板自检失败", existingDeviceTemplate)
return
} }
if err := c.deviceTemplateRepo.Update(existingDeviceTemplate); err != nil { if err := c.deviceTemplateRepo.Update(existingDeviceTemplate); err != nil {
c.logger.Errorf("%s: 数据库更新失败: %v, DeviceTemplate: %+v", actionType, err, existingDeviceTemplate) c.logger.Errorf("%s: 数据库更新失败: %v, DeviceTemplate: %+v", actionType, err, existingDeviceTemplate)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备模板失败: "+err.Error(), actionType, "数据库更新失败", existingDeviceTemplate) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备模板失败: "+err.Error(), actionType, "数据库更新失败", dtID)
return
} }
resp, err := dto.NewDeviceTemplateResponse(existingDeviceTemplate) resp, err := dto.NewDeviceTemplateResponse(existingDeviceTemplate)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, DeviceTemplate: %+v", actionType, err, existingDeviceTemplate) c.logger.Errorf("%s: 序列化响应失败: %v, DeviceTemplate: %+v", actionType, err, existingDeviceTemplate)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备模板更新成功,但响应生成失败", actionType, "响应序列化失败", existingDeviceTemplate) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备模板更新成功,但响应生成失败", actionType, "响应序列化失败", existingDeviceTemplate)
return
} }
c.logger.Infof("%s: 设备模板更新成功, ID: %d", actionType, existingDeviceTemplate.ID) 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 // DeleteDeviceTemplate godoc
@@ -853,15 +778,14 @@ func (c *Controller) UpdateDeviceTemplate(ctx *gin.Context) {
// @Param id path string true "设备模板ID" // @Param id path string true "设备模板ID"
// @Success 200 {object} controller.Response // @Success 200 {object} controller.Response
// @Router /api/v1/device-templates/{id} [delete] // @Router /api/v1/device-templates/{id} [delete]
func (c *Controller) DeleteDeviceTemplate(ctx *gin.Context) { func (c *Controller) DeleteDeviceTemplate(ctx echo.Context) error {
const actionType = "删除设备模板" const actionType = "删除设备模板"
dtID := ctx.Param("id") dtID := ctx.Param("id")
idUint, err := strconv.ParseUint(dtID, 10, 64) idUint, err := strconv.ParseUint(dtID, 10, 64)
if err != nil { if err != nil {
c.logger.Errorf("%s: 设备模板ID格式错误: %v, ID: %s", actionType, err, dtID) c.logger.Errorf("%s: 设备模板ID格式错误: %v, ID: %s", actionType, err, dtID)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备模板ID格式", actionType, "ID格式错误", dtID) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的设备模板ID格式", actionType, "ID格式错误", dtID)
return
} }
// 在尝试删除之前,先检查设备模板是否存在 // 在尝试删除之前,先检查设备模板是否存在
@@ -869,12 +793,10 @@ func (c *Controller) DeleteDeviceTemplate(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID) c.logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID)
return
} }
c.logger.Errorf("%s: 查找设备模板失败: %v, ID: %s", actionType, err, dtID) c.logger.Errorf("%s: 查找设备模板失败: %v, ID: %s", actionType, err, dtID)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备模板失败: 查找时发生内部错误", actionType, "数据库查询失败", dtID) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备模板失败: 查找时发生内部错误", actionType, "数据库查询失败", dtID)
return
} }
// 调用仓库层的删除方法,该方法会检查模板是否被使用 // 调用仓库层的删除方法,该方法会检查模板是否被使用
@@ -882,14 +804,13 @@ func (c *Controller) DeleteDeviceTemplate(ctx *gin.Context) {
c.logger.Errorf("%s: 数据库删除失败: %v, ID: %d", actionType, err, idUint) c.logger.Errorf("%s: 数据库删除失败: %v, ID: %d", actionType, err, idUint)
// 如果错误信息包含“设备模板正在被设备使用,无法删除”,则返回特定的错误码 // 如果错误信息包含“设备模板正在被设备使用,无法删除”,则返回特定的错误码
if strings.Contains(err.Error(), "设备模板正在被设备使用,无法删除") { 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 { } 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) 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)
} }

View File

@@ -7,39 +7,39 @@ import (
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller" "git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
"git.huangwc.com/pig/pig-farm-controller/internal/app/service" "git.huangwc.com/pig/pig-farm-controller/internal/app/service"
"github.com/gin-gonic/gin" "github.com/labstack/echo/v4"
) )
// mapAndSendError 统一映射服务层错误并发送响应。 // mapAndSendError 统一映射服务层错误并发送响应。
// 这个函数将服务层返回的错误转换为控制器层应返回的HTTP状态码和审计信息。 // 这个函数将服务层返回的错误转换为控制器层应返回的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) || if errors.Is(err, service.ErrPigBatchNotFound) ||
errors.Is(err, service.ErrPenNotFound) || errors.Is(err, service.ErrPenNotFound) ||
errors.Is(err, service.ErrPenNotAssociatedWithBatch) { 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) || } else if errors.Is(err, service.ErrInvalidOperation) ||
errors.Is(err, service.ErrPigBatchActive) || errors.Is(err, service.ErrPigBatchActive) ||
errors.Is(err, service.ErrPigBatchNotActive) || errors.Is(err, service.ErrPigBatchNotActive) ||
errors.Is(err, service.ErrPenOccupiedByOtherBatch) || errors.Is(err, service.ErrPenOccupiedByOtherBatch) ||
errors.Is(err, service.ErrPenStatusInvalidForAllocation) || errors.Is(err, service.ErrPenStatusInvalidForAllocation) ||
errors.Is(err, service.ErrPenNotEmpty) { 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 { } else {
c.logger.Errorf("操作[%s]业务逻辑失败: %v", action, err) 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。 // idExtractorFunc 定义了一个函数类型,用于从echo.Context中提取主ID。
type idExtractorFunc func(ctx *gin.Context) (uint, error) type idExtractorFunc func(ctx echo.Context) (uint, error)
// extractOperatorAndPrimaryID 封装了从gin.Context中提取操作员ID和主ID的通用逻辑。 // extractOperatorAndPrimaryID 封装了从echo.Context中提取操作员ID和主ID的通用逻辑。
// 它负责处理ID提取过程中的错误并发送相应的HTTP响应。 // 它负责处理ID提取过程中的错误并发送相应的HTTP响应。
// //
// 参数: // 参数:
// //
// c: *PigBatchController - 控制器实例,用于访问其日志。 // c: *PigBatchController - 控制器实例,用于访问其日志。
// ctx: *gin.Context - Gin上下文。 // ctx: echo.Context - Echo上下文。
// action: string - 当前操作的描述,用于日志和审计。 // action: string - 当前操作的描述,用于日志和审计。
// idExtractor: idExtractorFunc - 可选函数用于从ctx中提取主ID。如果为nil则尝试从":id"路径参数中提取。 // idExtractor: idExtractorFunc - 可选函数用于从ctx中提取主ID。如果为nil则尝试从":id"路径参数中提取。
// //
@@ -47,26 +47,24 @@ type idExtractorFunc func(ctx *gin.Context) (uint, error)
// //
// operatorID: uint - 提取到的操作员ID。 // operatorID: uint - 提取到的操作员ID。
// primaryID: uint - 提取到的主ID。 // primaryID: uint - 提取到的主ID。
// ok: bool - 如果ID提取成功且没有发送错误响应,则为true // err: error - 如果ID提取失败或发送错误响应,则返回错误
func extractOperatorAndPrimaryID( func extractOperatorAndPrimaryID(
c *PigBatchController, c *PigBatchController,
ctx *gin.Context, ctx echo.Context,
action string, action string,
idExtractor idExtractorFunc, idExtractor idExtractorFunc,
) (operatorID uint, primaryID uint, ok bool) { ) (operatorID uint, primaryID uint, err error) {
// 1. 获取操作员ID // 1. 获取操作员ID
operatorID, err := controller.GetOperatorIDFromContext(ctx) operatorID, err = controller.GetOperatorIDFromContext(ctx)
if err != nil { if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeUnauthorized, "未授权", action, "无法获取操作员ID", nil) return 0, 0, controller.SendErrorWithAudit(ctx, controller.CodeUnauthorized, "未授权", action, "无法获取操作员ID", nil)
return 0, 0, false
} }
// 2. 提取主ID // 2. 提取主ID
if idExtractor != nil { if idExtractor != nil {
primaryID, err = idExtractor(ctx) primaryID, err = idExtractor(ctx)
if err != nil { if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", err.Error()) return 0, 0, controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", err.Error())
return 0, 0, false
} }
} else { // 默认从 ":id" 路径参数提取 } else { // 默认从 ":id" 路径参数提取
idParam := ctx.Param("id") idParam := ctx.Param("id")
@@ -75,165 +73,155 @@ func extractOperatorAndPrimaryID(
} else { } else {
parsedID, err := strconv.ParseUint(idParam, 10, 32) parsedID, err := strconv.ParseUint(idParam, 10, 32)
if err != nil { if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", idParam) return 0, 0, controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", idParam)
return 0, 0, false
} }
primaryID = uint(parsedID) primaryID = uint(parsedID)
} }
} }
return operatorID, primaryID, true return operatorID, primaryID, nil
} }
// handleAPIRequest 封装了控制器中处理带有请求体和路径参数的API请求的通用逻辑。 // handleAPIRequest 封装了控制器中处理带有请求体和路径参数的API请求的通用逻辑。
// 它负责请求体绑定、操作员ID获取、服务层调用、错误映射和响应发送。 // 它负责请求体绑定、操作员ID获取、服务层调用、错误映射和响应发送。
func handleAPIRequest[Req any]( func handleAPIRequest[Req any](
c *PigBatchController, c *PigBatchController,
ctx *gin.Context, ctx echo.Context,
action string, action string,
reqDTO Req, 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, successMsg string,
idExtractor idExtractorFunc, idExtractor idExtractorFunc,
) { ) error {
// 1. 绑定请求体 // 1. 绑定请求体
if err := ctx.ShouldBindJSON(&reqDTO); err != nil { if err := ctx.Bind(&reqDTO); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", reqDTO) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", reqDTO)
return
} }
// 2. 提取操作员ID和主ID // 2. 提取操作员ID和主ID
operatorID, primaryID, ok := extractOperatorAndPrimaryID(c, ctx, action, idExtractor) operatorID, primaryID, err := extractOperatorAndPrimaryID(c, ctx, action, idExtractor)
if !ok { if err != nil {
return // 错误已在 extractOperatorAndPrimaryID 中处理 return err // 错误已在 extractOperatorAndPrimaryID 中处理
} }
// 3. 执行服务层逻辑 // 3. 执行服务层逻辑
err := serviceExecutor(ctx, operatorID, primaryID, reqDTO) err = serviceExecutor(ctx, operatorID, primaryID, reqDTO)
if err != nil { if err != nil {
mapAndSendError(c, ctx, action, err, primaryID) return mapAndSendError(c, ctx, action, err, primaryID)
return
} }
// 4. 发送成功响应 // 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请求的通用逻辑。 // handleNoBodyAPIRequest 封装了处理不带请求体但有路径参数和操作员ID的API请求的通用逻辑。
func handleNoBodyAPIRequest( func handleNoBodyAPIRequest(
c *PigBatchController, c *PigBatchController,
ctx *gin.Context, ctx echo.Context,
action string, action string,
serviceExecutor func(ctx *gin.Context, operatorID uint, primaryID uint) error, serviceExecutor func(ctx echo.Context, operatorID uint, primaryID uint) error,
successMsg string, successMsg string,
idExtractor idExtractorFunc, idExtractor idExtractorFunc,
) { ) error {
// 1. 提取操作员ID和主ID // 1. 提取操作员ID和主ID
operatorID, primaryID, ok := extractOperatorAndPrimaryID(c, ctx, action, idExtractor) operatorID, primaryID, err := extractOperatorAndPrimaryID(c, ctx, action, idExtractor)
if !ok { if err != nil {
return // 错误已在 extractOperatorAndPrimaryID 中处理 return err // 错误已在 extractOperatorAndPrimaryID 中处理
} }
// 2. 执行服务层逻辑 // 2. 执行服务层逻辑
err := serviceExecutor(ctx, operatorID, primaryID) err = serviceExecutor(ctx, operatorID, primaryID)
if err != nil { if err != nil {
mapAndSendError(c, ctx, action, err, primaryID) return mapAndSendError(c, ctx, action, err, primaryID)
return
} }
// 3. 发送成功响应 // 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请求的通用逻辑。 // handleAPIRequestWithResponse 封装了控制器中处理带有请求体、路径参数并返回响应DTO的API请求的通用逻辑。
func handleAPIRequestWithResponse[Req any, Resp any]( func handleAPIRequestWithResponse[Req any, Resp any](
c *PigBatchController, c *PigBatchController,
ctx *gin.Context, ctx echo.Context,
action string, action string,
reqDTO Req, 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, successMsg string,
idExtractor idExtractorFunc, idExtractor idExtractorFunc,
) { ) error {
// 1. 绑定请求体 // 1. 绑定请求体
if err := ctx.ShouldBindJSON(&reqDTO); err != nil { if err := ctx.Bind(&reqDTO); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, fmt.Sprintf("无效的请求体: %v", err), action, fmt.Sprintf("请求体绑定失败: %v", err), reqDTO) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, fmt.Sprintf("无效的请求体: %v", err), action, fmt.Sprintf("请求体绑定失败: %v", err), reqDTO)
return
} }
// 2. 提取操作员ID和主ID // 2. 提取操作员ID和主ID
operatorID, primaryID, ok := extractOperatorAndPrimaryID(c, ctx, action, idExtractor) operatorID, primaryID, err := extractOperatorAndPrimaryID(c, ctx, action, idExtractor)
if !ok { if err != nil {
return // 错误已在 extractOperatorAndPrimaryID 中处理 return err // 错误已在 extractOperatorAndPrimaryID 中处理
} }
// 3. 执行服务层逻辑 // 3. 执行服务层逻辑
respDTO, err := serviceExecutor(ctx, operatorID, primaryID, reqDTO) respDTO, err := serviceExecutor(ctx, operatorID, primaryID, reqDTO)
if err != nil { if err != nil {
mapAndSendError(c, ctx, action, err, primaryID) return mapAndSendError(c, ctx, action, err, primaryID)
return
} }
// 4. 发送成功响应 // 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请求的通用逻辑。 // handleNoBodyAPIRequestWithResponse 封装了处理不带请求体但有路径参数和操作员ID并返回响应DTO的API请求的通用逻辑。
func handleNoBodyAPIRequestWithResponse[Resp any]( func handleNoBodyAPIRequestWithResponse[Resp any](
c *PigBatchController, c *PigBatchController,
ctx *gin.Context, ctx echo.Context,
action string, 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, successMsg string,
idExtractor idExtractorFunc, idExtractor idExtractorFunc,
) { ) error {
// 1. 提取操作员ID和主ID // 1. 提取操作员ID和主ID
operatorID, primaryID, ok := extractOperatorAndPrimaryID(c, ctx, action, idExtractor) operatorID, primaryID, err := extractOperatorAndPrimaryID(c, ctx, action, idExtractor)
if !ok { if err != nil {
return // 错误已在 extractOperatorAndPrimaryID 中处理 return err // 错误已在 extractOperatorAndPrimaryID 中处理
} }
// 2. 执行服务层逻辑 // 2. 执行服务层逻辑
respDTO, err := serviceExecutor(ctx, operatorID, primaryID) respDTO, err := serviceExecutor(ctx, operatorID, primaryID)
if err != nil { if err != nil {
mapAndSendError(c, ctx, action, err, primaryID) return mapAndSendError(c, ctx, action, err, primaryID)
return
} }
// 3. 发送成功响应 // 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请求的通用逻辑。 // handleQueryAPIRequestWithResponse 封装了处理带有查询参数并返回响应DTO的API请求的通用逻辑。
func handleQueryAPIRequestWithResponse[Query any, Resp any]( func handleQueryAPIRequestWithResponse[Query any, Resp any](
c *PigBatchController, c *PigBatchController,
ctx *gin.Context, ctx echo.Context,
action string, action string,
queryDTO Query, 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, successMsg string,
) { ) error {
// 1. 绑定查询参数 // 1. 绑定查询参数
if err := ctx.ShouldBindQuery(&queryDTO); err != nil { if err := ctx.Bind(&queryDTO); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数", action, "查询参数绑定失败", queryDTO) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数", action, "查询参数绑定失败", queryDTO)
return
} }
// 2. 获取操作员ID // 2. 获取操作员ID
operatorID, err := controller.GetOperatorIDFromContext(ctx) operatorID, err := controller.GetOperatorIDFromContext(ctx)
if err != nil { if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeUnauthorized, "未授权", action, "无法获取操作员ID", nil) return controller.SendErrorWithAudit(ctx, controller.CodeUnauthorized, "未授权", action, "无法获取操作员ID", nil)
return
} }
// 3. 执行服务层逻辑 // 3. 执行服务层逻辑
respDTO, err := serviceExecutor(ctx, operatorID, queryDTO) respDTO, err := serviceExecutor(ctx, operatorID, queryDTO)
if err != nil { if err != nil {
// 对于列表查询通常没有primaryID所以传递0 // 对于列表查询通常没有primaryID所以传递0
mapAndSendError(c, ctx, action, err, 0) return mapAndSendError(c, ctx, action, err, 0)
return
} }
// 4. 发送成功响应 // 4. 发送成功响应
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, successMsg, respDTO, action, successMsg, nil) return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, successMsg, respDTO, action, successMsg, nil)
} }

View File

@@ -7,7 +7,7 @@ import (
"git.huangwc.com/pig/pig-farm-controller/internal/app/service" "git.huangwc.com/pig/pig-farm-controller/internal/app/service"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
"github.com/gin-gonic/gin" "github.com/labstack/echo/v4"
) )
// PigBatchController 负责处理猪批次相关的API请求 // PigBatchController 负责处理猪批次相关的API请求
@@ -34,13 +34,13 @@ func NewPigBatchController(logger *logs.Logger, service service.PigBatchService)
// @Param body body dto.PigBatchCreateDTO true "猪批次信息" // @Param body body dto.PigBatchCreateDTO true "猪批次信息"
// @Success 201 {object} controller.Response{data=dto.PigBatchResponseDTO} "创建成功" // @Success 201 {object} controller.Response{data=dto.PigBatchResponseDTO} "创建成功"
// @Router /api/v1/pig-batches [post] // @Router /api/v1/pig-batches [post]
func (c *PigBatchController) CreatePigBatch(ctx *gin.Context) { func (c *PigBatchController) CreatePigBatch(ctx echo.Context) error {
const action = "创建猪批次" const action = "创建猪批次"
var req dto.PigBatchCreateDTO var req dto.PigBatchCreateDTO
handleAPIRequestWithResponse( return handleAPIRequestWithResponse(
c, ctx, action, &req, 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通常不从路径中获取而是由服务层生成 // 对于创建操作primaryID通常不从路径中获取而是由服务层生成
return c.service.CreatePigBatch(operatorID, req) return c.service.CreatePigBatch(operatorID, req)
}, },
@@ -58,12 +58,12 @@ func (c *PigBatchController) CreatePigBatch(ctx *gin.Context) {
// @Param id path int true "猪批次ID" // @Param id path int true "猪批次ID"
// @Success 200 {object} controller.Response{data=dto.PigBatchResponseDTO} "获取成功" // @Success 200 {object} controller.Response{data=dto.PigBatchResponseDTO} "获取成功"
// @Router /api/v1/pig-batches/{id} [get] // @Router /api/v1/pig-batches/{id} [get]
func (c *PigBatchController) GetPigBatch(ctx *gin.Context) { func (c *PigBatchController) GetPigBatch(ctx echo.Context) error {
const action = "获取猪批次" const action = "获取猪批次"
handleNoBodyAPIRequestWithResponse( return handleNoBodyAPIRequestWithResponse(
c, ctx, action, 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) return c.service.GetPigBatch(primaryID)
}, },
"获取成功", "获取成功",
@@ -82,13 +82,13 @@ func (c *PigBatchController) GetPigBatch(ctx *gin.Context) {
// @Param body body dto.PigBatchUpdateDTO true "猪批次信息" // @Param body body dto.PigBatchUpdateDTO true "猪批次信息"
// @Success 200 {object} controller.Response{data=dto.PigBatchResponseDTO} "更新成功" // @Success 200 {object} controller.Response{data=dto.PigBatchResponseDTO} "更新成功"
// @Router /api/v1/pig-batches/{id} [put] // @Router /api/v1/pig-batches/{id} [put]
func (c *PigBatchController) UpdatePigBatch(ctx *gin.Context) { func (c *PigBatchController) UpdatePigBatch(ctx echo.Context) error {
const action = "更新猪批次" const action = "更新猪批次"
var req dto.PigBatchUpdateDTO var req dto.PigBatchUpdateDTO
handleAPIRequestWithResponse( return handleAPIRequestWithResponse(
c, ctx, action, &req, 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) return c.service.UpdatePigBatch(primaryID, req)
}, },
"更新成功", "更新成功",
@@ -105,12 +105,12 @@ func (c *PigBatchController) UpdatePigBatch(ctx *gin.Context) {
// @Param id path int true "猪批次ID" // @Param id path int true "猪批次ID"
// @Success 200 {object} controller.Response "删除成功" // @Success 200 {object} controller.Response "删除成功"
// @Router /api/v1/pig-batches/{id} [delete] // @Router /api/v1/pig-batches/{id} [delete]
func (c *PigBatchController) DeletePigBatch(ctx *gin.Context) { func (c *PigBatchController) DeletePigBatch(ctx echo.Context) error {
const action = "删除猪批次" const action = "删除猪批次"
handleNoBodyAPIRequest( return handleNoBodyAPIRequest(
c, ctx, action, 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) return c.service.DeletePigBatch(primaryID)
}, },
"删除成功", "删除成功",
@@ -127,13 +127,13 @@ func (c *PigBatchController) DeletePigBatch(ctx *gin.Context) {
// @Param is_active query bool false "是否活跃 (true/false)" // @Param is_active query bool false "是否活跃 (true/false)"
// @Success 200 {object} controller.Response{data=[]dto.PigBatchResponseDTO} "获取成功" // @Success 200 {object} controller.Response{data=[]dto.PigBatchResponseDTO} "获取成功"
// @Router /api/v1/pig-batches [get] // @Router /api/v1/pig-batches [get]
func (c *PigBatchController) ListPigBatches(ctx *gin.Context) { func (c *PigBatchController) ListPigBatches(ctx echo.Context) error {
const action = "获取猪批次列表" const action = "获取猪批次列表"
var query dto.PigBatchQueryDTO var query dto.PigBatchQueryDTO
handleQueryAPIRequestWithResponse( return handleQueryAPIRequestWithResponse(
c, ctx, action, &query, 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) return c.service.ListPigBatches(query.IsActive)
}, },
"获取成功", "获取成功",
@@ -151,13 +151,13 @@ func (c *PigBatchController) ListPigBatches(ctx *gin.Context) {
// @Param body body dto.AssignEmptyPensToBatchRequest true "待分配的猪栏ID列表" // @Param body body dto.AssignEmptyPensToBatchRequest true "待分配的猪栏ID列表"
// @Success 200 {object} controller.Response "分配成功" // @Success 200 {object} controller.Response "分配成功"
// @Router /api/v1/pig-batches/assign-pens/{id} [post] // @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 = "为猪批次分配空栏" const action = "为猪批次分配空栏"
var req dto.AssignEmptyPensToBatchRequest var req dto.AssignEmptyPensToBatchRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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) 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和备注)" // @Param body body dto.ReclassifyPenToNewBatchRequest true "划拨请求信息 (包含目标批次ID、猪栏ID和备注)"
// @Success 200 {object} controller.Response "划拨成功" // @Success 200 {object} controller.Response "划拨成功"
// @Router /api/v1/pig-batches/reclassify-pen/{fromBatchID} [post] // @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 = "划拨猪栏到新批次" const action = "划拨猪栏到新批次"
var req dto.ReclassifyPenToNewBatchRequest var req dto.ReclassifyPenToNewBatchRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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 // primaryID 在这里是 fromBatchID
return c.service.ReclassifyPenToNewBatch(primaryID, req.ToBatchID, req.PenID, operatorID, req.Remarks) 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") idParam := ctx.Param("fromBatchID")
parsedID, err := strconv.ParseUint(idParam, 10, 32) parsedID, err := strconv.ParseUint(idParam, 10, 32)
if err != nil { if err != nil {
@@ -208,22 +208,22 @@ func (c *PigBatchController) ReclassifyPenToNewBatch(ctx *gin.Context) {
// @Param penID path int true "待移除的猪栏ID" // @Param penID path int true "待移除的猪栏ID"
// @Success 200 {object} controller.Response "移除成功" // @Success 200 {object} controller.Response "移除成功"
// @Router /api/v1/pig-batches/remove-pen/{penID}/{batchID} [delete] // @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 = "从猪批次移除空栏" const action = "从猪批次移除空栏"
handleNoBodyAPIRequest( return handleNoBodyAPIRequest(
c, ctx, action, c, ctx, action,
func(ctx *gin.Context, operatorID uint, primaryID uint) error { func(ctx echo.Context, operatorID uint, primaryID uint) error {
// primaryID 在这里是 batchID // primaryID 在这里是 batchID
penIDParam := ctx.Param("penID") penIDParam := ctx.Param("penID")
penID, err := strconv.ParseUint(penIDParam, 10, 32) parsedPenID, err := strconv.ParseUint(penIDParam, 10, 32)
if err != nil { if err != nil {
return err // 返回错误,因为 penID 格式无效 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") idParam := ctx.Param("batchID")
parsedID, err := strconv.ParseUint(idParam, 10, 32) parsedID, err := strconv.ParseUint(idParam, 10, 32)
if err != nil { if err != nil {
@@ -245,13 +245,13 @@ func (c *PigBatchController) RemoveEmptyPenFromBatch(ctx *gin.Context) {
// @Param body body dto.MovePigsIntoPenRequest true "移入猪只请求信息 (包含目标猪栏ID、数量和备注)" // @Param body body dto.MovePigsIntoPenRequest true "移入猪只请求信息 (包含目标猪栏ID、数量和备注)"
// @Success 200 {object} controller.Response "移入成功" // @Success 200 {object} controller.Response "移入成功"
// @Router /api/v1/pig-batches/move-pigs-into-pen/{id} [post] // @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 = "将猪只移入猪栏" const action = "将猪只移入猪栏"
var req dto.MovePigsIntoPenRequest var req dto.MovePigsIntoPenRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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) return c.service.MovePigsIntoPen(primaryID, req.ToPenID, req.Quantity, operatorID, req.Remarks)
}, },
"移入成功", "移入成功",

View File

@@ -2,7 +2,7 @@ package management
import ( import (
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto" "git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
"github.com/gin-gonic/gin" "github.com/labstack/echo/v4"
) )
// RecordSickPigs godoc // RecordSickPigs godoc
@@ -16,13 +16,13 @@ import (
// @Param body body dto.RecordSickPigsRequest true "记录病猪请求信息" // @Param body body dto.RecordSickPigsRequest true "记录病猪请求信息"
// @Success 200 {object} controller.Response "记录成功" // @Success 200 {object} controller.Response "记录成功"
// @Router /api/v1/pig-batches/record-sick-pigs/{id} [post] // @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 = "记录新增病猪事件" const action = "记录新增病猪事件"
var req dto.RecordSickPigsRequest var req dto.RecordSickPigsRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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) 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 "记录病猪康复请求信息" // @Param body body dto.RecordSickPigRecoveryRequest true "记录病猪康复请求信息"
// @Success 200 {object} controller.Response "记录成功" // @Success 200 {object} controller.Response "记录成功"
// @Router /api/v1/pig-batches/record-sick-pig-recovery/{id} [post] // @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 = "记录病猪康复事件" const action = "记录病猪康复事件"
var req dto.RecordSickPigRecoveryRequest var req dto.RecordSickPigRecoveryRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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) 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 "记录病猪死亡请求信息" // @Param body body dto.RecordSickPigDeathRequest true "记录病猪死亡请求信息"
// @Success 200 {object} controller.Response "记录成功" // @Success 200 {object} controller.Response "记录成功"
// @Router /api/v1/pig-batches/record-sick-pig-death/{id} [post] // @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 = "记录病猪死亡事件" const action = "记录病猪死亡事件"
var req dto.RecordSickPigDeathRequest var req dto.RecordSickPigDeathRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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) 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 "记录病猪淘汰请求信息" // @Param body body dto.RecordSickPigCullRequest true "记录病猪淘汰请求信息"
// @Success 200 {object} controller.Response "记录成功" // @Success 200 {object} controller.Response "记录成功"
// @Router /api/v1/pig-batches/record-sick-pig-cull/{id} [post] // @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 = "记录病猪淘汰事件" const action = "记录病猪淘汰事件"
var req dto.RecordSickPigCullRequest var req dto.RecordSickPigCullRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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) 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 "记录正常猪只死亡请求信息" // @Param body body dto.RecordDeathRequest true "记录正常猪只死亡请求信息"
// @Success 200 {object} controller.Response "记录成功" // @Success 200 {object} controller.Response "记录成功"
// @Router /api/v1/pig-batches/record-death/{id} [post] // @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 = "记录正常猪只死亡事件" const action = "记录正常猪只死亡事件"
var req dto.RecordDeathRequest var req dto.RecordDeathRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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) 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 "记录正常猪只淘汰请求信息" // @Param body body dto.RecordCullRequest true "记录正常猪只淘汰请求信息"
// @Success 200 {object} controller.Response "记录成功" // @Success 200 {object} controller.Response "记录成功"
// @Router /api/v1/pig-batches/record-cull/{id} [post] // @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 = "记录正常猪只淘汰事件" const action = "记录正常猪只淘汰事件"
var req dto.RecordCullRequest var req dto.RecordCullRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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) return c.service.RecordCull(operatorID, primaryID, req.PenID, req.Quantity, req.HappenedAt, req.Remarks)
}, },
"记录成功", "记录成功",

View File

@@ -2,7 +2,7 @@ package management
import ( import (
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto" "git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
"github.com/gin-gonic/gin" "github.com/labstack/echo/v4"
) )
// SellPigs godoc // SellPigs godoc
@@ -16,13 +16,13 @@ import (
// @Param body body dto.SellPigsRequest true "卖猪请求信息" // @Param body body dto.SellPigsRequest true "卖猪请求信息"
// @Success 200 {object} controller.Response "卖猪成功" // @Success 200 {object} controller.Response "卖猪成功"
// @Router /api/v1/pig-batches/sell-pigs/{id} [post] // @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 = "卖猪" const action = "卖猪"
var req dto.SellPigsRequest var req dto.SellPigsRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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) 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 "买猪请求信息" // @Param body body dto.BuyPigsRequest true "买猪请求信息"
// @Success 200 {object} controller.Response "买猪成功" // @Success 200 {object} controller.Response "买猪成功"
// @Router /api/v1/pig-batches/buy-pigs/{id} [post] // @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 = "买猪" const action = "买猪"
var req dto.BuyPigsRequest var req dto.BuyPigsRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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) return c.service.BuyPigs(primaryID, req.PenID, req.Quantity, req.UnitPrice, req.TotalPrice, req.TraderName, req.TradeDate, req.Remarks, operatorID)
}, },
"买猪成功", "买猪成功",

View File

@@ -4,7 +4,7 @@ import (
"strconv" "strconv"
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto" "git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
"github.com/gin-gonic/gin" "github.com/labstack/echo/v4"
) )
// TransferPigsAcrossBatches godoc // TransferPigsAcrossBatches godoc
@@ -18,18 +18,18 @@ import (
// @Param body body dto.TransferPigsAcrossBatchesRequest true "跨群调栏请求信息" // @Param body body dto.TransferPigsAcrossBatchesRequest true "跨群调栏请求信息"
// @Success 200 {object} controller.Response "调栏成功" // @Success 200 {object} controller.Response "调栏成功"
// @Router /api/v1/pig-batches/transfer-across-batches/{sourceBatchID} [post] // @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 = "跨猪群调栏" const action = "跨猪群调栏"
var req dto.TransferPigsAcrossBatchesRequest var req dto.TransferPigsAcrossBatchesRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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 // primaryID 在这里是 sourceBatchID
return c.service.TransferPigsAcrossBatches(primaryID, req.DestBatchID, req.FromPenID, req.ToPenID, req.Quantity, operatorID, req.Remarks) 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") idParam := ctx.Param("sourceBatchID")
parsedID, err := strconv.ParseUint(idParam, 10, 32) parsedID, err := strconv.ParseUint(idParam, 10, 32)
if err != nil { if err != nil {
@@ -51,13 +51,13 @@ func (c *PigBatchController) TransferPigsAcrossBatches(ctx *gin.Context) {
// @Param body body dto.TransferPigsWithinBatchRequest true "群内调栏请求信息" // @Param body body dto.TransferPigsWithinBatchRequest true "群内调栏请求信息"
// @Success 200 {object} controller.Response "调栏成功" // @Success 200 {object} controller.Response "调栏成功"
// @Router /api/v1/pig-batches/transfer-within-batch/{id} [post] // @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 = "群内调栏" const action = "群内调栏"
var req dto.TransferPigsWithinBatchRequest var req dto.TransferPigsWithinBatchRequest
handleAPIRequest( return handleAPIRequest(
c, ctx, action, &req, 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 // primaryID 在这里是 batchID
return c.service.TransferPigsWithinBatch(primaryID, req.FromPenID, req.ToPenID, req.Quantity, operatorID, req.Remarks) return c.service.TransferPigsWithinBatch(primaryID, req.FromPenID, req.ToPenID, req.Quantity, operatorID, req.Remarks)
}, },

View File

@@ -8,7 +8,7 @@ import (
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto" "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/app/service"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "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 // CreatePigHouse godoc
// @Summary 创建猪舍 // @Summary 创建猪舍
// @Description 创建一个新猪舍 // @Description 根据提供的信息创建一个新猪舍
// @Tags 猪场管理 // @Tags 猪场管理
// @Security BearerAuth // @Security BearerAuth
// @Accept json // @Accept json
@@ -39,19 +39,18 @@ func NewPigFarmController(logger *logs.Logger, service service.PigFarmService) *
// @Param body body dto.CreatePigHouseRequest true "猪舍信息" // @Param body body dto.CreatePigHouseRequest true "猪舍信息"
// @Success 201 {object} controller.Response{data=dto.PigHouseResponse} "创建成功" // @Success 201 {object} controller.Response{data=dto.PigHouseResponse} "创建成功"
// @Router /api/v1/pig-houses [post] // @Router /api/v1/pig-houses [post]
func (c *PigFarmController) CreatePigHouse(ctx *gin.Context) { func (c *PigFarmController) CreatePigHouse(ctx echo.Context) error {
const action = "创建猪舍" const action = "创建猪舍"
var req dto.CreatePigHouseRequest var req dto.CreatePigHouseRequest
if err := ctx.ShouldBindJSON(&req); err != nil { if err := ctx.Bind(&req); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) c.logger.Errorf("%s: 参数绑定失败: %v", action, err)
return return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
} }
house, err := c.service.CreatePigHouse(req.Name, req.Description) house, err := c.service.CreatePigHouse(req.Name, req.Description)
if err != nil { if err != nil {
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪舍失败", action, "业务逻辑失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪舍失败", action, "业务逻辑失败", req)
return
} }
resp := dto.PigHouseResponse{ resp := dto.PigHouseResponse{
@@ -59,7 +58,7 @@ func (c *PigFarmController) CreatePigHouse(ctx *gin.Context) {
Name: house.Name, Name: house.Name,
Description: house.Description, Description: house.Description,
} }
controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp) return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp)
} }
// GetPigHouse godoc // GetPigHouse godoc
@@ -71,23 +70,20 @@ func (c *PigFarmController) CreatePigHouse(ctx *gin.Context) {
// @Param id path int true "猪舍ID" // @Param id path int true "猪舍ID"
// @Success 200 {object} controller.Response{data=dto.PigHouseResponse} "获取成功" // @Success 200 {object} controller.Response{data=dto.PigHouseResponse} "获取成功"
// @Router /api/v1/pig-houses/{id} [get] // @Router /api/v1/pig-houses/{id} [get]
func (c *PigFarmController) GetPigHouse(ctx *gin.Context) { func (c *PigFarmController) GetPigHouse(ctx echo.Context) error {
const action = "获取猪舍" const action = "获取猪舍"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil { if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
} }
house, err := c.service.GetPigHouseByID(uint(id)) house, err := c.service.GetPigHouseByID(uint(id))
if err != nil { if err != nil {
if errors.Is(err, service.ErrHouseNotFound) { if errors.Is(err, service.ErrHouseNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id)
return
} }
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪舍失败", action, "业务逻辑失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪舍失败", action, "业务逻辑失败", id)
return
} }
resp := dto.PigHouseResponse{ resp := dto.PigHouseResponse{
@@ -95,7 +91,7 @@ func (c *PigFarmController) GetPigHouse(ctx *gin.Context) {
Name: house.Name, Name: house.Name,
Description: house.Description, Description: house.Description,
} }
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp) return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp)
} }
// ListPigHouses godoc // ListPigHouses godoc
@@ -106,13 +102,12 @@ func (c *PigFarmController) GetPigHouse(ctx *gin.Context) {
// @Produce json // @Produce json
// @Success 200 {object} controller.Response{data=[]dto.PigHouseResponse} "获取成功" // @Success 200 {object} controller.Response{data=[]dto.PigHouseResponse} "获取成功"
// @Router /api/v1/pig-houses [get] // @Router /api/v1/pig-houses [get]
func (c *PigFarmController) ListPigHouses(ctx *gin.Context) { func (c *PigFarmController) ListPigHouses(ctx echo.Context) error {
const action = "获取猪舍列表" const action = "获取猪舍列表"
houses, err := c.service.ListPigHouses() houses, err := c.service.ListPigHouses()
if err != nil { if err != nil {
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil)
return
} }
var resp []dto.PigHouseResponse 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 // UpdatePigHouse godoc
@@ -138,29 +133,25 @@ func (c *PigFarmController) ListPigHouses(ctx *gin.Context) {
// @Param body body dto.UpdatePigHouseRequest true "猪舍信息" // @Param body body dto.UpdatePigHouseRequest true "猪舍信息"
// @Success 200 {object} controller.Response{data=dto.PigHouseResponse} "更新成功" // @Success 200 {object} controller.Response{data=dto.PigHouseResponse} "更新成功"
// @Router /api/v1/pig-houses/{id} [put] // @Router /api/v1/pig-houses/{id} [put]
func (c *PigFarmController) UpdatePigHouse(ctx *gin.Context) { func (c *PigFarmController) UpdatePigHouse(ctx echo.Context) error {
const action = "更新猪舍" const action = "更新猪舍"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil { if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
} }
var req dto.UpdatePigHouseRequest var req dto.UpdatePigHouseRequest
if err := ctx.ShouldBindJSON(&req); err != nil { if err := ctx.Bind(&req); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
return
} }
house, err := c.service.UpdatePigHouse(uint(id), req.Name, req.Description) house, err := c.service.UpdatePigHouse(uint(id), req.Name, req.Description)
if err != nil { if err != nil {
if errors.Is(err, service.ErrHouseNotFound) { if errors.Is(err, service.ErrHouseNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id)
return
} }
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req)
return
} }
resp := dto.PigHouseResponse{ resp := dto.PigHouseResponse{
@@ -168,7 +159,7 @@ func (c *PigFarmController) UpdatePigHouse(ctx *gin.Context) {
Name: house.Name, Name: house.Name,
Description: house.Description, Description: house.Description,
} }
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp)
} }
// DeletePigHouse godoc // DeletePigHouse godoc
@@ -180,30 +171,26 @@ func (c *PigFarmController) UpdatePigHouse(ctx *gin.Context) {
// @Param id path int true "猪舍ID" // @Param id path int true "猪舍ID"
// @Success 200 {object} controller.Response "删除成功" // @Success 200 {object} controller.Response "删除成功"
// @Router /api/v1/pig-houses/{id} [delete] // @Router /api/v1/pig-houses/{id} [delete]
func (c *PigFarmController) DeletePigHouse(ctx *gin.Context) { func (c *PigFarmController) DeletePigHouse(ctx echo.Context) error {
const action = "删除猪舍" const action = "删除猪舍"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil { if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
} }
if err := c.service.DeletePigHouse(uint(id)); err != nil { if err := c.service.DeletePigHouse(uint(id)); err != nil {
if errors.Is(err, service.ErrHouseNotFound) { if errors.Is(err, service.ErrHouseNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id)
return
} }
// 检查是否是业务逻辑错误 // 检查是否是业务逻辑错误
if errors.Is(err, service.ErrHouseContainsPens) { if errors.Is(err, service.ErrHouseContainsPens) {
controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id)
return
} }
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除失败", action, "业务逻辑失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除失败", action, "业务逻辑失败", id)
return
} }
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "删除成功", nil, action, "删除成功", id) return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "删除成功", nil, action, "删除成功", id)
} }
// --- 猪栏 (Pen) API 实现 --- // --- 猪栏 (Pen) API 实现 ---
@@ -218,24 +205,21 @@ func (c *PigFarmController) DeletePigHouse(ctx *gin.Context) {
// @Param body body dto.CreatePenRequest true "猪栏信息" // @Param body body dto.CreatePenRequest true "猪栏信息"
// @Success 201 {object} controller.Response{data=dto.PenResponse} "创建成功" // @Success 201 {object} controller.Response{data=dto.PenResponse} "创建成功"
// @Router /api/v1/pens [post] // @Router /api/v1/pens [post]
func (c *PigFarmController) CreatePen(ctx *gin.Context) { func (c *PigFarmController) CreatePen(ctx echo.Context) error {
const action = "创建猪栏" const action = "创建猪栏"
var req dto.CreatePenRequest var req dto.CreatePenRequest
if err := ctx.ShouldBindJSON(&req); err != nil { if err := ctx.Bind(&req); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
return
} }
pen, err := c.service.CreatePen(req.PenNumber, req.HouseID, req.Capacity) pen, err := c.service.CreatePen(req.PenNumber, req.HouseID, req.Capacity)
if err != nil { if err != nil {
// 检查是否是业务逻辑错误 // 检查是否是业务逻辑错误
if errors.Is(err, service.ErrHouseNotFound) { if errors.Is(err, service.ErrHouseNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), req) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), req)
return
} }
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪栏失败", action, "业务逻辑失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪栏失败", action, "业务逻辑失败", req)
return
} }
resp := dto.PenResponse{ resp := dto.PenResponse{
@@ -245,7 +229,7 @@ func (c *PigFarmController) CreatePen(ctx *gin.Context) {
Capacity: pen.Capacity, Capacity: pen.Capacity,
Status: pen.Status, Status: pen.Status,
} }
controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp) return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp)
} }
// GetPen godoc // GetPen godoc
@@ -257,26 +241,23 @@ func (c *PigFarmController) CreatePen(ctx *gin.Context) {
// @Param id path int true "猪栏ID" // @Param id path int true "猪栏ID"
// @Success 200 {object} controller.Response{data=dto.PenResponse} "获取成功" // @Success 200 {object} controller.Response{data=dto.PenResponse} "获取成功"
// @Router /api/v1/pens/{id} [get] // @Router /api/v1/pens/{id} [get]
func (c *PigFarmController) GetPen(ctx *gin.Context) { func (c *PigFarmController) GetPen(ctx echo.Context) error {
const action = "获取猪栏" const action = "获取猪栏"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil { if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
} }
pen, err := c.service.GetPenByID(uint(id)) pen, err := c.service.GetPenByID(uint(id))
if err != nil { if err != nil {
if errors.Is(err, service.ErrPenNotFound) { if errors.Is(err, service.ErrPenNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id)
return
} }
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪栏失败", action, "业务逻辑失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪栏失败", action, "业务逻辑失败", id)
return
} }
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", pen, action, "获取成功", pen) return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", pen, action, "获取成功", pen)
} }
// ListPens godoc // ListPens godoc
@@ -287,16 +268,15 @@ func (c *PigFarmController) GetPen(ctx *gin.Context) {
// @Produce json // @Produce json
// @Success 200 {object} controller.Response{data=[]dto.PenResponse} "获取成功" // @Success 200 {object} controller.Response{data=[]dto.PenResponse} "获取成功"
// @Router /api/v1/pens [get] // @Router /api/v1/pens [get]
func (c *PigFarmController) ListPens(ctx *gin.Context) { func (c *PigFarmController) ListPens(ctx echo.Context) error {
const action = "获取猪栏列表" const action = "获取猪栏列表"
pens, err := c.service.ListPens() pens, err := c.service.ListPens()
if err != nil { if err != nil {
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil)
return
} }
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", pens, action, "获取成功", pens) return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", pens, action, "获取成功", pens)
} }
// UpdatePen godoc // UpdatePen godoc
@@ -310,30 +290,26 @@ func (c *PigFarmController) ListPens(ctx *gin.Context) {
// @Param body body dto.UpdatePenRequest true "猪栏信息" // @Param body body dto.UpdatePenRequest true "猪栏信息"
// @Success 200 {object} controller.Response{data=dto.PenResponse} "更新成功" // @Success 200 {object} controller.Response{data=dto.PenResponse} "更新成功"
// @Router /api/v1/pens/{id} [put] // @Router /api/v1/pens/{id} [put]
func (c *PigFarmController) UpdatePen(ctx *gin.Context) { func (c *PigFarmController) UpdatePen(ctx echo.Context) error {
const action = "更新猪栏" const action = "更新猪栏"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil { if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
} }
var req dto.UpdatePenRequest var req dto.UpdatePenRequest
if err := ctx.ShouldBindJSON(&req); err != nil { if err := ctx.Bind(&req); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
return
} }
pen, err := c.service.UpdatePen(uint(id), req.PenNumber, req.HouseID, req.Capacity, req.Status) pen, err := c.service.UpdatePen(uint(id), req.PenNumber, req.HouseID, req.Capacity, req.Status)
if err != nil { if err != nil {
if errors.Is(err, service.ErrPenNotFound) { if errors.Is(err, service.ErrPenNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id)
return
} }
// 其他业务逻辑错误可以在这里添加处理 // 其他业务逻辑错误可以在这里添加处理
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req)
return
} }
resp := dto.PenResponse{ resp := dto.PenResponse{
@@ -344,7 +320,7 @@ func (c *PigFarmController) UpdatePen(ctx *gin.Context) {
Status: pen.Status, Status: pen.Status,
PigBatchID: pen.PigBatchID, PigBatchID: pen.PigBatchID,
} }
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp)
} }
// DeletePen godoc // DeletePen godoc
@@ -356,30 +332,26 @@ func (c *PigFarmController) UpdatePen(ctx *gin.Context) {
// @Param id path int true "猪栏ID" // @Param id path int true "猪栏ID"
// @Success 200 {object} controller.Response "删除成功" // @Success 200 {object} controller.Response "删除成功"
// @Router /api/v1/pens/{id} [delete] // @Router /api/v1/pens/{id} [delete]
func (c *PigFarmController) DeletePen(ctx *gin.Context) { func (c *PigFarmController) DeletePen(ctx echo.Context) error {
const action = "删除猪栏" const action = "删除猪栏"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil { if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
} }
if err := c.service.DeletePen(uint(id)); err != nil { if err := c.service.DeletePen(uint(id)); err != nil {
if errors.Is(err, service.ErrPenNotFound) { if errors.Is(err, service.ErrPenNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id)
return
} }
// 检查是否是业务逻辑错误 // 检查是否是业务逻辑错误
if errors.Is(err, service.ErrPenInUse) { if errors.Is(err, service.ErrPenInUse) {
controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id)
return
} }
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除失败", action, "业务逻辑失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除失败", action, "业务逻辑失败", id)
return
} }
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "删除成功", nil, action, "删除成功", id) return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "删除成功", nil, action, "删除成功", id)
} }
// UpdatePenStatus godoc // UpdatePenStatus godoc
@@ -393,32 +365,27 @@ func (c *PigFarmController) DeletePen(ctx *gin.Context) {
// @Param body body dto.UpdatePenStatusRequest true "新的猪栏状态" // @Param body body dto.UpdatePenStatusRequest true "新的猪栏状态"
// @Success 200 {object} controller.Response{data=dto.PenResponse} "更新成功" // @Success 200 {object} controller.Response{data=dto.PenResponse} "更新成功"
// @Router /api/v1/pens/{id}/status [put] // @Router /api/v1/pens/{id}/status [put]
func (c *PigFarmController) UpdatePenStatus(ctx *gin.Context) { func (c *PigFarmController) UpdatePenStatus(ctx echo.Context) error {
const action = "更新猪栏状态" const action = "更新猪栏状态"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil { if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
} }
var req dto.UpdatePenStatusRequest var req dto.UpdatePenStatusRequest
if err := ctx.ShouldBindJSON(&req); err != nil { if err := ctx.Bind(&req); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
return
} }
pen, err := c.service.UpdatePenStatus(uint(id), req.Status) pen, err := c.service.UpdatePenStatus(uint(id), req.Status)
if err != nil { if err != nil {
if errors.Is(err, service.ErrPenNotFound) { if errors.Is(err, service.ErrPenNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), id) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), id)
return
} else if errors.Is(err, service.ErrPenStatusInvalidForOccupiedPen) || errors.Is(err, service.ErrPenStatusInvalidForUnoccupiedPen) { } else if errors.Is(err, service.ErrPenStatusInvalidForOccupiedPen) || errors.Is(err, service.ErrPenStatusInvalidForUnoccupiedPen) {
controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id)
return
} }
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新猪栏状态失败", action, err.Error(), id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新猪栏状态失败", action, err.Error(), id)
return
} }
resp := dto.PenResponse{ resp := dto.PenResponse{
@@ -429,5 +396,5 @@ func (c *PigFarmController) UpdatePenStatus(ctx *gin.Context) {
Status: pen.Status, Status: pen.Status,
PigBatchID: pen.PigBatchID, PigBatchID: pen.PigBatchID,
} }
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp)
} }

View File

@@ -9,7 +9,7 @@ import (
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "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/models"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
"github.com/gin-gonic/gin" "github.com/labstack/echo/v4"
) )
// Controller 监控控制器,封装了所有与数据监控相关的业务逻辑 // Controller 监控控制器,封装了所有与数据监控相关的业务逻辑
@@ -35,14 +35,13 @@ func NewController(monitorService service.MonitorService, logger *logs.Logger) *
// @Param query query dto.ListSensorDataRequest true "查询参数" // @Param query query dto.ListSensorDataRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListSensorDataResponse} // @Success 200 {object} controller.Response{data=dto.ListSensorDataResponse}
// @Router /api/v1/monitor/sensor-data [get] // @Router /api/v1/monitor/sensor-data [get]
func (c *Controller) ListSensorData(ctx *gin.Context) { func (c *Controller) ListSensorData(ctx echo.Context) error {
const actionType = "获取传感器数据列表" const actionType = "获取传感器数据列表"
var req dto.ListSensorDataRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.SensorDataListOptions{ opts := repository.SensorDataListOptions{
@@ -60,18 +59,16 @@ func (c *Controller) ListSensorData(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取传感器数据失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取传感器数据失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListSensorDataResponse(data, total, req.Page, req.PageSize) resp := dto.NewListSensorDataResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListDeviceCommandLogs godoc
@@ -83,14 +80,13 @@ func (c *Controller) ListSensorData(ctx *gin.Context) {
// @Param query query dto.ListDeviceCommandLogRequest true "查询参数" // @Param query query dto.ListDeviceCommandLogRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListDeviceCommandLogResponse} // @Success 200 {object} controller.Response{data=dto.ListDeviceCommandLogResponse}
// @Router /api/v1/monitor/device-command-logs [get] // @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 = "获取设备命令日志列表" const actionType = "获取设备命令日志列表"
var req dto.ListDeviceCommandLogRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.DeviceCommandLogListOptions{ opts := repository.DeviceCommandLogListOptions{
@@ -105,18 +101,16 @@ func (c *Controller) ListDeviceCommandLogs(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备命令日志失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备命令日志失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListDeviceCommandLogResponse(data, total, req.Page, req.PageSize) resp := dto.NewListDeviceCommandLogResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListPlanExecutionLogs godoc
@@ -128,14 +122,13 @@ func (c *Controller) ListDeviceCommandLogs(ctx *gin.Context) {
// @Param query query dto.ListPlanExecutionLogRequest true "查询参数" // @Param query query dto.ListPlanExecutionLogRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListPlanExecutionLogResponse} // @Success 200 {object} controller.Response{data=dto.ListPlanExecutionLogResponse}
// @Router /api/v1/monitor/plan-execution-logs [get] // @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 = "获取计划执行日志列表" const actionType = "获取计划执行日志列表"
var req dto.ListPlanExecutionLogRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.PlanExecutionLogListOptions{ opts := repository.PlanExecutionLogListOptions{
@@ -153,18 +146,16 @@ func (c *Controller) ListPlanExecutionLogs(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划执行日志失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划执行日志失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListPlanExecutionLogResponse(planLogs, plans, total, req.Page, req.PageSize) resp := dto.NewListPlanExecutionLogResponse(planLogs, plans, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(planLogs), total) 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 // ListTaskExecutionLogs godoc
@@ -176,14 +167,13 @@ func (c *Controller) ListPlanExecutionLogs(ctx *gin.Context) {
// @Param query query dto.ListTaskExecutionLogRequest true "查询参数" // @Param query query dto.ListTaskExecutionLogRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListTaskExecutionLogResponse} // @Success 200 {object} controller.Response{data=dto.ListTaskExecutionLogResponse}
// @Router /api/v1/monitor/task-execution-logs [get] // @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 = "获取任务执行日志列表" const actionType = "获取任务执行日志列表"
var req dto.ListTaskExecutionLogRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.TaskExecutionLogListOptions{ opts := repository.TaskExecutionLogListOptions{
@@ -202,18 +192,16 @@ func (c *Controller) ListTaskExecutionLogs(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取任务执行日志失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取任务执行日志失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListTaskExecutionLogResponse(data, total, req.Page, req.PageSize) resp := dto.NewListTaskExecutionLogResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListPendingCollections godoc
@@ -225,14 +213,13 @@ func (c *Controller) ListTaskExecutionLogs(ctx *gin.Context) {
// @Param query query dto.ListPendingCollectionRequest true "查询参数" // @Param query query dto.ListPendingCollectionRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListPendingCollectionResponse} // @Success 200 {object} controller.Response{data=dto.ListPendingCollectionResponse}
// @Router /api/v1/monitor/pending-collections [get] // @Router /api/v1/monitor/pending-collections [get]
func (c *Controller) ListPendingCollections(ctx *gin.Context) { func (c *Controller) ListPendingCollections(ctx echo.Context) error {
const actionType = "获取待采集请求列表" const actionType = "获取待采集请求列表"
var req dto.ListPendingCollectionRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.PendingCollectionListOptions{ opts := repository.PendingCollectionListOptions{
@@ -250,18 +237,16 @@ func (c *Controller) ListPendingCollections(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取待采集请求失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取待采集请求失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListPendingCollectionResponse(data, total, req.Page, req.PageSize) resp := dto.NewListPendingCollectionResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListUserActionLogs godoc
@@ -273,14 +258,13 @@ func (c *Controller) ListPendingCollections(ctx *gin.Context) {
// @Param query query dto.ListUserActionLogRequest true "查询参数" // @Param query query dto.ListUserActionLogRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListUserActionLogResponse} // @Success 200 {object} controller.Response{data=dto.ListUserActionLogResponse}
// @Router /api/v1/monitor/user-action-logs [get] // @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 = "获取用户操作日志列表" const actionType = "获取用户操作日志列表"
var req dto.ListUserActionLogRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.UserActionLogListOptions{ opts := repository.UserActionLogListOptions{
@@ -300,18 +284,16 @@ func (c *Controller) ListUserActionLogs(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取用户操作日志失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取用户操作日志失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListUserActionLogResponse(data, total, req.Page, req.PageSize) resp := dto.NewListUserActionLogResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListRawMaterialPurchases godoc
@@ -323,14 +305,13 @@ func (c *Controller) ListUserActionLogs(ctx *gin.Context) {
// @Param query query dto.ListRawMaterialPurchaseRequest true "查询参数" // @Param query query dto.ListRawMaterialPurchaseRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListRawMaterialPurchaseResponse} // @Success 200 {object} controller.Response{data=dto.ListRawMaterialPurchaseResponse}
// @Router /api/v1/monitor/raw-material-purchases [get] // @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 = "获取原料采购记录列表" const actionType = "获取原料采购记录列表"
var req dto.ListRawMaterialPurchaseRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.RawMaterialPurchaseListOptions{ opts := repository.RawMaterialPurchaseListOptions{
@@ -345,18 +326,16 @@ func (c *Controller) ListRawMaterialPurchases(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取原料采购记录失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取原料采购记录失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListRawMaterialPurchaseResponse(data, total, req.Page, req.PageSize) resp := dto.NewListRawMaterialPurchaseResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListRawMaterialStockLogs godoc
@@ -368,14 +347,13 @@ func (c *Controller) ListRawMaterialPurchases(ctx *gin.Context) {
// @Param query query dto.ListRawMaterialStockLogRequest true "查询参数" // @Param query query dto.ListRawMaterialStockLogRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListRawMaterialStockLogResponse} // @Success 200 {object} controller.Response{data=dto.ListRawMaterialStockLogResponse}
// @Router /api/v1/monitor/raw-material-stock-logs [get] // @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 = "获取原料库存日志列表" const actionType = "获取原料库存日志列表"
var req dto.ListRawMaterialStockLogRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.RawMaterialStockLogListOptions{ opts := repository.RawMaterialStockLogListOptions{
@@ -394,18 +372,16 @@ func (c *Controller) ListRawMaterialStockLogs(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取原料库存日志失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取原料库存日志失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListRawMaterialStockLogResponse(data, total, req.Page, req.PageSize) resp := dto.NewListRawMaterialStockLogResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListFeedUsageRecords godoc
@@ -417,14 +393,13 @@ func (c *Controller) ListRawMaterialStockLogs(ctx *gin.Context) {
// @Param query query dto.ListFeedUsageRecordRequest true "查询参数" // @Param query query dto.ListFeedUsageRecordRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListFeedUsageRecordResponse} // @Success 200 {object} controller.Response{data=dto.ListFeedUsageRecordResponse}
// @Router /api/v1/monitor/feed-usage-records [get] // @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 = "获取饲料使用记录列表" const actionType = "获取饲料使用记录列表"
var req dto.ListFeedUsageRecordRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.FeedUsageRecordListOptions{ opts := repository.FeedUsageRecordListOptions{
@@ -440,18 +415,16 @@ func (c *Controller) ListFeedUsageRecords(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取饲料使用记录失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取饲料使用记录失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListFeedUsageRecordResponse(data, total, req.Page, req.PageSize) resp := dto.NewListFeedUsageRecordResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListMedicationLogs godoc
@@ -463,14 +436,13 @@ func (c *Controller) ListFeedUsageRecords(ctx *gin.Context) {
// @Param query query dto.ListMedicationLogRequest true "查询参数" // @Param query query dto.ListMedicationLogRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListMedicationLogResponse} // @Success 200 {object} controller.Response{data=dto.ListMedicationLogResponse}
// @Router /api/v1/monitor/medication-logs [get] // @Router /api/v1/monitor/medication-logs [get]
func (c *Controller) ListMedicationLogs(ctx *gin.Context) { func (c *Controller) ListMedicationLogs(ctx echo.Context) error {
const actionType = "获取用药记录列表" const actionType = "获取用药记录列表"
var req dto.ListMedicationLogRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.MedicationLogListOptions{ opts := repository.MedicationLogListOptions{
@@ -490,18 +462,16 @@ func (c *Controller) ListMedicationLogs(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取用药记录失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取用药记录失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListMedicationLogResponse(data, total, req.Page, req.PageSize) resp := dto.NewListMedicationLogResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListPigBatchLogs godoc
@@ -513,14 +483,13 @@ func (c *Controller) ListMedicationLogs(ctx *gin.Context) {
// @Param query query dto.ListPigBatchLogRequest true "查询参数" // @Param query query dto.ListPigBatchLogRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListPigBatchLogResponse} // @Success 200 {object} controller.Response{data=dto.ListPigBatchLogResponse}
// @Router /api/v1/monitor/pig-batch-logs [get] // @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 = "获取猪批次日志列表" const actionType = "获取猪批次日志列表"
var req dto.ListPigBatchLogRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.PigBatchLogListOptions{ opts := repository.PigBatchLogListOptions{
@@ -539,18 +508,16 @@ func (c *Controller) ListPigBatchLogs(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪批次日志失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪批次日志失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListPigBatchLogResponse(data, total, req.Page, req.PageSize) resp := dto.NewListPigBatchLogResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListWeighingBatches godoc
@@ -562,14 +529,13 @@ func (c *Controller) ListPigBatchLogs(ctx *gin.Context) {
// @Param query query dto.ListWeighingBatchRequest true "查询参数" // @Param query query dto.ListWeighingBatchRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListWeighingBatchResponse} // @Success 200 {object} controller.Response{data=dto.ListWeighingBatchResponse}
// @Router /api/v1/monitor/weighing-batches [get] // @Router /api/v1/monitor/weighing-batches [get]
func (c *Controller) ListWeighingBatches(ctx *gin.Context) { func (c *Controller) ListWeighingBatches(ctx echo.Context) error {
const actionType = "获取批次称重记录列表" const actionType = "获取批次称重记录列表"
var req dto.ListWeighingBatchRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.WeighingBatchListOptions{ opts := repository.WeighingBatchListOptions{
@@ -583,18 +549,16 @@ func (c *Controller) ListWeighingBatches(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取批次称重记录失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取批次称重记录失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListWeighingBatchResponse(data, total, req.Page, req.PageSize) resp := dto.NewListWeighingBatchResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListWeighingRecords godoc
@@ -606,14 +570,13 @@ func (c *Controller) ListWeighingBatches(ctx *gin.Context) {
// @Param query query dto.ListWeighingRecordRequest true "查询参数" // @Param query query dto.ListWeighingRecordRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListWeighingRecordResponse} // @Success 200 {object} controller.Response{data=dto.ListWeighingRecordResponse}
// @Router /api/v1/monitor/weighing-records [get] // @Router /api/v1/monitor/weighing-records [get]
func (c *Controller) ListWeighingRecords(ctx *gin.Context) { func (c *Controller) ListWeighingRecords(ctx echo.Context) error {
const actionType = "获取单次称重记录列表" const actionType = "获取单次称重记录列表"
var req dto.ListWeighingRecordRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.WeighingRecordListOptions{ opts := repository.WeighingRecordListOptions{
@@ -629,18 +592,16 @@ func (c *Controller) ListWeighingRecords(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取单次称重记录失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取单次称重记录失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListWeighingRecordResponse(data, total, req.Page, req.PageSize) resp := dto.NewListWeighingRecordResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListPigTransferLogs godoc
@@ -652,14 +613,13 @@ func (c *Controller) ListWeighingRecords(ctx *gin.Context) {
// @Param query query dto.ListPigTransferLogRequest true "查询参数" // @Param query query dto.ListPigTransferLogRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListPigTransferLogResponse} // @Success 200 {object} controller.Response{data=dto.ListPigTransferLogResponse}
// @Router /api/v1/monitor/pig-transfer-logs [get] // @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 = "获取猪只迁移日志列表" const actionType = "获取猪只迁移日志列表"
var req dto.ListPigTransferLogRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.PigTransferLogListOptions{ opts := repository.PigTransferLogListOptions{
@@ -680,18 +640,16 @@ func (c *Controller) ListPigTransferLogs(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪只迁移日志失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪只迁移日志失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListPigTransferLogResponse(data, total, req.Page, req.PageSize) resp := dto.NewListPigTransferLogResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListPigSickLogs godoc
@@ -703,14 +661,13 @@ func (c *Controller) ListPigTransferLogs(ctx *gin.Context) {
// @Param query query dto.ListPigSickLogRequest true "查询参数" // @Param query query dto.ListPigSickLogRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListPigSickLogResponse} // @Success 200 {object} controller.Response{data=dto.ListPigSickLogResponse}
// @Router /api/v1/monitor/pig-sick-logs [get] // @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 = "获取病猪日志列表" const actionType = "获取病猪日志列表"
var req dto.ListPigSickLogRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.PigSickLogListOptions{ opts := repository.PigSickLogListOptions{
@@ -734,18 +691,16 @@ func (c *Controller) ListPigSickLogs(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取病猪日志失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取病猪日志失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListPigSickLogResponse(data, total, req.Page, req.PageSize) resp := dto.NewListPigSickLogResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListPigPurchases godoc
@@ -757,14 +712,13 @@ func (c *Controller) ListPigSickLogs(ctx *gin.Context) {
// @Param query query dto.ListPigPurchaseRequest true "查询参数" // @Param query query dto.ListPigPurchaseRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListPigPurchaseResponse} // @Success 200 {object} controller.Response{data=dto.ListPigPurchaseResponse}
// @Router /api/v1/monitor/pig-purchases [get] // @Router /api/v1/monitor/pig-purchases [get]
func (c *Controller) ListPigPurchases(ctx *gin.Context) { func (c *Controller) ListPigPurchases(ctx echo.Context) error {
const actionType = "获取猪只采购记录列表" const actionType = "获取猪只采购记录列表"
var req dto.ListPigPurchaseRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.PigPurchaseListOptions{ opts := repository.PigPurchaseListOptions{
@@ -780,18 +734,16 @@ func (c *Controller) ListPigPurchases(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪只采购记录失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪只采购记录失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListPigPurchaseResponse(data, total, req.Page, req.PageSize) resp := dto.NewListPigPurchaseResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListPigSales godoc
@@ -803,14 +755,13 @@ func (c *Controller) ListPigPurchases(ctx *gin.Context) {
// @Param query query dto.ListPigSaleRequest true "查询参数" // @Param query query dto.ListPigSaleRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListPigSaleResponse} // @Success 200 {object} controller.Response{data=dto.ListPigSaleResponse}
// @Router /api/v1/monitor/pig-sales [get] // @Router /api/v1/monitor/pig-sales [get]
func (c *Controller) ListPigSales(ctx *gin.Context) { func (c *Controller) ListPigSales(ctx echo.Context) error {
const actionType = "获取猪只售卖记录列表" const actionType = "获取猪只售卖记录列表"
var req dto.ListPigSaleRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.PigSaleListOptions{ opts := repository.PigSaleListOptions{
@@ -826,18 +777,16 @@ func (c *Controller) ListPigSales(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪只售卖记录失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪只售卖记录失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListPigSaleResponse(data, total, req.Page, req.PageSize) resp := dto.NewListPigSaleResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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 // ListNotifications godoc
@@ -849,14 +798,13 @@ func (c *Controller) ListPigSales(ctx *gin.Context) {
// @Param query query dto.ListNotificationRequest true "查询参数" // @Param query query dto.ListNotificationRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListNotificationResponse} // @Success 200 {object} controller.Response{data=dto.ListNotificationResponse}
// @Router /api/v1/monitor/notifications [get] // @Router /api/v1/monitor/notifications [get]
func (c *Controller) ListNotifications(ctx *gin.Context) { func (c *Controller) ListNotifications(ctx echo.Context) error {
const actionType = "批量查询通知" const actionType = "批量查询通知"
var req dto.ListNotificationRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
opts := repository.NotificationListOptions{ opts := repository.NotificationListOptions{
@@ -873,16 +821,14 @@ func (c *Controller) ListNotifications(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "批量查询通知失败: "+err.Error(), actionType, "服务层查询失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "批量查询通知失败: "+err.Error(), actionType, "服务层查询失败", req)
return
} }
resp := dto.NewListNotificationResponse(data, total, req.Page, req.PageSize) resp := dto.NewListNotificationResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total) 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)
} }

View File

@@ -10,11 +10,11 @@ import (
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "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/models"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
"github.com/gin-gonic/gin" "github.com/labstack/echo/v4"
"gorm.io/gorm" "gorm.io/gorm"
) )
// --- Controller 定义 --- // --- 控制器定义 ---
// Controller 定义了计划相关的控制器 // Controller 定义了计划相关的控制器
type Controller struct { type Controller struct {
@@ -44,21 +44,19 @@ func NewController(logger *logs.Logger, planRepo repository.PlanRepository, anal
// @Param plan body dto.CreatePlanRequest true "计划信息" // @Param plan body dto.CreatePlanRequest true "计划信息"
// @Success 200 {object} controller.Response{data=dto.PlanResponse} "业务码为201代表创建成功" // @Success 200 {object} controller.Response{data=dto.PlanResponse} "业务码为201代表创建成功"
// @Router /api/v1/plans [post] // @Router /api/v1/plans [post]
func (c *Controller) CreatePlan(ctx *gin.Context) { func (c *Controller) CreatePlan(ctx echo.Context) error {
var req dto.CreatePlanRequest var req dto.CreatePlanRequest
const actionType = "创建计划" const actionType = "创建计划"
if err := ctx.ShouldBindJSON(&req); err != nil { if err := ctx.Bind(&req); err != nil {
c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
return
} }
// 使用已有的转换函数,它已经包含了验证和重排逻辑 // 使用已有的转换函数,它已经包含了验证和重排逻辑
planToCreate, err := dto.NewPlanFromCreateRequest(&req) planToCreate, err := dto.NewPlanFromCreateRequest(&req)
if err != nil { if err != nil {
c.logger.Errorf("%s: 计划数据校验失败: %v", actionType, err) c.logger.Errorf("%s: 计划数据校验失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划数据校验失败: "+err.Error(), actionType, "计划数据校验失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划数据校验失败: "+err.Error(), actionType, "计划数据校验失败", req)
return
} }
// --- 业务规则处理 --- // --- 业务规则处理 ---
@@ -76,8 +74,7 @@ func (c *Controller) CreatePlan(ctx *gin.Context) {
// 调用仓库方法创建计划 // 调用仓库方法创建计划
if err := c.planRepo.CreatePlan(planToCreate); err != nil { if err := c.planRepo.CreatePlan(planToCreate); err != nil {
c.logger.Errorf("%s: 数据库创建计划失败: %v", actionType, err) c.logger.Errorf("%s: 数据库创建计划失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建计划失败: "+err.Error(), actionType, "数据库创建计划失败", planToCreate) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建计划失败: "+err.Error(), actionType, "数据库创建计划失败", planToCreate)
return
} }
// 创建成功后,调用 manager 确保触发器任务定义存在,但不立即加入待执行队列 // 创建成功后,调用 manager 确保触发器任务定义存在,但不立即加入待执行队列
@@ -89,14 +86,13 @@ func (c *Controller) CreatePlan(ctx *gin.Context) {
// 使用已有的转换函数将创建后的模型转换为响应对象 // 使用已有的转换函数将创建后的模型转换为响应对象
resp, err := dto.NewPlanToResponse(planToCreate) resp, err := dto.NewPlanToResponse(planToCreate)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v", actionType, err) c.logger.Errorf("%s: 序列化响应失败: %v, Plan: %+v", actionType, err, planToCreate)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "计划创建成功,但响应生成失败", actionType, "响应序列化失败", planToCreate) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "计划创建成功,但响应生成失败", actionType, "响应序列化失败", planToCreate)
return
} }
// 使用统一的成功响应函数 // 使用统一的成功响应函数
c.logger.Infof("%s: 计划创建成功, ID: %d", actionType, planToCreate.ID) 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 // GetPlan godoc
@@ -108,15 +104,14 @@ func (c *Controller) CreatePlan(ctx *gin.Context) {
// @Param id path int true "计划ID" // @Param id path int true "计划ID"
// @Success 200 {object} controller.Response{data=dto.PlanResponse} "业务码为200代表成功获取" // @Success 200 {object} controller.Response{data=dto.PlanResponse} "业务码为200代表成功获取"
// @Router /api/v1/plans/{id} [get] // @Router /api/v1/plans/{id} [get]
func (c *Controller) GetPlan(ctx *gin.Context) { func (c *Controller) GetPlan(ctx echo.Context) error {
const actionType = "获取计划详情" const actionType = "获取计划详情"
// 1. 从 URL 路径中获取 ID // 1. 从 URL 路径中获取 ID
idStr := ctx.Param("id") idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32) id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil { if err != nil {
c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr) c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr)
return
} }
// 2. 调用仓库层获取计划详情 // 2. 调用仓库层获取计划详情
@@ -125,26 +120,23 @@ func (c *Controller) GetPlan(ctx *gin.Context) {
// 判断是否为“未找到”错误 // 判断是否为“未找到”错误
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id) c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id)
return
} }
// 其他数据库错误视为内部错误 // 其他数据库错误视为内部错误
c.logger.Errorf("%s: 数据库查询失败: %v, ID: %d", actionType, err, id) c.logger.Errorf("%s: 数据库查询失败: %v, ID: %d", actionType, err, id)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划详情时发生内部错误", actionType, "数据库查询失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划详情时发生内部错误", actionType, "数据库查询失败", id)
return
} }
// 3. 将模型转换为响应 DTO // 3. 将模型转换为响应 DTO
resp, err := dto.NewPlanToResponse(plan) resp, err := dto.NewPlanToResponse(plan)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, Plan: %+v", actionType, err, plan) c.logger.Errorf("%s: 序列化响应失败: %v, Plan: %+v", actionType, err, plan)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划详情失败: 内部数据格式错误", actionType, "响应序列化失败", plan) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划详情失败: 内部数据格式错误", actionType, "响应序列化失败", plan)
return
} }
// 4. 发送成功响应 // 4. 发送成功响应
c.logger.Infof("%s: 获取计划详情成功, ID: %d", actionType, id) 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 // ListPlans godoc
@@ -156,13 +148,12 @@ func (c *Controller) GetPlan(ctx *gin.Context) {
// @Param query query dto.ListPlansQuery false "查询参数" // @Param query query dto.ListPlansQuery false "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListPlansResponse} "业务码为200代表成功获取列表" // @Success 200 {object} controller.Response{data=dto.ListPlansResponse} "业务码为200代表成功获取列表"
// @Router /api/v1/plans [get] // @Router /api/v1/plans [get]
func (c *Controller) ListPlans(ctx *gin.Context) { func (c *Controller) ListPlans(ctx echo.Context) error {
const actionType = "获取计划列表" const actionType = "获取计划列表"
var query dto.ListPlansQuery 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) c.logger.Errorf("%s: 查询参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", query) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", query)
return
} }
// 1. 调用仓库层获取所有计划 // 1. 调用仓库层获取所有计划
@@ -170,8 +161,7 @@ func (c *Controller) ListPlans(ctx *gin.Context) {
plans, total, err := c.planRepo.ListPlans(opts, query.Page, query.PageSize) plans, total, err := c.planRepo.ListPlans(opts, query.Page, query.PageSize)
if err != nil { if err != nil {
c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err) c.logger.Errorf("%s: 数据库查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划列表时发生内部错误", actionType, "数据库查询失败", nil) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划列表时发生内部错误", actionType, "数据库查询失败", nil)
return
} }
// 2. 将模型转换为响应 DTO // 2. 将模型转换为响应 DTO
@@ -180,8 +170,7 @@ func (c *Controller) ListPlans(ctx *gin.Context) {
resp, err := dto.NewPlanToResponse(&p) resp, err := dto.NewPlanToResponse(&p)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, Plan: %+v", actionType, err, p) c.logger.Errorf("%s: 序列化响应失败: %v, Plan: %+v", actionType, err, p)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划列表失败: 内部数据格式错误", actionType, "响应序列化失败", p) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划列表失败: 内部数据格式错误", actionType, "响应序列化失败", p)
return
} }
planResponses = append(planResponses, *resp) planResponses = append(planResponses, *resp)
} }
@@ -192,7 +181,7 @@ func (c *Controller) ListPlans(ctx *gin.Context) {
Total: total, Total: total,
} }
c.logger.Infof("%s: 获取计划列表成功, 数量: %d", actionType, len(planResponses)) 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 // UpdatePlan godoc
@@ -206,23 +195,21 @@ func (c *Controller) ListPlans(ctx *gin.Context) {
// @Param plan body dto.UpdatePlanRequest true "更新后的计划信息" // @Param plan body dto.UpdatePlanRequest true "更新后的计划信息"
// @Success 200 {object} controller.Response{data=dto.PlanResponse} "业务码为200代表更新成功" // @Success 200 {object} controller.Response{data=dto.PlanResponse} "业务码为200代表更新成功"
// @Router /api/v1/plans/{id} [put] // @Router /api/v1/plans/{id} [put]
func (c *Controller) UpdatePlan(ctx *gin.Context) { func (c *Controller) UpdatePlan(ctx echo.Context) error {
const actionType = "更新计划" const actionType = "更新计划"
// 1. 从 URL 路径中获取 ID // 1. 从 URL 路径中获取 ID
idStr := ctx.Param("id") idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32) id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil { if err != nil {
c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr) c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr)
return
} }
// 2. 绑定请求体 // 2. 绑定请求体
var req dto.UpdatePlanRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
return
} }
// 3. 检查计划是否存在 // 3. 检查计划是否存在
@@ -230,27 +217,23 @@ func (c *Controller) UpdatePlan(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id) c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id)
return
} }
c.logger.Errorf("%s: 获取计划信息失败: %v, ID: %d", actionType, err, id) c.logger.Errorf("%s: 获取计划信息失败: %v, ID: %d", actionType, err, id)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id)
return
} }
// 4. 业务规则:系统计划不允许修改 // 4. 业务规则:系统计划不允许修改
if existingPlan.PlanType == models.PlanTypeSystem { if existingPlan.PlanType == models.PlanTypeSystem {
c.logger.Warnf("%s: 尝试修改系统计划, ID: %d", actionType, id) c.logger.Warnf("%s: 尝试修改系统计划, ID: %d", actionType, id)
controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许修改", actionType, "尝试修改系统计划", id) return controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许修改", actionType, "尝试修改系统计划", id)
return
} }
// 5. 将请求转换为模型(转换函数带校验) // 5. 将请求转换为模型(转换函数带校验)
planToUpdate, err := dto.NewPlanFromUpdateRequest(&req) planToUpdate, err := dto.NewPlanFromUpdateRequest(&req)
if err != nil { if err != nil {
c.logger.Errorf("%s: 计划数据校验失败: %v", actionType, err) c.logger.Errorf("%s: 计划数据校验失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划数据校验失败: "+err.Error(), actionType, "计划数据校验失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划数据校验失败: "+err.Error(), actionType, "计划数据校验失败", req)
return
} }
planToUpdate.ID = uint(id) // 确保ID被设置 planToUpdate.ID = uint(id) // 确保ID被设置
@@ -269,8 +252,7 @@ func (c *Controller) UpdatePlan(ctx *gin.Context) {
if err := c.planRepo.UpdatePlan(planToUpdate); err != nil { if err := c.planRepo.UpdatePlan(planToUpdate); err != nil {
c.logger.Errorf("%s: 数据库更新计划失败: %v, Plan: %+v", actionType, err, planToUpdate) c.logger.Errorf("%s: 数据库更新计划失败: %v, Plan: %+v", actionType, err, planToUpdate)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新计划失败: "+err.Error(), actionType, "数据库更新计划失败", planToUpdate) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新计划失败: "+err.Error(), actionType, "数据库更新计划失败", planToUpdate)
return
} }
// 更新成功后,调用 manager 确保触发器任务定义存在 // 更新成功后,调用 manager 确保触发器任务定义存在
@@ -283,21 +265,19 @@ func (c *Controller) UpdatePlan(ctx *gin.Context) {
updatedPlan, err := c.planRepo.GetPlanByID(uint(id)) updatedPlan, err := c.planRepo.GetPlanByID(uint(id))
if err != nil { if err != nil {
c.logger.Errorf("%s: 获取更新后计划详情失败: %v, ID: %d", actionType, err, id) c.logger.Errorf("%s: 获取更新后计划详情失败: %v, ID: %d", actionType, err, id)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取更新后计划详情时发生内部错误", actionType, "获取更新后计划详情失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取更新后计划详情时发生内部错误", actionType, "获取更新后计划详情失败", id)
return
} }
// 8. 将模型转换为响应 DTO // 8. 将模型转换为响应 DTO
resp, err := dto.NewPlanToResponse(updatedPlan) resp, err := dto.NewPlanToResponse(updatedPlan)
if err != nil { if err != nil {
c.logger.Errorf("%s: 序列化响应失败: %v, Updated Plan: %+v", actionType, err, updatedPlan) c.logger.Errorf("%s: 序列化响应失败: %v, Updated Plan: %+v", actionType, err, updatedPlan)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "计划更新成功,但响应生成失败", actionType, "响应序列化失败", updatedPlan) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "计划更新成功,但响应生成失败", actionType, "响应序列化失败", updatedPlan)
return
} }
// 9. 发送成功响应 // 9. 发送成功响应
c.logger.Infof("%s: 计划更新成功, ID: %d", actionType, updatedPlan.ID) 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 // DeletePlan godoc
@@ -309,15 +289,14 @@ func (c *Controller) UpdatePlan(ctx *gin.Context) {
// @Param id path int true "计划ID" // @Param id path int true "计划ID"
// @Success 200 {object} controller.Response "业务码为200代表删除成功" // @Success 200 {object} controller.Response "业务码为200代表删除成功"
// @Router /api/v1/plans/{id} [delete] // @Router /api/v1/plans/{id} [delete]
func (c *Controller) DeletePlan(ctx *gin.Context) { func (c *Controller) DeletePlan(ctx echo.Context) error {
const actionType = "删除计划" const actionType = "删除计划"
// 1. 从 URL 路径中获取 ID // 1. 从 URL 路径中获取 ID
idStr := ctx.Param("id") idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32) id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil { if err != nil {
c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr) c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr)
return
} }
// 2. 检查计划是否存在 // 2. 检查计划是否存在
@@ -325,40 +304,35 @@ func (c *Controller) DeletePlan(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id) c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id)
return
} }
c.logger.Errorf("%s: 获取计划信息失败: %v, ID: %d", actionType, err, id) c.logger.Errorf("%s: 获取计划信息失败: %v, ID: %d", actionType, err, id)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id)
return
} }
// 3. 业务规则:系统计划不允许删除 // 3. 业务规则:系统计划不允许删除
if plan.PlanType == models.PlanTypeSystem { if plan.PlanType == models.PlanTypeSystem {
c.logger.Warnf("%s: 尝试删除系统计划, ID: %d", actionType, id) c.logger.Warnf("%s: 尝试删除系统计划, ID: %d", actionType, id)
controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许删除", actionType, "尝试删除系统计划", id) return controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许删除", actionType, "尝试删除系统计划", id)
return
} }
// 4. 停止这个计划 // 4. 停止这个计划
if plan.Status == models.PlanStatusEnabled { if plan.Status == models.PlanStatusEnabled {
if err := c.planRepo.StopPlanTransactionally(uint(id)); err != nil { if err := c.planRepo.StopPlanTransactionally(uint(id)); err != nil {
c.logger.Errorf("%s: 停止计划失败: %v, ID: %d", actionType, err, id) c.logger.Errorf("%s: 停止计划失败: %v, ID: %d", actionType, err, id)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "停止计划时发生内部错误: "+err.Error(), actionType, "停止计划失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "停止计划时发生内部错误: "+err.Error(), actionType, "停止计划失败", id)
return
} }
} }
// 5. 调用仓库层删除计划 // 5. 调用仓库层删除计划
if err := c.planRepo.DeletePlan(uint(id)); err != nil { if err := c.planRepo.DeletePlan(uint(id)); err != nil {
c.logger.Errorf("%s: 数据库删除失败: %v, ID: %d", actionType, err, id) c.logger.Errorf("%s: 数据库删除失败: %v, ID: %d", actionType, err, id)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除计划时发生内部错误", actionType, "数据库删除失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除计划时发生内部错误", actionType, "数据库删除失败", id)
return
} }
// 6. 发送成功响应 // 6. 发送成功响应
c.logger.Infof("%s: 计划删除成功, ID: %d", actionType, id) 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 // StartPlan godoc
@@ -370,15 +344,14 @@ func (c *Controller) DeletePlan(ctx *gin.Context) {
// @Param id path int true "计划ID" // @Param id path int true "计划ID"
// @Success 200 {object} controller.Response "业务码为200代表成功启动计划" // @Success 200 {object} controller.Response "业务码为200代表成功启动计划"
// @Router /api/v1/plans/{id}/start [post] // @Router /api/v1/plans/{id}/start [post]
func (c *Controller) StartPlan(ctx *gin.Context) { func (c *Controller) StartPlan(ctx echo.Context) error {
const actionType = "启动计划" const actionType = "启动计划"
// 1. 从 URL 路径中获取 ID // 1. 从 URL 路径中获取 ID
idStr := ctx.Param("id") idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32) id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil { if err != nil {
c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr) c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr)
return
} }
// 2. 检查计划是否存在 // 2. 检查计划是否存在
@@ -386,24 +359,20 @@ func (c *Controller) StartPlan(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id) c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id)
return
} }
c.logger.Errorf("%s: 获取计划信息失败: %v, ID: %d", actionType, err, id) c.logger.Errorf("%s: 获取计划信息失败: %v, ID: %d", actionType, err, id)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id)
return
} }
// 3. 业务规则检查 // 3. 业务规则检查
if plan.PlanType == models.PlanTypeSystem { if plan.PlanType == models.PlanTypeSystem {
c.logger.Warnf("%s: 尝试手动启动系统计划, ID: %d", actionType, id) c.logger.Warnf("%s: 尝试手动启动系统计划, ID: %d", actionType, id)
controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许手动启动", actionType, "尝试手动启动系统计划", id) return controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许手动启动", actionType, "尝试手动启动系统计划", id)
return
} }
if plan.Status == models.PlanStatusEnabled { if plan.Status == models.PlanStatusEnabled {
c.logger.Warnf("%s: 计划已处于启动状态,无需重复操作, ID: %d", actionType, id) c.logger.Warnf("%s: 计划已处于启动状态,无需重复操作, ID: %d", actionType, id)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划已处于启动状态,无需重复操作", actionType, "计划已处于启动状态", id) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划已处于启动状态,无需重复操作", actionType, "计划已处于启动状态", id)
return
} }
// 4. 检查并重置执行计数器,然后更新计划状态为“已启动” // 4. 检查并重置执行计数器,然后更新计划状态为“已启动”
@@ -413,8 +382,7 @@ func (c *Controller) StartPlan(ctx *gin.Context) {
if plan.ExecuteCount > 0 { if plan.ExecuteCount > 0 {
if err := c.planRepo.UpdateExecuteCount(plan.ID, 0); err != nil { if err := c.planRepo.UpdateExecuteCount(plan.ID, 0); err != nil {
c.logger.Errorf("%s: 重置计划执行计数失败: %v, ID: %d", actionType, err, plan.ID) c.logger.Errorf("%s: 重置计划执行计数失败: %v, ID: %d", actionType, err, plan.ID)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "重置计划执行计数失败", actionType, "重置执行计数失败", plan.ID) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "重置计划执行计数失败", actionType, "重置执行计数失败", plan.ID)
return
} }
c.logger.Infof("计划 #%d 的执行计数器已重置为 0。", 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 { if err := c.planRepo.UpdatePlanStatus(plan.ID, models.PlanStatusEnabled); err != nil {
c.logger.Errorf("%s: 更新计划状态失败: %v, ID: %d", actionType, err, plan.ID) c.logger.Errorf("%s: 更新计划状态失败: %v, ID: %d", actionType, err, plan.ID)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新计划状态失败", actionType, "更新计划状态失败", plan.ID) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新计划状态失败", actionType, "更新计划状态失败", plan.ID)
return
} }
c.logger.Infof("已成功更新计划 #%d 的状态为 '已启动'。", plan.ID) c.logger.Infof("已成功更新计划 #%d 的状态为 '已启动'。", plan.ID)
} else { } else {
// 如果计划已经处于 Enabled 状态,则无需更新 // 如果计划已经处于 Enabled 状态,则无需更新
c.logger.Infof("计划 #%d 已处于启动状态,无需重复操作。", plan.ID) c.logger.Infof("计划 #%d 已处于启动状态,无需重复操作。", plan.ID)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划已处于启动状态,无需重复操作", actionType, "计划已处于启动状态", plan.ID) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划已处于启动状态,无需重复操作", actionType, "计划已处于启动状态", plan.ID)
return
} }
// 5. 为计划创建或更新触发器 // 5. 为计划创建或更新触发器
if err := c.analysisPlanTaskManager.CreateOrUpdateTrigger(plan.ID); err != nil { if err := c.analysisPlanTaskManager.CreateOrUpdateTrigger(plan.ID); err != nil {
// 此处错误不回滚状态,因为状态更新已成功,但需要明确告知用户触发器创建失败 // 此处错误不回滚状态,因为状态更新已成功,但需要明确告知用户触发器创建失败
c.logger.Errorf("%s: 创建或更新触发器失败: %v, ID: %d", actionType, err, plan.ID) c.logger.Errorf("%s: 创建或更新触发器失败: %v, ID: %d", actionType, err, plan.ID)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "计划状态已更新,但创建执行触发器失败,请检查计划配置或稍后重试", actionType, "创建执行触发器失败", plan.ID) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "计划状态已更新,但创建执行触发器失败,请检查计划配置或稍后重试", actionType, "创建执行触发器失败", plan.ID)
return
} }
// 6. 发送成功响应 // 6. 发送成功响应
c.logger.Infof("%s: 计划已成功启动, ID: %d", actionType, id) 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 // StopPlan godoc
@@ -455,15 +420,14 @@ func (c *Controller) StartPlan(ctx *gin.Context) {
// @Param id path int true "计划ID" // @Param id path int true "计划ID"
// @Success 200 {object} controller.Response "业务码为200代表成功停止计划" // @Success 200 {object} controller.Response "业务码为200代表成功停止计划"
// @Router /api/v1/plans/{id}/stop [post] // @Router /api/v1/plans/{id}/stop [post]
func (c *Controller) StopPlan(ctx *gin.Context) { func (c *Controller) StopPlan(ctx echo.Context) error {
const actionType = "停止计划" const actionType = "停止计划"
// 1. 从 URL 路径中获取 ID // 1. 从 URL 路径中获取 ID
idStr := ctx.Param("id") idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32) id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil { if err != nil {
c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr) c.logger.Errorf("%s: 计划ID格式错误: %v, ID: %s", actionType, err, idStr)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的计划ID格式", actionType, "计划ID格式错误", idStr)
return
} }
// 2. 检查计划是否存在 // 2. 检查计划是否存在
@@ -471,36 +435,31 @@ func (c *Controller) StopPlan(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id) c.logger.Warnf("%s: 计划不存在, ID: %d", actionType, id)
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id) return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "计划不存在", actionType, "计划不存在", id)
return
} }
c.logger.Errorf("%s: 获取计划信息失败: %v, ID: %d", actionType, err, id) c.logger.Errorf("%s: 获取计划信息失败: %v, ID: %d", actionType, err, id)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取计划信息时发生内部错误", actionType, "数据库查询失败", id)
return
} }
// 3. 业务规则:系统计划不允许停止 // 3. 业务规则:系统计划不允许停止
if plan.PlanType == models.PlanTypeSystem { if plan.PlanType == models.PlanTypeSystem {
c.logger.Warnf("%s: 尝试停止系统计划, ID: %d", actionType, id) c.logger.Warnf("%s: 尝试停止系统计划, ID: %d", actionType, id)
controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许停止", actionType, "尝试停止系统计划", id) return controller.SendErrorWithAudit(ctx, controller.CodeForbidden, "系统计划不允许停止", actionType, "尝试停止系统计划", id)
return
} }
// 4. 检查计划当前状态 // 4. 检查计划当前状态
if plan.Status != models.PlanStatusEnabled { if plan.Status != models.PlanStatusEnabled {
c.logger.Warnf("%s: 计划当前不是启用状态, ID: %d, Status: %s", actionType, id, plan.Status) c.logger.Warnf("%s: 计划当前不是启用状态, ID: %d, Status: %s", actionType, id, plan.Status)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划当前不是启用状态", actionType, "计划未启用", id) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "计划当前不是启用状态", actionType, "计划未启用", id)
return
} }
// 5. 调用仓库层方法,该方法内部处理事务 // 5. 调用仓库层方法,该方法内部处理事务
if err := c.planRepo.StopPlanTransactionally(uint(id)); err != nil { if err := c.planRepo.StopPlanTransactionally(uint(id)); err != nil {
c.logger.Errorf("%s: 停止计划失败: %v, ID: %d", actionType, err, id) c.logger.Errorf("%s: 停止计划失败: %v, ID: %d", actionType, err, id)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "停止计划时发生内部错误: "+err.Error(), actionType, "停止计划失败", id) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "停止计划时发生内部错误: "+err.Error(), actionType, "停止计划失败", id)
return
} }
// 6. 发送成功响应 // 6. 发送成功响应
c.logger.Infof("%s: 计划已成功停止, ID: %d", actionType, id) 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)
} }

View File

@@ -12,7 +12,7 @@ import (
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "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/models"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
"github.com/gin-gonic/gin" "github.com/labstack/echo/v4"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -53,12 +53,11 @@ func NewController(
// @Param user body dto.CreateUserRequest true "用户信息" // @Param user body dto.CreateUserRequest true "用户信息"
// @Success 200 {object} controller.Response{data=dto.CreateUserResponse} "业务码为201代表创建成功" // @Success 200 {object} controller.Response{data=dto.CreateUserResponse} "业务码为201代表创建成功"
// @Router /api/v1/users [post] // @Router /api/v1/users [post]
func (c *Controller) CreateUser(ctx *gin.Context) { func (c *Controller) CreateUser(ctx echo.Context) error {
var req dto.CreateUserRequest var req dto.CreateUserRequest
if err := ctx.ShouldBindJSON(&req); err != nil { if err := ctx.Bind(&req); err != nil {
c.logger.Errorf("创建用户: 参数绑定失败: %v", err) c.logger.Errorf("创建用户: 参数绑定失败: %v", err)
controller.SendErrorResponse(ctx, controller.CodeBadRequest, err.Error()) return controller.SendErrorResponse(ctx, controller.CodeBadRequest, err.Error())
return
} }
user := &models.User{ user := &models.User{
@@ -72,16 +71,14 @@ func (c *Controller) CreateUser(ctx *gin.Context) {
// 尝试查询用户,以判断是否是用户名重复导致的错误 // 尝试查询用户,以判断是否是用户名重复导致的错误
_, findErr := c.userRepo.FindByUsername(req.Username) _, findErr := c.userRepo.FindByUsername(req.Username)
if findErr == nil { // 如果能找到用户,说明是用户名重复 if findErr == nil { // 如果能找到用户,说明是用户名重复
controller.SendErrorResponse(ctx, controller.CodeConflict, "用户名已存在") return controller.SendErrorResponse(ctx, controller.CodeConflict, "用户名已存在")
return
} }
// 其他创建失败的情况 // 其他创建失败的情况
controller.SendErrorResponse(ctx, controller.CodeInternalError, "创建用户失败") return controller.SendErrorResponse(ctx, controller.CodeInternalError, "创建用户失败")
return
} }
controller.SendResponse(ctx, controller.CodeCreated, "用户创建成功", dto.CreateUserResponse{ return controller.SendResponse(ctx, controller.CodeCreated, "用户创建成功", dto.CreateUserResponse{
Username: user.Username, Username: user.Username,
ID: user.ID, ID: user.ID,
}) })
@@ -96,40 +93,35 @@ func (c *Controller) CreateUser(ctx *gin.Context) {
// @Param credentials body dto.LoginRequest true "登录凭证" // @Param credentials body dto.LoginRequest true "登录凭证"
// @Success 200 {object} controller.Response{data=dto.LoginResponse} "业务码为200代表登录成功" // @Success 200 {object} controller.Response{data=dto.LoginResponse} "业务码为200代表登录成功"
// @Router /api/v1/users/login [post] // @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 var req dto.LoginRequest
if err := ctx.ShouldBindJSON(&req); err != nil { if err := ctx.Bind(&req); err != nil {
c.logger.Errorf("登录: 参数绑定失败: %v", err) c.logger.Errorf("登录: 参数绑定失败: %v", err)
controller.SendErrorResponse(ctx, controller.CodeBadRequest, err.Error()) return controller.SendErrorResponse(ctx, controller.CodeBadRequest, err.Error())
return
} }
// 使用新的方法,通过唯一标识符(用户名、邮箱等)查找用户 // 使用新的方法,通过唯一标识符(用户名、邮箱等)查找用户
user, err := c.userRepo.FindUserForLogin(req.Identifier) user, err := c.userRepo.FindUserForLogin(req.Identifier)
if err != nil { if err != nil {
if err == gorm.ErrRecordNotFound { if err == gorm.ErrRecordNotFound {
controller.SendErrorResponse(ctx, controller.CodeUnauthorized, "登录凭证不正确") return controller.SendErrorResponse(ctx, controller.CodeUnauthorized, "登录凭证不正确")
return
} }
c.logger.Errorf("登录: 查询用户失败: %v", err) c.logger.Errorf("登录: 查询用户失败: %v", err)
controller.SendErrorResponse(ctx, controller.CodeInternalError, "登录失败") return controller.SendErrorResponse(ctx, controller.CodeInternalError, "登录失败")
return
} }
if !user.CheckPassword(req.Password) { if !user.CheckPassword(req.Password) {
controller.SendErrorResponse(ctx, controller.CodeUnauthorized, "登录凭证不正确") return controller.SendErrorResponse(ctx, controller.CodeUnauthorized, "登录凭证不正确")
return
} }
// 登录成功,生成 JWT token // 登录成功,生成 JWT token
tokenString, err := c.tokenService.GenerateToken(user.ID) tokenString, err := c.tokenService.GenerateToken(user.ID)
if err != nil { if err != nil {
c.logger.Errorf("登录: 生成令牌失败: %v", err) c.logger.Errorf("登录: 生成令牌失败: %v", err)
controller.SendErrorResponse(ctx, controller.CodeInternalError, "登录失败,无法生成认证信息") return controller.SendErrorResponse(ctx, controller.CodeInternalError, "登录失败,无法生成认证信息")
return
} }
controller.SendResponse(ctx, controller.CodeSuccess, "登录成功", dto.LoginResponse{ return controller.SendResponse(ctx, controller.CodeSuccess, "登录成功", dto.LoginResponse{
Username: user.Username, Username: user.Username,
ID: user.ID, ID: user.ID,
Token: tokenString, Token: tokenString,
@@ -146,7 +138,7 @@ func (c *Controller) Login(ctx *gin.Context) {
// @Param query query dto.ListUserActionLogRequest false "查询参数 (除了 user_id它被路径中的ID覆盖)" // @Param query query dto.ListUserActionLogRequest false "查询参数 (除了 user_id它被路径中的ID覆盖)"
// @Success 200 {object} controller.Response{data=dto.ListUserActionLogResponse} "业务码为200代表成功获取" // @Success 200 {object} controller.Response{data=dto.ListUserActionLogResponse} "业务码为200代表成功获取"
// @Router /api/v1/users/{id}/history [get] // @Router /api/v1/users/{id}/history [get]
func (c *Controller) ListUserHistory(ctx *gin.Context) { func (c *Controller) ListUserHistory(ctx echo.Context) error {
const actionType = "获取用户操作历史" const actionType = "获取用户操作历史"
// 1. 解析路径中的用户ID它的优先级最高 // 1. 解析路径中的用户ID它的优先级最高
@@ -154,16 +146,14 @@ func (c *Controller) ListUserHistory(ctx *gin.Context) {
userID, err := strconv.ParseUint(userIDStr, 10, 64) userID, err := strconv.ParseUint(userIDStr, 10, 64)
if err != nil { if err != nil {
c.logger.Errorf("%s: 无效的用户ID格式: %v, ID: %s", actionType, err, userIDStr) c.logger.Errorf("%s: 无效的用户ID格式: %v, ID: %s", actionType, err, userIDStr)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的用户ID格式", actionType, "无效的用户ID格式", userIDStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的用户ID格式", actionType, "无效的用户ID格式", userIDStr)
return
} }
// 2. 绑定通用的查询请求 DTO // 2. 绑定通用的查询请求 DTO
var req dto.ListUserActionLogRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
} }
// 3. 准备 Service 调用参数,并强制使用路径中的 UserID // 3. 准备 Service 调用参数,并强制使用路径中的 UserID
@@ -188,18 +178,16 @@ func (c *Controller) ListUserHistory(ctx *gin.Context) {
if err != nil { if err != nil {
if errors.Is(err, repository.ErrInvalidPagination) { if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err) c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", opts) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", opts)
return
} }
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err) c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取用户历史记录失败", actionType, "服务层查询失败", opts) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取用户历史记录失败", actionType, "服务层查询失败", opts)
return
} }
// 5. 使用复用的 DTO 构建并发送成功响应 // 5. 使用复用的 DTO 构建并发送成功响应
resp := dto.NewListUserActionLogResponse(data, total, req.Page, req.PageSize) resp := dto.NewListUserActionLogResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功获取用户 %d 的操作历史, 数量: %d", actionType, userID, len(data)) 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 // SendTestNotification godoc
@@ -213,34 +201,31 @@ func (c *Controller) ListUserHistory(ctx *gin.Context) {
// @Param body body dto.SendTestNotificationRequest true "请求体" // @Param body body dto.SendTestNotificationRequest true "请求体"
// @Success 200 {object} controller.Response{data=string} "成功响应" // @Success 200 {object} controller.Response{data=string} "成功响应"
// @Router /api/v1/users/{id}/notifications/test [post] // @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 = "发送测试通知" const actionType = "发送测试通知"
// 1. 从 URL 中获取用户 ID // 1. 从 URL 中获取用户 ID
userID, err := strconv.ParseUint(ctx.Param("id"), 10, 32) userID, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil { if err != nil {
c.logger.Errorf("%s: 无效的用户ID格式: %v", actionType, err) c.logger.Errorf("%s: 无效的用户ID格式: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的用户ID格式", actionType, "无效的用户ID格式", ctx.Param("id")) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的用户ID格式", actionType, "无效的用户ID格式", ctx.Param("id"))
return
} }
// 2. 从请求体 (JSON Body) 中获取要测试的通知类型 // 2. 从请求体 (JSON Body) 中获取要测试的通知类型
var req dto.SendTestNotificationRequest 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) c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "请求体格式错误或缺少 'type' 字段: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "请求体格式错误或缺少 'type' 字段: "+err.Error(), actionType, "请求体绑定失败", req)
return
} }
// 3. 调用领域服务 // 3. 调用领域服务
err = c.notifyService.SendTestMessage(uint(userID), req.Type) err = c.notifyService.SendTestMessage(uint(userID), req.Type)
if err != nil { if err != nil {
c.logger.Errorf("%s: 服务层调用失败: %v", actionType, err) c.logger.Errorf("%s: 服务层调用失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "发送测试消息失败: "+err.Error(), actionType, "服务层调用失败", gin.H{"userID": userID, "type": req.Type}) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "发送测试消息失败: "+err.Error(), actionType, "服务层调用失败", map[string]interface{}{"userID": userID, "type": req.Type})
return
} }
// 4. 返回成功响应 // 4. 返回成功响应
c.logger.Infof("%s: 成功为用户 %d 发送类型为 %s 的测试消息", actionType, userID, req.Type) 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})
} }

View File

@@ -26,27 +26,27 @@
- [x] **移除所有响应体捕获和解析的逻辑** (`bodyLogWriter`, `auditResponse` 等)。 - [x] **移除所有响应体捕获和解析的逻辑** (`bodyLogWriter`, `auditResponse` 等)。
- [x]`next(c)` 调用后,**直接从 `echo.Context` 中获取**由 `response.go` 设置好的最终审计状态和结果详情。 - [x]`next(c)` 调用后,**直接从 `echo.Context` 中获取**由 `response.go` 设置好的最终审计状态和结果详情。
- [ ] **4. 控制器 (`internal/app/controller/...`)** - [x] **4. 控制器 (`internal/app/controller/...`)**
- [ ] **通用修改**:对所有控制器文件执行以下操作: - [x] **通用修改**:对所有控制器文件执行以下操作:
- [ ]`import "github.com/gin-gonic/gin"` 替换为 `import "github.com/labstack/echo/v4"` - [x]`import "github.com/gin-gonic/gin"` 替换为 `import "github.com/labstack/echo/v4"`
- [ ] 将所有处理函数签名从 `func(c *gin.Context)` 修改为 `func(c echo.Context) error` - [x] 将所有处理函数签名从 `func(c *gin.Context)` 修改为 `func(c echo.Context) error`
- [ ]`c.ShouldBindJSON(&req)``c.ShouldBindQuery(&req)` 替换为 - [x]`c.ShouldBindJSON(&req)``c.ShouldBindQuery(&req)` 替换为
`if err := c.Bind(&req); err != nil { ... }` `if err := c.Bind(&req); err != nil { ... }`
- [ ]`c.Param("id")` 替换为 `c.Param("id")` (用法相同,检查返回值即可)。 - [x]`c.Param("id")` 替换为 `c.Param("id")` (用法相同,检查返回值即可)。
- [ ]`controller.SendResponse(c, ...)``controller.SendErrorResponse(c, ...)` 调用修改为 - [x]`controller.SendResponse(c, ...)``controller.SendErrorResponse(c, ...)` 调用修改为
`return controller.SendResponse(c, ...)``return controller.SendErrorResponse(c, ...)` `return controller.SendResponse(c, ...)``return controller.SendErrorResponse(c, ...)`
- [ ] **文件清单** (按依赖顺序建议): - [x] **文件清单** (按依赖顺序建议):
- [ ] `internal/app/controller/management/controller_helpers.go` (注意:其中的泛型辅助函数也需要修改为返回 - [x] `internal/app/controller/management/controller_helpers.go` (注意:其中的泛型辅助函数也需要修改为返回
`error`) `error`)
- [ ] `internal/app/controller/device/device_controller.go` - [x] `internal/app/controller/device/device_controller.go`
- [ ] `internal/app/controller/management/pig_farm_controller.go` - [x] `internal/app/controller/management/pig_farm_controller.go`
- [ ] `internal/app/controller/management/pig_batch_controller.go` - [x] `internal/app/controller/management/pig_batch_controller.go`
- [ ] `internal/app/controller/management/pig_batch_health_controller.go` - [x] `internal/app/controller/management/pig_batch_health_controller.go`
- [ ] `internal/app/controller/management/pig_batch_trade_controller.go` - [x] `internal/app/controller/management/pig_batch_trade_controller.go`
- [ ] `internal/app/controller/management/pig_batch_transfer_controller.go` - [x] `internal/app/controller/management/pig_batch_transfer_controller.go`
- [ ] `internal/app/controller/monitor/monitor_controller.go` - [x] `internal/app/controller/monitor/monitor_controller.go`
- [ ] `internal/app/controller/plan/plan_controller.go` - [x] `internal/app/controller/plan/plan_controller.go`
- [ ] `internal/app/controller/user/user_controller.go` - [x] `internal/app/controller/user/user_controller.go`
- [ ] **5. 核心 API 层 (`internal/app/api`)** - [ ] **5. 核心 API 层 (`internal/app/api`)**
- [ ] **`router.go`** - [ ] **`router.go`**