issue_29 #32
| @@ -37,19 +37,20 @@ import ( | |||||||
|  |  | ||||||
| // API 结构体定义了 HTTP 服务器及其依赖 | // API 结构体定义了 HTTP 服务器及其依赖 | ||||||
| type API struct { | type API struct { | ||||||
| 	engine              *gin.Engine                   // Gin 引擎实例,用于处理 HTTP 请求 | 	engine              *gin.Engine                    // Gin 引擎实例,用于处理 HTTP 请求 | ||||||
| 	logger              *logs.Logger                  // 日志记录器,用于输出日志信息 | 	logger              *logs.Logger                   // 日志记录器,用于输出日志信息 | ||||||
| 	userRepo            repository.UserRepository     // 用户数据仓库接口,用于用户数据操作 | 	userRepo            repository.UserRepository      // 用户数据仓库接口,用于用户数据操作 | ||||||
| 	tokenService        token.TokenService            // Token 服务接口,用于 JWT token 的生成和解析 | 	tokenService        token.TokenService             // Token 服务接口,用于 JWT token 的生成和解析 | ||||||
| 	auditService        audit.Service                 // 审计服务,用于记录用户操作 | 	auditService        audit.Service                  // 审计服务,用于记录用户操作 | ||||||
| 	httpServer          *http.Server                  // 标准库的 HTTP 服务器实例,用于启动和停止服务 | 	httpServer          *http.Server                   // 标准库的 HTTP 服务器实例,用于启动和停止服务 | ||||||
| 	config              config.ServerConfig           // API 服务器的配置,使用 infra/config 包中的 ServerConfig | 	config              config.ServerConfig            // API 服务器的配置,使用 infra/config 包中的 ServerConfig | ||||||
| 	userController      *user.Controller              // 用户控制器实例 | 	userController      *user.Controller               // 用户控制器实例 | ||||||
| 	deviceController    *device.Controller            // 设备控制器实例 | 	deviceController    *device.Controller             // 设备控制器实例 | ||||||
| 	planController      *plan.Controller              // 计划控制器实例 | 	planController      *plan.Controller               // 计划控制器实例 | ||||||
| 	pigFarmController   *management.PigFarmController // 猪场管理控制器实例 | 	pigFarmController   *management.PigFarmController  // 猪场管理控制器实例 | ||||||
| 	listenHandler       webhook.ListenHandler         // 设备上行事件监听器 | 	pigBatchController  *management.PigBatchController // 猪批次控制器实例 | ||||||
| 	analysisTaskManager *task.AnalysisPlanTaskManager // 计划触发器管理器实例 | 	listenHandler       webhook.ListenHandler          // 设备上行事件监听器 | ||||||
|  | 	analysisTaskManager *task.AnalysisPlanTaskManager  // 计划触发器管理器实例 | ||||||
| } | } | ||||||
|  |  | ||||||
| // NewAPI 创建并返回一个新的 API 实例 | // NewAPI 创建并返回一个新的 API 实例 | ||||||
| @@ -62,6 +63,7 @@ func NewAPI(cfg config.ServerConfig, | |||||||
| 	deviceTemplateRepository repository.DeviceTemplateRepository, // 添加设备模板仓库 | 	deviceTemplateRepository repository.DeviceTemplateRepository, // 添加设备模板仓库 | ||||||
| 	planRepository repository.PlanRepository, | 	planRepository repository.PlanRepository, | ||||||
| 	pigFarmService service.PigFarmService, | 	pigFarmService service.PigFarmService, | ||||||
|  | 	pigBatchService service.PigBatchService, // 添加猪批次服务 | ||||||
| 	userActionLogRepository repository.UserActionLogRepository, | 	userActionLogRepository repository.UserActionLogRepository, | ||||||
| 	tokenService token.TokenService, | 	tokenService token.TokenService, | ||||||
| 	auditService audit.Service, // 注入审计服务 | 	auditService audit.Service, // 注入审计服务 | ||||||
| @@ -96,6 +98,8 @@ func NewAPI(cfg config.ServerConfig, | |||||||
| 		planController: plan.NewController(logger, planRepository, analysisTaskManager), | 		planController: plan.NewController(logger, planRepository, analysisTaskManager), | ||||||
| 		// 在 NewAPI 中初始化猪场管理控制器 | 		// 在 NewAPI 中初始化猪场管理控制器 | ||||||
| 		pigFarmController: management.NewPigFarmController(logger, pigFarmService), | 		pigFarmController: management.NewPigFarmController(logger, pigFarmService), | ||||||
|  | 		// 在 NewAPI 中初始化猪批次控制器 | ||||||
|  | 		pigBatchController: management.NewPigBatchController(logger, pigBatchService), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	api.setupRoutes() // 设置所有路由 | 	api.setupRoutes() // 设置所有路由 | ||||||
| @@ -221,6 +225,17 @@ func (a *API) setupRoutes() { | |||||||
| 		} | 		} | ||||||
| 		a.logger.Info("猪圈相关接口注册成功 (需要认证和审计)") | 		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("猪批次相关接口注册成功 (需要认证和审计)") | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										190
									
								
								internal/app/controller/management/pig_batch_controller.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								internal/app/controller/management/pig_batch_controller.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								internal/app/dto/pig_batch_dto.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								internal/app/dto/pig_batch_dto.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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"`   // 更新时间 | ||||||
|  | } | ||||||
							
								
								
									
										176
									
								
								internal/app/service/pig_batch_service.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								internal/app/service/pig_batch_service.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  | } | ||||||
