diff --git a/design/archive/recipe-management/index.md b/design/archive/recipe-management/index.md index 0348367..9c25944 100644 --- a/design/archive/recipe-management/index.md +++ b/design/archive/recipe-management/index.md @@ -53,4 +53,5 @@ http://git.huangwc.com/pig/pig-farm-controller/issues/66 3. 定义配方领域, 实现营养元素的增删改查 4. 实现原材料的增删改查和仓库层的原料库存记录表增查 5. 定义猪的模型和营养需求模型 -6. 实现从json读取猪营养需求并写入数据库 \ No newline at end of file +6. 实现从json读取猪营养需求并写入数据库 +7. 实现配方领域关于猪模型和营养需求的增删改查 \ No newline at end of file diff --git a/docs/docs.go b/docs/docs.go index dc7ca45..a8352fe 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1826,7 +1826,6 @@ const docTemplate = `{ }, { "enum": [ - 7, -1, 0, 1, @@ -1836,12 +1835,12 @@ const docTemplate = `{ 5, -1, 5, - 6 + 6, + 7 ], "type": "integer", "format": "int32", "x-enum-varnames": [ - "_numLevels", "DebugLevel", "InfoLevel", "WarnLevel", @@ -1851,7 +1850,8 @@ const docTemplate = `{ "FatalLevel", "_minLevel", "_maxLevel", - "InvalidLevel" + "InvalidLevel", + "_numLevels" ], "name": "level", "in": "query" @@ -7563,32 +7563,24 @@ const docTemplate = `{ "models.PigBatchStatus": { "type": "string", "enum": [ - "保育", - "生长", - "育肥", + "生产中", "待售", "已出售", "已归档" ], "x-enum-comments": { + "BatchStatusActive": "饲养中", "BatchStatusArchived": "批次结束(如全群淘汰等)", - "BatchStatusFinishing": "最后的育肥阶段", - "BatchStatusForSale": "达到出栏标准", - "BatchStatusGrowing": "生长育肥阶段", - "BatchStatusWeaning": "从断奶到保育结束" + "BatchStatusForSale": "达到出栏标准" }, "x-enum-descriptions": [ - "从断奶到保育结束", - "生长育肥阶段", - "最后的育肥阶段", + "饲养中", "达到出栏标准", "", "批次结束(如全群淘汰等)" ], "x-enum-varnames": [ - "BatchStatusWeaning", - "BatchStatusGrowing", - "BatchStatusFinishing", + "BatchStatusActive", "BatchStatusForSale", "BatchStatusSold", "BatchStatusArchived" @@ -7837,7 +7829,6 @@ const docTemplate = `{ "type": "integer", "format": "int32", "enum": [ - 7, -1, 0, 1, @@ -7847,10 +7838,10 @@ const docTemplate = `{ 5, -1, 5, - 6 + 6, + 7 ], "x-enum-varnames": [ - "_numLevels", "DebugLevel", "InfoLevel", "WarnLevel", @@ -7860,7 +7851,8 @@ const docTemplate = `{ "FatalLevel", "_minLevel", "_maxLevel", - "InvalidLevel" + "InvalidLevel", + "_numLevels" ] } }, diff --git a/docs/swagger.json b/docs/swagger.json index e300abb..01c16a5 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1818,7 +1818,6 @@ }, { "enum": [ - 7, -1, 0, 1, @@ -1828,12 +1827,12 @@ 5, -1, 5, - 6 + 6, + 7 ], "type": "integer", "format": "int32", "x-enum-varnames": [ - "_numLevels", "DebugLevel", "InfoLevel", "WarnLevel", @@ -1843,7 +1842,8 @@ "FatalLevel", "_minLevel", "_maxLevel", - "InvalidLevel" + "InvalidLevel", + "_numLevels" ], "name": "level", "in": "query" @@ -7555,32 +7555,24 @@ "models.PigBatchStatus": { "type": "string", "enum": [ - "保育", - "生长", - "育肥", + "生产中", "待售", "已出售", "已归档" ], "x-enum-comments": { + "BatchStatusActive": "饲养中", "BatchStatusArchived": "批次结束(如全群淘汰等)", - "BatchStatusFinishing": "最后的育肥阶段", - "BatchStatusForSale": "达到出栏标准", - "BatchStatusGrowing": "生长育肥阶段", - "BatchStatusWeaning": "从断奶到保育结束" + "BatchStatusForSale": "达到出栏标准" }, "x-enum-descriptions": [ - "从断奶到保育结束", - "生长育肥阶段", - "最后的育肥阶段", + "饲养中", "达到出栏标准", "", "批次结束(如全群淘汰等)" ], "x-enum-varnames": [ - "BatchStatusWeaning", - "BatchStatusGrowing", - "BatchStatusFinishing", + "BatchStatusActive", "BatchStatusForSale", "BatchStatusSold", "BatchStatusArchived" @@ -7829,7 +7821,6 @@ "type": "integer", "format": "int32", "enum": [ - 7, -1, 0, 1, @@ -7839,10 +7830,10 @@ 5, -1, 5, - 6 + 6, + 7 ], "x-enum-varnames": [ - "_numLevels", "DebugLevel", "InfoLevel", "WarnLevel", @@ -7852,7 +7843,8 @@ "FatalLevel", "_minLevel", "_maxLevel", - "InvalidLevel" + "InvalidLevel", + "_numLevels" ] } }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 50e51df..d9aff30 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1905,30 +1905,22 @@ definitions: - TreatmentLocationSickBay models.PigBatchStatus: enum: - - 保育 - - 生长 - - 育肥 + - 生产中 - 待售 - 已出售 - 已归档 type: string x-enum-comments: + BatchStatusActive: 饲养中 BatchStatusArchived: 批次结束(如全群淘汰等) - BatchStatusFinishing: 最后的育肥阶段 BatchStatusForSale: 达到出栏标准 - BatchStatusGrowing: 生长育肥阶段 - BatchStatusWeaning: 从断奶到保育结束 x-enum-descriptions: - - 从断奶到保育结束 - - 生长育肥阶段 - - 最后的育肥阶段 + - 饲养中 - 达到出栏标准 - "" - 批次结束(如全群淘汰等) x-enum-varnames: - - BatchStatusWeaning - - BatchStatusGrowing - - BatchStatusFinishing + - BatchStatusActive - BatchStatusForSale - BatchStatusSold - BatchStatusArchived @@ -2129,7 +2121,6 @@ definitions: - PlanTypeFilterSystem zapcore.Level: enum: - - 7 - -1 - 0 - 1 @@ -2140,10 +2131,10 @@ definitions: - -1 - 5 - 6 + - 7 format: int32 type: integer x-enum-varnames: - - _numLevels - DebugLevel - InfoLevel - WarnLevel @@ -2154,6 +2145,7 @@ definitions: - _minLevel - _maxLevel - InvalidLevel + - _numLevels info: contact: email: divano@example.com @@ -3270,7 +3262,6 @@ paths: name: end_time type: string - enum: - - 7 - -1 - 0 - 1 @@ -3281,12 +3272,12 @@ paths: - -1 - 5 - 6 + - 7 format: int32 in: query name: level type: integer x-enum-varnames: - - _numLevels - DebugLevel - InfoLevel - WarnLevel @@ -3297,6 +3288,7 @@ paths: - _minLevel - _maxLevel - InvalidLevel + - _numLevels - enum: - 邮件 - 企业微信 diff --git a/internal/domain/recipe/recipe_service.go b/internal/domain/recipe/recipe_service.go index f6b22e2..c7d6483 100644 --- a/internal/domain/recipe/recipe_service.go +++ b/internal/domain/recipe/recipe_service.go @@ -14,12 +14,15 @@ import ( // 定义领域特定的错误 var ( - ErrNutrientNameConflict = fmt.Errorf("营养种类名称已存在") - ErrNutrientNotFound = fmt.Errorf("营养种类不存在") - ErrNutrientInUse = fmt.Errorf("营养种类正在被原料使用,无法删除") - + ErrNutrientNameConflict = fmt.Errorf("营养种类名称已存在") + ErrNutrientNotFound = fmt.Errorf("营养种类不存在") ErrRawMaterialNameConflict = fmt.Errorf("原料名称已存在") ErrRawMaterialNotFound = fmt.Errorf("原料不存在") + ErrPigBreedInUse = fmt.Errorf("猪品种正在被猪类型使用,无法删除") + ErrPigBreedNotFound = fmt.Errorf("猪品种不存在") + ErrPigAgeStageInUse = fmt.Errorf("猪年龄阶段正在被猪类型使用,无法删除") + ErrPigAgeStageNotFound = fmt.Errorf("猪年龄阶段不存在") + ErrPigTypeNotFound = fmt.Errorf("猪类型不存在") ) // Service 定义了配方与原料领域的核心业务服务接口 @@ -37,6 +40,27 @@ type Service interface { DeleteRawMaterial(ctx context.Context, id uint32) error GetRawMaterial(ctx context.Context, id uint32) (*models.RawMaterial, error) ListRawMaterials(ctx context.Context, page, pageSize int) ([]models.RawMaterial, int64, error) + + // 猪品种相关接口 + CreatePigBreed(ctx context.Context, breed *models.PigBreed) error + GetPigBreedByID(ctx context.Context, id uint32) (*models.PigBreed, error) + UpdatePigBreed(ctx context.Context, breed *models.PigBreed) error + DeletePigBreed(ctx context.Context, id uint32) error + ListPigBreeds(ctx context.Context, opts repository.PigBreedListOptions, page, pageSize int) ([]models.PigBreed, int64, error) + + // 猪年龄阶段相关接口 + CreatePigAgeStage(ctx context.Context, ageStage *models.PigAgeStage) error + GetPigAgeStageByID(ctx context.Context, id uint32) (*models.PigAgeStage, error) + UpdatePigAgeStage(ctx context.Context, ageStage *models.PigAgeStage) error + DeletePigAgeStage(ctx context.Context, id uint32) error + ListPigAgeStages(ctx context.Context, opts repository.PigAgeStageListOptions, page, pageSize int) ([]models.PigAgeStage, int64, error) + + // 猪类型相关接口 + CreatePigType(ctx context.Context, pigType *models.PigType) error + GetPigTypeByID(ctx context.Context, id uint32) (*models.PigType, error) + UpdatePigType(ctx context.Context, pigType *models.PigType) error + DeletePigType(ctx context.Context, id uint32) error + ListPigTypes(ctx context.Context, opts repository.PigTypeListOptions, page, pageSize int) ([]models.PigType, int64, error) } // recipeServiceImpl 是 RecipeService 的实现 @@ -44,14 +68,16 @@ type recipeServiceImpl struct { ctx context.Context nutrientRepo repository.NutrientRepository rawMaterialRepo repository.RawMaterialRepository + pigTypeRepo repository.PigTypeRepository } // NewRecipeService 创建一个新的 RecipeService 实例 -func NewRecipeService(ctx context.Context, nutrientRepo repository.NutrientRepository, rawMaterialRepo repository.RawMaterialRepository) Service { +func NewRecipeService(ctx context.Context, nutrientRepo repository.NutrientRepository, rawMaterialRepo repository.RawMaterialRepository, pigTypeRepo repository.PigTypeRepository) Service { return &recipeServiceImpl{ ctx: ctx, nutrientRepo: nutrientRepo, rawMaterialRepo: rawMaterialRepo, + pigTypeRepo: pigTypeRepo, } } @@ -262,3 +288,203 @@ func (s *recipeServiceImpl) ListRawMaterials(ctx context.Context, page, pageSize } return rawMaterials, total, nil } + +// CreatePigBreed 实现了创建猪品种的核心业务逻辑 +func (s *recipeServiceImpl) CreatePigBreed(ctx context.Context, breed *models.PigBreed) error { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreatePigBreed") + if err := s.pigTypeRepo.CreatePigBreed(serviceCtx, breed); err != nil { + return fmt.Errorf("创建猪品种失败: %w", err) + } + return nil +} + +// GetPigBreedByID 实现了获取单个猪品种的逻辑 +func (s *recipeServiceImpl) GetPigBreedByID(ctx context.Context, id uint32) (*models.PigBreed, error) { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetPigBreedByID") + breed, err := s.pigTypeRepo.GetPigBreedByID(serviceCtx, id) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, ErrPigBreedNotFound + } + return nil, fmt.Errorf("获取猪品种失败: %w", err) + } + return breed, nil +} + +// UpdatePigBreed 实现了更新猪品种的核心业务逻辑 +func (s *recipeServiceImpl) UpdatePigBreed(ctx context.Context, breed *models.PigBreed) error { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigBreed") + if err := s.pigTypeRepo.UpdatePigBreed(serviceCtx, breed); err != nil { + return fmt.Errorf("更新猪品种失败: %w", err) + } + return nil +} + +// DeletePigBreed 实现了删除猪品种的核心业务逻辑 +func (s *recipeServiceImpl) DeletePigBreed(ctx context.Context, id uint32) error { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeletePigBreed") + + // 检查是否有猪类型关联到该品种 + opts := repository.PigTypeListOptions{BreedID: &id} + pigTypes, _, err := s.pigTypeRepo.ListPigTypes(serviceCtx, opts, 1, 1) // 只需检查是否存在,所以取1条 + if err != nil { + return fmt.Errorf("检查猪品种关联失败: %w", err) + } + if len(pigTypes) > 0 { + return ErrPigBreedInUse + } + + // 检查实体是否存在 + _, err = s.pigTypeRepo.GetPigBreedByID(serviceCtx, id) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return ErrPigBreedNotFound + } + return fmt.Errorf("获取待删除的猪品种失败: %w", err) + } + + if err := s.pigTypeRepo.DeletePigBreed(serviceCtx, id); err != nil { + return fmt.Errorf("删除猪品种失败: %w", err) + } + return nil +} + +// ListPigBreeds 实现了列出猪品种的逻辑 +func (s *recipeServiceImpl) ListPigBreeds(ctx context.Context, opts repository.PigBreedListOptions, page, pageSize int) ([]models.PigBreed, int64, error) { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListPigBreeds") + breeds, total, err := s.pigTypeRepo.ListPigBreeds(serviceCtx, opts, page, pageSize) + if err != nil { + return nil, 0, fmt.Errorf("获取猪品种列表失败: %w", err) + } + return breeds, total, nil +} + +// CreatePigAgeStage 实现了创建猪年龄阶段的核心业务逻辑 +func (s *recipeServiceImpl) CreatePigAgeStage(ctx context.Context, ageStage *models.PigAgeStage) error { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreatePigAgeStage") + if err := s.pigTypeRepo.CreatePigAgeStage(serviceCtx, ageStage); err != nil { + return fmt.Errorf("创建猪年龄阶段失败: %w", err) + } + return nil +} + +// GetPigAgeStageByID 实现了获取单个猪年龄阶段的逻辑 +func (s *recipeServiceImpl) GetPigAgeStageByID(ctx context.Context, id uint32) (*models.PigAgeStage, error) { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetPigAgeStageByID") + ageStage, err := s.pigTypeRepo.GetPigAgeStageByID(serviceCtx, id) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, ErrPigAgeStageNotFound + } + return nil, fmt.Errorf("获取猪年龄阶段失败: %w", err) + } + return ageStage, nil +} + +// UpdatePigAgeStage 实现了更新猪年龄阶段的核心业务逻辑 +func (s *recipeServiceImpl) UpdatePigAgeStage(ctx context.Context, ageStage *models.PigAgeStage) error { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigAgeStage") + if err := s.pigTypeRepo.UpdatePigAgeStage(serviceCtx, ageStage); err != nil { + return fmt.Errorf("更新猪年龄阶段失败: %w", err) + } + return nil +} + +// DeletePigAgeStage 实现了删除猪年龄阶段的核心业务逻辑 +func (s *recipeServiceImpl) DeletePigAgeStage(ctx context.Context, id uint32) error { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeletePigAgeStage") + + // 检查是否有猪类型关联到该年龄阶段 + opts := repository.PigTypeListOptions{AgeStageID: &id} + pigTypes, _, err := s.pigTypeRepo.ListPigTypes(serviceCtx, opts, 1, 1) // 只需检查是否存在,所以取1条 + if err != nil { + return fmt.Errorf("检查猪年龄阶段关联失败: %w", err) + } + if len(pigTypes) > 0 { + return ErrPigAgeStageInUse + } + + // 检查实体是否存在 + _, err = s.pigTypeRepo.GetPigAgeStageByID(serviceCtx, id) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return ErrPigAgeStageNotFound + } + return fmt.Errorf("获取待删除的猪年龄阶段失败: %w", err) + } + + if err := s.pigTypeRepo.DeletePigAgeStage(serviceCtx, id); err != nil { + return fmt.Errorf("删除猪年龄阶段失败: %w", err) + } + return nil +} + +// ListPigAgeStages 实现了列出猪年龄阶段的逻辑 +func (s *recipeServiceImpl) ListPigAgeStages(ctx context.Context, opts repository.PigAgeStageListOptions, page, pageSize int) ([]models.PigAgeStage, int64, error) { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListPigAgeStages") + ageStages, total, err := s.pigTypeRepo.ListPigAgeStages(serviceCtx, opts, page, pageSize) + if err != nil { + return nil, 0, fmt.Errorf("获取猪年龄阶段列表失败: %w", err) + } + return ageStages, total, nil +} + +// CreatePigType 实现了创建猪类型的核心业务逻辑 +func (s *recipeServiceImpl) CreatePigType(ctx context.Context, pigType *models.PigType) error { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreatePigType") + if err := s.pigTypeRepo.CreatePigType(serviceCtx, pigType); err != nil { + return fmt.Errorf("创建猪类型失败: %w", err) + } + return nil +} + +// GetPigTypeByID 实现了获取单个猪类型的逻辑 +func (s *recipeServiceImpl) GetPigTypeByID(ctx context.Context, id uint32) (*models.PigType, error) { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetPigTypeByID") + pigType, err := s.pigTypeRepo.GetPigTypeByID(serviceCtx, id) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, ErrPigTypeNotFound + } + return nil, fmt.Errorf("获取猪类型失败: %w", err) + } + return pigType, nil +} + +// UpdatePigType 实现了更新猪类型的核心业务逻辑 +func (s *recipeServiceImpl) UpdatePigType(ctx context.Context, pigType *models.PigType) error { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdatePigType") + if err := s.pigTypeRepo.UpdatePigType(serviceCtx, pigType); err != nil { + return fmt.Errorf("更新猪类型失败: %m", err) + } + return nil +} + +// DeletePigType 实现了删除猪类型的核心业务逻辑 +func (s *recipeServiceImpl) DeletePigType(ctx context.Context, id uint32) error { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeletePigType") + + // 检查实体是否存在 + _, err := s.pigTypeRepo.GetPigTypeByID(serviceCtx, id) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return ErrPigTypeNotFound + } + return fmt.Errorf("获取待删除的猪类型失败: %w", err) + } + + if err := s.pigTypeRepo.DeletePigType(serviceCtx, id); err != nil { + return fmt.Errorf("删除猪类型失败: %w", err) + } + return nil +} + +// ListPigTypes 实现了列出猪类型的逻辑 +func (s *recipeServiceImpl) ListPigTypes(ctx context.Context, opts repository.PigTypeListOptions, page, pageSize int) ([]models.PigType, int64, error) { + serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListPigTypes") + pigTypes, total, err := s.pigTypeRepo.ListPigTypes(serviceCtx, opts, page, pageSize) + if err != nil { + return nil, 0, fmt.Errorf("获取猪类型列表失败: %w", err) + } + return pigTypes, total, nil +} diff --git a/internal/infra/models/pig.go b/internal/infra/models/pig.go index 788e575..3796a3c 100644 --- a/internal/infra/models/pig.go +++ b/internal/infra/models/pig.go @@ -4,7 +4,7 @@ package models type PigBreed struct { Model Name string `gorm:"size:50;not null;comment:品种名称"` - Description string `gorm:"type:text" json:"description"` // 保留描述字段 + Description string `gorm:"type:text" json:"description"` // 其他描述 ParentInfo string `gorm:"type:text" json:"parent_info"` // 父母信息 AppearanceFeatures string `gorm:"type:text" json:"appearance_features"` // 外貌特征 BreedAdvantages string `gorm:"type:text" json:"breed_advantages"` // 品种优点 @@ -29,17 +29,18 @@ func (PigAgeStage) TableName() string { // PigType 猪类型模型,代表特定品种和年龄阶段的组合 type PigType struct { Model - BreedID uint32 `gorm:"not null;index;comment:关联的猪品种ID"` - Breed PigBreed `gorm:"foreignKey:BreedID"` - AgeStageID uint32 `gorm:"not null;index;comment:关联的猪年龄阶段ID"` - AgeStage PigAgeStage `gorm:"foreignKey:AgeStageID"` - Description string `gorm:"size:255;comment:该猪类型的描述或特点"` - DailyFeedIntake float32 `gorm:"comment:理论日均食量 (g/天)"` - DailyGainWeight float32 `gorm:"comment:理论日增重 (g/天)"` - MinDays uint32 `gorm:"comment:该猪类型在该年龄阶段的最小日龄"` - MaxDays uint32 `gorm:"comment:该猪类型在该年龄阶段的最大日龄"` - MinWeight float32 `gorm:"comment:该猪类型在该年龄阶段的最小体重 (g)"` - MaxWeight float32 `gorm:"comment:该猪类型在该年龄阶段的最大体重 (g)"` + BreedID uint32 `gorm:"not null;index;comment:关联的猪品种ID"` + Breed PigBreed `gorm:"foreignKey:BreedID"` + AgeStageID uint32 `gorm:"not null;index;comment:关联的猪年龄阶段ID"` + AgeStage PigAgeStage `gorm:"foreignKey:AgeStageID"` + Description string `gorm:"size:255;comment:该猪类型的描述或特点"` + DailyFeedIntake float32 `gorm:"comment:理论日均食量 (g/天)"` + DailyGainWeight float32 `gorm:"comment:理论日增重 (g/天)"` + MinDays uint32 `gorm:"comment:该猪类型在该年龄阶段的最小日龄"` + MaxDays uint32 `gorm:"comment:该猪类型在该年龄阶段的最大日龄"` + MinWeight float32 `gorm:"comment:该猪类型在该年龄阶段的最小体重 (g)"` + MaxWeight float32 `gorm:"comment:该猪类型在该年龄阶段的最大体重 (g)"` + PigNutrientRequirements []PigNutrientRequirement `gorm:"foreignKey:PigTypeID"` } func (PigType) TableName() string { diff --git a/internal/infra/repository/pig_type_repository.go b/internal/infra/repository/pig_type_repository.go new file mode 100644 index 0000000..05a9e65 --- /dev/null +++ b/internal/infra/repository/pig_type_repository.go @@ -0,0 +1,281 @@ +package repository + +import ( + "context" + + "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" + "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" + + "gorm.io/gorm" +) + +// PigBreedListOptions 定义了查询猪品种记录时的可选参数 +type PigBreedListOptions struct { + Name *string // 品种名称 + OrderBy string // 例如 "name asc" +} + +// PigAgeStageListOptions 定义了查询猪年龄阶段记录时的可选参数 +type PigAgeStageListOptions struct { + Name *string // 年龄阶段名称 + OrderBy string // 例如 "name asc" +} + +// PigTypeListOptions 定义了查询猪类型记录时的可选参数 +type PigTypeListOptions struct { + BreedID *uint32 // 关联的猪品种ID + AgeStageID *uint32 // 关联的猪年龄阶段ID + BreedName *string // 关联的猪品种名称 (用于模糊查询) + AgeStageName *string // 关联的猪年龄阶段名称 (用于模糊查询) + OrderBy string // 例如 "id desc" +} + +// PigTypeRepository 定义了猪品种、猪年龄阶段和猪类型数据持久化的接口。 +type PigTypeRepository interface { + + // <-- 猪品种相关接口 --> + + // CreatePigBreed 在数据库中创建一条猪品种记录。 + CreatePigBreed(ctx context.Context, breed *models.PigBreed) error + // GetPigBreedByID 根据ID获取猪品种记录。 + GetPigBreedByID(ctx context.Context, id uint32) (*models.PigBreed, error) + // UpdatePigBreed 更新猪品种记录。 + UpdatePigBreed(ctx context.Context, breed *models.PigBreed) error + // DeletePigBreed 根据ID删除猪品种记录。 + DeletePigBreed(ctx context.Context, id uint32) error + // ListPigBreeds 支持分页和过滤的猪品种记录列表查询。 + ListPigBreeds(ctx context.Context, opts PigBreedListOptions, page, pageSize int) ([]models.PigBreed, int64, error) + + // <-- 猪年龄阶段相关接口 --> + + // CreatePigAgeStage 在数据库中创建一条猪年龄阶段记录。 + CreatePigAgeStage(ctx context.Context, ageStage *models.PigAgeStage) error + // GetPigAgeStageByID 根据ID获取猪年龄阶段记录。 + GetPigAgeStageByID(ctx context.Context, id uint32) (*models.PigAgeStage, error) + // UpdatePigAgeStage 更新猪年龄阶段记录。 + UpdatePigAgeStage(ctx context.Context, ageStage *models.PigAgeStage) error + // DeletePigAgeStage 根据ID删除猪年龄阶段记录。 + DeletePigAgeStage(ctx context.Context, id uint32) error + // ListPigAgeStages 支持分页和过滤的猪年龄阶段记录列表查询。 + ListPigAgeStages(ctx context.Context, opts PigAgeStageListOptions, page, pageSize int) ([]models.PigAgeStage, int64, error) + + // <-- 猪类型相关接口 --> + + // CreatePigType 在数据库中创建一条猪类型记录。 + CreatePigType(ctx context.Context, pigType *models.PigType) error + // GetPigTypeByID 根据ID获取猪类型记录。 + GetPigTypeByID(ctx context.Context, id uint32) (*models.PigType, error) + // UpdatePigType 更新猪类型记录。 + UpdatePigType(ctx context.Context, pigType *models.PigType) error + // DeletePigType 根据ID删除猪类型记录。 + DeletePigType(ctx context.Context, id uint32) error + // ListPigTypes 支持分页和过滤的猪类型记录列表查询。 + ListPigTypes(ctx context.Context, opts PigTypeListOptions, page, pageSize int) ([]models.PigType, int64, error) +} + +// gormPigTypeRepository 是 PigTypeRepository 接口的 GORM 实现。 +type gormPigTypeRepository struct { + ctx context.Context + db *gorm.DB +} + +// NewGormPigTypeRepository 创建一个新的 PigTypeRepository GORM 实现实例。 +func NewGormPigTypeRepository(ctx context.Context, db *gorm.DB) PigTypeRepository { + return &gormPigTypeRepository{ctx: ctx, db: db} +} + +// CreatePigBreed 实现了在数据库中创建猪品种记录的逻辑。 +func (r *gormPigTypeRepository) CreatePigBreed(ctx context.Context, breed *models.PigBreed) error { + repoCtx := logs.AddFuncName(ctx, r.ctx, "CreatePigBreed") + return r.db.WithContext(repoCtx).Create(breed).Error +} + +// GetPigBreedByID 实现了根据ID获取猪品种记录的逻辑。 +func (r *gormPigTypeRepository) GetPigBreedByID(ctx context.Context, id uint32) (*models.PigBreed, error) { + repoCtx := logs.AddFuncName(ctx, r.ctx, "GetPigBreedByID") + var breed models.PigBreed + err := r.db.WithContext(repoCtx).First(&breed, id).Error + if err != nil { + return nil, err + } + return &breed, nil +} + +// UpdatePigBreed 实现了更新猪品种记录的逻辑。 +func (r *gormPigTypeRepository) UpdatePigBreed(ctx context.Context, breed *models.PigBreed) error { + repoCtx := logs.AddFuncName(ctx, r.ctx, "UpdatePigBreed") + return r.db.WithContext(repoCtx).Save(breed).Error +} + +// DeletePigBreed 实现了根据ID删除猪品种记录的逻辑。 +func (r *gormPigTypeRepository) DeletePigBreed(ctx context.Context, id uint32) error { + repoCtx := logs.AddFuncName(ctx, r.ctx, "DeletePigBreed") + return r.db.WithContext(repoCtx).Delete(&models.PigBreed{}, id).Error +} + +// ListPigBreeds 实现了分页和过滤查询猪品种记录的功能。 +func (r *gormPigTypeRepository) ListPigBreeds(ctx context.Context, opts PigBreedListOptions, page, pageSize int) ([]models.PigBreed, int64, error) { + repoCtx := logs.AddFuncName(ctx, r.ctx, "ListPigBreeds") + if page <= 0 || pageSize <= 0 { + return nil, 0, ErrInvalidPagination + } + + var results []models.PigBreed + var total int64 + + query := r.db.WithContext(repoCtx).Model(&models.PigBreed{}) + + if opts.Name != nil { + query = query.Where("name LIKE ?", "%"+*opts.Name+"%") + } + + if err := query.Count(&total).Error; err != nil { + return nil, 0, err + } + + orderBy := "id DESC" // 默认排序 + if opts.OrderBy != "" { + orderBy = opts.OrderBy + } + query = query.Order(orderBy) + + offset := (page - 1) * pageSize + err := query.Limit(pageSize).Offset(offset).Find(&results).Error + + return results, total, err +} + +// CreatePigAgeStage 实现了在数据库中创建猪年龄阶段记录的逻辑。 +func (r *gormPigTypeRepository) CreatePigAgeStage(ctx context.Context, ageStage *models.PigAgeStage) error { + repoCtx := logs.AddFuncName(ctx, r.ctx, "CreatePigAgeStage") + return r.db.WithContext(repoCtx).Create(ageStage).Error +} + +// GetPigAgeStageByID 实现了根据ID获取猪年龄阶段记录的逻辑。 +func (r *gormPigTypeRepository) GetPigAgeStageByID(ctx context.Context, id uint32) (*models.PigAgeStage, error) { + repoCtx := logs.AddFuncName(ctx, r.ctx, "GetPigAgeStageByID") + var ageStage models.PigAgeStage + err := r.db.WithContext(repoCtx).First(&ageStage, id).Error + if err != nil { + return nil, err + } + return &ageStage, nil +} + +// UpdatePigAgeStage 实现了更新猪年龄阶段记录的逻辑。 +func (r *gormPigTypeRepository) UpdatePigAgeStage(ctx context.Context, ageStage *models.PigAgeStage) error { + repoCtx := logs.AddFuncName(ctx, r.ctx, "UpdatePigAgeStage") + return r.db.WithContext(repoCtx).Save(ageStage).Error +} + +// DeletePigAgeStage 实现了根据ID删除猪年龄阶段记录的逻辑。 +func (r *gormPigTypeRepository) DeletePigAgeStage(ctx context.Context, id uint32) error { + repoCtx := logs.AddFuncName(ctx, r.ctx, "DeletePigAgeStage") + return r.db.WithContext(repoCtx).Delete(&models.PigAgeStage{}, id).Error +} + +// ListPigAgeStages 实现了分页和过滤查询猪年龄阶段记录的功能。 +func (r *gormPigTypeRepository) ListPigAgeStages(ctx context.Context, opts PigAgeStageListOptions, page, pageSize int) ([]models.PigAgeStage, int64, error) { + repoCtx := logs.AddFuncName(ctx, r.ctx, "ListPigAgeStages") + if page <= 0 || pageSize <= 0 { + return nil, 0, ErrInvalidPagination + } + + var results []models.PigAgeStage + var total int64 + + query := r.db.WithContext(repoCtx).Model(&models.PigAgeStage{}) + + if opts.Name != nil { + query = query.Where("name LIKE ?", "%"+*opts.Name+"%") + } + + if err := query.Count(&total).Error; err != nil { + return nil, 0, err + } + + orderBy := "id DESC" // 默认排序 + if opts.OrderBy != "" { + orderBy = opts.OrderBy + } + query = query.Order(orderBy) + + offset := (page - 1) * pageSize + err := query.Limit(pageSize).Offset(offset).Find(&results).Error + + return results, total, err +} + +// CreatePigType 实现了在数据库中创建猪类型记录的逻辑。 +func (r *gormPigTypeRepository) CreatePigType(ctx context.Context, pigType *models.PigType) error { + repoCtx := logs.AddFuncName(ctx, r.ctx, "CreatePigType") + return r.db.WithContext(repoCtx).Create(pigType).Error +} + +// GetPigTypeByID 实现了根据ID获取猪类型记录的逻辑。 +func (r *gormPigTypeRepository) GetPigTypeByID(ctx context.Context, id uint32) (*models.PigType, error) { + repoCtx := logs.AddFuncName(ctx, r.ctx, "GetPigTypeByID") + var pigType models.PigType + err := r.db.WithContext(repoCtx).Preload("Breed").Preload("AgeStage").First(&pigType, id).Error + if err != nil { + return nil, err + } + return &pigType, nil +} + +// UpdatePigType 实现了更新猪类型记录的逻辑。 +func (r *gormPigTypeRepository) UpdatePigType(ctx context.Context, pigType *models.PigType) error { + repoCtx := logs.AddFuncName(ctx, r.ctx, "UpdatePigType") + return r.db.WithContext(repoCtx).Save(pigType).Error +} + +// DeletePigType 实现了根据ID删除猪类型记录的逻辑。 +func (r *gormPigTypeRepository) DeletePigType(ctx context.Context, id uint32) error { + repoCtx := logs.AddFuncName(ctx, r.ctx, "DeletePigType") + return r.db.WithContext(repoCtx).Delete(&models.PigType{}, id).Error +} + +// ListPigTypes 实现了分页和过滤查询猪类型记录的功能。 +func (r *gormPigTypeRepository) ListPigTypes(ctx context.Context, opts PigTypeListOptions, page, pageSize int) ([]models.PigType, int64, error) { + repoCtx := logs.AddFuncName(ctx, r.ctx, "ListPigTypes") + + if page <= 0 || pageSize <= 0 { + return nil, 0, ErrInvalidPagination + } + + var results []models.PigType + var total int64 + + query := r.db.WithContext(repoCtx).Model(&models.PigType{}) + + if opts.BreedID != nil { + query = query.Where("breed_id = ?", *opts.BreedID) + } + if opts.AgeStageID != nil { + query = query.Where("age_stage_id = ?", *opts.AgeStageID) + } + + if opts.BreedName != nil { + query = query.Joins("left join pig_breeds on pig_types.breed_id = pig_breeds.id"). + Where("pig_breeds.name LIKE ?", "%"+*opts.BreedName+"%") + } + if opts.AgeStageName != nil { + query = query.Joins("left join pig_age_stages on pig_types.age_stage_id = pig_age_stages.id"). + Where("pig_age_stages.name LIKE ?", "%"+*opts.AgeStageName+"%") + } + + if err := query.Count(&total).Error; err != nil { + return nil, 0, err + } + + orderBy := "id DESC" // 默认排序 + if opts.OrderBy != "" { + orderBy = opts.OrderBy + } + query = query.Order(orderBy) + + offset := (page - 1) * pageSize + err := query.Limit(pageSize).Offset(offset).Preload("Breed").Preload("AgeStage").Find(&results).Error + + return results, total, err +} diff --git a/project_structure.txt b/project_structure.txt index dbd7129..ab57131 100644 --- a/project_structure.txt +++ b/project_structure.txt @@ -1,4 +1,6 @@  +.continue/mcpServers/new-mcp-server.yaml +.continue/rules/new-rule.md .gitignore AGENTS.md Makefile @@ -10,6 +12,7 @@ config/.golangci.yml config/config.example.yml config/config.yml config/presets-data/nutrient.json +config/presets-data/pig_nutrient_requirement.json config/presets-data/system_plans.json design/archive/2025-11-03-verification-before-device-deletion/add_get_device_id_configs_to_task.md design/archive/2025-11-03-verification-before-device-deletion/check_before_device_deletion.md @@ -163,6 +166,7 @@ internal/infra/repository/pig_pen_repository.go internal/infra/repository/pig_sick_repository.go internal/infra/repository/pig_trade_repository.go internal/infra/repository/pig_transfer_log_repository.go +internal/infra/repository/pig_type_repository.go internal/infra/repository/plan_repository.go internal/infra/repository/raw_material_repository.go internal/infra/repository/repository.go