重构配方类服务层

This commit is contained in:
2025-11-23 15:16:45 +08:00
parent 1b2e211bfa
commit 1200f36d14
16 changed files with 815 additions and 705 deletions

View File

@@ -56,7 +56,6 @@ type API struct {
monitorController *monitor.Controller // 数据监控控制器实例 monitorController *monitor.Controller // 数据监控控制器实例
healthController *health.Controller // 健康检查控制器实例 healthController *health.Controller // 健康检查控制器实例
alarmController *alarm.ThresholdAlarmController // 阈值告警控制器 alarmController *alarm.ThresholdAlarmController // 阈值告警控制器
feedController *feed.Controller // 饲料管理控制器实例
nutrientController *feed.NutrientController // 营养控制器实例 nutrientController *feed.NutrientController // 营养控制器实例
pigAgeStageController *feed.PigAgeStageController // 猪龄阶段控制器实例 pigAgeStageController *feed.PigAgeStageController // 猪龄阶段控制器实例
pigBreedController *feed.PigBreedController // 猪品种控制器实例 pigBreedController *feed.PigBreedController // 猪品种控制器实例
@@ -79,7 +78,11 @@ func NewAPI(cfg config.ServerConfig,
userService service.UserService, userService service.UserService,
auditService service.AuditService, auditService service.AuditService,
alarmService service.ThresholdAlarmService, alarmService service.ThresholdAlarmService,
feedManagementService service.FeedManagementService, nutrientService service.NutrientService,
rawMaterialService service.RawMaterialService,
pigBreedService service.PigBreedService,
pigAgeStageService service.PigAgeStageService,
pigTypeService service.PigTypeService,
tokenGenerator token.Generator, tokenGenerator token.Generator,
listenHandler webhook.ListenHandler, listenHandler webhook.ListenHandler,
) *API { ) *API {
@@ -111,12 +114,11 @@ func NewAPI(cfg config.ServerConfig,
monitorController: monitor.NewController(logs.AddCompName(baseCtx, "MonitorController"), monitorService), monitorController: monitor.NewController(logs.AddCompName(baseCtx, "MonitorController"), monitorService),
healthController: health.NewController(logs.AddCompName(baseCtx, "HealthController")), healthController: health.NewController(logs.AddCompName(baseCtx, "HealthController")),
alarmController: alarm.NewThresholdAlarmController(logs.AddCompName(baseCtx, "ThresholdAlarmController"), alarmService), alarmController: alarm.NewThresholdAlarmController(logs.AddCompName(baseCtx, "ThresholdAlarmController"), alarmService),
feedController: feed.NewController(logs.AddCompName(baseCtx, "FeedController"), feedManagementService), nutrientController: feed.NewNutrientController(logs.AddCompName(baseCtx, "NutrientController"), nutrientService),
nutrientController: feed.NewNutrientController(logs.AddCompName(baseCtx, "NutrientController"), feedManagementService), pigAgeStageController: feed.NewPigAgeStageController(logs.AddCompName(baseCtx, "PigAgeStageController"), pigAgeStageService),
pigAgeStageController: feed.NewPigAgeStageController(logs.AddCompName(baseCtx, "PigAgeStageController"), feedManagementService), pigBreedController: feed.NewPigBreedController(logs.AddCompName(baseCtx, "PigBreedController"), pigBreedService),
pigBreedController: feed.NewPigBreedController(logs.AddCompName(baseCtx, "PigBreedController"), feedManagementService), pigTypeController: feed.NewPigTypeController(logs.AddCompName(baseCtx, "PigTypeController"), pigTypeService),
pigTypeController: feed.NewPigTypeController(logs.AddCompName(baseCtx, "PigTypeController"), feedManagementService), rawMaterialController: feed.NewRawMaterialController(logs.AddCompName(baseCtx, "RawMaterialController"), rawMaterialService),
rawMaterialController: feed.NewRawMaterialController(logs.AddCompName(baseCtx, "RawMaterialController"), feedManagementService),
} }
api.setupRoutes() // 设置所有路由 api.setupRoutes() // 设置所有路由

View File

@@ -1,21 +0,0 @@
package feed
import (
"context"
"git.huangwc.com/pig/pig-farm-controller/internal/app/service"
)
// Controller 定义了饲料管理相关的控制器,作为各个子控制器的入口
type Controller struct {
ctx context.Context
feedManagementService service.FeedManagementService
}
// NewController 创建一个新的 Controller 实例
func NewController(ctx context.Context, feedManagementService service.FeedManagementService) *Controller {
return &Controller{
ctx: ctx,
feedManagementService: feedManagementService,
}
}

View File

@@ -15,15 +15,15 @@ import (
// NutrientController 定义了营养种类相关的控制器 // NutrientController 定义了营养种类相关的控制器
type NutrientController struct { type NutrientController struct {
ctx context.Context ctx context.Context
feedManagementService service.FeedManagementService nutrientService service.NutrientService
} }
// NewNutrientController 创建一个新的 NutrientController 实例 // NewNutrientController 创建一个新的 NutrientController 实例
func NewNutrientController(ctx context.Context, feedManagementService service.FeedManagementService) *NutrientController { func NewNutrientController(ctx context.Context, feedManagementService service.NutrientService) *NutrientController {
return &NutrientController{ return &NutrientController{
ctx: ctx, ctx: ctx,
feedManagementService: feedManagementService, nutrientService: feedManagementService,
} }
} }
@@ -46,7 +46,7 @@ func (c *NutrientController) CreateNutrient(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
} }
resp, err := c.feedManagementService.CreateNutrient(reqCtx, &req) resp, err := c.nutrientService.CreateNutrient(reqCtx, &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层创建营养种类失败: %v", actionType, err) logger.Errorf("%s: 服务层创建营养种类失败: %v", actionType, err)
if errors.Is(err, service.ErrNutrientNameConflict) { if errors.Is(err, service.ErrNutrientNameConflict) {
@@ -86,7 +86,7 @@ func (c *NutrientController) UpdateNutrient(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
} }
resp, err := c.feedManagementService.UpdateNutrient(reqCtx, uint32(id), &req) resp, err := c.nutrientService.UpdateNutrient(reqCtx, uint32(id), &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层更新营养种类失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层更新营养种类失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrNutrientNotFound) { if errors.Is(err, service.ErrNutrientNotFound) {
@@ -121,7 +121,7 @@ func (c *NutrientController) DeleteNutrient(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的营养种类ID格式", actionType, "营养种类ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的营养种类ID格式", actionType, "营养种类ID格式错误", idStr)
} }
err = c.feedManagementService.DeleteNutrient(reqCtx, uint32(id)) err = c.nutrientService.DeleteNutrient(reqCtx, uint32(id))
if err != nil { if err != nil {
logger.Errorf("%s: 服务层删除营养种类失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层删除营养种类失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrNutrientNotFound) { if errors.Is(err, service.ErrNutrientNotFound) {
@@ -153,7 +153,7 @@ func (c *NutrientController) GetNutrient(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的营养种类ID格式", actionType, "营养种类ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的营养种类ID格式", actionType, "营养种类ID格式错误", idStr)
} }
resp, err := c.feedManagementService.GetNutrient(reqCtx, uint32(id)) resp, err := c.nutrientService.GetNutrient(reqCtx, uint32(id))
if err != nil { if err != nil {
logger.Errorf("%s: 服务层获取营养种类详情失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层获取营养种类详情失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrNutrientNotFound) { if errors.Is(err, service.ErrNutrientNotFound) {
@@ -184,7 +184,7 @@ func (c *NutrientController) ListNutrients(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", req)
} }
resp, err := c.feedManagementService.ListNutrients(reqCtx, &req) resp, err := c.nutrientService.ListNutrients(reqCtx, &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层获取营养种类列表失败: %v", actionType, err) logger.Errorf("%s: 服务层获取营养种类列表失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取营养种类列表失败: "+err.Error(), actionType, "服务层获取营养种类列表失败", nil) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取营养种类列表失败: "+err.Error(), actionType, "服务层获取营养种类列表失败", nil)

View File

@@ -15,15 +15,15 @@ import (
// PigAgeStageController 定义了猪年龄阶段相关的控制器 // PigAgeStageController 定义了猪年龄阶段相关的控制器
type PigAgeStageController struct { type PigAgeStageController struct {
ctx context.Context ctx context.Context
feedManagementService service.FeedManagementService pigAgeStageService service.PigAgeStageService
} }
// NewPigAgeStageController 创建一个新的 PigAgeStageController 实例 // NewPigAgeStageController 创建一个新的 PigAgeStageController 实例
func NewPigAgeStageController(ctx context.Context, feedManagementService service.FeedManagementService) *PigAgeStageController { func NewPigAgeStageController(ctx context.Context, feedManagementService service.PigAgeStageService) *PigAgeStageController {
return &PigAgeStageController{ return &PigAgeStageController{
ctx: ctx, ctx: ctx,
feedManagementService: feedManagementService, pigAgeStageService: feedManagementService,
} }
} }
@@ -46,7 +46,7 @@ func (c *PigAgeStageController) CreatePigAgeStage(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
} }
resp, err := c.feedManagementService.CreatePigAgeStage(reqCtx, &req) resp, err := c.pigAgeStageService.CreatePigAgeStage(reqCtx, &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层创建猪年龄阶段失败: %v", actionType, err) logger.Errorf("%s: 服务层创建猪年龄阶段失败: %v", actionType, err)
// 猪年龄阶段没有名称冲突的领域错误,这里直接返回内部错误 // 猪年龄阶段没有名称冲突的领域错误,这里直接返回内部错误
@@ -84,7 +84,7 @@ func (c *PigAgeStageController) UpdatePigAgeStage(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
} }
resp, err := c.feedManagementService.UpdatePigAgeStage(reqCtx, uint32(id), &req) resp, err := c.pigAgeStageService.UpdatePigAgeStage(reqCtx, uint32(id), &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层更新猪年龄阶段失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层更新猪年龄阶段失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrPigAgeStageNotFound) { if errors.Is(err, service.ErrPigAgeStageNotFound) {
@@ -116,7 +116,7 @@ func (c *PigAgeStageController) DeletePigAgeStage(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪年龄阶段ID格式", actionType, "猪年龄阶段ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪年龄阶段ID格式", actionType, "猪年龄阶段ID格式错误", idStr)
} }
err = c.feedManagementService.DeletePigAgeStage(reqCtx, uint32(id)) err = c.pigAgeStageService.DeletePigAgeStage(reqCtx, uint32(id))
if err != nil { if err != nil {
logger.Errorf("%s: 服务层删除猪年龄阶段失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层删除猪年龄阶段失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrPigAgeStageNotFound) { if errors.Is(err, service.ErrPigAgeStageNotFound) {
@@ -151,7 +151,7 @@ func (c *PigAgeStageController) GetPigAgeStage(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪年龄阶段ID格式", actionType, "猪年龄阶段ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪年龄阶段ID格式", actionType, "猪年龄阶段ID格式错误", idStr)
} }
resp, err := c.feedManagementService.GetPigAgeStage(reqCtx, uint32(id)) resp, err := c.pigAgeStageService.GetPigAgeStage(reqCtx, uint32(id))
if err != nil { if err != nil {
logger.Errorf("%s: 服务层获取猪年龄阶段详情失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层获取猪年龄阶段详情失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrPigAgeStageNotFound) { if errors.Is(err, service.ErrPigAgeStageNotFound) {
@@ -182,7 +182,7 @@ func (c *PigAgeStageController) ListPigAgeStages(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", req)
} }
resp, err := c.feedManagementService.ListPigAgeStages(reqCtx, &req) resp, err := c.pigAgeStageService.ListPigAgeStages(reqCtx, &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层获取猪年龄阶段列表失败: %v", actionType, err) logger.Errorf("%s: 服务层获取猪年龄阶段列表失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪年龄阶段列表失败: "+err.Error(), actionType, "服务层获取猪年龄阶段列表失败", nil) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪年龄阶段列表失败: "+err.Error(), actionType, "服务层获取猪年龄阶段列表失败", nil)

View File

@@ -15,15 +15,15 @@ import (
// PigBreedController 定义了猪品种相关的控制器 // PigBreedController 定义了猪品种相关的控制器
type PigBreedController struct { type PigBreedController struct {
ctx context.Context ctx context.Context
feedManagementService service.FeedManagementService pigBreedService service.PigBreedService
} }
// NewPigBreedController 创建一个新的 PigBreedController 实例 // NewPigBreedController 创建一个新的 PigBreedController 实例
func NewPigBreedController(ctx context.Context, feedManagementService service.FeedManagementService) *PigBreedController { func NewPigBreedController(ctx context.Context, feedManagementService service.PigBreedService) *PigBreedController {
return &PigBreedController{ return &PigBreedController{
ctx: ctx, ctx: ctx,
feedManagementService: feedManagementService, pigBreedService: feedManagementService,
} }
} }
@@ -46,7 +46,7 @@ func (c *PigBreedController) CreatePigBreed(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
} }
resp, err := c.feedManagementService.CreatePigBreed(reqCtx, &req) resp, err := c.pigBreedService.CreatePigBreed(reqCtx, &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层创建猪品种失败: %v", actionType, err) logger.Errorf("%s: 服务层创建猪品种失败: %v", actionType, err)
// 猪品种没有名称冲突的领域错误,这里直接返回内部错误 // 猪品种没有名称冲突的领域错误,这里直接返回内部错误
@@ -84,7 +84,7 @@ func (c *PigBreedController) UpdatePigBreed(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
} }
resp, err := c.feedManagementService.UpdatePigBreed(reqCtx, uint32(id), &req) resp, err := c.pigBreedService.UpdatePigBreed(reqCtx, uint32(id), &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层更新猪品种失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层更新猪品种失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrPigBreedNotFound) { if errors.Is(err, service.ErrPigBreedNotFound) {
@@ -116,7 +116,7 @@ func (c *PigBreedController) DeletePigBreed(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪品种ID格式", actionType, "猪品种ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪品种ID格式", actionType, "猪品种ID格式错误", idStr)
} }
err = c.feedManagementService.DeletePigBreed(reqCtx, uint32(id)) err = c.pigBreedService.DeletePigBreed(reqCtx, uint32(id))
if err != nil { if err != nil {
logger.Errorf("%s: 服务层删除猪品种失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层删除猪品种失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrPigBreedNotFound) { if errors.Is(err, service.ErrPigBreedNotFound) {
@@ -151,7 +151,7 @@ func (c *PigBreedController) GetPigBreed(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪品种ID格式", actionType, "猪品种ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪品种ID格式", actionType, "猪品种ID格式错误", idStr)
} }
resp, err := c.feedManagementService.GetPigBreed(reqCtx, uint32(id)) resp, err := c.pigBreedService.GetPigBreed(reqCtx, uint32(id))
if err != nil { if err != nil {
logger.Errorf("%s: 服务层获取猪品种详情失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层获取猪品种详情失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrPigBreedNotFound) { if errors.Is(err, service.ErrPigBreedNotFound) {
@@ -182,7 +182,7 @@ func (c *PigBreedController) ListPigBreeds(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", req)
} }
resp, err := c.feedManagementService.ListPigBreeds(reqCtx, &req) resp, err := c.pigBreedService.ListPigBreeds(reqCtx, &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层获取猪品种列表失败: %v", actionType, err) logger.Errorf("%s: 服务层获取猪品种列表失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪品种列表失败: "+err.Error(), actionType, "服务层获取猪品种列表失败", nil) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪品种列表失败: "+err.Error(), actionType, "服务层获取猪品种列表失败", nil)

View File

@@ -15,15 +15,15 @@ import (
// PigTypeController 定义了猪类型相关的控制器 // PigTypeController 定义了猪类型相关的控制器
type PigTypeController struct { type PigTypeController struct {
ctx context.Context ctx context.Context
feedManagementService service.FeedManagementService typeService service.PigTypeService
} }
// NewPigTypeController 创建一个新的 PigTypeController 实例 // NewPigTypeController 创建一个新的 PigTypeController 实例
func NewPigTypeController(ctx context.Context, feedManagementService service.FeedManagementService) *PigTypeController { func NewPigTypeController(ctx context.Context, feedManagementService service.PigTypeService) *PigTypeController {
return &PigTypeController{ return &PigTypeController{
ctx: ctx, ctx: ctx,
feedManagementService: feedManagementService, typeService: feedManagementService,
} }
} }
@@ -46,7 +46,7 @@ func (c *PigTypeController) CreatePigType(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
} }
resp, err := c.feedManagementService.CreatePigType(reqCtx, &req) resp, err := c.typeService.CreatePigType(reqCtx, &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层创建猪类型失败: %v", actionType, err) logger.Errorf("%s: 服务层创建猪类型失败: %v", actionType, err)
if errors.Is(err, service.ErrPigBreedNotFound) { if errors.Is(err, service.ErrPigBreedNotFound) {
@@ -89,7 +89,7 @@ func (c *PigTypeController) UpdatePigType(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
} }
resp, err := c.feedManagementService.UpdatePigType(reqCtx, uint32(id), &req) resp, err := c.typeService.UpdatePigType(reqCtx, uint32(id), &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层更新猪类型失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层更新猪类型失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrPigTypeNotFound) { if errors.Is(err, service.ErrPigTypeNotFound) {
@@ -127,7 +127,7 @@ func (c *PigTypeController) DeletePigType(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪类型ID格式", actionType, "猪类型ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪类型ID格式", actionType, "猪类型ID格式错误", idStr)
} }
err = c.feedManagementService.DeletePigType(reqCtx, uint32(id)) err = c.typeService.DeletePigType(reqCtx, uint32(id))
if err != nil { if err != nil {
logger.Errorf("%s: 服务层删除猪类型失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层删除猪类型失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrPigTypeNotFound) { if errors.Is(err, service.ErrPigTypeNotFound) {
@@ -159,7 +159,7 @@ func (c *PigTypeController) GetPigType(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪类型ID格式", actionType, "猪类型ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪类型ID格式", actionType, "猪类型ID格式错误", idStr)
} }
resp, err := c.feedManagementService.GetPigType(reqCtx, uint32(id)) resp, err := c.typeService.GetPigType(reqCtx, uint32(id))
if err != nil { if err != nil {
logger.Errorf("%s: 服务层获取猪类型详情失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层获取猪类型详情失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrPigTypeNotFound) { if errors.Is(err, service.ErrPigTypeNotFound) {
@@ -190,7 +190,7 @@ func (c *PigTypeController) ListPigTypes(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", req)
} }
resp, err := c.feedManagementService.ListPigTypes(reqCtx, &req) resp, err := c.typeService.ListPigTypes(reqCtx, &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层获取猪类型列表失败: %v", actionType, err) logger.Errorf("%s: 服务层获取猪类型列表失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪类型列表失败: "+err.Error(), actionType, "服务层获取猪类型列表失败", nil) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪类型列表失败: "+err.Error(), actionType, "服务层获取猪类型列表失败", nil)
@@ -228,7 +228,7 @@ func (c *PigTypeController) UpdatePigTypeNutrientRequirements(ctx echo.Context)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
} }
resp, err := c.feedManagementService.UpdatePigTypeNutrientRequirements(reqCtx, uint32(id), &req) resp, err := c.typeService.UpdatePigTypeNutrientRequirements(reqCtx, uint32(id), &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层更新猪类型营养需求失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层更新猪类型营养需求失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrPigTypeNotFound) { if errors.Is(err, service.ErrPigTypeNotFound) {

View File

@@ -15,15 +15,15 @@ import (
// RawMaterialController 定义了原料相关的控制器 // RawMaterialController 定义了原料相关的控制器
type RawMaterialController struct { type RawMaterialController struct {
ctx context.Context ctx context.Context
feedManagementService service.FeedManagementService rawMaterialService service.RawMaterialService
} }
// NewRawMaterialController 创建一个新的 RawMaterialController 实例 // NewRawMaterialController 创建一个新的 RawMaterialController 实例
func NewRawMaterialController(ctx context.Context, feedManagementService service.FeedManagementService) *RawMaterialController { func NewRawMaterialController(ctx context.Context, feedManagementService service.RawMaterialService) *RawMaterialController {
return &RawMaterialController{ return &RawMaterialController{
ctx: ctx, ctx: ctx,
feedManagementService: feedManagementService, rawMaterialService: feedManagementService,
} }
} }
@@ -46,7 +46,7 @@ func (c *RawMaterialController) CreateRawMaterial(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
} }
resp, err := c.feedManagementService.CreateRawMaterial(reqCtx, &req) resp, err := c.rawMaterialService.CreateRawMaterial(reqCtx, &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层创建原料失败: %v", actionType, err) logger.Errorf("%s: 服务层创建原料失败: %v", actionType, err)
if errors.Is(err, service.ErrRawMaterialNameConflict) { if errors.Is(err, service.ErrRawMaterialNameConflict) {
@@ -86,7 +86,7 @@ func (c *RawMaterialController) UpdateRawMaterial(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
} }
resp, err := c.feedManagementService.UpdateRawMaterial(reqCtx, uint32(id), &req) resp, err := c.rawMaterialService.UpdateRawMaterial(reqCtx, uint32(id), &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层更新原料失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层更新原料失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrRawMaterialNotFound) { if errors.Is(err, service.ErrRawMaterialNotFound) {
@@ -121,7 +121,7 @@ func (c *RawMaterialController) DeleteRawMaterial(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的原料ID格式", actionType, "原料ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的原料ID格式", actionType, "原料ID格式错误", idStr)
} }
err = c.feedManagementService.DeleteRawMaterial(reqCtx, uint32(id)) err = c.rawMaterialService.DeleteRawMaterial(reqCtx, uint32(id))
if err != nil { if err != nil {
logger.Errorf("%s: 服务层删除原料失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层删除原料失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrRawMaterialNotFound) { if errors.Is(err, service.ErrRawMaterialNotFound) {
@@ -153,7 +153,7 @@ func (c *RawMaterialController) GetRawMaterial(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的原料ID格式", actionType, "原料ID格式错误", idStr) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的原料ID格式", actionType, "原料ID格式错误", idStr)
} }
resp, err := c.feedManagementService.GetRawMaterial(reqCtx, uint32(id)) resp, err := c.rawMaterialService.GetRawMaterial(reqCtx, uint32(id))
if err != nil { if err != nil {
logger.Errorf("%s: 服务层获取原料详情失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层获取原料详情失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrRawMaterialNotFound) { if errors.Is(err, service.ErrRawMaterialNotFound) {
@@ -184,7 +184,7 @@ func (c *RawMaterialController) ListRawMaterials(ctx echo.Context) error {
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "查询参数绑定失败", req)
} }
resp, err := c.feedManagementService.ListRawMaterials(reqCtx, &req) resp, err := c.rawMaterialService.ListRawMaterials(reqCtx, &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层获取原料列表失败: %v", actionType, err) logger.Errorf("%s: 服务层获取原料列表失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取原料列表失败: "+err.Error(), actionType, "服务层获取原料列表失败", nil) return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取原料列表失败: "+err.Error(), actionType, "服务层获取原料列表失败", nil)
@@ -222,7 +222,7 @@ func (c *RawMaterialController) UpdateRawMaterialNutrients(ctx echo.Context) err
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req) return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
} }
resp, err := c.feedManagementService.UpdateRawMaterialNutrients(reqCtx, uint32(id), &req) resp, err := c.rawMaterialService.UpdateRawMaterialNutrients(reqCtx, uint32(id), &req)
if err != nil { if err != nil {
logger.Errorf("%s: 服务层更新原料营养成分失败: %v, ID: %d", actionType, err, id) logger.Errorf("%s: 服务层更新原料营养成分失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, service.ErrRawMaterialNotFound) { if errors.Is(err, service.ErrRawMaterialNotFound) {

View File

@@ -1,618 +0,0 @@
package service
import (
"context"
"errors"
"fmt"
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
"git.huangwc.com/pig/pig-farm-controller/internal/domain/recipe"
"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"
)
// 定义服务层特定的错误
var (
ErrNutrientNameConflict = errors.New("营养种类名称已存在")
ErrNutrientNotFound = errors.New("营养种类不存在")
ErrRawMaterialNameConflict = errors.New("原料名称已存在")
ErrRawMaterialNotFound = errors.New("原料不存在")
ErrPigBreedInUse = errors.New("猪品种正在被猪类型使用,无法删除")
ErrPigBreedNotFound = errors.New("猪品种不存在")
ErrPigAgeStageInUse = errors.New("猪年龄阶段正在被猪类型使用,无法删除")
ErrPigAgeStageNotFound = errors.New("猪年龄阶段不存在")
ErrPigTypeNotFound = errors.New("猪类型不存在")
)
// FeedManagementService 定义了饲料管理的应用服务接口
type FeedManagementService interface {
// 营养种类相关
CreateNutrient(ctx context.Context, req *dto.CreateNutrientRequest) (*dto.NutrientResponse, error)
UpdateNutrient(ctx context.Context, id uint32, req *dto.UpdateNutrientRequest) (*dto.NutrientResponse, error)
DeleteNutrient(ctx context.Context, id uint32) error
GetNutrient(ctx context.Context, id uint32) (*dto.NutrientResponse, error)
ListNutrients(ctx context.Context, req *dto.ListNutrientRequest) (*dto.ListNutrientResponse, error)
// 原料相关
CreateRawMaterial(ctx context.Context, req *dto.CreateRawMaterialRequest) (*dto.RawMaterialResponse, error)
UpdateRawMaterial(ctx context.Context, id uint32, req *dto.UpdateRawMaterialRequest) (*dto.RawMaterialResponse, error)
DeleteRawMaterial(ctx context.Context, id uint32) error
GetRawMaterial(ctx context.Context, id uint32) (*dto.RawMaterialResponse, error)
ListRawMaterials(ctx context.Context, req *dto.ListRawMaterialRequest) (*dto.ListRawMaterialResponse, error)
UpdateRawMaterialNutrients(ctx context.Context, id uint32, req *dto.UpdateRawMaterialNutrientsRequest) (*dto.RawMaterialResponse, error) // 新增
// 猪品种相关
CreatePigBreed(ctx context.Context, req *dto.CreatePigBreedRequest) (*dto.PigBreedResponse, error)
UpdatePigBreed(ctx context.Context, id uint32, req *dto.UpdatePigBreedRequest) (*dto.PigBreedResponse, error)
DeletePigBreed(ctx context.Context, id uint32) error
GetPigBreed(ctx context.Context, id uint32) (*dto.PigBreedResponse, error)
ListPigBreeds(ctx context.Context, req *dto.ListPigBreedRequest) (*dto.ListPigBreedResponse, error)
// 猪年龄阶段相关
CreatePigAgeStage(ctx context.Context, req *dto.CreatePigAgeStageRequest) (*dto.PigAgeStageResponse, error)
UpdatePigAgeStage(ctx context.Context, id uint32, req *dto.UpdatePigAgeStageRequest) (*dto.PigAgeStageResponse, error)
DeletePigAgeStage(ctx context.Context, id uint32) error
GetPigAgeStage(ctx context.Context, id uint32) (*dto.PigAgeStageResponse, error)
ListPigAgeStages(ctx context.Context, req *dto.ListPigAgeStageRequest) (*dto.ListPigAgeStageResponse, error)
// 猪类型相关
CreatePigType(ctx context.Context, req *dto.CreatePigTypeRequest) (*dto.PigTypeResponse, error)
UpdatePigType(ctx context.Context, id uint32, req *dto.UpdatePigTypeRequest) (*dto.PigTypeResponse, error)
DeletePigType(ctx context.Context, id uint32) error
GetPigType(ctx context.Context, id uint32) (*dto.PigTypeResponse, error)
ListPigTypes(ctx context.Context, req *dto.ListPigTypeRequest) (*dto.ListPigTypeResponse, error)
UpdatePigTypeNutrientRequirements(ctx context.Context, id uint32, req *dto.UpdatePigTypeNutrientRequirementsRequest) (*dto.PigTypeResponse, error) // 新增
}
// feedManagementServiceImpl 是 FeedManagementService 接口的实现
type feedManagementServiceImpl struct {
ctx context.Context
recipeSvc recipe.Service
}
// NewFeedManagementService 创建一个新的 FeedManagementService 实例
func NewFeedManagementService(ctx context.Context, recipeSvc recipe.Service) FeedManagementService {
return &feedManagementServiceImpl{
ctx: ctx,
recipeSvc: recipeSvc,
}
}
// =====================================================================================================================
// 营养种类 (Nutrient) 实现
// =====================================================================================================================
// CreateNutrient 创建营养种类
func (s *feedManagementServiceImpl) CreateNutrient(ctx context.Context, req *dto.CreateNutrientRequest) (*dto.NutrientResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateNutrient")
nutrient, err := s.recipeSvc.CreateNutrient(serviceCtx, req.Name, req.Description)
if err != nil {
if errors.Is(err, recipe.ErrNutrientNameConflict) {
return nil, ErrNutrientNameConflict
}
return nil, fmt.Errorf("创建营养种类失败: %w", err)
}
return dto.ConvertNutrientToDTO(nutrient), nil
}
// UpdateNutrient 更新营养种类
func (s *feedManagementServiceImpl) UpdateNutrient(ctx context.Context, id uint32, req *dto.UpdateNutrientRequest) (*dto.NutrientResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateNutrient")
nutrient, err := s.recipeSvc.UpdateNutrient(serviceCtx, id, req.Name, req.Description)
if err != nil {
if errors.Is(err, recipe.ErrNutrientNotFound) {
return nil, ErrNutrientNotFound
}
if errors.Is(err, recipe.ErrNutrientNameConflict) {
return nil, ErrNutrientNameConflict
}
return nil, fmt.Errorf("更新营养种类失败: %w", err)
}
return dto.ConvertNutrientToDTO(nutrient), nil
}
// DeleteNutrient 删除营养种类
func (s *feedManagementServiceImpl) DeleteNutrient(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteNutrient")
err := s.recipeSvc.DeleteNutrient(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrNutrientNotFound) {
return ErrNutrientNotFound
}
return fmt.Errorf("删除营养种类失败: %w", err)
}
return nil
}
// GetNutrient 获取单个营养种类
func (s *feedManagementServiceImpl) GetNutrient(ctx context.Context, id uint32) (*dto.NutrientResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetNutrient")
nutrient, err := s.recipeSvc.GetNutrient(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrNutrientNotFound) {
return nil, ErrNutrientNotFound
}
return nil, fmt.Errorf("获取营养种类失败: %w", err)
}
return dto.ConvertNutrientToDTO(nutrient), nil
}
// ListNutrients 列出营养种类
func (s *feedManagementServiceImpl) ListNutrients(ctx context.Context, req *dto.ListNutrientRequest) (*dto.ListNutrientResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListNutrients")
opts := repository.NutrientListOptions{
Name: req.Name,
RawMaterialName: req.RawMaterialName,
OrderBy: req.OrderBy,
}
nutrients, total, err := s.recipeSvc.ListNutrients(serviceCtx, opts, req.Page, req.PageSize)
if err != nil {
return nil, fmt.Errorf("获取营养种类列表失败: %w", err)
}
return dto.ConvertNutrientListToDTO(nutrients, total, req.Page, req.PageSize), nil
}
// =====================================================================================================================
// 原料 (RawMaterial) 实现
// =====================================================================================================================
// CreateRawMaterial 创建原料
func (s *feedManagementServiceImpl) CreateRawMaterial(ctx context.Context, req *dto.CreateRawMaterialRequest) (*dto.RawMaterialResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateRawMaterial")
rawMaterial, err := s.recipeSvc.CreateRawMaterial(serviceCtx, req.Name, req.Description)
if err != nil {
if errors.Is(err, recipe.ErrRawMaterialNameConflict) {
return nil, ErrRawMaterialNameConflict
}
return nil, fmt.Errorf("创建原料失败: %w", err)
}
return dto.ConvertRawMaterialToDTO(rawMaterial), nil
}
// UpdateRawMaterial 更新原料
func (s *feedManagementServiceImpl) UpdateRawMaterial(ctx context.Context, id uint32, req *dto.UpdateRawMaterialRequest) (*dto.RawMaterialResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateRawMaterial")
rawMaterial, err := s.recipeSvc.UpdateRawMaterial(serviceCtx, id, req.Name, req.Description)
if err != nil {
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
return nil, ErrRawMaterialNotFound
}
if errors.Is(err, recipe.ErrRawMaterialNameConflict) {
return nil, ErrRawMaterialNameConflict
}
return nil, fmt.Errorf("更新原料失败: %w", err)
}
return dto.ConvertRawMaterialToDTO(rawMaterial), nil
}
// DeleteRawMaterial 删除原料
func (s *feedManagementServiceImpl) DeleteRawMaterial(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteRawMaterial")
err := s.recipeSvc.DeleteRawMaterial(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
return ErrRawMaterialNotFound
}
return fmt.Errorf("删除原料失败: %w", err)
}
return nil
}
// GetRawMaterial 获取单个原料
func (s *feedManagementServiceImpl) GetRawMaterial(ctx context.Context, id uint32) (*dto.RawMaterialResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetRawMaterial")
rawMaterial, err := s.recipeSvc.GetRawMaterial(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
return nil, ErrRawMaterialNotFound
}
return nil, fmt.Errorf("获取原料失败: %w", err)
}
return dto.ConvertRawMaterialToDTO(rawMaterial), nil
}
// ListRawMaterials 列出原料
func (s *feedManagementServiceImpl) ListRawMaterials(ctx context.Context, req *dto.ListRawMaterialRequest) (*dto.ListRawMaterialResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListRawMaterials")
opts := repository.RawMaterialListOptions{
Name: req.Name,
NutrientName: req.NutrientName,
OrderBy: req.OrderBy,
}
rawMaterials, total, err := s.recipeSvc.ListRawMaterials(serviceCtx, opts, req.Page, req.PageSize)
if err != nil {
return nil, fmt.Errorf("获取原料列表失败: %w", err)
}
return dto.ConvertRawMaterialListToDTO(rawMaterials, total, req.Page, req.PageSize), nil
}
// UpdateRawMaterialNutrients 全量更新原料的营养成分
func (s *feedManagementServiceImpl) UpdateRawMaterialNutrients(ctx context.Context, id uint32, req *dto.UpdateRawMaterialNutrientsRequest) (*dto.RawMaterialResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateRawMaterialNutrients")
// 1. 将 DTO 转换为领域模型
nutrients := make([]models.RawMaterialNutrient, len(req.Nutrients))
for i, item := range req.Nutrients {
nutrients[i] = models.RawMaterialNutrient{
RawMaterialID: id,
NutrientID: item.NutrientID,
Value: item.Value,
}
}
// 2. 调用领域服务执行更新命令
err := s.recipeSvc.UpdateRawMaterialNutrients(serviceCtx, id, nutrients)
if err != nil {
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
return nil, ErrRawMaterialNotFound
}
// 此处可以根据领域层可能返回的其他特定错误进行转换
return nil, fmt.Errorf("更新原料营养成分失败: %w", err)
}
// 3. 更新成功后,调用查询服务获取最新的原料信息
updatedRawMaterial, err := s.recipeSvc.GetRawMaterial(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
// 理论上不应该发生,因为刚更新成功
return nil, ErrRawMaterialNotFound
}
return nil, fmt.Errorf("更新后获取原料信息失败: %w", err)
}
// 4. 将领域模型转换为 DTO 并返回
return dto.ConvertRawMaterialToDTO(updatedRawMaterial), nil
}
// =====================================================================================================================
// 猪品种 (PigBreed) 实现
// =====================================================================================================================
// CreatePigBreed 创建猪品种
func (s *feedManagementServiceImpl) CreatePigBreed(ctx context.Context, req *dto.CreatePigBreedRequest) (*dto.PigBreedResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreatePigBreed")
breed := &models.PigBreed{
Name: req.Name,
Description: req.Description,
ParentInfo: req.ParentInfo,
AppearanceFeatures: req.AppearanceFeatures,
BreedAdvantages: req.BreedAdvantages,
BreedDisadvantages: req.BreedDisadvantages,
}
if err := s.recipeSvc.CreatePigBreed(serviceCtx, breed); err != nil {
return nil, fmt.Errorf("创建猪品种失败: %w", err)
}
return dto.ConvertPigBreedToDTO(breed), nil
}
// UpdatePigBreed 更新猪品种
func (s *feedManagementServiceImpl) UpdatePigBreed(ctx context.Context, id uint32, req *dto.UpdatePigBreedRequest) (*dto.PigBreedResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigBreed")
breed := &models.PigBreed{
Model: models.Model{ID: id},
Name: req.Name,
Description: req.Description,
ParentInfo: req.ParentInfo,
AppearanceFeatures: req.AppearanceFeatures,
BreedAdvantages: req.BreedAdvantages,
BreedDisadvantages: req.BreedDisadvantages,
}
if err := s.recipeSvc.UpdatePigBreed(serviceCtx, breed); err != nil {
if errors.Is(err, recipe.ErrPigBreedNotFound) {
return nil, ErrPigBreedNotFound
}
return nil, fmt.Errorf("更新猪品种失败: %w", err)
}
return dto.ConvertPigBreedToDTO(breed), nil
}
// DeletePigBreed 删除猪品种
func (s *feedManagementServiceImpl) DeletePigBreed(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeletePigBreed")
err := s.recipeSvc.DeletePigBreed(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigBreedNotFound) {
return ErrPigBreedNotFound
}
if errors.Is(err, recipe.ErrPigBreedInUse) {
return ErrPigBreedInUse
}
return fmt.Errorf("删除猪品种失败: %w", err)
}
return nil
}
// GetPigBreed 获取单个猪品种
func (s *feedManagementServiceImpl) GetPigBreed(ctx context.Context, id uint32) (*dto.PigBreedResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetPigBreed")
breed, err := s.recipeSvc.GetPigBreedByID(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigBreedNotFound) {
return nil, ErrPigBreedNotFound
}
return nil, fmt.Errorf("获取猪品种失败: %w", err)
}
return dto.ConvertPigBreedToDTO(breed), nil
}
// ListPigBreeds 列出猪品种
func (s *feedManagementServiceImpl) ListPigBreeds(ctx context.Context, req *dto.ListPigBreedRequest) (*dto.ListPigBreedResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListPigBreeds")
opts := repository.PigBreedListOptions{
Name: req.Name,
OrderBy: req.OrderBy,
}
breeds, total, err := s.recipeSvc.ListPigBreeds(serviceCtx, opts, req.Page, req.PageSize)
if err != nil {
return nil, fmt.Errorf("获取猪品种列表失败: %w", err)
}
return dto.ConvertPigBreedListToDTO(breeds, total, req.Page, req.PageSize), nil
}
// =====================================================================================================================
// 猪年龄阶段 (PigAgeStage) 实现
// =====================================================================================================================
// CreatePigAgeStage 创建猪年龄阶段
func (s *feedManagementServiceImpl) CreatePigAgeStage(ctx context.Context, req *dto.CreatePigAgeStageRequest) (*dto.PigAgeStageResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreatePigAgeStage")
ageStage := &models.PigAgeStage{
Name: req.Name,
Description: req.Description,
}
if err := s.recipeSvc.CreatePigAgeStage(serviceCtx, ageStage); err != nil {
return nil, fmt.Errorf("创建猪年龄阶段失败: %w", err)
}
return dto.ConvertPigAgeStageToDTO(ageStage), nil
}
// UpdatePigAgeStage 更新猪年龄阶段
func (s *feedManagementServiceImpl) UpdatePigAgeStage(ctx context.Context, id uint32, req *dto.UpdatePigAgeStageRequest) (*dto.PigAgeStageResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigAgeStage")
ageStage := &models.PigAgeStage{
Model: models.Model{ID: id},
Name: req.Name,
Description: req.Description,
}
if err := s.recipeSvc.UpdatePigAgeStage(serviceCtx, ageStage); err != nil {
if errors.Is(err, recipe.ErrPigAgeStageNotFound) {
return nil, ErrPigAgeStageNotFound
}
return nil, fmt.Errorf("更新猪年龄阶段失败: %w", err)
}
return dto.ConvertPigAgeStageToDTO(ageStage), nil
}
// DeletePigAgeStage 删除猪年龄阶段
func (s *feedManagementServiceImpl) DeletePigAgeStage(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeletePigAgeStage")
err := s.recipeSvc.DeletePigAgeStage(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigAgeStageNotFound) {
return ErrPigAgeStageNotFound
}
if errors.Is(err, recipe.ErrPigAgeStageInUse) {
return ErrPigAgeStageInUse
}
return fmt.Errorf("删除猪年龄阶段失败: %w", err)
}
return nil
}
// GetPigAgeStage 获取单个猪年龄阶段
func (s *feedManagementServiceImpl) GetPigAgeStage(ctx context.Context, id uint32) (*dto.PigAgeStageResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetPigAgeStage")
ageStage, err := s.recipeSvc.GetPigAgeStageByID(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigAgeStageNotFound) {
return nil, ErrPigAgeStageNotFound
}
return nil, fmt.Errorf("获取猪年龄阶段失败: %w", err)
}
return dto.ConvertPigAgeStageToDTO(ageStage), nil
}
// ListPigAgeStages 列出猪年龄阶段
func (s *feedManagementServiceImpl) ListPigAgeStages(ctx context.Context, req *dto.ListPigAgeStageRequest) (*dto.ListPigAgeStageResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListPigAgeStages")
opts := repository.PigAgeStageListOptions{
Name: req.Name,
OrderBy: req.OrderBy,
}
ageStages, total, err := s.recipeSvc.ListPigAgeStages(serviceCtx, opts, req.Page, req.PageSize)
if err != nil {
return nil, fmt.Errorf("获取猪年龄阶段列表失败: %w", err)
}
return dto.ConvertPigAgeStageListToDTO(ageStages, total, req.Page, req.PageSize), nil
}
// =====================================================================================================================
// 猪类型 (PigType) 实现
// =====================================================================================================================
// CreatePigType 创建猪类型
func (s *feedManagementServiceImpl) CreatePigType(ctx context.Context, req *dto.CreatePigTypeRequest) (*dto.PigTypeResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreatePigType")
pigType := &models.PigType{
BreedID: req.BreedID,
AgeStageID: req.AgeStageID,
Description: req.Description,
DailyFeedIntake: req.DailyFeedIntake,
DailyGainWeight: req.DailyGainWeight,
MinDays: req.MinDays,
MaxDays: req.MaxDays,
MinWeight: req.MinWeight,
MaxWeight: req.MaxWeight,
}
if err := s.recipeSvc.CreatePigType(serviceCtx, pigType); err != nil {
if errors.Is(err, recipe.ErrPigBreedNotFound) {
return nil, ErrPigBreedNotFound
}
if errors.Is(err, recipe.ErrPigAgeStageNotFound) {
return nil, ErrPigAgeStageNotFound
}
return nil, fmt.Errorf("创建猪类型失败: %w", err)
}
// 创建后需要重新获取,以包含关联数据
createdPigType, err := s.recipeSvc.GetPigTypeByID(serviceCtx, pigType.ID)
if err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) { // 理论上不应该发生,因为刚创建
return nil, ErrPigTypeNotFound
}
return nil, fmt.Errorf("创建猪类型后获取详情失败: %w", err)
}
return dto.ConvertPigTypeToDTO(createdPigType), nil
}
// UpdatePigType 更新猪类型
func (s *feedManagementServiceImpl) UpdatePigType(ctx context.Context, id uint32, req *dto.UpdatePigTypeRequest) (*dto.PigTypeResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigType")
pigType := &models.PigType{
Model: models.Model{ID: id},
BreedID: req.BreedID,
AgeStageID: req.AgeStageID,
Description: req.Description,
DailyFeedIntake: req.DailyFeedIntake,
DailyGainWeight: req.DailyGainWeight,
MinDays: req.MinDays,
MaxDays: req.MaxDays,
MinWeight: req.MinWeight,
MaxWeight: req.MaxWeight,
}
if err := s.recipeSvc.UpdatePigType(serviceCtx, pigType); err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) {
return nil, ErrPigTypeNotFound
}
if errors.Is(err, recipe.ErrPigBreedNotFound) {
return nil, ErrPigBreedNotFound
}
if errors.Is(err, recipe.ErrPigAgeStageNotFound) {
return nil, ErrPigAgeStageNotFound
}
return nil, fmt.Errorf("更新猪类型失败: %w", err)
}
// 更新后需要重新获取,以包含关联数据
updatedPigType, err := s.recipeSvc.GetPigTypeByID(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) { // 理论上不应该发生,因为刚更新成功
return nil, ErrPigTypeNotFound
}
return nil, fmt.Errorf("更新猪类型后获取详情失败: %w", err)
}
return dto.ConvertPigTypeToDTO(updatedPigType), nil
}
// DeletePigType 删除猪类型
func (s *feedManagementServiceImpl) DeletePigType(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeletePigType")
err := s.recipeSvc.DeletePigType(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) {
return ErrPigTypeNotFound
}
return fmt.Errorf("删除猪类型失败: %w", err)
}
return nil
}
// GetPigType 获取单个猪类型
func (s *feedManagementServiceImpl) GetPigType(ctx context.Context, id uint32) (*dto.PigTypeResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetPigType")
pigType, err := s.recipeSvc.GetPigTypeByID(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) {
return nil, ErrPigTypeNotFound
}
return nil, fmt.Errorf("获取猪类型失败: %w", err)
}
return dto.ConvertPigTypeToDTO(pigType), nil
}
// ListPigTypes 列出猪类型
func (s *feedManagementServiceImpl) ListPigTypes(ctx context.Context, req *dto.ListPigTypeRequest) (*dto.ListPigTypeResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListPigTypes")
opts := repository.PigTypeListOptions{
BreedID: req.BreedID,
AgeStageID: req.AgeStageID,
BreedName: req.BreedName,
AgeStageName: req.AgeStageName,
OrderBy: req.OrderBy,
}
pigTypes, total, err := s.recipeSvc.ListPigTypes(serviceCtx, opts, req.Page, req.PageSize)
if err != nil {
return nil, fmt.Errorf("获取猪类型列表失败: %w", err)
}
return dto.ConvertPigTypeListToDTO(pigTypes, total, req.Page, req.PageSize), nil
}
// UpdatePigTypeNutrientRequirements 全量更新猪类型的营养需求
func (s *feedManagementServiceImpl) UpdatePigTypeNutrientRequirements(ctx context.Context, id uint32, req *dto.UpdatePigTypeNutrientRequirementsRequest) (*dto.PigTypeResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigTypeNutrientRequirements")
// 1. 将 DTO 转换为领域模型
requirements := make([]models.PigNutrientRequirement, len(req.NutrientRequirements))
for i, item := range req.NutrientRequirements {
requirements[i] = models.PigNutrientRequirement{
PigTypeID: id, // 设置所属的 PigTypeID
NutrientID: item.NutrientID,
MinRequirement: item.MinRequirement,
MaxRequirement: item.MaxRequirement,
}
}
// 2. 调用领域服务执行更新命令
err := s.recipeSvc.UpdatePigTypeNutrientRequirements(serviceCtx, id, requirements)
if err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) {
return nil, ErrPigTypeNotFound
}
// 此处可以根据领域层可能返回的其他特定错误进行转换
return nil, fmt.Errorf("更新猪类型营养需求失败: %w", err)
}
// 3. 更新成功后,调用查询服务获取最新的猪类型信息
updatedPigType, err := s.recipeSvc.GetPigTypeByID(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) {
// 理论上不应该发生,因为刚更新成功
return nil, ErrPigTypeNotFound
}
return nil, fmt.Errorf("更新后获取猪类型信息失败: %w", err)
}
// 4. 将领域模型转换为 DTO 并返回
return dto.ConvertPigTypeToDTO(updatedPigType), nil
}

View File

@@ -0,0 +1,116 @@
package service
import (
"context"
"errors"
"fmt"
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
"git.huangwc.com/pig/pig-farm-controller/internal/domain/recipe"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
)
// 定义营养种类服务特定的错误
var (
ErrNutrientNameConflict = errors.New("营养种类名称已存在")
ErrNutrientNotFound = errors.New("营养种类不存在")
)
// NutrientService 定义了营养种类相关的应用服务接口
type NutrientService interface {
CreateNutrient(ctx context.Context, req *dto.CreateNutrientRequest) (*dto.NutrientResponse, error)
UpdateNutrient(ctx context.Context, id uint32, req *dto.UpdateNutrientRequest) (*dto.NutrientResponse, error)
DeleteNutrient(ctx context.Context, id uint32) error
GetNutrient(ctx context.Context, id uint32) (*dto.NutrientResponse, error)
ListNutrients(ctx context.Context, req *dto.ListNutrientRequest) (*dto.ListNutrientResponse, error)
}
// nutrientServiceImpl 是 NutrientService 接口的实现
type nutrientServiceImpl struct {
ctx context.Context
recipeSvc recipe.Service
}
// NewNutrientService 创建一个新的 NutrientService 实例
func NewNutrientService(ctx context.Context, recipeSvc recipe.Service) NutrientService {
return &nutrientServiceImpl{
ctx: ctx,
recipeSvc: recipeSvc,
}
}
// CreateNutrient 创建营养种类
func (s *nutrientServiceImpl) CreateNutrient(ctx context.Context, req *dto.CreateNutrientRequest) (*dto.NutrientResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateNutrient")
nutrient, err := s.recipeSvc.CreateNutrient(serviceCtx, req.Name, req.Description)
if err != nil {
if errors.Is(err, recipe.ErrNutrientNameConflict) {
return nil, ErrNutrientNameConflict
}
return nil, fmt.Errorf("创建营养种类失败: %w", err)
}
return dto.ConvertNutrientToDTO(nutrient), nil
}
// UpdateNutrient 更新营养种类
func (s *nutrientServiceImpl) UpdateNutrient(ctx context.Context, id uint32, req *dto.UpdateNutrientRequest) (*dto.NutrientResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateNutrient")
nutrient, err := s.recipeSvc.UpdateNutrient(serviceCtx, id, req.Name, req.Description)
if err != nil {
if errors.Is(err, recipe.ErrNutrientNotFound) {
return nil, ErrNutrientNotFound
}
if errors.Is(err, recipe.ErrNutrientNameConflict) {
return nil, ErrNutrientNameConflict
}
return nil, fmt.Errorf("更新营养种类失败: %w", err)
}
return dto.ConvertNutrientToDTO(nutrient), nil
}
// DeleteNutrient 删除营养种类
func (s *nutrientServiceImpl) DeleteNutrient(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteNutrient")
err := s.recipeSvc.DeleteNutrient(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrNutrientNotFound) {
return ErrNutrientNotFound
}
return fmt.Errorf("删除营养种类失败: %w", err)
}
return nil
}
// GetNutrient 获取单个营养种类
func (s *nutrientServiceImpl) GetNutrient(ctx context.Context, id uint32) (*dto.NutrientResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetNutrient")
nutrient, err := s.recipeSvc.GetNutrient(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrNutrientNotFound) {
return nil, ErrNutrientNotFound
}
return nil, fmt.Errorf("获取营养种类失败: %w", err)
}
return dto.ConvertNutrientToDTO(nutrient), nil
}
// ListNutrients 列出营养种类
func (s *nutrientServiceImpl) ListNutrients(ctx context.Context, req *dto.ListNutrientRequest) (*dto.ListNutrientResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListNutrients")
opts := repository.NutrientListOptions{
Name: req.Name,
RawMaterialName: req.RawMaterialName,
OrderBy: req.OrderBy,
}
nutrients, total, err := s.recipeSvc.ListNutrients(serviceCtx, opts, req.Page, req.PageSize)
if err != nil {
return nil, fmt.Errorf("获取营养种类列表失败: %w", err)
}
return dto.ConvertNutrientListToDTO(nutrients, total, req.Page, req.PageSize), nil
}

View File

@@ -0,0 +1,122 @@
package service
import (
"context"
"errors"
"fmt"
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
"git.huangwc.com/pig/pig-farm-controller/internal/domain/recipe"
"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"
)
// 定义猪年龄阶段服务特定的错误
var (
ErrPigAgeStageInUse = errors.New("猪年龄阶段正在被猪类型使用,无法删除")
ErrPigAgeStageNotFound = errors.New("猪年龄阶段不存在")
)
// PigAgeStageService 定义了猪年龄阶段相关的应用服务接口
type PigAgeStageService interface {
CreatePigAgeStage(ctx context.Context, req *dto.CreatePigAgeStageRequest) (*dto.PigAgeStageResponse, error)
UpdatePigAgeStage(ctx context.Context, id uint32, req *dto.UpdatePigAgeStageRequest) (*dto.PigAgeStageResponse, error)
DeletePigAgeStage(ctx context.Context, id uint32) error
GetPigAgeStage(ctx context.Context, id uint32) (*dto.PigAgeStageResponse, error)
ListPigAgeStages(ctx context.Context, req *dto.ListPigAgeStageRequest) (*dto.ListPigAgeStageResponse, error)
}
// pigAgeStageServiceImpl 是 PigAgeStageService 接口的实现
type pigAgeStageServiceImpl struct {
ctx context.Context
recipeSvc recipe.Service
}
// NewPigAgeStageService 创建一个新的 PigAgeStageService 实例
func NewPigAgeStageService(ctx context.Context, recipeSvc recipe.Service) PigAgeStageService {
return &pigAgeStageServiceImpl{
ctx: ctx,
recipeSvc: recipeSvc,
}
}
// CreatePigAgeStage 创建猪年龄阶段
func (s *pigAgeStageServiceImpl) CreatePigAgeStage(ctx context.Context, req *dto.CreatePigAgeStageRequest) (*dto.PigAgeStageResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreatePigAgeStage")
ageStage := &models.PigAgeStage{
Name: req.Name,
Description: req.Description,
}
if err := s.recipeSvc.CreatePigAgeStage(serviceCtx, ageStage); err != nil {
return nil, fmt.Errorf("创建猪年龄阶段失败: %w", err)
}
return dto.ConvertPigAgeStageToDTO(ageStage), nil
}
// UpdatePigAgeStage 更新猪年龄阶段
func (s *pigAgeStageServiceImpl) UpdatePigAgeStage(ctx context.Context, id uint32, req *dto.UpdatePigAgeStageRequest) (*dto.PigAgeStageResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigAgeStage")
ageStage := &models.PigAgeStage{
Model: models.Model{ID: id},
Name: req.Name,
Description: req.Description,
}
if err := s.recipeSvc.UpdatePigAgeStage(serviceCtx, ageStage); err != nil {
if errors.Is(err, recipe.ErrPigAgeStageNotFound) {
return nil, ErrPigAgeStageNotFound
}
return nil, fmt.Errorf("更新猪年龄阶段失败: %w", err)
}
return dto.ConvertPigAgeStageToDTO(ageStage), nil
}
// DeletePigAgeStage 删除猪年龄阶段
func (s *pigAgeStageServiceImpl) DeletePigAgeStage(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeletePigAgeStage")
err := s.recipeSvc.DeletePigAgeStage(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigAgeStageNotFound) {
return ErrPigAgeStageNotFound
}
if errors.Is(err, recipe.ErrPigAgeStageInUse) {
return ErrPigAgeStageInUse
}
return fmt.Errorf("删除猪年龄阶段失败: %w", err)
}
return nil
}
// GetPigAgeStage 获取单个猪年龄阶段
func (s *pigAgeStageServiceImpl) GetPigAgeStage(ctx context.Context, id uint32) (*dto.PigAgeStageResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetPigAgeStage")
ageStage, err := s.recipeSvc.GetPigAgeStageByID(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigAgeStageNotFound) {
return nil, ErrPigAgeStageNotFound
}
return nil, fmt.Errorf("获取猪年龄阶段失败: %w", err)
}
return dto.ConvertPigAgeStageToDTO(ageStage), nil
}
// ListPigAgeStages 列出猪年龄阶段
func (s *pigAgeStageServiceImpl) ListPigAgeStages(ctx context.Context, req *dto.ListPigAgeStageRequest) (*dto.ListPigAgeStageResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListPigAgeStages")
opts := repository.PigAgeStageListOptions{
Name: req.Name,
OrderBy: req.OrderBy,
}
ageStages, total, err := s.recipeSvc.ListPigAgeStages(serviceCtx, opts, req.Page, req.PageSize)
if err != nil {
return nil, fmt.Errorf("获取猪年龄阶段列表失败: %w", err)
}
return dto.ConvertPigAgeStageListToDTO(ageStages, total, req.Page, req.PageSize), nil
}

View File

@@ -0,0 +1,130 @@
package service
import (
"context"
"errors"
"fmt"
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
"git.huangwc.com/pig/pig-farm-controller/internal/domain/recipe"
"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"
)
// 定义猪品种服务特定的错误
var (
ErrPigBreedInUse = errors.New("猪品种正在被猪类型使用,无法删除")
ErrPigBreedNotFound = errors.New("猪品种不存在")
)
// PigBreedService 定义了猪品种相关的应用服务接口
type PigBreedService interface {
CreatePigBreed(ctx context.Context, req *dto.CreatePigBreedRequest) (*dto.PigBreedResponse, error)
UpdatePigBreed(ctx context.Context, id uint32, req *dto.UpdatePigBreedRequest) (*dto.PigBreedResponse, error)
DeletePigBreed(ctx context.Context, id uint32) error
GetPigBreed(ctx context.Context, id uint32) (*dto.PigBreedResponse, error)
ListPigBreeds(ctx context.Context, req *dto.ListPigBreedRequest) (*dto.ListPigBreedResponse, error)
}
// pigBreedServiceImpl 是 PigBreedService 接口的实现
type pigBreedServiceImpl struct {
ctx context.Context
recipeSvc recipe.Service
}
// NewPigBreedService 创建一个新的 PigBreedService 实例
func NewPigBreedService(ctx context.Context, recipeSvc recipe.Service) PigBreedService {
return &pigBreedServiceImpl{
ctx: ctx,
recipeSvc: recipeSvc,
}
}
// CreatePigBreed 创建猪品种
func (s *pigBreedServiceImpl) CreatePigBreed(ctx context.Context, req *dto.CreatePigBreedRequest) (*dto.PigBreedResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreatePigBreed")
breed := &models.PigBreed{
Name: req.Name,
Description: req.Description,
ParentInfo: req.ParentInfo,
AppearanceFeatures: req.AppearanceFeatures,
BreedAdvantages: req.BreedAdvantages,
BreedDisadvantages: req.BreedDisadvantages,
}
if err := s.recipeSvc.CreatePigBreed(serviceCtx, breed); err != nil {
return nil, fmt.Errorf("创建猪品种失败: %w", err)
}
return dto.ConvertPigBreedToDTO(breed), nil
}
// UpdatePigBreed 更新猪品种
func (s *pigBreedServiceImpl) UpdatePigBreed(ctx context.Context, id uint32, req *dto.UpdatePigBreedRequest) (*dto.PigBreedResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigBreed")
breed := &models.PigBreed{
Model: models.Model{ID: id},
Name: req.Name,
Description: req.Description,
ParentInfo: req.ParentInfo,
AppearanceFeatures: req.AppearanceFeatures,
BreedAdvantages: req.BreedAdvantages,
BreedDisadvantages: req.BreedDisadvantages,
}
if err := s.recipeSvc.UpdatePigBreed(serviceCtx, breed); err != nil {
if errors.Is(err, recipe.ErrPigBreedNotFound) {
return nil, ErrPigBreedNotFound
}
return nil, fmt.Errorf("更新猪品种失败: %w", err)
}
return dto.ConvertPigBreedToDTO(breed), nil
}
// DeletePigBreed 删除猪品种
func (s *pigBreedServiceImpl) DeletePigBreed(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeletePigBreed")
err := s.recipeSvc.DeletePigBreed(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigBreedNotFound) {
return ErrPigBreedNotFound
}
if errors.Is(err, recipe.ErrPigBreedInUse) {
return ErrPigBreedInUse
}
return fmt.Errorf("删除猪品种失败: %w", err)
}
return nil
}
// GetPigBreed 获取单个猪品种
func (s *pigBreedServiceImpl) GetPigBreed(ctx context.Context, id uint32) (*dto.PigBreedResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetPigBreed")
breed, err := s.recipeSvc.GetPigBreedByID(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigBreedNotFound) {
return nil, ErrPigBreedNotFound
}
return nil, fmt.Errorf("获取猪品种失败: %w", err)
}
return dto.ConvertPigBreedToDTO(breed), nil
}
// ListPigBreeds 列出猪品种
func (s *pigBreedServiceImpl) ListPigBreeds(ctx context.Context, req *dto.ListPigBreedRequest) (*dto.ListPigBreedResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListPigBreeds")
opts := repository.PigBreedListOptions{
Name: req.Name,
OrderBy: req.OrderBy,
}
breeds, total, err := s.recipeSvc.ListPigBreeds(serviceCtx, opts, req.Page, req.PageSize)
if err != nil {
return nil, fmt.Errorf("获取猪品种列表失败: %w", err)
}
return dto.ConvertPigBreedListToDTO(breeds, total, req.Page, req.PageSize), nil
}

View File

@@ -0,0 +1,203 @@
package service
import (
"context"
"errors"
"fmt"
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
"git.huangwc.com/pig/pig-farm-controller/internal/domain/recipe"
"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"
)
// 定义猪类型服务特定的错误
var (
ErrPigTypeNotFound = errors.New("猪类型不存在")
)
// PigTypeService 定义了猪类型相关的应用服务接口
type PigTypeService interface {
CreatePigType(ctx context.Context, req *dto.CreatePigTypeRequest) (*dto.PigTypeResponse, error)
UpdatePigType(ctx context.Context, id uint32, req *dto.UpdatePigTypeRequest) (*dto.PigTypeResponse, error)
DeletePigType(ctx context.Context, id uint32) error
GetPigType(ctx context.Context, id uint32) (*dto.PigTypeResponse, error)
ListPigTypes(ctx context.Context, req *dto.ListPigTypeRequest) (*dto.ListPigTypeResponse, error)
UpdatePigTypeNutrientRequirements(ctx context.Context, id uint32, req *dto.UpdatePigTypeNutrientRequirementsRequest) (*dto.PigTypeResponse, error)
}
// pigTypeServiceImpl 是 PigTypeService 接口的实现
type pigTypeServiceImpl struct {
ctx context.Context
recipeSvc recipe.Service
}
// NewPigTypeService 创建一个新的 PigTypeService 实例
func NewPigTypeService(ctx context.Context, recipeSvc recipe.Service) PigTypeService {
return &pigTypeServiceImpl{
ctx: ctx,
recipeSvc: recipeSvc,
}
}
// CreatePigType 创建猪类型
func (s *pigTypeServiceImpl) CreatePigType(ctx context.Context, req *dto.CreatePigTypeRequest) (*dto.PigTypeResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreatePigType")
pigType := &models.PigType{
BreedID: req.BreedID,
AgeStageID: req.AgeStageID,
Description: req.Description,
DailyFeedIntake: req.DailyFeedIntake,
DailyGainWeight: req.DailyGainWeight,
MinDays: req.MinDays,
MaxDays: req.MaxDays,
MinWeight: req.MinWeight,
MaxWeight: req.MaxWeight,
}
if err := s.recipeSvc.CreatePigType(serviceCtx, pigType); err != nil {
if errors.Is(err, recipe.ErrPigBreedNotFound) {
return nil, ErrPigBreedNotFound
}
if errors.Is(err, recipe.ErrPigAgeStageNotFound) {
return nil, ErrPigAgeStageNotFound
}
return nil, fmt.Errorf("创建猪类型失败: %w", err)
}
// 创建后需要重新获取,以包含关联数据
createdPigType, err := s.recipeSvc.GetPigTypeByID(serviceCtx, pigType.ID)
if err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) { // 理论上不应该发生,因为刚创建
return nil, ErrPigTypeNotFound
}
return nil, fmt.Errorf("创建猪类型后获取详情失败: %w", err)
}
return dto.ConvertPigTypeToDTO(createdPigType), nil
}
// UpdatePigType 更新猪类型
func (s *pigTypeServiceImpl) UpdatePigType(ctx context.Context, id uint32, req *dto.UpdatePigTypeRequest) (*dto.PigTypeResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigType")
pigType := &models.PigType{
Model: models.Model{ID: id},
BreedID: req.BreedID,
AgeStageID: req.AgeStageID,
Description: req.Description,
DailyFeedIntake: req.DailyFeedIntake,
DailyGainWeight: req.DailyGainWeight,
MinDays: req.MinDays,
MaxDays: req.MaxDays,
MinWeight: req.MinWeight,
MaxWeight: req.MaxWeight,
}
if err := s.recipeSvc.UpdatePigType(serviceCtx, pigType); err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) {
return nil, ErrPigTypeNotFound
}
if errors.Is(err, recipe.ErrPigBreedNotFound) {
return nil, ErrPigBreedNotFound
}
if errors.Is(err, recipe.ErrPigAgeStageNotFound) {
return nil, ErrPigAgeStageNotFound
}
return nil, fmt.Errorf("更新猪类型失败: %w", err)
}
// 更新后需要重新获取,以包含关联数据
updatedPigType, err := s.recipeSvc.GetPigTypeByID(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) { // 理论上不应该发生,因为刚更新成功
return nil, ErrPigTypeNotFound
}
return nil, fmt.Errorf("更新猪类型后获取详情失败: %w", err)
}
return dto.ConvertPigTypeToDTO(updatedPigType), nil
}
// DeletePigType 删除猪类型
func (s *pigTypeServiceImpl) DeletePigType(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeletePigType")
err := s.recipeSvc.DeletePigType(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) {
return ErrPigTypeNotFound
}
return fmt.Errorf("删除猪类型失败: %w", err)
}
return nil
}
// GetPigType 获取单个猪类型
func (s *pigTypeServiceImpl) GetPigType(ctx context.Context, id uint32) (*dto.PigTypeResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetPigType")
pigType, err := s.recipeSvc.GetPigTypeByID(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) {
return nil, ErrPigTypeNotFound
}
return nil, fmt.Errorf("获取猪类型失败: %w", err)
}
return dto.ConvertPigTypeToDTO(pigType), nil
}
// ListPigTypes 列出猪类型
func (s *pigTypeServiceImpl) ListPigTypes(ctx context.Context, req *dto.ListPigTypeRequest) (*dto.ListPigTypeResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListPigTypes")
opts := repository.PigTypeListOptions{
BreedID: req.BreedID,
AgeStageID: req.AgeStageID,
BreedName: req.BreedName,
AgeStageName: req.AgeStageName,
OrderBy: req.OrderBy,
}
pigTypes, total, err := s.recipeSvc.ListPigTypes(serviceCtx, opts, req.Page, req.PageSize)
if err != nil {
return nil, fmt.Errorf("获取猪类型列表失败: %w", err)
}
return dto.ConvertPigTypeListToDTO(pigTypes, total, req.Page, req.PageSize), nil
}
// UpdatePigTypeNutrientRequirements 全量更新猪类型的营养需求
func (s *pigTypeServiceImpl) UpdatePigTypeNutrientRequirements(ctx context.Context, id uint32, req *dto.UpdatePigTypeNutrientRequirementsRequest) (*dto.PigTypeResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigTypeNutrientRequirements")
// 1. 将 DTO 转换为领域模型
requirements := make([]models.PigNutrientRequirement, len(req.NutrientRequirements))
for i, item := range req.NutrientRequirements {
requirements[i] = models.PigNutrientRequirement{
PigTypeID: id, // 设置所属的 PigTypeID
NutrientID: item.NutrientID,
MinRequirement: item.MinRequirement,
MaxRequirement: item.MaxRequirement,
}
}
// 2. 调用领域服务执行更新命令
err := s.recipeSvc.UpdatePigTypeNutrientRequirements(serviceCtx, id, requirements)
if err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) {
return nil, ErrPigTypeNotFound
}
// 此处可以根据领域层可能返回的其他特定错误进行转换
return nil, fmt.Errorf("更新猪类型营养需求失败: %w", err)
}
// 3. 更新成功后,调用查询服务获取最新的猪类型信息
updatedPigType, err := s.recipeSvc.GetPigTypeByID(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrPigTypeNotFound) {
// 理论上不应该发生,因为刚更新成功
return nil, ErrPigTypeNotFound
}
return nil, fmt.Errorf("更新后获取猪类型信息失败: %w", err)
}
// 4. 将领域模型转换为 DTO 并返回
return dto.ConvertPigTypeToDTO(updatedPigType), nil
}

