From 4e17ddf6384ed546818585f121c8a9c9ecab4171 Mon Sep 17 00:00:00 2001 From: huang <1724659546@qq.com> Date: Fri, 3 Oct 2025 23:42:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=8C=AA=E6=89=B9=E6=AC=A1?= =?UTF-8?q?=E5=A2=9E=E5=88=A0=E6=94=B9=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/app/api/api.go | 41 ++-- .../management/pig_batch_controller.go | 190 ++++++++++++++++++ internal/app/dto/pig_batch_dto.go | 45 +++++ internal/app/service/pig_batch_service.go | 176 ++++++++++++++++ internal/core/application.go | 3 + .../infra/repository/pig_batch_repository.go | 89 ++++++++ 6 files changed, 531 insertions(+), 13 deletions(-) create mode 100644 internal/app/controller/management/pig_batch_controller.go create mode 100644 internal/app/dto/pig_batch_dto.go create mode 100644 internal/app/service/pig_batch_service.go create mode 100644 internal/infra/repository/pig_batch_repository.go diff --git a/internal/app/api/api.go b/internal/app/api/api.go index 8af8009..5758ab9 100644 --- a/internal/app/api/api.go +++ b/internal/app/api/api.go @@ -37,19 +37,20 @@ import ( // API 结构体定义了 HTTP 服务器及其依赖 type API struct { - engine *gin.Engine // Gin 引擎实例,用于处理 HTTP 请求 - logger *logs.Logger // 日志记录器,用于输出日志信息 - userRepo repository.UserRepository // 用户数据仓库接口,用于用户数据操作 - tokenService token.TokenService // Token 服务接口,用于 JWT token 的生成和解析 - auditService audit.Service // 审计服务,用于记录用户操作 - httpServer *http.Server // 标准库的 HTTP 服务器实例,用于启动和停止服务 - config config.ServerConfig // API 服务器的配置,使用 infra/config 包中的 ServerConfig - userController *user.Controller // 用户控制器实例 - deviceController *device.Controller // 设备控制器实例 - planController *plan.Controller // 计划控制器实例 - pigFarmController *management.PigFarmController // 猪场管理控制器实例 - listenHandler webhook.ListenHandler // 设备上行事件监听器 - analysisTaskManager *task.AnalysisPlanTaskManager // 计划触发器管理器实例 + engine *gin.Engine // Gin 引擎实例,用于处理 HTTP 请求 + logger *logs.Logger // 日志记录器,用于输出日志信息 + userRepo repository.UserRepository // 用户数据仓库接口,用于用户数据操作 + tokenService token.TokenService // Token 服务接口,用于 JWT token 的生成和解析 + auditService audit.Service // 审计服务,用于记录用户操作 + httpServer *http.Server // 标准库的 HTTP 服务器实例,用于启动和停止服务 + config config.ServerConfig // API 服务器的配置,使用 infra/config 包中的 ServerConfig + userController *user.Controller // 用户控制器实例 + deviceController *device.Controller // 设备控制器实例 + planController *plan.Controller // 计划控制器实例 + pigFarmController *management.PigFarmController // 猪场管理控制器实例 + pigBatchController *management.PigBatchController // 猪批次控制器实例 + listenHandler webhook.ListenHandler // 设备上行事件监听器 + analysisTaskManager *task.AnalysisPlanTaskManager // 计划触发器管理器实例 } // NewAPI 创建并返回一个新的 API 实例 @@ -62,6 +63,7 @@ func NewAPI(cfg config.ServerConfig, deviceTemplateRepository repository.DeviceTemplateRepository, // 添加设备模板仓库 planRepository repository.PlanRepository, pigFarmService service.PigFarmService, + pigBatchService service.PigBatchService, // 添加猪批次服务 userActionLogRepository repository.UserActionLogRepository, tokenService token.TokenService, auditService audit.Service, // 注入审计服务 @@ -96,6 +98,8 @@ func NewAPI(cfg config.ServerConfig, planController: plan.NewController(logger, planRepository, analysisTaskManager), // 在 NewAPI 中初始化猪场管理控制器 pigFarmController: management.NewPigFarmController(logger, pigFarmService), + // 在 NewAPI 中初始化猪批次控制器 + pigBatchController: management.NewPigBatchController(logger, pigBatchService), } api.setupRoutes() // 设置所有路由 @@ -221,6 +225,17 @@ func (a *API) setupRoutes() { } a.logger.Info("猪圈相关接口注册成功 (需要认证和审计)") + // 猪批次相关路由组 + pigBatchGroup := authGroup.Group("/pig-batches") + { + pigBatchGroup.POST("", a.pigBatchController.CreatePigBatch) + pigBatchGroup.GET("", a.pigBatchController.ListPigBatches) + pigBatchGroup.GET("/:id", a.pigBatchController.GetPigBatch) + pigBatchGroup.PUT("/:id", a.pigBatchController.UpdatePigBatch) + pigBatchGroup.DELETE("/:id", a.pigBatchController.DeletePigBatch) + } + a.logger.Info("猪批次相关接口注册成功 (需要认证和审计)") + } } diff --git a/internal/app/controller/management/pig_batch_controller.go b/internal/app/controller/management/pig_batch_controller.go new file mode 100644 index 0000000..538947f --- /dev/null +++ b/internal/app/controller/management/pig_batch_controller.go @@ -0,0 +1,190 @@ +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" +) + +// PigBatchController 负责处理猪批次相关的API请求 +type PigBatchController struct { + logger *logs.Logger + service service.PigBatchService +} + +// NewPigBatchController 创建一个新的 PigBatchController 实例 +func NewPigBatchController(logger *logs.Logger, service service.PigBatchService) *PigBatchController { + return &PigBatchController{ + logger: logger, + service: service, + } +} + +// CreatePigBatch godoc +// @Summary 创建猪批次 +// @Description 创建一个新的猪批次 +// @Tags 猪批次管理 +// @Accept json +// @Produce json +// @Param body body dto.PigBatchCreateDTO true "猪批次信息" +// @Success 201 {object} controller.Response{data=dto.PigBatchResponseDTO} "创建成功" +// @Failure 400 {object} controller.Response "请求参数错误" +// @Failure 500 {object} controller.Response "内部服务器错误" +// @Router /api/v1/pig-batches [post] +func (c *PigBatchController) CreatePigBatch(ctx *gin.Context) { + const action = "创建猪批次" + var req dto.PigBatchCreateDTO + if err := ctx.ShouldBindJSON(&req); err != nil { + controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) + return + } + + respDTO, err := c.service.CreatePigBatch(&req) + if err != nil { + c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) + controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪批次失败", action, "业务逻辑失败", req) + return + } + + controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", respDTO, action, "创建成功", respDTO) +} + +// GetPigBatch godoc +// @Summary 获取单个猪批次 +// @Description 根据ID获取单个猪批次信息 +// @Tags 猪批次管理 +// @Produce json +// @Param id path int true "猪批次ID" +// @Success 200 {object} controller.Response{data=dto.PigBatchResponseDTO} "获取成功" +// @Failure 400 {object} controller.Response "无效的ID格式" +// @Failure 404 {object} controller.Response "猪批次不存在" +// @Failure 500 {object} controller.Response "内部服务器错误" +// @Router /api/v1/pig-batches/{id} [get] +func (c *PigBatchController) GetPigBatch(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 + } + + respDTO, err := c.service.GetPigBatch(uint(id)) + if err != nil { + if errors.Is(err, service.ErrPigBatchNotFound) { + controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪批次不存在", action, "猪批次不存在", id) + return + } + c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) + controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪批次失败", action, "业务逻辑失败", id) + return + } + + controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", respDTO, action, "获取成功", respDTO) +} + +// UpdatePigBatch godoc +// @Summary 更新猪批次 +// @Description 更新一个已存在的猪批次信息 +// @Tags 猪批次管理 +// @Accept json +// @Produce json +// @Param id path int true "猪批次ID" +// @Param body body dto.PigBatchUpdateDTO true "猪批次信息" +// @Success 200 {object} controller.Response{data=dto.PigBatchResponseDTO} "更新成功" +// @Failure 400 {object} controller.Response "请求参数错误或无效的ID格式" +// @Failure 404 {object} controller.Response "猪批次不存在" +// @Failure 500 {object} controller.Response "内部服务器错误" +// @Router /api/v1/pig-batches/{id} [put] +func (c *PigBatchController) UpdatePigBatch(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.PigBatchUpdateDTO + if err := ctx.ShouldBindJSON(&req); err != nil { + controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req) + return + } + + respDTO, err := c.service.UpdatePigBatch(uint(id), &req) + if err != nil { + if errors.Is(err, service.ErrPigBatchNotFound) { + controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪批次不存在", action, "猪批次不存在", id) + return + } + c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) + controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新猪批次失败", action, "业务逻辑失败", req) + return + } + + controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", respDTO, action, "更新成功", respDTO) +} + +// DeletePigBatch godoc +// @Summary 删除猪批次 +// @Description 根据ID删除一个猪批次 +// @Tags 猪批次管理 +// @Produce json +// @Param id path int true "猪批次ID" +// @Success 200 {object} controller.Response "删除成功" +// @Failure 400 {object} controller.Response "无效的ID格式" +// @Failure 404 {object} controller.Response "猪批次不存在" +// @Failure 500 {object} controller.Response "内部服务器错误" +// @Router /api/v1/pig-batches/{id} [delete] +func (c *PigBatchController) DeletePigBatch(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.DeletePigBatch(uint(id)); err != nil { + if errors.Is(err, service.ErrPigBatchNotFound) { + controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪批次不存在", action, "猪批次不存在", 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) +} + +// ListPigBatches godoc +// @Summary 获取猪批次列表 +// @Description 获取所有猪批次的列表,支持按活跃状态筛选 +// @Tags 猪批次管理 +// @Produce json +// @Param is_active query bool false "是否活跃 (true/false)" +// @Success 200 {object} controller.Response{data=[]dto.PigBatchResponseDTO} "获取成功" +// @Failure 500 {object} controller.Response "内部服务器错误" +// @Router /api/v1/pig-batches [get] +func (c *PigBatchController) ListPigBatches(ctx *gin.Context) { + const action = "获取猪批次列表" + var query dto.PigBatchQueryDTO + // ShouldBindQuery 会自动处理 URL 查询参数,例如 ?is_active=true + if err := ctx.ShouldBindQuery(&query); err != nil { + controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数", action, "查询参数绑定失败", nil) + return + } + + respDTOs, err := c.service.ListPigBatches(query.IsActive) + if err != nil { + c.logger.Errorf("%s: 业务逻辑失败: %v", action, err) + controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪批次列表失败", action, "业务逻辑失败", nil) + return + } + + controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", respDTOs, action, "获取成功", respDTOs) +} diff --git a/internal/app/dto/pig_batch_dto.go b/internal/app/dto/pig_batch_dto.go new file mode 100644 index 0000000..c90bedd --- /dev/null +++ b/internal/app/dto/pig_batch_dto.go @@ -0,0 +1,45 @@ +package dto + +import ( + "time" + + "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" // 导入 models 包以使用 PigBatchOriginType 和 PigBatchStatus +) + +// PigBatchCreateDTO 定义了创建猪批次的请求结构 +type PigBatchCreateDTO struct { + BatchNumber string `json:"batch_number" binding:"required"` // 批次编号,必填 + OriginType models.PigBatchOriginType `json:"origin_type" binding:"required"` // 批次来源,必填 + StartDate time.Time `json:"start_date" binding:"required"` // 批次开始日期,必填 + InitialCount int `json:"initial_count" binding:"required,min=1"` // 初始数量,必填,最小为1 + Status models.PigBatchStatus `json:"status" binding:"required"` // 批次状态,必填 +} + +// PigBatchUpdateDTO 定义了更新猪批次的请求结构 +type PigBatchUpdateDTO struct { + BatchNumber *string `json:"batch_number"` // 批次编号,可选 + OriginType *models.PigBatchOriginType `json:"origin_type"` // 批次来源,可选 + StartDate *time.Time `json:"start_date"` // 批次开始日期,可选 + EndDate *time.Time `json:"end_date"` // 批次结束日期,可选 + InitialCount *int `json:"initial_count"` // 初始数量,可选 + Status *models.PigBatchStatus `json:"status"` // 批次状态,可选 +} + +// PigBatchQueryDTO 定义了查询猪批次的请求结构 +type PigBatchQueryDTO struct { + IsActive *bool `json:"is_active" form:"is_active"` // 是否活跃,可选,用于URL查询参数 +} + +// PigBatchResponseDTO 定义了猪批次信息的响应结构 +type PigBatchResponseDTO struct { + ID uint `json:"id"` // 批次ID + BatchNumber string `json:"batch_number"` // 批次编号 + OriginType models.PigBatchOriginType `json:"origin_type"` // 批次来源 + StartDate time.Time `json:"start_date"` // 批次开始日期 + EndDate time.Time `json:"end_date"` // 批次结束日期 + InitialCount int `json:"initial_count"` // 初始数量 + Status models.PigBatchStatus `json:"status"` // 批次状态 + IsActive bool `json:"is_active"` // 是否活跃 + CreateTime time.Time `json:"create_time"` // 创建时间 + UpdateTime time.Time `json:"update_time"` // 更新时间 +} diff --git a/internal/app/service/pig_batch_service.go b/internal/app/service/pig_batch_service.go new file mode 100644 index 0000000..5b6eb13 --- /dev/null +++ b/internal/app/service/pig_batch_service.go @@ -0,0 +1,176 @@ +package service + +import ( + "errors" + + "git.huangwc.com/pig/pig-farm-controller/internal/app/dto" + "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" + "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" + "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" + + "gorm.io/gorm" +) + +var ( + ErrPigBatchNotFound = errors.New("指定的猪批次不存在") + ErrPigBatchActive = errors.New("活跃的猪批次不能被删除") // 新增错误:活跃的猪批次不能被删除 +) + +// PigBatchService 提供了猪批次管理的业务逻辑 +type PigBatchService interface { + CreatePigBatch(dto *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error) + GetPigBatch(id uint) (*dto.PigBatchResponseDTO, error) + UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error) + DeletePigBatch(id uint) error + ListPigBatches(isActive *bool) ([]*dto.PigBatchResponseDTO, error) +} + +type pigBatchService struct { + logger *logs.Logger + repo repository.PigBatchRepository +} + +// NewPigBatchService 创建一个新的 PigBatchService 实例 +func NewPigBatchService(repo repository.PigBatchRepository, logger *logs.Logger) PigBatchService { + return &pigBatchService{ + logger: logger, + repo: repo, + } +} + +// toPigBatchResponseDTO 将 models.PigBatch 转换为 dto.PigBatchResponseDTO +func (s *pigBatchService) toPigBatchResponseDTO(batch *models.PigBatch) *dto.PigBatchResponseDTO { + if batch == nil { + return nil + } + return &dto.PigBatchResponseDTO{ + ID: batch.ID, + BatchNumber: batch.BatchNumber, + OriginType: batch.OriginType, + StartDate: batch.StartDate, + EndDate: batch.EndDate, + InitialCount: batch.InitialCount, + Status: batch.Status, + IsActive: batch.IsActive(), // 使用模型自带的 IsActive 方法 + CreateTime: batch.CreatedAt, + UpdateTime: batch.UpdatedAt, + } +} + +// CreatePigBatch 处理创建猪批次的业务逻辑 +func (s *pigBatchService) CreatePigBatch(dto *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error) { + batch := &models.PigBatch{ + BatchNumber: dto.BatchNumber, + OriginType: dto.OriginType, + StartDate: dto.StartDate, + InitialCount: dto.InitialCount, + Status: dto.Status, + } + + createdBatch, err := s.repo.CreatePigBatch(batch) + if err != nil { + s.logger.Errorf("创建猪批次失败: %v", err) + return nil, err + } + + return s.toPigBatchResponseDTO(createdBatch), nil +} + +// GetPigBatch 处理获取单个猪批次的业务逻辑 +func (s *pigBatchService) GetPigBatch(id uint) (*dto.PigBatchResponseDTO, error) { + batch, err := s.repo.GetPigBatchByID(id) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, ErrPigBatchNotFound + } + s.logger.Errorf("获取猪批次失败,ID: %d, 错误: %v", id, err) + return nil, err + } + + return s.toPigBatchResponseDTO(batch), nil +} + +// UpdatePigBatch 处理更新猪批次的业务逻辑 +func (s *pigBatchService) UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error) { + existingBatch, err := s.repo.GetPigBatchByID(id) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, ErrPigBatchNotFound + } + s.logger.Errorf("更新猪批次失败,获取原批次信息错误,ID: %d, 错误: %v", id, err) + return nil, err + } + + // 根据 DTO 中的非空字段更新模型 + if dto.BatchNumber != nil { + existingBatch.BatchNumber = *dto.BatchNumber + } + if dto.OriginType != nil { + existingBatch.OriginType = *dto.OriginType + } + if dto.StartDate != nil { + existingBatch.StartDate = *dto.StartDate + } + if dto.EndDate != nil { + existingBatch.EndDate = *dto.EndDate + } + if dto.InitialCount != nil { + existingBatch.InitialCount = *dto.InitialCount + } + if dto.Status != nil { + existingBatch.Status = *dto.Status + } + + updatedBatch, err := s.repo.UpdatePigBatch(existingBatch) + if err != nil { + s.logger.Errorf("更新猪批次失败,ID: %d, 错误: %v", id, err) + return nil, err + } + + return s.toPigBatchResponseDTO(updatedBatch), nil +} + +// DeletePigBatch 处理删除猪批次的业务逻辑 +func (s *pigBatchService) DeletePigBatch(id uint) error { + // 1. 获取猪批次信息 + batch, err := s.repo.GetPigBatchByID(id) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return ErrPigBatchNotFound + } + s.logger.Errorf("删除猪批次失败,获取批次信息错误,ID: %d, 错误: %v", id, err) + return err + } + + // 2. 检查猪批次是否活跃 + if batch.IsActive() { + return ErrPigBatchActive // 如果活跃,则不允许删除 + } + + // 3. 执行删除操作 + err = s.repo.DeletePigBatch(id) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) || errors.New("未找到要删除的猪批次").Error() == err.Error() { + return ErrPigBatchNotFound + } + s.logger.Errorf("删除猪批次失败,ID: %d, 错误: %v", id, err) + return err + } + return nil +} + +// ListPigBatches 处理批量查询猪批次的业务逻辑 +func (s *pigBatchService) ListPigBatches(isActive *bool) ([]*dto.PigBatchResponseDTO, error) { + batches, err := s.repo.ListPigBatches(isActive) + if err != nil { + s.logger.Errorf("批量查询猪批次失败,错误: %v", err) + return nil, err + } + + var responseDTOs []*dto.PigBatchResponseDTO + for _, batch := range batches { + responseDTOs = append(responseDTOs, s.toPigBatchResponseDTO(batch)) + } + + return responseDTOs, nil +} diff --git a/internal/core/application.go b/internal/core/application.go index 427279f..02039e2 100644 --- a/internal/core/application.go +++ b/internal/core/application.go @@ -72,9 +72,11 @@ func NewApplication(configPath string) (*Application, error) { deviceCommandLogRepo := repository.NewGormDeviceCommandLogRepository(storage.GetDB()) pendingCollectionRepo := repository.NewGormPendingCollectionRepository(storage.GetDB()) userActionLogRepo := repository.NewGormUserActionLogRepository(storage.GetDB()) + pigBatchRepo := repository.NewGormPigBatchRepository(storage.GetDB()) // --- 业务逻辑处理器初始化 --- pigFarmService := service.NewPigFarmService(pigFarmRepo, logger) + pigBatchService := service.NewPigBatchService(pigBatchRepo, logger) // 初始化审计服务 auditService := audit.NewService(userActionLogRepo, logger) @@ -121,6 +123,7 @@ func NewApplication(configPath string) (*Application, error) { deviceTemplateRepo, planRepo, pigFarmService, + pigBatchService, userActionLogRepo, tokenService, auditService, diff --git a/internal/infra/repository/pig_batch_repository.go b/internal/infra/repository/pig_batch_repository.go new file mode 100644 index 0000000..eb3bdf3 --- /dev/null +++ b/internal/infra/repository/pig_batch_repository.go @@ -0,0 +1,89 @@ +package repository + +import ( + "errors" + + "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" + "gorm.io/gorm" +) + +// PigBatchRepository 定义了与猪批次相关的数据库操作接口 +type PigBatchRepository interface { + CreatePigBatch(batch *models.PigBatch) (*models.PigBatch, error) + GetPigBatchByID(id uint) (*models.PigBatch, error) + UpdatePigBatch(batch *models.PigBatch) (*models.PigBatch, error) + DeletePigBatch(id uint) error + ListPigBatches(isActive *bool) ([]*models.PigBatch, error) +} + +// gormPigBatchRepository 是 PigBatchRepository 的 GORM 实现 +type gormPigBatchRepository struct { + db *gorm.DB +} + +// NewGormPigBatchRepository 创建一个新的 PigBatchRepository GORM 实现实例 +func NewGormPigBatchRepository(db *gorm.DB) PigBatchRepository { + return &gormPigBatchRepository{db: db} +} + +// CreatePigBatch 创建一个新的猪批次 +func (r *gormPigBatchRepository) CreatePigBatch(batch *models.PigBatch) (*models.PigBatch, error) { + if err := r.db.Create(batch).Error; err != nil { + return nil, err + } + return batch, nil +} + +// GetPigBatchByID 根据ID获取单个猪批次 +func (r *gormPigBatchRepository) GetPigBatchByID(id uint) (*models.PigBatch, error) { + var batch models.PigBatch + if err := r.db.First(&batch, id).Error; err != nil { + return nil, err + } + return &batch, nil +} + +// UpdatePigBatch 更新一个猪批次 +func (r *gormPigBatchRepository) UpdatePigBatch(batch *models.PigBatch) (*models.PigBatch, error) { + result := r.db.Model(&models.PigBatch{}).Where("id = ?", batch.ID).Updates(batch) + if result.Error != nil { + return nil, result.Error + } + if result.RowsAffected == 0 { + return nil, errors.New("未找到要更新的猪批次或数据未改变") // 明确返回错误,而不是 gorm.ErrRecordNotFound + } + return batch, nil +} + +// DeletePigBatch 根据ID删除一个猪批次 (GORM 会执行软删除) +func (r *gormPigBatchRepository) DeletePigBatch(id uint) error { + result := r.db.Delete(&models.PigBatch{}, id) + if result.Error != nil { + return result.Error + } + if result.RowsAffected == 0 { + return errors.New("未找到要删除的猪批次") // 明确返回错误 + } + return nil +} + +// ListPigBatches 批量查询猪批次,支持根据 IsActive 筛选 +func (r *gormPigBatchRepository) ListPigBatches(isActive *bool) ([]*models.PigBatch, error) { + var batches []*models.PigBatch + query := r.db.Model(&models.PigBatch{}) + + if isActive != nil { + if *isActive { + // 查询活跃的批次:状态不是已出售或已归档 + query = query.Where("status NOT IN (?) ", []models.PigBatchStatus{models.BatchStatusSold, models.BatchStatusArchived}) + } else { + // 查询非活跃的批次:状态是已出售或已归档 + query = query.Where("status IN (?) ", []models.PigBatchStatus{models.BatchStatusSold, models.BatchStatusArchived}) + } + } + + if err := query.Find(&batches).Error; err != nil { + return nil, err + } + return batches, nil +}