From 324a533c94e1dbe22526ac7fab5348e0c2ea11c6 Mon Sep 17 00:00:00 2001 From: huang <1724659546@qq.com> Date: Thu, 23 Oct 2025 11:29:48 +0800 Subject: [PATCH] =?UTF-8?q?=E7=8C=AA=E7=BE=A4=E7=9B=B8=E5=85=B3=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=A2=9E=E5=8A=A0=E5=BD=93=E5=89=8D=E6=80=BB=E9=87=8F?= =?UTF-8?q?=E5=92=8C=E5=BD=93=E5=89=8D=E6=80=BB=E5=AD=98=E6=A0=8F=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs.go | 8 +++ docs/swagger.json | 8 +++ docs/swagger.yaml | 6 ++ internal/app/dto/pig_batch_dto.go | 22 +++--- internal/app/service/pig_batch_service.go | 67 ++++++++++++----- internal/domain/pig/pig_batch_service.go | 61 +--------------- .../pig/pig_batch_service_pen_transfer.go | 72 +++++++++++++++++++ 7 files changed, 158 insertions(+), 86 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 7fc54ea..460adbc 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -4906,6 +4906,14 @@ const docTemplate = `{ "description": "创建时间", "type": "string" }, + "currentTotalPigsInPens": { + "description": "当前存栏总数", + "type": "integer" + }, + "currentTotalQuantity": { + "description": "当前总数", + "type": "integer" + }, "end_date": { "description": "批次结束日期", "type": "string" diff --git a/docs/swagger.json b/docs/swagger.json index 77b9d90..067a487 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -4898,6 +4898,14 @@ "description": "创建时间", "type": "string" }, + "currentTotalPigsInPens": { + "description": "当前存栏总数", + "type": "integer" + }, + "currentTotalQuantity": { + "description": "当前总数", + "type": "integer" + }, "end_date": { "description": "批次结束日期", "type": "string" diff --git a/docs/swagger.yaml b/docs/swagger.yaml index ca941fa..0953c91 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -662,6 +662,12 @@ definitions: create_time: description: 创建时间 type: string + currentTotalPigsInPens: + description: 当前存栏总数 + type: integer + currentTotalQuantity: + description: 当前总数 + type: integer end_date: description: 批次结束日期 type: string diff --git a/internal/app/dto/pig_batch_dto.go b/internal/app/dto/pig_batch_dto.go index 8485d87..64f2c25 100644 --- a/internal/app/dto/pig_batch_dto.go +++ b/internal/app/dto/pig_batch_dto.go @@ -32,16 +32,18 @@ type PigBatchQueryDTO struct { // 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"` // 更新时间 + 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"` // 是否活跃 + CurrentTotalQuantity int `json:"currentTotalQuantity"` // 当前总数 + CurrentTotalPigsInPens int `json:"currentTotalPigsInPens"` // 当前存栏总数 + CreateTime time.Time `json:"create_time"` // 创建时间 + UpdateTime time.Time `json:"update_time"` // 更新时间 } // AssignEmptyPensToBatchRequest 用于为猪批次分配空栏的请求体 diff --git a/internal/app/service/pig_batch_service.go b/internal/app/service/pig_batch_service.go index 4f362c5..9ba4d3c 100644 --- a/internal/app/service/pig_batch_service.go +++ b/internal/app/service/pig_batch_service.go @@ -57,21 +57,23 @@ func NewPigBatchService(domainService domain_pig.PigBatchService, logger *logs.L } // toPigBatchResponseDTO 负责将领域模型转换为应用层DTO,这个职责保留在应用层。 -func (s *pigBatchService) toPigBatchResponseDTO(batch *models.PigBatch) *dto.PigBatchResponseDTO { +func (s *pigBatchService) toPigBatchResponseDTO(batch *models.PigBatch, currentTotalQuantity, currentTotalPigsInPens int) *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(), - CreateTime: batch.CreatedAt, - UpdateTime: batch.UpdatedAt, + ID: batch.ID, + BatchNumber: batch.BatchNumber, + OriginType: batch.OriginType, + StartDate: batch.StartDate, + EndDate: batch.EndDate, + InitialCount: batch.InitialCount, + Status: batch.Status, + IsActive: batch.IsActive(), + CurrentTotalQuantity: currentTotalQuantity, + CurrentTotalPigsInPens: currentTotalPigsInPens, + CreateTime: batch.CreatedAt, + UpdateTime: batch.UpdatedAt, } } @@ -94,7 +96,7 @@ func (s *pigBatchService) CreatePigBatch(operatorID uint, dto *dto.PigBatchCreat } // 3. 领域模型 -> DTO - return s.toPigBatchResponseDTO(createdBatch), nil + return s.toPigBatchResponseDTO(createdBatch, dto.InitialCount, 0), nil } // GetPigBatch 从领域服务获取数据并转换为DTO,同时处理错误转换。 @@ -104,8 +106,17 @@ func (s *pigBatchService) GetPigBatch(id uint) (*dto.PigBatchResponseDTO, error) s.logger.Warnf("应用层: 获取猪批次失败, ID: %d, 错误: %v", id, err) return nil, MapDomainError(err) } - - return s.toPigBatchResponseDTO(batch), nil + currentTotalQuantity, err := s.domainService.GetCurrentPigsInPen(id) + if err != nil { + s.logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", id, err) + return nil, MapDomainError(err) + } + currentTotalPigsInPens, err := s.domainService.GetCurrentPigsInPen(id) + if err != nil { + s.logger.Warnf("应用层: 获取猪批次存栏总数失败, ID: %d, 错误: %v", id, err) + return nil, MapDomainError(err) + } + return s.toPigBatchResponseDTO(batch, currentTotalQuantity, currentTotalPigsInPens), nil } // UpdatePigBatch 协调获取、更新和保存的流程,并处理错误转换。 @@ -144,8 +155,20 @@ func (s *pigBatchService) UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (* return nil, MapDomainError(err) } - // 4. 转换并返回结果 - return s.toPigBatchResponseDTO(updatedBatch), nil + // 4. 填充猪群信息 + currentTotalQuantity, err := s.domainService.GetCurrentPigsInPen(id) + if err != nil { + s.logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", id, err) + return nil, MapDomainError(err) + } + currentTotalPigsInPens, err := s.domainService.GetCurrentPigsInPen(id) + if err != nil { + s.logger.Warnf("应用层: 获取猪批次存栏总数失败, ID: %d, 错误: %v", id, err) + return nil, MapDomainError(err) + } + + // 5. 转换并返回结果 + return s.toPigBatchResponseDTO(updatedBatch, currentTotalQuantity, currentTotalPigsInPens), nil } // DeletePigBatch 将删除操作委托给领域服务,并转换领域错误为应用层错误。 @@ -168,7 +191,17 @@ func (s *pigBatchService) ListPigBatches(isActive *bool) ([]*dto.PigBatchRespons var responseDTOs []*dto.PigBatchResponseDTO for _, batch := range batches { - responseDTOs = append(responseDTOs, s.toPigBatchResponseDTO(batch)) + currentTotalQuantity, err := s.domainService.GetCurrentPigsInPen(batch.ID) + if err != nil { + s.logger.Warnf("应用层: 获取猪批次总数失败, ID: %d, 错误: %v", batch.ID, err) + return nil, MapDomainError(err) + } + currentTotalPigsInPens, err := s.domainService.GetCurrentPigsInPen(batch.ID) + if err != nil { + s.logger.Warnf("应用层: 获取猪批次存栏总数失败, ID: %d, 错误: %v", batch.ID, err) + return nil, MapDomainError(err) + } + responseDTOs = append(responseDTOs, s.toPigBatchResponseDTO(batch, currentTotalQuantity, currentTotalPigsInPens)) } return responseDTOs, nil diff --git a/internal/domain/pig/pig_batch_service.go b/internal/domain/pig/pig_batch_service.go index 004c9a3..dbe88c1 100644 --- a/internal/domain/pig/pig_batch_service.go +++ b/internal/domain/pig/pig_batch_service.go @@ -6,7 +6,6 @@ import ( "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" - "gorm.io/gorm" ) // --- 业务错误定义 --- @@ -60,6 +59,8 @@ type PigBatchService interface { GetCurrentPigQuantity(batchID uint) (int, error) // GetCurrentPigsInPen 获取指定猪栏的当前存栏量。 GetCurrentPigsInPen(penID uint) (int, error) + // GetTotalPigsInPensForBatch 获取指定猪群下所有猪栏的当前总存栏数 + GetTotalPigsInPensForBatch(batchID uint) (int, error) UpdatePigBatchQuantity(operatorID uint, batchID uint, changeType models.LogChangeType, changeAmount int, changeReason string, happenedAt time.Time) error @@ -120,61 +121,3 @@ func NewPigBatchService( sickSvc: sickSvc, } } - -func (s *pigBatchService) RemoveEmptyPenFromBatch(batchID uint, penID uint) error { - return s.uow.ExecuteInTransaction(func(tx *gorm.DB) error { - // 1. 检查猪批次是否存在且活跃 - batch, err := s.pigBatchRepo.GetPigBatchByIDTx(tx, batchID) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return ErrPigBatchNotFound - } - return err - } - if !batch.IsActive() { - return ErrPigBatchNotActive - } - - // 2. 检查猪栏是否存在 - pen, err := s.transferSvc.GetPenByID(tx, penID) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return ErrPenNotFound - } - return err - } - - // 3. 检查猪栏是否与当前批次关联 - if pen.PigBatchID == nil || *pen.PigBatchID != batchID { - return ErrPenNotAssociatedWithBatch - } - - // 4. 检查猪栏是否为空 - pigsInPen, err := s.transferSvc.GetCurrentPigsInPen(tx, penID) - if err != nil { - return err - } - if pigsInPen > 0 { - return ErrPenNotEmpty - } - - // 5. 释放猪栏 (将 pig_batch_id 设置为 nil,状态设置为空闲) - if err := s.transferSvc.ReleasePen(tx, penID); err != nil { - return err - } - return nil - }) -} - -func (s *pigBatchService) GetCurrentPigsInPen(penID uint) (int, error) { - var currentPigs int - err := s.uow.ExecuteInTransaction(func(tx *gorm.DB) error { - pigs, err := s.transferSvc.GetCurrentPigsInPen(tx, penID) - if err != nil { - return err - } - currentPigs = pigs - return nil - }) - return currentPigs, err -} diff --git a/internal/domain/pig/pig_batch_service_pen_transfer.go b/internal/domain/pig/pig_batch_service_pen_transfer.go index 0ef76a7..874f761 100644 --- a/internal/domain/pig/pig_batch_service_pen_transfer.go +++ b/internal/domain/pig/pig_batch_service_pen_transfer.go @@ -381,3 +381,75 @@ func (s *pigBatchService) ReclassifyPenToNewBatch(fromBatchID uint, toBatchID ui return nil }) } + +func (s *pigBatchService) RemoveEmptyPenFromBatch(batchID uint, penID uint) error { + return s.uow.ExecuteInTransaction(func(tx *gorm.DB) error { + // 1. 检查猪批次是否存在且活跃 + batch, err := s.pigBatchRepo.GetPigBatchByIDTx(tx, batchID) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return ErrPigBatchNotFound + } + return err + } + if !batch.IsActive() { + return ErrPigBatchNotActive + } + + // 2. 检查猪栏是否存在 + pen, err := s.transferSvc.GetPenByID(tx, penID) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return ErrPenNotFound + } + return err + } + + // 3. 检查猪栏是否与当前批次关联 + if pen.PigBatchID == nil || *pen.PigBatchID != batchID { + return ErrPenNotAssociatedWithBatch + } + + // 4. 检查猪栏是否为空 + pigsInPen, err := s.transferSvc.GetCurrentPigsInPen(tx, penID) + if err != nil { + return err + } + if pigsInPen > 0 { + return ErrPenNotEmpty + } + + // 5. 释放猪栏 (将 pig_batch_id 设置为 nil,状态设置为空闲) + if err := s.transferSvc.ReleasePen(tx, penID); err != nil { + return err + } + return nil + }) +} + +func (s *pigBatchService) GetCurrentPigsInPen(penID uint) (int, error) { + var currentPigs int + err := s.uow.ExecuteInTransaction(func(tx *gorm.DB) error { + pigs, err := s.transferSvc.GetCurrentPigsInPen(tx, penID) + if err != nil { + return err + } + currentPigs = pigs + return nil + }) + return currentPigs, err +} + +// GetTotalPigsInPensForBatch 实现了获取指定猪群下所有猪栏的当前总存栏数的逻辑。 +func (s *pigBatchService) GetTotalPigsInPensForBatch(batchID uint) (int, error) { + var totalPigs int + err := s.uow.ExecuteInTransaction(func(tx *gorm.DB) error { + pigs, err := s.transferSvc.GetTotalPigsInPensForBatchTx(tx, batchID) + if err != nil { + return err + } + totalPigs = pigs + return nil + }) + return totalPigs, err +}