View File

@@ -0,0 +1,157 @@
package service
import (
"context"
"errors"
"fmt"
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
"git.huangwc.com/pig/pig-farm-controller/internal/domain/recipe"
"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"
)
// 定义原料服务特定的错误
var (
ErrRawMaterialNameConflict = errors.New("原料名称已存在")
ErrRawMaterialNotFound = errors.New("原料不存在")
)
// RawMaterialService 定义了原料相关的应用服务接口
type RawMaterialService interface {
CreateRawMaterial(ctx context.Context, req *dto.CreateRawMaterialRequest) (*dto.RawMaterialResponse, error)
UpdateRawMaterial(ctx context.Context, id uint32, req *dto.UpdateRawMaterialRequest) (*dto.RawMaterialResponse, error)
DeleteRawMaterial(ctx context.Context, id uint32) error
GetRawMaterial(ctx context.Context, id uint32) (*dto.RawMaterialResponse, error)
ListRawMaterials(ctx context.Context, req *dto.ListRawMaterialRequest) (*dto.ListRawMaterialResponse, error)
UpdateRawMaterialNutrients(ctx context.Context, id uint32, req *dto.UpdateRawMaterialNutrientsRequest) (*dto.RawMaterialResponse, error)
}
// rawMaterialServiceImpl 是 RawMaterialService 接口的实现
type rawMaterialServiceImpl struct {
ctx context.Context
recipeSvc recipe.Service
}
// NewRawMaterialService 创建一个新的 RawMaterialService 实例
func NewRawMaterialService(ctx context.Context, recipeSvc recipe.Service) RawMaterialService {
return &rawMaterialServiceImpl{
ctx: ctx,
recipeSvc: recipeSvc,
}
}
// CreateRawMaterial 创建原料
func (s *rawMaterialServiceImpl) CreateRawMaterial(ctx context.Context, req *dto.CreateRawMaterialRequest) (*dto.RawMaterialResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateRawMaterial")
rawMaterial, err := s.recipeSvc.CreateRawMaterial(serviceCtx, req.Name, req.Description)
if err != nil {
if errors.Is(err, recipe.ErrRawMaterialNameConflict) {
return nil, ErrRawMaterialNameConflict
}
return nil, fmt.Errorf("创建原料失败: %w", err)
}
return dto.ConvertRawMaterialToDTO(rawMaterial), nil
}
// UpdateRawMaterial 更新原料
func (s *rawMaterialServiceImpl) UpdateRawMaterial(ctx context.Context, id uint32, req *dto.UpdateRawMaterialRequest) (*dto.RawMaterialResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateRawMaterial")
rawMaterial, err := s.recipeSvc.UpdateRawMaterial(serviceCtx, id, req.Name, req.Description)
if err != nil {
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
return nil, ErrRawMaterialNotFound
}
if errors.Is(err, recipe.ErrRawMaterialNameConflict) {
return nil, ErrRawMaterialNameConflict
}
return nil, fmt.Errorf("更新原料失败: %w", err)
}
return dto.ConvertRawMaterialToDTO(rawMaterial), nil
}
// DeleteRawMaterial 删除原料
func (s *rawMaterialServiceImpl) DeleteRawMaterial(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteRawMaterial")
err := s.recipeSvc.DeleteRawMaterial(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
return ErrRawMaterialNotFound
}
return fmt.Errorf("删除原料失败: %w", err)
}
return nil
}
// GetRawMaterial 获取单个原料
func (s *rawMaterialServiceImpl) GetRawMaterial(ctx context.Context, id uint32) (*dto.RawMaterialResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetRawMaterial")
rawMaterial, err := s.recipeSvc.GetRawMaterial(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
return nil, ErrRawMaterialNotFound
}
return nil, fmt.Errorf("获取原料失败: %w", err)
}
return dto.ConvertRawMaterialToDTO(rawMaterial), nil
}
// ListRawMaterials 列出原料
func (s *rawMaterialServiceImpl) ListRawMaterials(ctx context.Context, req *dto.ListRawMaterialRequest) (*dto.ListRawMaterialResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListRawMaterials")
opts := repository.RawMaterialListOptions{
Name: req.Name,
NutrientName: req.NutrientName,
OrderBy: req.OrderBy,
}
rawMaterials, total, err := s.recipeSvc.ListRawMaterials(serviceCtx, opts, req.Page, req.PageSize)
if err != nil {
return nil, fmt.Errorf("获取原料列表失败: %w", err)
}
return dto.ConvertRawMaterialListToDTO(rawMaterials, total, req.Page, req.PageSize), nil
}
// UpdateRawMaterialNutrients 全量更新原料的营养成分
func (s *rawMaterialServiceImpl) UpdateRawMaterialNutrients(ctx context.Context, id uint32, req *dto.UpdateRawMaterialNutrientsRequest) (*dto.RawMaterialResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateRawMaterialNutrients")
// 1. 将 DTO 转换为领域模型
nutrients := make([]models.RawMaterialNutrient, len(req.Nutrients))
for i, item := range req.Nutrients {
nutrients[i] = models.RawMaterialNutrient{
RawMaterialID: id,
NutrientID: item.NutrientID,
Value: item.Value,
}
}
// 2. 调用领域服务执行更新命令
err := s.recipeSvc.UpdateRawMaterialNutrients(serviceCtx, id, nutrients)
if err != nil {
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
return nil, ErrRawMaterialNotFound
}
// 此处可以根据领域层可能返回的其他特定错误进行转换
return nil, fmt.Errorf("更新原料营养成分失败: %w", err)
}
// 3. 更新成功后,调用查询服务获取最新的原料信息
updatedRawMaterial, err := s.recipeSvc.GetRawMaterial(serviceCtx, id)
if err != nil {
if errors.Is(err, recipe.ErrRawMaterialNotFound) {
// 理论上不应该发生,因为刚更新成功
return nil, ErrRawMaterialNotFound
}
return nil, fmt.Errorf("更新后获取原料信息失败: %w", err)
}
// 4. 将领域模型转换为 DTO 并返回
return dto.ConvertRawMaterialToDTO(updatedRawMaterial), nil
}

