实现修改原料营养信息
This commit is contained in:
@@ -365,6 +365,48 @@ func (c *Controller) ListRawMaterials(ctx echo.Context) error {
|
||||
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取原料列表成功", resp, actionType, "获取原料列表成功", resp)
|
||||
}
|
||||
|
||||
// UpdateRawMaterialNutrients godoc
|
||||
// @Summary 全量更新原料的营养成分
|
||||
// @Description 根据原料ID,替换其所有的营养成分信息。这是一个覆盖操作。
|
||||
// @Tags 饲料管理
|
||||
// @Security BearerAuth
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "原料ID"
|
||||
// @Param nutrients body dto.UpdateRawMaterialNutrientsRequest true "新的营养成分列表"
|
||||
// @Success 200 {object} controller.Response{data=dto.RawMaterialResponse} "业务码为200代表更新成功"
|
||||
// @Router /api/v1/feed/raw-materials/{id}/nutrients [put]
|
||||
func (c *Controller) UpdateRawMaterialNutrients(ctx echo.Context) error {
|
||||
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "UpdateRawMaterialNutrients")
|
||||
const actionType = "更新原料营养成分"
|
||||
|
||||
idStr := ctx.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||
if err != nil {
|
||||
logger.Errorf("%s: 原料ID格式错误: %v, ID: %s", actionType, err, idStr)
|
||||
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的原料ID格式", actionType, "原料ID格式错误", idStr)
|
||||
}
|
||||
|
||||
var req dto.UpdateRawMaterialNutrientsRequest
|
||||
if err := ctx.Bind(&req); err != nil {
|
||||
logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
|
||||
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
|
||||
}
|
||||
|
||||
resp, err := c.feedManagementService.UpdateRawMaterialNutrients(reqCtx, uint32(id), &req)
|
||||
if err != nil {
|
||||
logger.Errorf("%s: 服务层更新原料营养成分失败: %v, ID: %d", actionType, err, id)
|
||||
if errors.Is(err, service.ErrRawMaterialNotFound) {
|
||||
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), actionType, "原料不存在", id)
|
||||
}
|
||||
// 这里可以根据未来可能从服务层返回的其他特定错误进行处理
|
||||
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新原料营养成分失败: "+err.Error(), actionType, "服务层更新失败", req)
|
||||
}
|
||||
|
||||
logger.Infof("%s: 原料营养成分更新成功, ID: %d", actionType, resp.ID)
|
||||
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "原料营养成分更新成功", resp, actionType, "原料营养成分更新成功", resp)
|
||||
}
|
||||
|
||||
// --- 猪品种 (PigBreed) 接口方法实现 ---
|
||||
|
||||
// CreatePigBreed godoc
|
||||
|
||||
@@ -22,8 +22,6 @@ func ConvertNutrientToDTO(nutrient *models.Nutrient) *NutrientResponse {
|
||||
|
||||
return &NutrientResponse{
|
||||
ID: nutrient.ID,
|
||||
CreatedAt: nutrient.CreatedAt,
|
||||
UpdatedAt: nutrient.UpdatedAt,
|
||||
Name: nutrient.Name,
|
||||
Description: nutrient.Description,
|
||||
RawMaterials: rawMaterials,
|
||||
@@ -57,8 +55,6 @@ func ConvertRawMaterialToDTO(rm *models.RawMaterial) *RawMaterialResponse {
|
||||
for i, rmn := range rm.RawMaterialNutrients {
|
||||
rawMaterialNutrientDTOs[i] = RawMaterialNutrientDTO{
|
||||
ID: rmn.ID,
|
||||
CreatedAt: rmn.CreatedAt,
|
||||
UpdatedAt: rmn.UpdatedAt,
|
||||
NutrientID: rmn.NutrientID,
|
||||
Nutrient: rmn.Nutrient.Name, // 假设 Nutrient 已经被预加载
|
||||
Value: rmn.Value,
|
||||
@@ -67,8 +63,6 @@ func ConvertRawMaterialToDTO(rm *models.RawMaterial) *RawMaterialResponse {
|
||||
|
||||
return &RawMaterialResponse{
|
||||
ID: rm.ID,
|
||||
CreatedAt: rm.CreatedAt,
|
||||
UpdatedAt: rm.UpdatedAt,
|
||||
Name: rm.Name,
|
||||
Description: rm.Description,
|
||||
RawMaterialNutrients: rawMaterialNutrientDTOs,
|
||||
@@ -99,8 +93,6 @@ func ConvertPigBreedToDTO(breed *models.PigBreed) *PigBreedResponse {
|
||||
}
|
||||
return &PigBreedResponse{
|
||||
ID: breed.ID,
|
||||
CreatedAt: breed.CreatedAt,
|
||||
UpdatedAt: breed.UpdatedAt,
|
||||
Name: breed.Name,
|
||||
Description: breed.Description,
|
||||
ParentInfo: breed.ParentInfo,
|
||||
@@ -134,8 +126,6 @@ func ConvertPigAgeStageToDTO(ageStage *models.PigAgeStage) *PigAgeStageResponse
|
||||
}
|
||||
return &PigAgeStageResponse{
|
||||
ID: ageStage.ID,
|
||||
CreatedAt: ageStage.CreatedAt,
|
||||
UpdatedAt: ageStage.UpdatedAt,
|
||||
Name: ageStage.Name,
|
||||
Description: ageStage.Description,
|
||||
}
|
||||
@@ -168,8 +158,6 @@ func ConvertPigTypeToDTO(pt *models.PigType) *PigTypeResponse {
|
||||
for i, pnr := range pt.PigNutrientRequirements {
|
||||
pigNutrientRequirementDTOs[i] = PigNutrientRequirementDTO{
|
||||
ID: pnr.ID,
|
||||
CreatedAt: pnr.CreatedAt,
|
||||
UpdatedAt: pnr.UpdatedAt,
|
||||
NutrientID: pnr.NutrientID,
|
||||
NutrientName: pnr.Nutrient.Name, // 假设 Nutrient 已经被预加载
|
||||
MinRequirement: pnr.MinRequirement,
|
||||
@@ -179,8 +167,6 @@ func ConvertPigTypeToDTO(pt *models.PigType) *PigTypeResponse {
|
||||
|
||||
return &PigTypeResponse{
|
||||
ID: pt.ID,
|
||||
CreatedAt: pt.CreatedAt,
|
||||
UpdatedAt: pt.UpdatedAt,
|
||||
BreedID: pt.BreedID,
|
||||
BreedName: pt.Breed.Name, // 假设 Breed 已经被预加载
|
||||
AgeStageID: pt.AgeStageID,
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// =============================================================================================================
|
||||
// 营养种类 (Nutrient) 相关 DTO
|
||||
// =============================================================================================================
|
||||
@@ -30,8 +26,6 @@ type NutrientRawMaterialDTO struct {
|
||||
// NutrientResponse 营养种类响应体
|
||||
type NutrientResponse struct {
|
||||
ID uint32 `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
RawMaterials []NutrientRawMaterialDTO `json:"raw_materials"` // 包含此营养的原料列表
|
||||
@@ -70,19 +64,15 @@ type UpdateRawMaterialRequest struct {
|
||||
|
||||
// RawMaterialNutrientDTO 原料营养素响应体
|
||||
type RawMaterialNutrientDTO struct {
|
||||
ID uint32 `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
NutrientID uint32 `json:"nutrient_id"`
|
||||
Nutrient string `json:"nutrient_name"` // 营养素名称
|
||||
Value float32 `json:"value"` // 营养价值含量
|
||||
ID uint32 `json:"id"`
|
||||
NutrientID uint32 `json:"nutrient_id"`
|
||||
Nutrient string `json:"nutrient_name"` // 营养素名称
|
||||
Value float32 `json:"value"` // 营养价值含量
|
||||
}
|
||||
|
||||
// RawMaterialResponse 原料响应体
|
||||
type RawMaterialResponse struct {
|
||||
ID uint32 `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
RawMaterialNutrients []RawMaterialNutrientDTO `json:"raw_material_nutrients"` // 关联的营养素信息
|
||||
@@ -103,6 +93,17 @@ type ListRawMaterialResponse struct {
|
||||
Pagination PaginationDTO `json:"pagination"`
|
||||
}
|
||||
|
||||
// UpdateRawMaterialNutrientsRequest 更新原料营养成分的请求体
|
||||
type UpdateRawMaterialNutrientsRequest struct {
|
||||
Nutrients []RawMaterialNutrientItem `json:"nutrients" validate:"required,dive"`
|
||||
}
|
||||
|
||||
// RawMaterialNutrientItem 代表一个营养成分及其含量
|
||||
type RawMaterialNutrientItem struct {
|
||||
NutrientID uint32 `json:"nutrient_id" validate:"required"` // 营养素ID
|
||||
Value float32 `json:"value" validate:"gte=0"` // 含量值,必须大于等于0
|
||||
}
|
||||
|
||||
// =============================================================================================================
|
||||
// 猪品种 (PigBreed) 相关 DTO
|
||||
// =============================================================================================================
|
||||
@@ -129,15 +130,13 @@ type UpdatePigBreedRequest struct {
|
||||
|
||||
// PigBreedResponse 猪品种响应体
|
||||
type PigBreedResponse struct {
|
||||
ID uint32 `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ParentInfo string `json:"parent_info"`
|
||||
AppearanceFeatures string `json:"appearance_features"`
|
||||
BreedAdvantages string `json:"breed_advantages"`
|
||||
BreedDisadvantages string `json:"breed_disadvantages"`
|
||||
ID uint32 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ParentInfo string `json:"parent_info"`
|
||||
AppearanceFeatures string `json:"appearance_features"`
|
||||
BreedAdvantages string `json:"breed_advantages"`
|
||||
BreedDisadvantages string `json:"breed_disadvantages"`
|
||||
}
|
||||
|
||||
// ListPigBreedRequest 定义了获取猪品种列表的请求参数
|
||||
@@ -172,11 +171,9 @@ type UpdatePigAgeStageRequest struct {
|
||||
|
||||
// PigAgeStageResponse 猪年龄阶段响应体
|
||||
type PigAgeStageResponse struct {
|
||||
ID uint32 `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ID uint32 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// ListPigAgeStageRequest 定义了获取猪年龄阶段列表的请求参数
|
||||
@@ -225,20 +222,16 @@ type UpdatePigTypeRequest struct {
|
||||
|
||||
// PigNutrientRequirementDTO 猪营养需求响应体
|
||||
type PigNutrientRequirementDTO struct {
|
||||
ID uint32 `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
NutrientID uint32 `json:"nutrient_id"`
|
||||
NutrientName string `json:"nutrient_name"` // 营养素名称
|
||||
MinRequirement float32 `json:"min_requirement"` // 最低营养需求量
|
||||
MaxRequirement float32 `json:"max_requirement"` // 最高营养需求量
|
||||
ID uint32 `json:"id"`
|
||||
NutrientID uint32 `json:"nutrient_id"`
|
||||
NutrientName string `json:"nutrient_name"` // 营养素名称
|
||||
MinRequirement float32 `json:"min_requirement"` // 最低营养需求量
|
||||
MaxRequirement float32 `json:"max_requirement"` // 最高营养需求量
|
||||
}
|
||||
|
||||
// PigTypeResponse 猪类型响应体
|
||||
type PigTypeResponse struct {
|
||||
ID uint32 `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
BreedID uint32 `json:"breed_id"`
|
||||
BreedName string `json:"breed_name"` // 猪品种名称
|
||||
AgeStageID uint32 `json:"age_stage_id"`
|
||||
|
||||
@@ -40,6 +40,7 @@ type FeedManagementService interface {
|
||||
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)
|
||||
@@ -236,6 +237,43 @@ func (s *feedManagementServiceImpl) ListRawMaterials(ctx context.Context, req *d
|
||||
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{
|
||||
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) 实现
|
||||
// =====================================================================================================================
|
||||
|
||||
Reference in New Issue
Block a user