From c5df4f5f5e9cc58c778f79d2def2b0e0980ac5f0 Mon Sep 17 00:00:00 2001 From: xujianhua Date: Fri, 20 Sep 2019 15:25:39 +0800 Subject: [PATCH] =?UTF-8?q?Accept=20Merge=20Request=20#6:=20(don=20->=20ma?= =?UTF-8?q?rk)=20Merge=20Request:=20=E5=9F=8E=E5=B8=82=E5=95=86=E5=93=81?= =?UTF-8?q?=E9=94=80=E9=87=8F=E7=BB=9F=E8=AE=A1=20Created=20By:=20@zhudan?= =?UTF-8?q?=20Accepted=20By:=20@xujianhua=20URL:=20https://rosydev.coding.?= =?UTF-8?q?net/p/jx-callback/d/jx-callback/git/merge/6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- business/jxstore/misc/store_sku_sales.go | 171 +++++++++++++++++++++++ business/model/dao/store_sku_sales.go | 78 +++++++++++ business/model/store_sku_sales.go | 17 +++ controllers/cms_sku.go | 15 ++ routers/commentsRouter_controllers.go | 9 ++ 5 files changed, 290 insertions(+) create mode 100644 business/jxstore/misc/store_sku_sales.go create mode 100644 business/model/dao/store_sku_sales.go create mode 100644 business/model/store_sku_sales.go diff --git a/business/jxstore/misc/store_sku_sales.go b/business/jxstore/misc/store_sku_sales.go new file mode 100644 index 000000000..5ba3f19de --- /dev/null +++ b/business/jxstore/misc/store_sku_sales.go @@ -0,0 +1,171 @@ +package misc + +import ( + "math" + "sync" + + "git.rosy.net.cn/jx-callback/business/jxstore/cms" + "git.rosy.net.cn/jx-callback/business/jxutils" + "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" + "git.rosy.net.cn/jx-callback/business/jxutils/tasksch" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/model/dao" +) + +const ( + DayNum = 30 //请求天数 + LimitNum = 100 //最大数据限制 +) + +func GetStoreSkuSalesInfo(ctx *jxcontext.Context, storeID int) (outStoreSkuSales []*model.StoreSkuSales, err error) { + db := dao.GetDB() + //得到所有门店 + storeList, err := GetStoreList(ctx) + if err == nil { + storeList = GetFilterStoreListEx(storeList, nil) + } else { + return nil, err + } + storeMapData := make(map[int]*cms.StoreExt) + for _, value := range storeList { + storeMapData[value.ID] = value + } + curStoreInfo := storeMapData[storeID] + cityCode := curStoreInfo.CityCode + + //获取本市商品总销量 + citySkuSalesCntMap := make(map[int]int) + citySkuSalesCntList, err := dao.GetSkuSalesCntList(db, -1, cityCode, DayNum, LimitNum, nil) + citySkuIDs := []int{} + if err == nil { + for _, value := range citySkuSalesCntList { + citySkuSalesCntMap[value.SkuID] = value.Count + citySkuIDs = append(citySkuIDs, value.SkuID) + } + } else { + return nil, err + } + + //获取本店商品总销量 + storeSkuSalesCntMap := make(map[int]int) + storeSkuSalesCntList, err := dao.GetSkuSalesCntList(db, storeID, cityCode, DayNum, -1, citySkuIDs) + if err == nil { + for _, value := range storeSkuSalesCntList { + storeSkuSalesCntMap[value.SkuID] = value.Count + } + } else { + return nil, err + } + + //获取本店商品差评数量 + storeSkuBadCommentCntMap := make(map[int]int) + storeSkuBadCommentCntList, err := dao.GetSkuBadCommentCntList(db, storeID, DayNum) + if err == nil { + for _, value := range storeSkuBadCommentCntList { + storeSkuBadCommentCntMap[value.SkuID] = value.Count + } + } else { + return nil, err + } + + //得到当前门店商品数据 + storeSkuMapData := make(map[int]*cms.StoreSkuNameExt) + storeSkuData, err := cms.GetStoreSkus(ctx, storeID, citySkuIDs, true, "", true, map[string]interface{}{}, 0, -1) + if err == nil { + for _, value := range storeSkuData.SkuNames { + for _, skuInfo := range value.Skus2 { + storeSkuMapData[skuInfo.SkuID] = value + } + } + } else { + return nil, err + } + + //得到5KM内的所有门店 + rangeStoreList := GetRangeStoreList(storeID, curStoreInfo.FloatLng, curStoreInfo.FloatLat, SaleSkuCheckRange, storeList) + + //得到5KM内的所有门店的商品的价格 + allStoreSkus := make(map[int]map[int]int) + var locker sync.RWMutex + taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + storeInfo := batchItemList[0].(*cms.StoreExt) + storeID := storeInfo.ID + jxSkuInfoData, err := cms.GetStoreSkus(ctx, storeID, citySkuIDs, true, "", true, map[string]interface{}{}, 0, -1) + jxSkuPriceMapData := make(map[int]int) + for _, value := range jxSkuInfoData.SkuNames { + for _, skuInfo := range value.Skus2 { + jxSkuPriceMapData[skuInfo.SkuID] = skuInfo.BindPrice + } + } + locker.Lock() + defer locker.Unlock() + allStoreSkus[storeID] = jxSkuPriceMapData + return retVal, err + } + taskParallel := tasksch.NewParallelTask("得到所有门店商品", nil, ctx, taskFunc, rangeStoreList) + taskParallel.Run() + _, err = taskParallel.GetResult(0) + if err != nil { + return nil, err + } + + //计算商品的平均价格 + skusTotalPrice := make(map[int]int) + skusCount := make(map[int]int) + skusAveragePrice := make(map[int]int) + for _, storeInfo := range rangeStoreList { + storeID := storeInfo.ID + storeSkuMapData := allStoreSkus[storeID] + for skuID, skuPrice := range storeSkuMapData { + skusTotalPrice[skuID] += skuPrice + skusCount[skuID]++ + } + } + for id, totalPrice := range skusTotalPrice { + skusAveragePrice[id] = int(math.Round(float64(totalPrice) / float64(skusCount[id]))) + } + + //输出商品销量统计结果 + skuAndNameMapData := make(map[int]*model.SkuAndName) + if len(storeSkuMapData) < len(citySkuIDs) { + skuAndNameList, err := dao.GetSkus(db, citySkuIDs, nil, nil, nil) + if err == nil { + for _, value := range skuAndNameList { + skuAndNameMapData[value.ID] = value + } + } + } + for _, value := range citySkuSalesCntList { + skuID := value.SkuID + storeSkuSales := &model.StoreSkuSales{} + storeSkuSales.SkuID = skuID + storeSkuInfo := storeSkuMapData[skuID] + skuAndNameInfo := skuAndNameMapData[skuID] + if storeSkuInfo != nil { + skuName := storeSkuInfo.SkuName + skuInfo := storeSkuInfo.Skus2[0] + storeSkuSales.SkuName = jxutils.ComposeSkuName(skuName.Prefix, skuName.Name, skuInfo.Comment, skuName.Unit, skuInfo.SkuSpecQuality, skuInfo.SkuSpecUnit, 0) + storeSkuSales.SkuImage = storeSkuInfo.Img + storeSkuSales.SkuPrice = jxutils.IntPrice2StandardCurrencyString(int64(storeSkuInfo.Skus2[0].BindPrice)) + } else if skuAndNameInfo != nil { + skuNameList, err := dao.GetSkuNames(db, []int{skuAndNameInfo.NameID}) + prefix := "" + if err == nil && len(skuNameList) > 0 { + storeSkuSales.SkuImage = skuNameList[0].Img + prefix = skuNameList[0].Prefix + } + storeSkuSales.SkuName = jxutils.ComposeSkuName(prefix, skuAndNameInfo.Name, skuAndNameInfo.Comment, skuAndNameInfo.Unit, skuAndNameInfo.SpecQuality, skuAndNameInfo.SpecUnit, 0) + storeSkuSales.SkuPrice = "N/A" + } else { + storeSkuSales.SkuName = "N/A" + storeSkuSales.SkuPrice = "N/A" + } + storeSkuSales.SkuAvgPrice = jxutils.IntPrice2StandardCurrencyString(int64(skusAveragePrice[skuID])) + storeSkuSales.BadCommentCnt = storeSkuBadCommentCntMap[skuID] + storeSkuSales.StoreSkuSalesCnt = storeSkuSalesCntMap[skuID] + storeSkuSales.CitySkuSalesCnt = citySkuSalesCntMap[skuID] + outStoreSkuSales = append(outStoreSkuSales, storeSkuSales) + } + + return outStoreSkuSales, err +} diff --git a/business/model/dao/store_sku_sales.go b/business/model/dao/store_sku_sales.go new file mode 100644 index 000000000..5c8b05940 --- /dev/null +++ b/business/model/dao/store_sku_sales.go @@ -0,0 +1,78 @@ +package dao + +import ( + "time" + + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" +) + +func GetSkuSalesCntList(db *DaoDB, storeID, cityCode, dayNum, limit int, skuIDs []int) (skuCountList []*model.SkuCount, err error) { + sql := ` + SELECT t2.jx_sku_id sku_id, SUM(t2.count) count + FROM goods_order t1 + JOIN order_sku t2 on t1.vendor_order_id = t2.vendor_order_id and t1.vendor_id = t2.vendor_id + JOIN store t3 on t1.jx_store_id = t3.id + WHERE t1.order_finished_at >= ? AND t1.order_finished_at < ? + AND t1.status = ? + AND t2.jx_sku_id <> 0 + AND t3.city_code = ? + ` + if dayNum < 0 { + dayNum = 30 + } + beginTime := utils.GetCurDate().Add(-time.Hour * 24 * time.Duration(dayNum)) + endTime := utils.GetCurDate() + sqlParams := []interface{}{ + beginTime, + endTime, + model.OrderStatusFinished, + cityCode, + } + if storeID > 0 { + sql += ` + AND t1.jx_store_id = ? + ` + sqlParams = append(sqlParams, storeID) + } + if len(skuIDs) > 0 { + sql += ` + AND t2.jx_sku_id IN (` + GenQuestionMarks(len(skuIDs)) + `)` + sqlParams = append(sqlParams, skuIDs) + } + sql += ` + GROUP BY jx_sku_id + ORDER BY count DESC + ` + if limit > 0 { + sql += ` + LIMIT ? + ` + sqlParams = append(sqlParams, limit) + } + err = GetRows(db, &skuCountList, sql, sqlParams) + return skuCountList, err +} + +func GetSkuBadCommentCntList(db *DaoDB, storeID, dayNum int) (skuCountList []*model.SkuCount, err error) { + sql := ` + SELECT t2.jx_sku_id sku_id, COUNT(*) count + FROM jx_bad_comments t1 + JOIN order_sku t2 ON t1.order_id = t2.vendor_order_id + WHERE t1.createtime >= ? AND t1.createtime < ? + AND t1.jxstoreid = ? + GROUP BY t2.jx_sku_id + ` + if dayNum < 0 { + dayNum = 30 + } + beginTime := utils.GetCurDate().Add(-time.Hour * 24 * time.Duration(dayNum)) + endTime := utils.GetCurDate() + sqlParams := []interface{}{ + beginTime, + endTime, + storeID, + } + err = GetRows(db, &skuCountList, sql, sqlParams) + return skuCountList, err +} diff --git a/business/model/store_sku_sales.go b/business/model/store_sku_sales.go new file mode 100644 index 000000000..2f6bc3bba --- /dev/null +++ b/business/model/store_sku_sales.go @@ -0,0 +1,17 @@ +package model + +type StoreSkuSales struct { + SkuID int `json:"skuID"` + SkuName string `json:"skuName"` + SkuImage string `json:"skuImage"` + SkuPrice string `json:"skuPrice"` + SkuAvgPrice string `json:"skuAvgPrice"` + BadCommentCnt int `json:"badCommentCnt"` + StoreSkuSalesCnt int `json:"storeSkuSalesCnt"` + CitySkuSalesCnt int `json:"citySkuSalesCnt"` +} + +type SkuCount struct { + SkuID int `orm:"column(sku_id)"` + Count int +} diff --git a/controllers/cms_sku.go b/controllers/cms_sku.go index af1750251..11e26496c 100644 --- a/controllers/cms_sku.go +++ b/controllers/cms_sku.go @@ -3,6 +3,7 @@ package controllers import ( "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxstore/cms" + "git.rosy.net.cn/jx-callback/business/jxstore/misc" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" @@ -359,3 +360,17 @@ func (c *SkuController) SortCategorySkus() { return retVal, "", err }) } + +// @Title 按照当前城市近30天销量排序,显示本店价格,附近5公里平均价格,差评数量,本店销量情况,本市总销量, +// @Description 按照当前城市近30天销量排序,显示本店价格,附近5公里平均价格,差评数量,本店销量情况,本市总销量, +// @Param token header string true "认证token" +// @Param storeID query int true "京西门店ID" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /GetStoreSkuSalesInfo [get] +func (c *SkuController) GetStoreSkuSalesInfo() { + c.callGetStoreSkuSalesInfo(func(params *tSkuGetStoreSkuSalesInfoParams) (retVal interface{}, errCode string, err error) { + retVal, err = misc.GetStoreSkuSalesInfo(params.Ctx, params.StoreID) + return retVal, "", err + }) +} diff --git a/routers/commentsRouter_controllers.go b/routers/commentsRouter_controllers.go index 5baa4b15a..ce7539ee3 100644 --- a/routers/commentsRouter_controllers.go +++ b/routers/commentsRouter_controllers.go @@ -1161,6 +1161,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"], + beego.ControllerComments{ + Method: "GetStoreSkuSalesInfo", + Router: `/GetStoreSkuSalesInfo`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:SkuController"], beego.ControllerComments{ Method: "GetVendorCategories",