package management import ( "errors" "strconv" "git.huangwc.com/pig/pig-farm-controller/internal/app/controller" "git.huangwc.com/pig/pig-farm-controller/internal/app/dto" "git.huangwc.com/pig/pig-farm-controller/internal/app/service" "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "github.com/gin-gonic/gin" ) // --- 控制器定义 --- // PigFarmController 负责处理猪舍和猪栏相关的API请求 type PigFarmController struct { logger *logs.Logger service service.PigFarmService } // NewPigFarmController 创建一个新的 PigFarmController 实例 func NewPigFarmController(logger *logs.Logger, service service.PigFarmService) *PigFarmController { return &PigFarmController{ logger: logger, service: service, } } // --- 猪舍 (PigHouse) API 实现 --- // CreatePigHouse godoc // @Summary 创建猪舍 // @Description 创建一个新的猪舍 // @Tags 猪场管理 // @Security BearerAuth // @Accept json // @Produce json // @Param body body dto.CreatePigHouseRequest true "猪舍信息" // @Success 201 {object} controller.Response{data=dto.PigHouseResponse} "创建成功" // @Router /api/v1/pig-houses [post] func (c *PigFarmController) CreatePigHouse(ctx *gin.Context) { const action = "创建猪舍" var req dto.CreatePigHouseRequest if err := ctx.ShouldBindJSON(&req); err != nil { controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) return } house, err := c.service.CreatePigHouse(req.Name, req.Description) if err != nil { c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪舍失败", action, "业务逻辑失败", req) return } resp := dto.PigHouseResponse{ ID: house.ID, Name: house.Name, Description: house.Description, } controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp) } // GetPigHouse godoc // @Summary 获取单个猪舍 // @Description 根据ID获取单个猪舍信息 // @Tags 猪场管理 // @Security BearerAuth // @Produce json // @Param id path int true "猪舍ID" // @Success 200 {object} controller.Response{data=dto.PigHouseResponse} "获取成功" // @Router /api/v1/pig-houses/{id} [get] func (c *PigFarmController) GetPigHouse(ctx *gin.Context) { const action = "获取猪舍" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return } house, err := c.service.GetPigHouseByID(uint(id)) if err != nil { if errors.Is(err, service.ErrHouseNotFound) { controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id) return } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪舍失败", action, "业务逻辑失败", id) return } resp := dto.PigHouseResponse{ ID: house.ID, Name: house.Name, Description: house.Description, } controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp) } // ListPigHouses godoc // @Summary 获取猪舍列表 // @Description 获取所有猪舍的列表 // @Tags 猪场管理 // @Security BearerAuth // @Produce json // @Success 200 {object} controller.Response{data=[]dto.PigHouseResponse} "获取成功" // @Router /api/v1/pig-houses [get] func (c *PigFarmController) ListPigHouses(ctx *gin.Context) { const action = "获取猪舍列表" houses, err := c.service.ListPigHouses() if err != nil { c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil) return } var resp []dto.PigHouseResponse for _, house := range houses { resp = append(resp, dto.PigHouseResponse{ ID: house.ID, Name: house.Name, Description: house.Description, }) } controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp) } // UpdatePigHouse godoc // @Summary 更新猪舍 // @Description 更新一个已存在的猪舍信息 // @Tags 猪场管理 // @Security BearerAuth // @Accept json // @Produce json // @Param id path int true "猪舍ID" // @Param body body dto.UpdatePigHouseRequest true "猪舍信息" // @Success 200 {object} controller.Response{data=dto.PigHouseResponse} "更新成功" // @Router /api/v1/pig-houses/{id} [put] func (c *PigFarmController) UpdatePigHouse(ctx *gin.Context) { const action = "更新猪舍" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return } var req dto.UpdatePigHouseRequest if err := ctx.ShouldBindJSON(&req); err != nil { controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) return } house, err := c.service.UpdatePigHouse(uint(id), req.Name, req.Description) if err != nil { if errors.Is(err, service.ErrHouseNotFound) { controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id) return } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req) return } resp := dto.PigHouseResponse{ ID: house.ID, Name: house.Name, Description: house.Description, } controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) } // DeletePigHouse godoc // @Summary 删除猪舍 // @Description 根据ID删除一个猪舍 // @Tags 猪场管理 // @Security BearerAuth // @Produce json // @Param id path int true "猪舍ID" // @Success 200 {object} controller.Response "删除成功" // @Router /api/v1/pig-houses/{id} [delete] func (c *PigFarmController) DeletePigHouse(ctx *gin.Context) { const action = "删除猪舍" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return } if err := c.service.DeletePigHouse(uint(id)); err != nil { if errors.Is(err, service.ErrHouseNotFound) { controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id) return } // 检查是否是业务逻辑错误 if errors.Is(err, service.ErrHouseContainsPens) { controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) return } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除失败", action, "业务逻辑失败", id) return } controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "删除成功", nil, action, "删除成功", id) } // --- 猪栏 (Pen) API 实现 --- // CreatePen godoc // @Summary 创建猪栏 // @Description 创建一个新的猪栏 // @Tags 猪场管理 // @Security BearerAuth // @Accept json // @Produce json // @Param body body dto.CreatePenRequest true "猪栏信息" // @Success 201 {object} controller.Response{data=dto.PenResponse} "创建成功" // @Router /api/v1/pens [post] func (c *PigFarmController) CreatePen(ctx *gin.Context) { const action = "创建猪栏" var req dto.CreatePenRequest if err := ctx.ShouldBindJSON(&req); err != nil { controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) return } pen, err := c.service.CreatePen(req.PenNumber, req.HouseID, req.Capacity) if err != nil { // 检查是否是业务逻辑错误 if errors.Is(err, service.ErrHouseNotFound) { controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), req) return } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪栏失败", action, "业务逻辑失败", req) return } resp := dto.PenResponse{ ID: pen.ID, PenNumber: pen.PenNumber, HouseID: pen.HouseID, Capacity: pen.Capacity, Status: pen.Status, } controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp) } // GetPen godoc // @Summary 获取单个猪栏 // @Description 根据ID获取单个猪栏信息 // @Tags 猪场管理 // @Security BearerAuth // @Produce json // @Param id path int true "猪栏ID" // @Success 200 {object} controller.Response{data=dto.PenResponse} "获取成功" // @Router /api/v1/pens/{id} [get] func (c *PigFarmController) GetPen(ctx *gin.Context) { const action = "获取猪栏" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return } pen, err := c.service.GetPenByID(uint(id)) if err != nil { if errors.Is(err, service.ErrPenNotFound) { controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id) return } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪栏失败", action, "业务逻辑失败", id) return } resp := dto.PenResponse{ ID: pen.ID, PenNumber: pen.PenNumber, HouseID: pen.HouseID, Capacity: pen.Capacity, Status: pen.Status, } if pen.PigBatchID != nil { resp.PigBatchID = *pen.PigBatchID } controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp) } // ListPens godoc // @Summary 获取猪栏列表 // @Description 获取所有猪栏的列表 // @Tags 猪场管理 // @Security BearerAuth // @Produce json // @Success 200 {object} controller.Response{data=[]dto.PenResponse} "获取成功" // @Router /api/v1/pens [get] func (c *PigFarmController) ListPens(ctx *gin.Context) { const action = "获取猪栏列表" pens, err := c.service.ListPens() if err != nil { c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil) return } var resp []dto.PenResponse for _, pen := range pens { res := dto.PenResponse{ ID: pen.ID, PenNumber: pen.PenNumber, HouseID: pen.HouseID, Capacity: pen.Capacity, Status: pen.Status, } if pen.PigBatchID != nil { res.PigBatchID = *pen.PigBatchID } resp = append(resp, res) } controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp) } // UpdatePen godoc // @Summary 更新猪栏 // @Description 更新一个已存在的猪栏信息 // @Tags 猪场管理 // @Security BearerAuth // @Accept json // @Produce json // @Param id path int true "猪栏ID" // @Param body body dto.UpdatePenRequest true "猪栏信息" // @Success 200 {object} controller.Response{data=dto.PenResponse} "更新成功" // @Router /api/v1/pens/{id} [put] func (c *PigFarmController) UpdatePen(ctx *gin.Context) { const action = "更新猪栏" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return } var req dto.UpdatePenRequest if err := ctx.ShouldBindJSON(&req); err != nil { controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) return } pen, err := c.service.UpdatePen(uint(id), req.PenNumber, req.HouseID, req.Capacity, req.Status) if err != nil { if errors.Is(err, service.ErrPenNotFound) { controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id) return } // 其他业务逻辑错误可以在这里添加处理 c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req) return } resp := dto.PenResponse{ ID: pen.ID, PenNumber: pen.PenNumber, HouseID: pen.HouseID, Capacity: pen.Capacity, Status: pen.Status, } if pen.PigBatchID != nil { resp.PigBatchID = *pen.PigBatchID } controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) } // DeletePen godoc // @Summary 删除猪栏 // @Description 根据ID删除一个猪栏 // @Tags 猪场管理 // @Security BearerAuth // @Produce json // @Param id path int true "猪栏ID" // @Success 200 {object} controller.Response "删除成功" // @Router /api/v1/pens/{id} [delete] func (c *PigFarmController) DeletePen(ctx *gin.Context) { const action = "删除猪栏" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return } if err := c.service.DeletePen(uint(id)); err != nil { if errors.Is(err, service.ErrPenNotFound) { controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id) return } // 检查是否是业务逻辑错误 if errors.Is(err, service.ErrPenInUse) { controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) return } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除失败", action, "业务逻辑失败", id) return } controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "删除成功", nil, action, "删除成功", id) } // UpdatePenStatus godoc // @Summary 更新猪栏状态 // @Description 更新指定猪栏的当前状态 // @Tags 猪场管理 // @Security BearerAuth // @Accept json // @Produce json // @Param id path int true "猪栏ID" // @Param body body dto.UpdatePenStatusRequest true "新的猪栏状态" // @Success 200 {object} controller.Response{data=dto.PenResponse} "更新成功" // @Router /api/v1/pens/{id}/status [put] func (c *PigFarmController) UpdatePenStatus(ctx *gin.Context) { const action = "更新猪栏状态" id, err := strconv.ParseUint(ctx.Param("id"), 10, 32) if err != nil { controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id")) return } var req dto.UpdatePenStatusRequest if err := ctx.ShouldBindJSON(&req); err != nil { controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) return } pen, err := c.service.UpdatePenStatus(uint(id), req.Status) if err != nil { if errors.Is(err, service.ErrPenNotFound) { controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), id) return } else if errors.Is(err, service.ErrPenStatusInvalidForOccupiedPen) || errors.Is(err, service.ErrPenStatusInvalidForUnoccupiedPen) { controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id) return } c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新猪栏状态失败", action, err.Error(), id) return } resp := dto.PenResponse{ ID: pen.ID, PenNumber: pen.PenNumber, HouseID: pen.HouseID, Capacity: pen.Capacity, Status: pen.Status, PigBatchID: *pen.PigBatchID, } controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) }