View File

@@ -63,7 +63,11 @@ func NewApplication(configPath string) (*Application, error) {
appServices.userService, appServices.userService,
appServices.auditService, appServices.auditService,
appServices.thresholdAlarmService, appServices.thresholdAlarmService,
appServices.feedManagementService, appServices.nutrientService,
appServices.rawMaterialService,
appServices.pigBreedService,
appServices.pigAgeStageService,
appServices.pigTypeService,
infra.tokenGenerator, infra.tokenGenerator,
infra.lora.listenHandler, infra.lora.listenHandler,
) )

View File

@@ -259,7 +259,11 @@ type AppServices struct {
userService service.UserService userService service.UserService
auditService service.AuditService auditService service.AuditService
thresholdAlarmService service.ThresholdAlarmService thresholdAlarmService service.ThresholdAlarmService
feedManagementService service.FeedManagementService nutrientService service.NutrientService
pigAgeStageService service.PigAgeStageService
pigBreedService service.PigBreedService
pigTypeService service.PigTypeService
rawMaterialService service.RawMaterialService
} }
// initAppServices 初始化所有的应用服务。 // initAppServices 初始化所有的应用服务。
@@ -307,7 +311,11 @@ func initAppServices(ctx context.Context, infra *Infrastructure, domainServices
auditService := service.NewAuditService(logs.AddCompName(baseCtx, "AuditService"), infra.repos.userActionLogRepo) auditService := service.NewAuditService(logs.AddCompName(baseCtx, "AuditService"), infra.repos.userActionLogRepo)
planService := service.NewPlanService(logs.AddCompName(baseCtx, "AppPlanService"), domainServices.planService) planService := service.NewPlanService(logs.AddCompName(baseCtx, "AppPlanService"), domainServices.planService)
userService := service.NewUserService(logs.AddCompName(baseCtx, "UserService"), infra.repos.userRepo, infra.tokenGenerator, domainServices.notifyService) userService := service.NewUserService(logs.AddCompName(baseCtx, "UserService"), infra.repos.userRepo, infra.tokenGenerator, domainServices.notifyService)
feedManagementService := service.NewFeedManagementService(logs.AddCompName(baseCtx, "FeedManagementService"), domainServices.recipeService) nutrientService := service.NewNutrientService(logs.AddCompName(baseCtx, "NutrientService"), domainServices.recipeService)
pigAgeStageService := service.NewPigAgeStageService(logs.AddCompName(baseCtx, "PigAgeStageService"), domainServices.recipeService)
pigBreedService := service.NewPigBreedService(logs.AddCompName(baseCtx, "PigBreedService"), domainServices.recipeService)
pigTypeService := service.NewPigTypeService(logs.AddCompName(baseCtx, "PigTypeService"), domainServices.recipeService)
rawMaterialService := service.NewRawMaterialService(logs.AddCompName(baseCtx, "RawMaterialService"), domainServices.recipeService)
return &AppServices{ return &AppServices{
pigFarmService: pigFarmService, pigFarmService: pigFarmService,
@@ -318,7 +326,11 @@ func initAppServices(ctx context.Context, infra *Infrastructure, domainServices
planService: planService, planService: planService,
userService: userService, userService: userService,
thresholdAlarmService: thresholdAlarmService, thresholdAlarmService: thresholdAlarmService,
feedManagementService: feedManagementService, nutrientService: nutrientService,
pigAgeStageService: pigAgeStageService,
pigBreedService: pigBreedService,
pigTypeService: pigTypeService,
rawMaterialService: rawMaterialService,
} }
} }

