diff --git a/internal/app/controller/management/pig_farm_controller.go b/internal/app/controller/management/pig_farm_controller.go index 0d78048..45f311c 100644 --- a/internal/app/controller/management/pig_farm_controller.go +++ b/internal/app/controller/management/pig_farm_controller.go @@ -53,12 +53,7 @@ func (c *PigFarmController) CreatePigHouse(ctx echo.Context) error { return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪舍失败", action, "业务逻辑失败", req) } - resp := dto.PigHouseResponse{ - ID: house.ID, - Name: house.Name, - Description: house.Description, - } - return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", house, action, "创建成功", house) } // GetPigHouse godoc @@ -86,12 +81,7 @@ func (c *PigFarmController) GetPigHouse(ctx echo.Context) error { return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪舍失败", action, "业务逻辑失败", id) } - resp := dto.PigHouseResponse{ - ID: house.ID, - Name: house.Name, - Description: house.Description, - } - return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", house, action, "获取成功", house) } // ListPigHouses godoc @@ -110,16 +100,7 @@ func (c *PigFarmController) ListPigHouses(ctx echo.Context) error { return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil) } - var resp []dto.PigHouseResponse - for _, house := range houses { - resp = append(resp, dto.PigHouseResponse{ - ID: house.ID, - Name: house.Name, - Description: house.Description, - }) - } - - return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", houses, action, "获取成功", houses) } // UpdatePigHouse godoc @@ -154,12 +135,7 @@ func (c *PigFarmController) UpdatePigHouse(ctx echo.Context) error { return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req) } - resp := dto.PigHouseResponse{ - ID: house.ID, - Name: house.Name, - Description: house.Description, - } - return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", house, action, "更新成功", house) } // DeletePigHouse godoc @@ -222,14 +198,7 @@ func (c *PigFarmController) CreatePen(ctx echo.Context) error { return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪栏失败", action, "业务逻辑失败", req) } - resp := dto.PenResponse{ - ID: pen.ID, - PenNumber: pen.PenNumber, - HouseID: pen.HouseID, - Capacity: pen.Capacity, - Status: pen.Status, - } - return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", pen, action, "创建成功", pen) } // GetPen godoc @@ -312,15 +281,7 @@ func (c *PigFarmController) UpdatePen(ctx echo.Context) error { return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req) } - resp := dto.PenResponse{ - ID: pen.ID, - PenNumber: pen.PenNumber, - HouseID: pen.HouseID, - Capacity: pen.Capacity, - Status: pen.Status, - PigBatchID: pen.PigBatchID, - } - return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", pen, action, "更新成功", pen) } // DeletePen godoc @@ -388,13 +349,5 @@ func (c *PigFarmController) UpdatePenStatus(ctx echo.Context) error { return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新猪栏状态失败", action, err.Error(), id) } - resp := dto.PenResponse{ - ID: pen.ID, - PenNumber: pen.PenNumber, - HouseID: pen.HouseID, - Capacity: pen.Capacity, - Status: pen.Status, - PigBatchID: pen.PigBatchID, - } - return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp) + return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", pen, action, "更新成功", pen) } diff --git a/internal/app/service/pig_farm_service.go b/internal/app/service/pig_farm_service.go index 65bbb97..b24f65f 100644 --- a/internal/app/service/pig_farm_service.go +++ b/internal/app/service/pig_farm_service.go @@ -16,20 +16,20 @@ import ( // PigFarmService 提供了猪场资产管理的业务逻辑 type PigFarmService interface { // PigHouse methods - CreatePigHouse(name, description string) (*models.PigHouse, error) - GetPigHouseByID(id uint) (*models.PigHouse, error) - ListPigHouses() ([]models.PigHouse, error) - UpdatePigHouse(id uint, name, description string) (*models.PigHouse, error) + CreatePigHouse(name, description string) (*dto.PigHouseResponse, error) + GetPigHouseByID(id uint) (*dto.PigHouseResponse, error) + ListPigHouses() ([]dto.PigHouseResponse, error) + UpdatePigHouse(id uint, name, description string) (*dto.PigHouseResponse, error) DeletePigHouse(id uint) error // Pen methods - CreatePen(penNumber string, houseID uint, capacity int) (*models.Pen, error) + CreatePen(penNumber string, houseID uint, capacity int) (*dto.PenResponse, error) GetPenByID(id uint) (*dto.PenResponse, error) ListPens() ([]*dto.PenResponse, error) - UpdatePen(id uint, penNumber string, houseID uint, capacity int, status models.PenStatus) (*models.Pen, error) + UpdatePen(id uint, penNumber string, houseID uint, capacity int, status models.PenStatus) (*dto.PenResponse, error) DeletePen(id uint) error // UpdatePenStatus 更新猪栏状态 - UpdatePenStatus(id uint, newStatus models.PenStatus) (*models.Pen, error) + UpdatePenStatus(id uint, newStatus models.PenStatus) (*dto.PenResponse, error) } type pigFarmService struct { @@ -60,24 +60,51 @@ func NewPigFarmService(farmRepository repository.PigFarmRepository, // --- PigHouse Implementation --- -func (s *pigFarmService) CreatePigHouse(name, description string) (*models.PigHouse, error) { +func (s *pigFarmService) CreatePigHouse(name, description string) (*dto.PigHouseResponse, error) { house := &models.PigHouse{ Name: name, Description: description, } err := s.farmRepository.CreatePigHouse(house) - return house, err + if err != nil { + return nil, err + } + return &dto.PigHouseResponse{ + ID: house.ID, + Name: house.Name, + Description: house.Description, + }, nil } -func (s *pigFarmService) GetPigHouseByID(id uint) (*models.PigHouse, error) { - return s.farmRepository.GetPigHouseByID(id) +func (s *pigFarmService) GetPigHouseByID(id uint) (*dto.PigHouseResponse, error) { + house, err := s.farmRepository.GetPigHouseByID(id) + if err != nil { + return nil, err + } + return &dto.PigHouseResponse{ + ID: house.ID, + Name: house.Name, + Description: house.Description, + }, nil } -func (s *pigFarmService) ListPigHouses() ([]models.PigHouse, error) { - return s.farmRepository.ListPigHouses() +func (s *pigFarmService) ListPigHouses() ([]dto.PigHouseResponse, error) { + houses, err := s.farmRepository.ListPigHouses() + if err != nil { + return nil, err + } + var resp []dto.PigHouseResponse + for _, house := range houses { + resp = append(resp, dto.PigHouseResponse{ + ID: house.ID, + Name: house.Name, + Description: house.Description, + }) + } + return resp, nil } -func (s *pigFarmService) UpdatePigHouse(id uint, name, description string) (*models.PigHouse, error) { +func (s *pigFarmService) UpdatePigHouse(id uint, name, description string) (*dto.PigHouseResponse, error) { house := &models.PigHouse{ Model: gorm.Model{ID: id}, Name: name, @@ -91,7 +118,15 @@ func (s *pigFarmService) UpdatePigHouse(id uint, name, description string) (*mod return nil, ErrHouseNotFound } // 返回更新后的完整信息 - return s.farmRepository.GetPigHouseByID(id) + updatedHouse, err := s.farmRepository.GetPigHouseByID(id) + if err != nil { + return nil, err + } + return &dto.PigHouseResponse{ + ID: updatedHouse.ID, + Name: updatedHouse.Name, + Description: updatedHouse.Description, + }, nil } func (s *pigFarmService) DeletePigHouse(id uint) error { @@ -117,7 +152,7 @@ func (s *pigFarmService) DeletePigHouse(id uint) error { // --- Pen Implementation --- -func (s *pigFarmService) CreatePen(penNumber string, houseID uint, capacity int) (*models.Pen, error) { +func (s *pigFarmService) CreatePen(penNumber string, houseID uint, capacity int) (*dto.PenResponse, error) { // 业务逻辑:验证所属猪舍是否存在 _, err := s.farmRepository.GetPigHouseByID(houseID) if err != nil { @@ -134,7 +169,16 @@ func (s *pigFarmService) CreatePen(penNumber string, houseID uint, capacity int) Status: models.PenStatusEmpty, } err = s.penRepository.CreatePen(pen) - return pen, err + if err != nil { + return nil, err + } + return &dto.PenResponse{ + ID: pen.ID, + PenNumber: pen.PenNumber, + HouseID: pen.HouseID, + Capacity: pen.Capacity, + Status: pen.Status, + }, nil } func (s *pigFarmService) GetPenByID(id uint) (*dto.PenResponse, error) { @@ -197,7 +241,7 @@ func (s *pigFarmService) ListPens() ([]*dto.PenResponse, error) { return response, nil } -func (s *pigFarmService) UpdatePen(id uint, penNumber string, houseID uint, capacity int, status models.PenStatus) (*models.Pen, error) { +func (s *pigFarmService) UpdatePen(id uint, penNumber string, houseID uint, capacity int, status models.PenStatus) (*dto.PenResponse, error) { // 业务逻辑:验证所属猪舍是否存在 _, err := s.farmRepository.GetPigHouseByID(houseID) if err != nil { @@ -222,7 +266,18 @@ func (s *pigFarmService) UpdatePen(id uint, penNumber string, houseID uint, capa return nil, ErrPenNotFound } // 返回更新后的完整信息 - return s.penRepository.GetPenByID(id) + updatedPen, err := s.penRepository.GetPenByID(id) + if err != nil { + return nil, err + } + return &dto.PenResponse{ + ID: updatedPen.ID, + PenNumber: updatedPen.PenNumber, + HouseID: updatedPen.HouseID, + Capacity: updatedPen.Capacity, + Status: updatedPen.Status, + PigBatchID: updatedPen.PigBatchID, + }, nil } func (s *pigFarmService) DeletePen(id uint) error { @@ -260,7 +315,7 @@ func (s *pigFarmService) DeletePen(id uint) error { } // UpdatePenStatus 更新猪栏状态 -func (s *pigFarmService) UpdatePenStatus(id uint, newStatus models.PenStatus) (*models.Pen, error) { +func (s *pigFarmService) UpdatePenStatus(id uint, newStatus models.PenStatus) (*dto.PenResponse, error) { var updatedPen *models.Pen err := s.uow.ExecuteInTransaction(func(tx *gorm.DB) error { pen, err := s.penRepository.GetPenByIDTx(tx, id) @@ -310,5 +365,12 @@ func (s *pigFarmService) UpdatePenStatus(id uint, newStatus models.PenStatus) (* if err != nil { return nil, err } - return updatedPen, nil + return &dto.PenResponse{ + ID: updatedPen.ID, + PenNumber: updatedPen.PenNumber, + HouseID: updatedPen.HouseID, + Capacity: updatedPen.Capacity, + Status: updatedPen.Status, + PigBatchID: updatedPen.PigBatchID, + }, nil } diff --git a/openspec/changes/refactor-business-logic-layering/design.md b/openspec/changes/refactor-business-logic-layering/design.md index a10eac0..3a8f58a 100644 --- a/openspec/changes/refactor-business-logic-layering/design.md +++ b/openspec/changes/refactor-business-logic-layering/design.md @@ -162,3 +162,70 @@ ### Open Questions - 暂无。 + +--- + +## `pig-farm` 模块重构设计 + +### Context + +与 `monitor` 模块类似, `pig_farm_controller.go` 当前包含了将 `service` 层返回的 `models.PigHouse` 和 `models.Pen` +实体手动转换为 `dto.PigHouseResponse` 和 `dto.PenResponse` 的逻辑。此外, +控制器还处理了部分本应由服务层处理的业务错误判断 (例如 `service.ErrHouseNotFound`)。 + +这种模式导致了与 `monitor` 模块相同的职责不清、代码重复和可测试性差的问题。 + +### Goals / Non-Goals + +#### Goals + +- **迁移数据转换逻辑**: 将 `pig-farm` 模块中所有的数据转换逻辑从控制器层 (`pig_farm_controller.go`) 迁移到服务层 ( + `pig_farm_service.go`)。 +- **统一服务层接口**: 修改 `PigFarmService` 接口, 使其直接返回响应 DTO (`dto.XxxResponse`)。 +- **简化控制器**: 精简 `PigFarmController` 中的代码, 移除所有 `models` 到 `dto` 的转换代码, 使其直接使用服务层返回的 + DTO。 + +#### Non-Goals + +- **不修改业务逻辑**: 本次重构严格保证业务逻辑不变。服务层将精确复制控制器层现有的转换逻辑, 不增加或减少任何字段。 +- **不改变 API 契约**: API 的请求和响应对最终用户保持完全一致。 + +### Decisions + +- **决策:在服务层完成 `models` 到 `dto` 的转换** + - **理由**: 与其他模块保持一致, 将数据转换视为服务层业务逻辑的一部分。这确保了服务接口的稳定性和调用方的便利性。 + - **具体实现**: `pig_farm_service.go` 中的方法在从 `repository` 获取 `models` 实体后, 将其转换为对应的 `dto` 再返回。 + +### Migration Plan + +1. **修改 `internal/app/service/pig_farm_service.go`** + - **更新 `PigFarmService` 接口**: + - `CreatePigHouse(...) (*models.PigHouse, error)` -> `CreatePigHouse(...) (*dto.PigHouseResponse, error)` + - `GetPigHouseByID(...) (*models.PigHouse, error)` -> `GetPigHouseByID(...) (*dto.PigHouseResponse, error)` + - `ListPigHouses(...) ([]models.PigHouse, error)` -> `ListPigHouses(...) ([]dto.PigHouseResponse, error)` + - `UpdatePigHouse(...) (*models.PigHouse, error)` -> `UpdatePigHouse(...) (*dto.PigHouseResponse, error)` + - `CreatePen(...) (*models.Pen, error)` -> `CreatePen(...) (*dto.PenResponse, error)` + - `UpdatePen(...) (*models.Pen, error)` -> `UpdatePen(...) (*dto.PenResponse, error)` + - `UpdatePenStatus(...) (*models.Pen, error)` -> `UpdatePenStatus(...) (*dto.PenResponse, error)` + - **实现数据转换**: + - 在上述每个方法的实现中, 在从 `repository` 获得 `models` 对象后, 添加代码将其转换为对应的 `dto.XxxResponse` 对象。 + - 转换逻辑将严格按照 `pig_farm_controller.go` 中现有的实现, 确保字段一一对应, 无任何增删。 + - 例如, 在 `UpdatePigHouse` 中: + + +2. **修改 `internal/app/controller/management/pig_farm_controller.go`** + - **移除 DTO 转换代码**: + - 在 `CreatePigHouse`, `GetPigHouse`, `UpdatePigHouse` 方法中, 删除手动创建 `dto.PigHouseResponse` 的代码。 + - 在 `ListPigHouses` 方法中, 删除用于遍历 `houses` 并创建 `[]dto.PigHouseResponse` 的 `for` 循环。 + - 在 `CreatePen`, `UpdatePen`, `UpdatePenStatus` 方法中, 删除手动创建 `dto.PenResponse` 的代码。 + - **更新服务调用**: + - 将服务层返回的 DTO 对象直接传递给 `controller.SendSuccessWithAudit`。 + + +3. **验证** + - 通过代码审查确认转换逻辑被精确迁移。 + - 运行相关测试, 并通过手动 API 测试验证端点行为与重构前完全一致。 + +### Open Questions + +- 暂无。 diff --git a/openspec/changes/refactor-business-logic-layering/tasks.md b/openspec/changes/refactor-business-logic-layering/tasks.md index e8b8ddb..23edf1c 100644 --- a/openspec/changes/refactor-business-logic-layering/tasks.md +++ b/openspec/changes/refactor-business-logic-layering/tasks.md @@ -51,17 +51,17 @@ ### 2.3 `pig-farm` 模块 -- [ ] 2.3.1 **修改 `internal/app/service/pig_farm_service.go`:** - - [ ] 将 `CreatePigHouse`, `GetPigHouseByID`, `ListPigHouses`, `UpdatePigHouse`, `CreatePen`, `GetPenByID`, +- [x] 2.3.1 **修改 `internal/app/service/pig_farm_service.go`:** + - [x] 将 `CreatePigHouse`, `GetPigHouseByID`, `ListPigHouses`, `UpdatePigHouse`, `CreatePen`, `GetPenByID`, `ListPens`, `UpdatePen`, `UpdatePenStatus` 方法的返回值 `models.Xxx` 或 `[]models.Xxx` 替换为 `dto.XxxResponse` 或 `[]dto.XxxResponse`。 - - [ ] 在服务层内部将 `repository` 返回的 `models` 对象转换为 `dto.XxxResponse`。 - - [ ] 将控制器中处理服务层特定业务错误(如 `service.ErrHouseNotFound`)的逻辑移入服务层,服务层应返回更抽象的错误或直接返回 + - [x] 在服务层内部将 `repository` 返回的 `models` 对象转换为 `dto.XxxResponse`。 + - [x] 将控制器中处理服务层特定业务错误(如 `service.ErrHouseNotFound`)的逻辑移入服务层,服务层应返回更抽象的错误或直接返回 DTO。 -- [ ] 2.3.2 **修改 `internal/app/controller/management/pig_farm_controller.go`:** - - [ ] 移除控制器中手动将领域实体转换为 DTO 的逻辑。 - - [ ] 移除控制器中直接处理服务层特定业务错误类型的逻辑。 - - [ ] 调整服务层方法的调用,使其直接处理服务层返回的 `dto.XxxResponse`。 +- [x] 2.3.2 **修改 `internal/app/controller/management/pig_farm_controller.go`:** + - [x] 移除控制器中手动将领域实体转换为 DTO 的逻辑。 + - [x] 移除控制器中直接处理服务层特定业务错误类型的逻辑。 + - [x] 调整服务层方法的调用,使其直接处理服务层返回的 `dto.XxxResponse`。 ### 2.4 `plan` 模块