Files
pig-farm-controller/internal/app/controller/feed/recipe_controller.go

228 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package feed
import (
"context"
"errors"
"strconv"
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
"git.huangwc.com/pig/pig-farm-controller/internal/app/service"
"git.huangwc.com/pig/pig-farm-controller/internal/domain/recipe"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
"github.com/labstack/echo/v4"
)
// RecipeController 包含配方相关的处理器
type RecipeController struct {
ctx context.Context
recipeService service.RecipeService
}
// NewRecipeController 创建一个新的 RecipeController
func NewRecipeController(ctx context.Context, recipeService service.RecipeService) *RecipeController {
return &RecipeController{
ctx: ctx,
recipeService: recipeService,
}
}
// CreateRecipe godoc
// @Summary 创建配方
// @Description 创建一个新的配方,包含其原料组成。
// @Tags 饲料管理-配方
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param recipe body dto.CreateRecipeRequest true "配方信息"
// @Success 200 {object} controller.Response{data=dto.RecipeResponse} "业务码为201代表创建成功"
// @Router /api/v1/feed/recipes [post]
func (c *RecipeController) CreateRecipe(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "CreateRecipe")
var req dto.CreateRecipeRequest
const actionType = "创建配方"
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.recipeService.CreateRecipe(reqCtx, &req)
if err != nil {
logger.Errorf("%s: 服务层创建配方失败: %v", actionType, err)
if errors.Is(err, recipe.ErrRecipeNameConflict) {
return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), actionType, "配方名称已存在", req)
}
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建配方失败: "+err.Error(), actionType, "服务层创建配方失败", req)
}
logger.Infof("%s: 配方创建成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "配方创建成功", resp, actionType, "配方创建成功", resp)
}
// UpdateRecipe godoc
// @Summary 更新配方
// @Description 根据ID更新配方信息及其原料组成。
// @Tags 饲料管理-配方
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param id path int true "配方ID"
// @Param recipe body dto.UpdateRecipeRequest true "更新后的配方信息"
// @Success 200 {object} controller.Response{data=dto.RecipeResponse} "业务码为200代表更新成功"
// @Router /api/v1/feed/recipes/{id} [put]
func (c *RecipeController) UpdateRecipe(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "UpdateRecipe")
const actionType = "更新配方"
idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
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.UpdateRecipeRequest
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.recipeService.UpdateRecipe(reqCtx, uint32(id), &req)
if err != nil {
logger.Errorf("%s: 服务层更新配方失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, recipe.ErrRecipeNotFound) {
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), actionType, "配方不存在", id)
}
if errors.Is(err, recipe.ErrRecipeNameConflict) {
return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), actionType, "配方名称已存在", req)
}
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)
}
// DeleteRecipe godoc
// @Summary 删除配方
// @Description 根据ID删除配方。
// @Tags 饲料管理-配方
// @Security BearerAuth
// @Produce json
// @Param id path int true "配方ID"
// @Success 200 {object} controller.Response "业务码为200代表删除成功"
// @Router /api/v1/feed/recipes/{id} [delete]
func (c *RecipeController) DeleteRecipe(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "DeleteRecipe")
const actionType = "删除配方"
idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
logger.Errorf("%s: 配方ID格式错误: %v, ID: %s", actionType, err, idStr)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的配方ID格式", actionType, "配方ID格式错误", idStr)
}
err = c.recipeService.DeleteRecipe(reqCtx, uint32(id))
if err != nil {
logger.Errorf("%s: 服务层删除配方失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, recipe.ErrRecipeNotFound) {
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), actionType, "配方不存在", id)
}
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除配方失败: "+err.Error(), actionType, "服务层删除配方失败", id)
}
logger.Infof("%s: 配方删除成功, ID: %d", actionType, id)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "配方删除成功", nil, actionType, "配方删除成功", id)
}
// GetRecipe godoc
// @Summary 获取配方详情
// @Description 根据ID获取单个配方的详细信息。
// @Tags 饲料管理-配方
// @Security BearerAuth
// @Produce json
// @Param id path int true "配方ID"
// @Success 200 {object} controller.Response{data=dto.RecipeResponse} "业务码为200代表成功获取"
// @Router /api/v1/feed/recipes/{id} [get]
func (c *RecipeController) GetRecipe(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "GetRecipe")
const actionType = "获取配方详情"
idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
logger.Errorf("%s: 配方ID格式错误: %v, ID: %s", actionType, err, idStr)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的配方ID格式", actionType, "配方ID格式错误", idStr)
}
resp, err := c.recipeService.GetRecipeByID(reqCtx, uint32(id))
if err != nil {
logger.Errorf("%s: 服务层获取配方详情失败: %v, ID: %d", actionType, err, id)
if errors.Is(err, recipe.ErrRecipeNotFound) {
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), actionType, "配方不存在", id)
}
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取配方详情失败: "+err.Error(), actionType, "服务层获取配方详情失败", id)
}
logger.Infof("%s: 获取配方详情成功, ID: %d", actionType, id)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取配方详情成功", resp, actionType, "获取配方详情成功", resp)
}
// ListRecipes godoc
// @Summary 获取配方列表
// @Description 获取所有配方的列表,支持分页和过滤。
// @Tags 饲料管理-配方
// @Security BearerAuth
// @Produce json
// @Param query query dto.ListRecipeRequest false "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListRecipeResponse} "业务码为200代表成功获取列表"
// @Router /api/v1/feed/recipes [get]
func (c *RecipeController) ListRecipes(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "ListRecipes")
const actionType = "获取配方列表"
var req dto.ListRecipeRequest
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.recipeService.ListRecipes(reqCtx, &req)
if err != nil {
logger.Errorf("%s: 服务层获取配方列表失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取配方列表失败: "+err.Error(), actionType, "服务层获取配方列表失败", nil)
}
logger.Infof("%s: 获取配方列表成功, 数量: %d", actionType, len(resp.List))
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取配方列表成功", resp, actionType, "获取配方列表成功", resp)
}
// GenerateFromAllMaterials godoc
// @Summary 使用系统中所有可用的原料一键生成配方
// @Description 根据指定的猪类型ID使用系统中所有可用的原料自动计算并创建一个成本最优的配方。
// @Tags 饲料管理-配方
// @Security BearerAuth
// @Produce json
// @Param pig_type_id path int true "猪类型ID"
// @Success 201 {object} controller.Response{data=dto.GenerateRecipeResponse} "业务码为201代表创建成功"
// @Router /api/v1/feed/recipes/generate-from-all-materials/{pig_type_id} [post]
func (c *RecipeController) GenerateFromAllMaterials(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "GenerateFromAllMaterials")
const actionType = "使用系统中所有可用的原料一键生成配方"
idStr := ctx.Param("pig_type_id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
logger.Errorf("%s: 猪类型ID格式错误: %v, ID: %s", actionType, err, idStr)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪类型ID格式", actionType, "猪类型ID格式错误", idStr)
}
recipe, err := c.recipeService.GenerateRecipeWithAllRawMaterials(reqCtx, uint32(id))
if err != nil {
logger.Errorf("%s: 服务层生成配方失败: %v, PigTypeID: %d", actionType, err, id)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "生成配方失败: "+err.Error(), actionType, "服务层生成配方失败", id)
}
resp := dto.ToGenerateRecipeResponse(recipe)
logger.Infof("%s: 配方生成成功, 新配方ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "配方生成成功", resp, actionType, "配方生成成功", resp)
}