View File

@@ -48,7 +48,6 @@ internal/app/api/router.go
internal/app/controller/alarm/threshold_alarm_controller.go internal/app/controller/alarm/threshold_alarm_controller.go
internal/app/controller/auth_utils.go internal/app/controller/auth_utils.go
internal/app/controller/device/device_controller.go internal/app/controller/device/device_controller.go
internal/app/controller/feed/feed_controller.go
internal/app/controller/feed/nutrient_controller.go internal/app/controller/feed/nutrient_controller.go
internal/app/controller/feed/pig_age_stage_controller.go internal/app/controller/feed/pig_age_stage_controller.go
internal/app/controller/feed/pig_breed_controller.go internal/app/controller/feed/pig_breed_controller.go
@@ -85,12 +84,16 @@ internal/app/middleware/audit.go
internal/app/middleware/auth.go internal/app/middleware/auth.go
internal/app/service/audit_service.go internal/app/service/audit_service.go
internal/app/service/device_service.go internal/app/service/device_service.go
internal/app/service/feed_management_service.go
internal/app/service/monitor_service.go internal/app/service/monitor_service.go
internal/app/service/nutrient_service.go
internal/app/service/pig_age_stage_service.go
internal/app/service/pig_batch_service.go internal/app/service/pig_batch_service.go
internal/app/service/pig_breed_service.go
internal/app/service/pig_farm_service.go internal/app/service/pig_farm_service.go
internal/app/service/pig_service.go internal/app/service/pig_service.go
internal/app/service/pig_type_service.go
internal/app/service/plan_service.go internal/app/service/plan_service.go
internal/app/service/raw_material_service.go
internal/app/service/threshold_alarm_service.go internal/app/service/threshold_alarm_service.go
internal/app/service/user_service.go internal/app/service/user_service.go
internal/app/webhook/chirp_stack.go internal/app/webhook/chirp_stack.go