diff --git a/business/jxstore/cms/store.go b/business/jxstore/cms/store.go index 5088a5e8c..f9d3ea169 100644 --- a/business/jxstore/cms/store.go +++ b/business/jxstore/cms/store.go @@ -1789,6 +1789,7 @@ func SaveAndSendAlarmVendorSnapshot(ctx *jxcontext.Context, vendorIDs, storeIDs err = SaveStoresVendorSnapshot(db, curSnapshotAt, curSnapshotList) case 2: prevSnapshotList, err = dao.GetVendorStoreSnapshot(db, prevSnapshotAt) + curSnapshotList, err = dao.GetVendorStoreSnapshot(db, curSnapshotAt) // 因为排序的原因,重新取一下 case 3: err = SendAlarmVendorSnapshot(ctx, task, prevSnapshotList, curSnapshotList) } diff --git a/business/jxutils/jxutils_cms.go b/business/jxutils/jxutils_cms.go index 273347ad7..c427da090 100644 --- a/business/jxutils/jxutils_cms.go +++ b/business/jxutils/jxutils_cms.go @@ -495,3 +495,35 @@ func CreateQrOrBarCode(width, height int, codeType, srcData string) (imgBase64 s return imgBase64, err } + +// 高德地图面积计算公式 +// https://blog.csdn.net/zdb1314/article/details/80661602 +func CalcPolygonAreaAutonavi(points [][2]float64) (area float64) { + sJ := float64(6378137) + Hq := float64(0.017453292519943295) + c := float64(sJ * Hq) + d := float64(0) + + if 3 > len(points) { + return 0 + } + + for i := 0; i < len(points)-1; i++ { + h := points[i] + k := points[i+1] + u := h[0] * c * math.Cos(h[1]*Hq) + + hhh := h[1] * c + v := k[0] * c * math.Cos(k[1]*Hq) + d = d + (u*k[1]*c - v*hhh) + } + + g1 := points[len(points)-1] + point := points[0] + eee := g1[0] * c * math.Cos(g1[1]*Hq) + g2 := g1[1] * c + + k := point[0] * c * math.Cos(point[1]*Hq) + d += eee*point[1]*c - k*g2 + return 0.5 * math.Abs(d) / float64(1000000) +} diff --git a/business/jxutils/jxutils_cms_test.go b/business/jxutils/jxutils_cms_test.go index 07507520e..2782fbf6b 100644 --- a/business/jxutils/jxutils_cms_test.go +++ b/business/jxutils/jxutils_cms_test.go @@ -2,9 +2,12 @@ package jxutils import ( "fmt" + "strings" "testing" "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/model/dao" ) func TestSplitSlice(t *testing.T) { @@ -101,3 +104,25 @@ func TestSplitStoreName(t *testing.T) { } } } + +func TestCalcPolygonAreaAutonavi(t *testing.T) { + // pointers := GetPolygonFromCircle(104.065702, 30.657488, 3000, 128) + // area := CalcPolygonAreaAutonavi(pointers) + // t.Logf("area:%f", area) + db := dao.GetDB() + storeList, err := dao.GetStoreList(db, nil, nil, "") + if err != nil { + t.Fatal(err) + } + + strBuilder := &strings.Builder{} + strBuilder.WriteString("\n") + for _, v := range storeList { + if v.DeliveryRangeType == model.DeliveryRangeTypePolygon { + pointers := CoordinateStr2Points(v.DeliveryRange) + area1 := CalcPolygonAreaAutonavi(pointers) + strBuilder.WriteString(fmt.Sprintf("%d,%f\n", v.ID, area1)) + } + } + t.Log(strBuilder.String()) +} diff --git a/business/model/common.go b/business/model/common.go new file mode 100644 index 000000000..5745c8662 --- /dev/null +++ b/business/model/common.go @@ -0,0 +1,31 @@ +package model + +var ( + ValideMimeTypes = map[string]int{ + "image/jpeg": 1, + "image/png": 1, + + "video/mpeg": 1, + "video/mp4": 1, + } +) + +type DataResource struct { + ModelIDCUL + + HashCode string `orm:"size(48);unique" json:"hash_code"` + ResoureType string // 资料的mime type + + Name string `orm:"size(48)" json:"name"` + + MainURL string + QiniuURL string + EbaiURL string + MtwmURL string +} + +func (*DataResource) TableUnique() [][]string { + return [][]string{ + []string{"HashCode", "ResoureType"}, + } +} diff --git a/business/model/dao/food_recipe.go b/business/model/dao/food_recipe.go new file mode 100644 index 000000000..1f44d6887 --- /dev/null +++ b/business/model/dao/food_recipe.go @@ -0,0 +1,2 @@ +package dao + diff --git a/business/model/dao/store.go b/business/model/dao/store.go index 3f6d92bd6..88e0a53e9 100644 --- a/business/model/dao/store.go +++ b/business/model/dao/store.go @@ -301,9 +301,11 @@ func FormalizeStoreStatus(db *DaoDB, storeID, storeStatus int) (err error) { func GetVendorStoreSnapshot(db *DaoDB, snapshotAt time.Time) (snapshotList []*model.VendorStoreSnapshot, err error) { sql := ` - SELECT * + SELECT t1.* FROM vendor_store_snapshot t1 - WHERE t1.snapshot_at = ?` + LEFT JOIN store t2 ON t2.id = t1.store_id + WHERE t1.snapshot_at = ? + ORDER BY t2.city_code, t1.store_id, t1.vendor_id` err = GetRows(db, &snapshotList, sql, snapshotAt) return snapshotList, err } diff --git a/business/model/food_recipe.go b/business/model/food_recipe.go new file mode 100644 index 000000000..05fe82cb2 --- /dev/null +++ b/business/model/food_recipe.go @@ -0,0 +1,105 @@ +package model + +const ( + RecipeActionCollect = 1 // 收藏 + RecipeActionUpvote = 2 // 顶 + RecipeActionDownvote = 4 // 踩 +) + +type FoodRecipe struct { + ModelIDCULD + + Name string `orm:"size(48)" json:"name"` + AuthorID string `orm:"size(48);column(author_id);index" json:"authorID"` + + Description string `orm:"size(4096)" json:"description"` + Img string `orm:"size(48)" json:"img"` + TimeInMinute int `json:"timeInMinute"` // 大约时间(分钟) + UpvoteCount int `json:"upvoteCount"` + DownvoteCount int `json:"downvoteCount"` + Score int `json:"score"` // 分数 + + TagCategory string `orm:"size(48)" json:"tagCategory"` // 菜系(川,粤,鲁等等) + TagCookType string `orm:"size(48)" json:"tagCookType"` // 制作工艺(煮,炒,蒸等等) + TagTaste string `orm:"size(48)" json:"tagTaste"` // 口味(辣,麻,甜) +} + +func (*FoodRecipe) TableUnique() [][]string { + return [][]string{ + []string{"Name", "AuthorID", "DeletedAt"}, + } +} + +// 菜谱步骤 +type FoodRecipeStep struct { + ModelIDCULD + + RecipeID int `orm:"column(recipe_id)" json:"recipeID"` + Index int8 `json:"index"` // 步骤序号,从1开始 + + Name string `orm:"size(48)" json:"name"` + Description string `orm:"size(4096)" json:"description"` + Img string `orm:"size(48)" json:"img"` +} + +func (*FoodRecipeStep) TableUnique() [][]string { + return [][]string{ + []string{"RecipeID", "Index", "DeletedAt"}, + } +} + +// 菜谱配料 +type FoodRecipeItem struct { + ModelIDCULD + + RecipeID int `orm:"column(recipe_id)" json:"recipeID"` + Index int8 `json:"index"` // 配料序号,从1开始 + + Name string `orm:"size(48)" json:"name"` + + // SpecQuality float32 `json:"specQuality"` + // SpecUnit string `orm:"size(8)" json:"specUnit"` // 质量或容量 +} + +func (*FoodRecipeItem) TableUnique() [][]string { + return [][]string{ + []string{"RecipeID", "Index", "DeletedAt"}, + } +} + +// 菜谱配料选择 +type FoodRecipeItemChoice struct { + ModelIDCULD + + RecipeID int `orm:"column(recipe_id)" json:"recipeID"` + Index int8 `json:"index"` // 配料序号,从1开始 + SkuID int `orm:"column(sku_id)" json:"skuID"` + + ChoiceIndex int8 `json:"choiceIndex"` // 选择序号,从1开始 +} + +func (*FoodRecipeItemChoice) TableUnique() [][]string { + return [][]string{ + []string{"RecipeID", "Index", "SkuID", "DeletedAt"}, + } +} + +type FoodRecipeUser struct { + ModelIDCULD + + RecipeID int `orm:"column(recipe_id)" json:"recipeID"` + UserID string `orm:"size(48);column(user_id)" json:"userID" compact:"userID"` + ActionType int8 `json:"actionType"` +} + +func (*FoodRecipeUser) TableUnique() [][]string { + return [][]string{ + []string{"RecipeID", "UserID", "DeletedAt"}, + } +} + +func (*FoodRecipeUser) TableIndex() [][]string { + return [][]string{ + []string{"UserID", "RecipeID", "DeletedAt"}, + } +} diff --git a/business/partner/purchase/ebai/store.go b/business/partner/purchase/ebai/store.go index a89188a5e..d4a51f115 100644 --- a/business/partner/purchase/ebai/store.go +++ b/business/partner/purchase/ebai/store.go @@ -375,8 +375,8 @@ func genStoreMapFromStore(store *tEbaiStoreInfo) map[string]interface{} { tel = store.Tel2 } if tel != "" { - params["phone"] = tel - params["ivr_phone"] = tel + // params["phone"] = tel // 外卖客服联系电话,这个有时能修改,有时不能修改,暂时统一不改 + params["ivr_phone"] = tel // 订单提醒电话 } if store.VendorStoreID != "" { params["baidu_shop_id"] = store.VendorStoreID diff --git a/business/userstore/food_recipe.go b/business/userstore/food_recipe.go new file mode 100644 index 000000000..4eadec204 --- /dev/null +++ b/business/userstore/food_recipe.go @@ -0,0 +1,93 @@ +package userstore + +import ( + "fmt" + + "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/model/dao" +) + +type FoodRecipeItemParam struct { + Name string `json:"name"` + SkuIDs []int `json:"skuIDs"` +} + +type FoodRecipeStepParam struct { + Name string `orm:"size(48)" json:"name"` + Description string `orm:"size(4096)" json:"description"` + Img string `orm:"size(48)" json:"img"` +} + +func CreateFoodRecipe(ctx *jxcontext.Context, foodRecipe *model.FoodRecipe, itemList []*FoodRecipeItemParam, stepList []*FoodRecipeStepParam) (err error) { + db := dao.GetDB() + dao.Begin(db) + defer func() { + if r := recover(); r != nil || err != nil { + dao.Rollback(db) + if r != nil { + panic(r) + } + } + }() + + _, foodRecipe.AuthorID = ctx.GetMobileAndUserID() + dao.WrapAddIDCULEntity(foodRecipe, ctx.GetUserName()) + if err = dao.CreateEntity(db, foodRecipe); err != nil { + return err + } + for k, v := range itemList { + if len(v.SkuIDs) == 0 { + return fmt.Errorf("SkuIDs必须要有值") + } + skuIDs, err2 := dao.GetSkus(db, v.SkuIDs, nil, nil, nil) + if err = err2; err != nil { + return err + } + if len(v.SkuIDs) != len(skuIDs) { + return fmt.Errorf("某些SkuIDs不存在") + } + + item := &model.FoodRecipeItem{ + RecipeID: foodRecipe.ID, + Index: int8(k + 1), + Name: v.Name, + } + dao.WrapAddIDCULEntity(item, ctx.GetUserName()) + if err = dao.CreateEntity(db, item); err != nil { + return err + } + for k2, v2 := range v.SkuIDs { + choice := &model.FoodRecipeItemChoice{ + RecipeID: foodRecipe.ID, + Index: item.Index, + SkuID: v2, + + ChoiceIndex: int8(k2 + 1), + } + dao.WrapAddIDCULEntity(choice, ctx.GetUserName()) + if err = dao.CreateEntity(db, choice); err != nil { + return err + } + } + } + + for k, v := range stepList { + step := &model.FoodRecipeStep{ + RecipeID: foodRecipe.ID, + Index: int8(k + 1), + Name: v.Name, + } + dao.WrapAddIDCULEntity(step, ctx.GetUserName()) + if err = dao.CreateEntity(db, step); err != nil { + return err + } + } + dao.Commit(db) + + return err +} + +func UpdateFoodRecipe(ctx *jxcontext.Context, foodRecipe *model.FoodRecipe, itemList []*FoodRecipeItemParam, stepList []*FoodRecipeStepParam) (err error) { + return err +} diff --git a/controllers/cmd_food_recipe.go b/controllers/cmd_food_recipe.go new file mode 100644 index 000000000..f0ace9f50 --- /dev/null +++ b/controllers/cmd_food_recipe.go @@ -0,0 +1,43 @@ +package controllers + +import ( + "git.rosy.net.cn/jx-callback/business/jxutils" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/userstore" + "github.com/astaxie/beego" +) + +type FoodRecipeController struct { + beego.Controller +} + +// @Title 创建活动 +// @Description 创建活动 +// @Param token header string true "认证token" +// @Param name formData string true "菜谱名" +// @Param description formData string true "菜谱描述" +// @Param img formData string true "图片"" +// @Param timeInMinute formData string true "大约需要时间(分钟)" +// @Param recipeItems formData string true "菜谱配料" +// @Param recipeSteps formData string true "菜谱步骤" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /CreateFoodRecipe [post] +func (c *FoodRecipeController) CreateFoodRecipe() { + c.callCreateFoodRecipe(func(params *tFoodrecipeCreateFoodRecipeParams) (retVal interface{}, errCode string, err error) { + var ( + foodRecipe *model.FoodRecipe + itemList []*userstore.FoodRecipeItemParam + stepList []*userstore.FoodRecipeStepParam + ) + if err = jxutils.Strings2Objs(params.RecipeItems, &itemList, params.RecipeSteps, &stepList); err == nil { + foodRecipe = &model.FoodRecipe{ + Name: params.Name, + Description: params.Description, + Img: params.Img, + } + err = userstore.CreateFoodRecipe(params.Ctx, foodRecipe, itemList, stepList) + } + return retVal, "", err + }) +} diff --git a/controllers/cms_user2.go b/controllers/cms_user2.go index f045cac40..d907a8d56 100644 --- a/controllers/cms_user2.go +++ b/controllers/cms_user2.go @@ -147,14 +147,12 @@ func (c *User2Controller) GetRolesUserList() { if err = jxutils.Strings2Objs(params.RoleNames, &roleNames, params.StoreIDs, &storeIDs); err == nil { var roleList []*authz.RoleInfo for _, roleName := range roleNames { - if len(storeIDs) == 0 { - roleList = append(roleList, autils.NewRole(roleName, 0)) - } else { - if roleName == authz.StoreRoleBoss { - for _, storeID := range storeIDs { - roleList = append(roleList, autils.NewRole(roleName, storeID)) - } + if roleName == authz.StoreRoleBoss { + for _, storeID := range storeIDs { + roleList = append(roleList, autils.NewRole(roleName, storeID)) } + } else { + roleList = append(roleList, autils.NewRole(roleName, 0)) } } retVal, err = cms.GetRolesUserList(params.Ctx, roleList) diff --git a/globals/beegodb/beegodb.go b/globals/beegodb/beegodb.go index c86321240..70da7febd 100644 --- a/globals/beegodb/beegodb.go +++ b/globals/beegodb/beegodb.go @@ -55,6 +55,8 @@ func Init() { orm.RegisterModel(&model.CasbinRule{}) orm.RegisterModel(&model.SensitiveWord{}) orm.RegisterModel(&model.StoreScore{}) + orm.RegisterModel(&model.FoodRecipe{}, &model.FoodRecipeStep{}, &model.FoodRecipeItem{}, &model.FoodRecipeItemChoice{}, &model.FoodRecipeUser{}) + // create table orm.RunSyncdb("default", false, true) } diff --git a/routers/router.go b/routers/router.go index 99df270ae..387316631 100644 --- a/routers/router.go +++ b/routers/router.go @@ -116,6 +116,11 @@ func init() { &controllers.JxShopController{}, ), ), + beego.NSNamespace("/foodrecipe", + beego.NSInclude( + &controllers.FoodRecipeController{}, + ), + ), ) beego.AddNamespace(ns)