From bf8fd2f25543e6587f182c221ec5b38dc5615608 Mon Sep 17 00:00:00 2001 From: gazebo Date: Tue, 17 Sep 2019 14:36:39 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E8=8F=9C=E8=B0=B1API=E5=9F=BA=E6=9C=ACOK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- business/model/dao/food_recipe.go | 101 ++++++++++++++++-- business/model/dao/food_recipe_test.go | 40 +++++++ business/model/dao/store_test.go | 2 +- business/userstore/food_recipe.go | 141 ++++++++++++++++++++++++- controllers/cmd_food_recipe.go | 88 ++++++++++++++- routers/commentsRouter_controllers.go | 45 ++++++++ 6 files changed, 401 insertions(+), 16 deletions(-) create mode 100644 business/model/dao/food_recipe_test.go diff --git a/business/model/dao/food_recipe.go b/business/model/dao/food_recipe.go index 376647d4f..bac34ad31 100644 --- a/business/model/dao/food_recipe.go +++ b/business/model/dao/food_recipe.go @@ -1,27 +1,108 @@ package dao -import "git.rosy.net.cn/jx-callback/business/model" +import ( + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" +) -func QueryFoodRecipes(db *DaoDB, keyword, userID string) (recipeList []*model.FoodRecipe, err error) { - sql := ` - SELECT t1.* - FROM food_recipe t1 - WHERE 1 = 1` - sqlParams := []interface{}{} +type FoodRecipeWithAction struct { + model.FoodRecipe + ActionType int8 `json:"actionType"` +} + +func QueryFoodRecipes(db *DaoDB, keyword string, recipeID int, authorID, userID string) (recipeList []*FoodRecipeWithAction, err error) { + var sql string + var sqlParams []interface{} + if userID != "" { + sql = ` + SELECT t1.*, t2.action_type + FROM food_recipe t1 + LEFT JOIN food_recipe_user t2 ON t2.recipe_id = t1.id AND t2.user_id = ? AND t2.deleted_at = ? + WHERE t1.deleted_at = ?` + sqlParams = []interface{}{ + userID, + utils.DefaultTimeValue, + utils.DefaultTimeValue, + } + } else { + sql = ` + SELECT t1.* + FROM food_recipe t1 + WHERE t1.deleted_at = ?` + sqlParams = []interface{}{ + utils.DefaultTimeValue, + } + } if keyword != "" { keywordLike := "%" + keyword + "%" sql += " AND (t1.name LIKE ?" sqlParams = append(sqlParams, keywordLike) sql += ")" } - if userID != "" { + if recipeID > 0 { + sql += " AND t1.id = ?" + sqlParams = append(sqlParams, recipeID) + } + if authorID != "" { sql += " AND t1.author_id = ?" - sqlParams = append(sqlParams, userID) + sqlParams = append(sqlParams, authorID) } err = GetRows(db, &recipeList, sql, sqlParams...) return recipeList, err } func GetRecommendFoodRecipes(db *DaoDB, keyword, userID string) (recipeList []*model.FoodRecipe, err error) { - return QueryFoodRecipes(db, keyword, userID) + if list, err := QueryFoodRecipes(db, keyword, 0, userID, ""); err == nil { + recipeList = FoodRecipeWithActionList2Recipe(list) + } + return recipeList, err +} + +func FoodRecipeWithActionList2Recipe(recipeList []*FoodRecipeWithAction) (outRecipeList []*model.FoodRecipe) { + for _, v := range recipeList { + outRecipeList = append(outRecipeList, &v.FoodRecipe) + } + return outRecipeList +} + +func QueryFoodRecipesItems(db *DaoDB, recipeID int) (recipeItemList []*model.FoodRecipeItem, err error) { + sql := ` + SELECT t1.* + FROM food_recipe_item t1 + WHERE t1.deleted_at = ? AND t1.recipe_id = ?` + sqlParams := []interface{}{ + utils.DefaultTimeValue, + recipeID, + } + sql += " ORDER BY t1.index" + err = GetRows(db, &recipeItemList, sql, sqlParams...) + return recipeItemList, err +} + +func QueryFoodRecipesItemChoices(db *DaoDB, recipeID int) (recipeItemChoiceList []*model.FoodRecipeItemChoice, err error) { + sql := ` + SELECT t1.* + FROM food_recipe_item_choice t1 + WHERE t1.deleted_at = ? AND t1.recipe_id = ?` + sqlParams := []interface{}{ + utils.DefaultTimeValue, + recipeID, + } + sql += " ORDER BY t1.index, t1.choice_index" + err = GetRows(db, &recipeItemChoiceList, sql, sqlParams...) + return recipeItemChoiceList, err +} + +func QueryFoodRecipesSteps(db *DaoDB, recipeID int) (recipeStepList []*model.FoodRecipeStep, err error) { + sql := ` + SELECT t1.* + FROM food_recipe_step t1 + WHERE t1.deleted_at = ? AND t1.recipe_id = ?` + sqlParams := []interface{}{ + utils.DefaultTimeValue, + recipeID, + } + sql += " ORDER BY t1.index" + err = GetRows(db, &recipeStepList, sql, sqlParams...) + return recipeStepList, err } diff --git a/business/model/dao/food_recipe_test.go b/business/model/dao/food_recipe_test.go new file mode 100644 index 000000000..689ee2439 --- /dev/null +++ b/business/model/dao/food_recipe_test.go @@ -0,0 +1,40 @@ +package dao + +import ( + "testing" +) + +func TestQueryRecipes(t *testing.T) { + db := GetDB() + recipeList, err := QueryFoodRecipes(db, "", -1, "", "") + if err != nil { + t.Fatal(err) + } + if len(recipeList) > 0 { + t.Fatal("should not return list") + } + + recipeItemList, err := QueryFoodRecipesItems(db, -1) + if err != nil { + t.Fatal(err) + } + if len(recipeItemList) > 0 { + t.Fatal("should not return list") + } + + choiceList, err := QueryFoodRecipesItemChoices(db, -1) + if err != nil { + t.Fatal(err) + } + if len(choiceList) > 0 { + t.Fatal("should not return list") + } + + stepList, err := QueryFoodRecipesSteps(db, -1) + if err != nil { + t.Fatal(err) + } + if len(stepList) > 0 { + t.Fatal("should not return list") + } +} diff --git a/business/model/dao/store_test.go b/business/model/dao/store_test.go index 71e84092b..d0455d9e6 100644 --- a/business/model/dao/store_test.go +++ b/business/model/dao/store_test.go @@ -32,7 +32,7 @@ func TestFormalizeStoreStatus(t *testing.T) { } func TestGetStoreList4Role(t *testing.T) { - storeList, err := GetStoreList(GetDB(), "NiuBi") + storeList, err := GetStoreList(GetDB(), nil, nil, "NiuBi") t.Log(utils.Format4Output(storeList, false)) if err != nil { t.Fatal(err) diff --git a/business/userstore/food_recipe.go b/business/userstore/food_recipe.go index 7e58fb389..c1639cf96 100644 --- a/business/userstore/food_recipe.go +++ b/business/userstore/food_recipe.go @@ -19,6 +19,17 @@ type FoodRecipeStepParam struct { Img string `orm:"size(48)" json:"img"` } +type FoodRecipeItem struct { + model.FoodRecipeItem + ItemChoiceList []*model.FoodRecipeItemChoice +} + +type FoodRecipeDetail struct { + model.FoodRecipe + ItemList []*FoodRecipeItem + StepList []*model.FoodRecipeStep +} + func updateFoodRecipeItemAndStep(ctx *jxcontext.Context, db *dao.DaoDB, recipeID int, itemList []*FoodRecipeItemParam, stepList []*FoodRecipeStepParam) (err error) { for k, v := range itemList { if len(v.SkuIDs) == 0 { @@ -29,7 +40,7 @@ func updateFoodRecipeItemAndStep(ctx *jxcontext.Context, db *dao.DaoDB, recipeID return err } if len(v.SkuIDs) != len(skuIDs) { - return fmt.Errorf("某些SkuIDs不存在") + return fmt.Errorf("某些SkuID不存在") } item := &model.FoodRecipeItem{ @@ -158,7 +169,131 @@ func UpdateFoodRecipe(ctx *jxcontext.Context, recipeID int, mapData map[string]i return err } -func QueryFoodRecipes(ctx *jxcontext.Context, keyword, userID string) (recipeList []*model.FoodRecipe, err error) { - recipeList, err = dao.QueryFoodRecipes(dao.GetDB(), keyword, userID) +func QueryFoodRecipes(ctx *jxcontext.Context, keyword, authorID string) (recipeList []*dao.FoodRecipeWithAction, err error) { + _, userID := ctx.GetMobileAndUserID() + recipeList, err = dao.QueryFoodRecipes(dao.GetDB(), keyword, 0, authorID, userID) return recipeList, err } + +func GetRecommendFoodRecipes(ctx *jxcontext.Context, keyword string) (recipeList []*model.FoodRecipe, err error) { + _, userID := ctx.GetMobileAndUserID() + recipeList, err = dao.GetRecommendFoodRecipes(dao.GetDB(), keyword, userID) + return recipeList, err +} + +func GetRecipeDetail(ctx *jxcontext.Context, recipeID int) (recipeDetail *FoodRecipeDetail, err error) { + _, userID := ctx.GetMobileAndUserID() + db := dao.GetDB() + recipeList, err := dao.QueryFoodRecipes(db, "", recipeID, "", userID) + if err != nil { + return nil, err + } + if len(recipeList) == 0 { + return nil, fmt.Errorf("找不到菜谱:%d", recipeID) + } + + itemList, err := dao.QueryFoodRecipesItems(db, recipeID) + if err != nil { + return nil, err + } + + itemChoiceList, err := dao.QueryFoodRecipesItemChoices(db, recipeID) + if err != nil { + return nil, err + } + choiceMap := make(map[int8][]*model.FoodRecipeItemChoice) + for _, v := range itemChoiceList { + choiceMap[v.Index] = append(choiceMap[v.Index], v) + } + + stepList, err := dao.QueryFoodRecipesSteps(db, recipeID) + if err != nil { + return nil, err + } + + recipeDetail = &FoodRecipeDetail{ + FoodRecipe: recipeList[0].FoodRecipe, + StepList: stepList, + } + for _, v := range itemList { + recipeDetail.ItemList = append(recipeDetail.ItemList, &FoodRecipeItem{ + FoodRecipeItem: *v, + ItemChoiceList: choiceMap[v.Index], + }) + } + return recipeDetail, err +} + +func VoteFoodRecipe(ctx *jxcontext.Context, recipeID, voteType int) (err error) { + _, userID := ctx.GetMobileAndUserID() + if userID == "" { + return fmt.Errorf("内部错误,找不到用户") + } + + db := dao.GetDB() + recipeList, err := dao.QueryFoodRecipes(db, "", recipeID, "", userID) + if err != nil { + return err + } + if len(recipeList) == 0 { + return fmt.Errorf("找不到菜谱:%d", recipeID) + } + recipe := &recipeList[0].FoodRecipe + + dao.Begin(db) + defer func() { + if r := recover(); r != nil || err != nil { + dao.Rollback(db) + if r != nil { + panic(r) + } + } + }() + + recipeUser := &model.FoodRecipeUser{ + RecipeID: recipeID, + UserID: userID, + } + if err = dao.GetEntity(db, recipeUser); err != nil { + if dao.IsNoRowsError(err) { + return err + } + } + + actionMask := int8(0) + if voteType > 0 { + recipe.UpvoteCount++ + actionMask = model.RecipeActionUpvote + } else if voteType < 0 { + recipe.DownvoteCount++ + actionMask = model.RecipeActionDownvote + } + if recipeUser.ActionType&model.RecipeActionUpvote != 0 { + recipe.UpvoteCount-- + } else if recipeUser.ActionType&model.RecipeActionDownvote != 0 { + recipe.DownvoteCount-- + } + + if recipeUser.ActionType&actionMask != 0 || recipeUser.ActionType&(model.RecipeActionUpvote|model.RecipeActionDownvote) == 0 { + return fmt.Errorf("已经做过此操作了") + } + + recipeUser.ActionType &= actionMask | ^(model.RecipeActionUpvote | model.RecipeActionDownvote) + if recipeUser.ID == 0 { + dao.WrapAddIDCULDEntity(recipeUser, ctx.GetUserName()) + err = dao.CreateEntity(db, recipeUser) + } else { + recipeUser.LastOperator = ctx.GetUserName() + _, err = dao.UpdateEntity(db, recipeUser) + } + if err != nil { + return err + } + _, err = dao.UpdateEntity(db, recipe, "UpvoteCount", "DownvoteCount") + if err != nil { + return err + } + + dao.Commit(db) + return err +} diff --git a/controllers/cmd_food_recipe.go b/controllers/cmd_food_recipe.go index f0ace9f50..95637cbb5 100644 --- a/controllers/cmd_food_recipe.go +++ b/controllers/cmd_food_recipe.go @@ -11,8 +11,8 @@ type FoodRecipeController struct { beego.Controller } -// @Title 创建活动 -// @Description 创建活动 +// @Title 创建菜谱 +// @Description 创建菜谱 // @Param token header string true "认证token" // @Param name formData string true "菜谱名" // @Param description formData string true "菜谱描述" @@ -41,3 +41,87 @@ func (c *FoodRecipeController) CreateFoodRecipe() { return retVal, "", err }) } + +// @Title 编辑菜谱 +// @Description 编辑菜谱 +// @Param token header string true "认证token" +// @Param recipeID formData int true "菜谱ID" +// @Param name formData string false "菜谱名" +// @Param description formData string false "菜谱描述" +// @Param img formData string false "图片"" +// @Param timeInMinute formData string false "大约需要时间(分钟)" +// @Param recipeItems formData string false "菜谱配料" +// @Param recipeSteps formData string false "菜谱步骤" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /UpdateFoodRecipe [put] +func (c *FoodRecipeController) UpdateFoodRecipe() { + c.callUpdateFoodRecipe(func(params *tFoodrecipeUpdateFoodRecipeParams) (retVal interface{}, errCode string, err error) { + var ( + itemList []*userstore.FoodRecipeItemParam + stepList []*userstore.FoodRecipeStepParam + ) + if err = jxutils.Strings2Objs(params.RecipeItems, &itemList, params.RecipeSteps, &stepList); err == nil { + err = userstore.UpdateFoodRecipe(params.Ctx, params.RecipeID, params.MapData, itemList, stepList) + } + return retVal, "", err + }) +} + +// @Title 查询菜谱列表 +// @Description 查询菜谱列表 +// @Param token header string true "认证token" +// @Param keyword query string false "关键字" +// @Param userID query string false "厂商ID" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /QueryFoodRecipes [get] +func (c *FoodRecipeController) QueryFoodRecipes() { + c.callQueryFoodRecipes(func(params *tFoodrecipeQueryFoodRecipesParams) (retVal interface{}, errCode string, err error) { + retVal, err = userstore.QueryFoodRecipes(params.Ctx, params.Keyword, params.UserID) + return retVal, "", err + }) +} + +// @Title 得到我的推荐菜谱列表 +// @Description 得到我的推荐菜谱列表 +// @Param token header string true "认证token" +// @Param keyword query string false "关键字" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /GetRecommendFoodRecipes [get] +func (c *FoodRecipeController) GetRecommendFoodRecipes() { + c.callGetRecommendFoodRecipes(func(params *tFoodrecipeGetRecommendFoodRecipesParams) (retVal interface{}, errCode string, err error) { + retVal, err = userstore.GetRecommendFoodRecipes(params.Ctx, params.Keyword) + return retVal, "", err + }) +} + +// @Title 得到菜谱详情 +// @Description 得到菜谱详情 +// @Param token header string true "认证token" +// @Param recipeID query int true "菜谱ID" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /GetRecipeDetail [get] +func (c *FoodRecipeController) GetRecipeDetail() { + c.callGetRecipeDetail(func(params *tFoodrecipeGetRecipeDetailParams) (retVal interface{}, errCode string, err error) { + retVal, err = userstore.GetRecipeDetail(params.Ctx, params.RecipeID) + return retVal, "", err + }) +} + +// @Title 对菜谱投票 +// @Description 对菜谱投票 +// @Param token header string true "认证token" +// @Param recipeID formData int true "菜谱ID" +// @Param voteType formData int true "-1:踩,0:取消之前的投票,1:赞" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /VoteFoodRecipe [post] +func (c *FoodRecipeController) VoteFoodRecipe() { + c.callVoteFoodRecipe(func(params *tFoodrecipeVoteFoodRecipeParams) (retVal interface{}, errCode string, err error) { + err = userstore.VoteFoodRecipe(params.Ctx, params.RecipeID, params.VoteType) + return retVal, "", err + }) +} diff --git a/routers/commentsRouter_controllers.go b/routers/commentsRouter_controllers.go index 86bd3bf1f..45e453cf0 100644 --- a/routers/commentsRouter_controllers.go +++ b/routers/commentsRouter_controllers.go @@ -484,6 +484,51 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:FoodRecipeController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:FoodRecipeController"], + beego.ControllerComments{ + Method: "GetRecipeDetail", + Router: `/GetRecipeDetail`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:FoodRecipeController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:FoodRecipeController"], + beego.ControllerComments{ + Method: "GetRecommendFoodRecipes", + Router: `/GetRecommendFoodRecipes`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:FoodRecipeController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:FoodRecipeController"], + beego.ControllerComments{ + Method: "QueryFoodRecipes", + Router: `/QueryFoodRecipes`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:FoodRecipeController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:FoodRecipeController"], + beego.ControllerComments{ + Method: "UpdateFoodRecipe", + Router: `/UpdateFoodRecipe`, + AllowHTTPMethods: []string{"put"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:FoodRecipeController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:FoodRecipeController"], + beego.ControllerComments{ + Method: "VoteFoodRecipe", + Router: `/VoteFoodRecipe`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:InitDataController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:InitDataController"], beego.ControllerComments{ Method: "BuildSkuFromEbaiStore",