| @@ -72,9 +72,11 @@ func NewApplication(configPath string) (*Application, error) { | |||||||
| 	deviceCommandLogRepo := repository.NewGormDeviceCommandLogRepository(storage.GetDB()) | 	deviceCommandLogRepo := repository.NewGormDeviceCommandLogRepository(storage.GetDB()) | ||||||
| 	pendingCollectionRepo := repository.NewGormPendingCollectionRepository(storage.GetDB()) | 	pendingCollectionRepo := repository.NewGormPendingCollectionRepository(storage.GetDB()) | ||||||
| 	userActionLogRepo := repository.NewGormUserActionLogRepository(storage.GetDB()) | 	userActionLogRepo := repository.NewGormUserActionLogRepository(storage.GetDB()) | ||||||
|  | 	pigBatchRepo := repository.NewGormPigBatchRepository(storage.GetDB()) | ||||||
|  |  | ||||||
| 	// --- 业务逻辑处理器初始化 --- | 	// --- 业务逻辑处理器初始化 --- | ||||||
| 	pigFarmService := service.NewPigFarmService(pigFarmRepo, logger) | 	pigFarmService := service.NewPigFarmService(pigFarmRepo, logger) | ||||||
|  | 	pigBatchService := service.NewPigBatchService(pigBatchRepo, logger) | ||||||
|  |  | ||||||
| 	// 初始化审计服务 | 	// 初始化审计服务 | ||||||
| 	auditService := audit.NewService(userActionLogRepo, logger) | 	auditService := audit.NewService(userActionLogRepo, logger) | ||||||
| @@ -121,6 +123,7 @@ func NewApplication(configPath string) (*Application, error) { | |||||||
| 		deviceTemplateRepo, | 		deviceTemplateRepo, | ||||||
| 		planRepo, | 		planRepo, | ||||||
| 		pigFarmService, | 		pigFarmService, | ||||||
|  | 		pigBatchService, | ||||||
| 		userActionLogRepo, | 		userActionLogRepo, | ||||||
| 		tokenService, | 		tokenService, | ||||||
| 		auditService, | 		auditService, | ||||||
|   | |||||||
							
								
								
									
										89
									
								
								internal/infra/repository/pig_batch_repository.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								internal/infra/repository/pig_batch_repository.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user