门店评分

This commit is contained in:
Rosy-zhudan
2019-09-06 17:29:09 +08:00
parent 40d9312acb
commit 52bdbdb4ff
6 changed files with 212 additions and 47 deletions

View File

@@ -6,6 +6,8 @@ import (
"sync"
"time"
"git.rosy.net.cn/jx-callback/globals/refutil"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxutils"
@@ -15,12 +17,12 @@ import (
)
const (
ItemScore = 10
TotalScore = 100
ItemTotalScore = 10
ItemCount = 10
StoreOpenTimeNormalTime = 12.0 //小时
SaleSkuNormalCount = 1000
SaleSkuScorePerUnit = float64(ItemScore) / SaleSkuNormalCount
SaleSkuScorePerUnit = float64(ItemTotalScore) / SaleSkuNormalCount
PromotionSkuNormalCount = 20
AveragePickupTimeNormalTime = 10.0 //分钟
BadCommentOrderNormalRatio = 0.2
@@ -28,19 +30,34 @@ const (
StoreRangeGoodRadius = 2.0 //千米
StoreRangeBadRadius = 1.0 //千米
SaleSkuPriceRatio = 90 //百分比
WeekDayCount = 7
)
var (
scoreStoreTimeList = []string{
"23:30:00",
}
storeScoreDataWrapper StoreScoreDataWrapper
fullVendorList = map[int]bool{
fullVendorList = map[int]bool{
model.VendorIDJD: true,
model.VendorIDMTWM: true,
model.VendorIDEBAI: true,
}
allStoreSkus map[int]map[int]*cms.StoreSkuNameExt
storeScoreFieldName = []string{
"StoreOpenTime",
"SaleSkuCount",
"AveragePickupTime",
"BadCommentOrder",
"UnfinishOrder",
"AbsentGoodsOrder",
"PromotionSku",
"FullVendor",
"StoreRange",
"SaleSkuPrice",
}
storeScoreDataWrapper StoreScoreDataWrapper
allStoreSkus map[int]map[int]*cms.StoreSkuNameExt
)
type StoreScoreDataWrapper struct {
@@ -52,13 +69,14 @@ func (s *StoreScoreDataWrapper) InitData() {
s.storeScoreData = make(map[int]*model.StoreScore)
}
func (s *StoreScoreDataWrapper) SetData(storeID int, valueName string, value int) {
func (s *StoreScoreDataWrapper) SetData(storeID int, storeName, valueName string, value int) {
s.locker.Lock()
defer s.locker.Unlock()
data := s.storeScoreData[storeID]
if data == nil {
data = &model.StoreScore{}
data.StoreID = storeID
data.StoreName = storeName
s.storeScoreData[storeID] = data
}
valueInfo := reflect.ValueOf(data).Elem()
@@ -106,6 +124,7 @@ func GetOpenTime(opTimeList []int16) (opTime float64) {
func ScoreStoreOpenTime(storeList []*cms.StoreExt) {
for _, storeInfo := range storeList {
storeID := storeInfo.ID
storeName := storeInfo.Name
storeStatus := storeInfo.Status
isStoreOpen := storeStatus == model.StoreStatusOpened
for _, storeMap := range storeInfo.StoreMaps {
@@ -116,15 +135,15 @@ func ScoreStoreOpenTime(storeList []*cms.StoreExt) {
finalScore := 0
opTime := GetOpenTime(opTimeList)
if opTime >= StoreOpenTimeNormalTime {
finalScore = ItemScore
finalScore = ItemTotalScore
} else {
decScore := int(math.Round(StoreOpenTimeNormalTime - opTime))
finalScore = ItemScore - decScore
finalScore = ItemTotalScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
storeScoreDataWrapper.SetData(storeID, "StoreOpenTime", finalScore)
storeScoreDataWrapper.SetData(storeID, storeName, "StoreOpenTime", finalScore)
}
}
}
@@ -134,6 +153,7 @@ func ScoreStoreOpenTime(storeList []*cms.StoreExt) {
func ScoreSaleSkuCount(ctx *jxcontext.Context, storeList []*cms.StoreExt) {
for _, storeInfo := range storeList {
storeID := storeInfo.ID
storeName := storeInfo.Name
skusMapData := allStoreSkus[storeID]
if len(skusMapData) > 0 {
finalScore := 0
@@ -147,10 +167,10 @@ func ScoreSaleSkuCount(ctx *jxcontext.Context, storeList []*cms.StoreExt) {
}
}
finalScore = int(math.Round(float64(saleSkuCount) * SaleSkuScorePerUnit))
if finalScore > ItemScore {
finalScore = ItemScore
if finalScore > ItemTotalScore {
finalScore = ItemTotalScore
}
storeScoreDataWrapper.SetData(storeID, "SaleSkuCount", finalScore)
storeScoreDataWrapper.SetData(storeID, storeName, "SaleSkuCount", finalScore)
}
}
}
@@ -159,6 +179,7 @@ func ScoreSaleSkuCount(ctx *jxcontext.Context, storeList []*cms.StoreExt) {
func ScoreAveragePickupTime(storeList []*cms.StoreExt) {
for _, storeInfo := range storeList {
storeID := storeInfo.ID
storeName := storeInfo.Name
db := dao.GetDB()
orderList, err := dao.GetDailyFinishOrderList(db, storeID)
orderListCount := len(orderList)
@@ -168,10 +189,10 @@ func ScoreAveragePickupTime(storeList []*cms.StoreExt) {
statusTime := value.StatusTime.Unix()
pickDeadline := value.PickDeadline.Unix()
if statusTime <= pickDeadline {
totalScore += ItemScore
totalScore += ItemTotalScore
} else {
decScore := int(math.Round(float64(statusTime-pickDeadline) / 60))
tempScore := ItemScore - decScore
tempScore := ItemTotalScore - decScore
if tempScore < 0 {
tempScore = 0
}
@@ -179,7 +200,7 @@ func ScoreAveragePickupTime(storeList []*cms.StoreExt) {
}
}
finalScore := totalScore / orderListCount
storeScoreDataWrapper.SetData(storeID, "AveragePickupTime", finalScore)
storeScoreDataWrapper.SetData(storeID, storeName, "AveragePickupTime", finalScore)
}
}
}
@@ -188,6 +209,7 @@ func ScoreAveragePickupTime(storeList []*cms.StoreExt) {
func ScoreBadCommentOrder(storeList []*cms.StoreExt) {
for _, storeInfo := range storeList {
storeID := storeInfo.ID
storeName := storeInfo.Name
db := dao.GetDB()
badCommentOrderCount, _ := dao.GetDailyBadCommentOrderCount(db, storeID)
finishOrderCount, _ := dao.GetDailyFinishOrderCount(db, storeID)
@@ -195,15 +217,15 @@ func ScoreBadCommentOrder(storeList []*cms.StoreExt) {
finalScore := 0
badCommentOrderRatio := float64(badCommentOrderCount) * 100 / float64(finishOrderCount)
if badCommentOrderRatio <= BadCommentOrderNormalRatio {
finalScore = ItemScore
finalScore = ItemTotalScore
} else {
decScore := int(math.Round((badCommentOrderRatio - BadCommentOrderNormalRatio) / 0.1))
finalScore = ItemScore - decScore
finalScore = ItemTotalScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
storeScoreDataWrapper.SetData(storeID, "BadCommentOrder", finalScore)
storeScoreDataWrapper.SetData(storeID, storeName, "BadCommentOrder", finalScore)
}
}
}
@@ -212,6 +234,7 @@ func ScoreBadCommentOrder(storeList []*cms.StoreExt) {
func ScoreUnfinishOrder(storeList []*cms.StoreExt) {
for _, storeInfo := range storeList {
storeID := storeInfo.ID
storeName := storeInfo.Name
db := dao.GetDB()
unFinishOrderCount, _ := dao.GetDailyUnFinishOrderCount(db, storeID)
finishOrderCount, _ := dao.GetDailyFinishOrderCount(db, storeID)
@@ -219,15 +242,15 @@ func ScoreUnfinishOrder(storeList []*cms.StoreExt) {
finalScore := 0
unfinishOrderRatio := float64(unFinishOrderCount) * 100 / float64(finishOrderCount)
if unfinishOrderRatio <= UnfinishOrderNormalRatio {
finalScore = ItemScore
finalScore = ItemTotalScore
} else {
decScore := int(math.Round((unfinishOrderRatio - UnfinishOrderNormalRatio) / 5))
finalScore = ItemScore - decScore
finalScore = ItemTotalScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
storeScoreDataWrapper.SetData(storeID, "UnfinishOrder", finalScore)
storeScoreDataWrapper.SetData(storeID, storeName, "UnfinishOrder", finalScore)
}
}
}
@@ -241,6 +264,7 @@ func ScoreAbsentGoodsOrder(storeList []*cms.StoreExt) {
func ScorePromotionSku(storeList []*cms.StoreExt) {
for _, storeInfo := range storeList {
storeID := storeInfo.ID
storeName := storeInfo.Name
db := dao.GetDB()
beginTime := time.Now()
endTime := time.Now()
@@ -255,15 +279,15 @@ func ScorePromotionSku(storeList []*cms.StoreExt) {
}
promotionSkuCount := len(actStoreSkuMap)
if promotionSkuCount >= PromotionSkuNormalCount {
finalScore = ItemScore
finalScore = ItemTotalScore
} else {
decScore := (PromotionSkuNormalCount - promotionSkuCount) / 2
finalScore = ItemScore - decScore
finalScore = ItemTotalScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
storeScoreDataWrapper.SetData(storeID, "PromotionSku", finalScore)
storeScoreDataWrapper.SetData(storeID, storeName, "PromotionSku", finalScore)
}
}
}
@@ -274,6 +298,7 @@ func ScoreFullVendor(storeList []*cms.StoreExt) {
for _, storeInfo := range storeList {
finalScore := 0
storeID := storeInfo.ID
storeName := storeInfo.Name
storeStatus := storeInfo.Status
isStoreOpen := storeStatus == model.StoreStatusOpened
count := 0
@@ -286,12 +311,12 @@ func ScoreFullVendor(storeList []*cms.StoreExt) {
}
}
if count == fullVendorCount {
finalScore = ItemScore
finalScore = ItemTotalScore
} else {
decScore := (fullVendorCount - count) * 2
finalScore = ItemScore - decScore
finalScore = ItemTotalScore - decScore
}
storeScoreDataWrapper.SetData(storeID, "FullVendor", finalScore)
storeScoreDataWrapper.SetData(storeID, storeName, "FullVendor", finalScore)
}
}
@@ -311,33 +336,34 @@ func ScoreStoreRange(storeList []*cms.StoreExt) {
for _, storeInfo := range storeList {
finalScore := 0
storeID := storeInfo.ID
storeName := storeInfo.Name
if storeInfo.DeliveryRangeType == model.DeliveryRangeTypePolygon {
points := jxutils.CoordinateStr2Points(storeInfo.DeliveryRange)
area := CalcPolygonArea(points)
goodArea := math.Pi * StoreRangeGoodRadius * StoreRangeGoodRadius
badArea := math.Pi * StoreRangeBadRadius * StoreRangeBadRadius
if area >= goodArea {
finalScore = ItemScore
finalScore = ItemTotalScore
} else if area <= badArea {
finalScore = 0
} else {
diff := goodArea - area
ratio := float64(ItemScore) / (goodArea - badArea)
finalScore = ItemScore - int(math.Round(diff*ratio))
ratio := float64(ItemTotalScore) / (goodArea - badArea)
finalScore = ItemTotalScore - int(math.Round(diff*ratio))
}
} else if storeInfo.DeliveryRangeType == model.DeliveryRangeTypeRadius {
deliveryRadius := utils.Str2Float64WithDefault(storeInfo.DeliveryRange, 0)
if deliveryRadius >= StoreRangeGoodRadius {
finalScore = ItemScore
finalScore = ItemTotalScore
} else if deliveryRadius <= StoreRangeBadRadius {
finalScore = 0
} else {
diff := StoreRangeGoodRadius - deliveryRadius
ratio := float64(ItemScore) / (StoreRangeGoodRadius - StoreRangeBadRadius)
finalScore = ItemScore - int(math.Round(diff*ratio))
ratio := float64(ItemTotalScore) / (StoreRangeGoodRadius - StoreRangeBadRadius)
finalScore = ItemTotalScore - int(math.Round(diff*ratio))
}
}
storeScoreDataWrapper.SetData(storeID, "StoreRange", finalScore)
storeScoreDataWrapper.SetData(storeID, storeName, "StoreRange", finalScore)
}
}
@@ -395,6 +421,7 @@ func ScoreSaleSkuPrice(ctx *jxcontext.Context, storeList []*cms.StoreExt) {
for _, storeInfo := range storeList {
finalScore := 0
storeID := storeInfo.ID
storeName := storeInfo.Name
totalCount := len(allStoreSkus[storeID])
if totalCount > 0 {
rangeStoreList := GetRangeStoreList(storeID, storeInfo.FloatLng, storeInfo.FloatLat, 5, storeList)
@@ -402,15 +429,15 @@ func ScoreSaleSkuPrice(ctx *jxcontext.Context, storeList []*cms.StoreExt) {
count := GetSkusCountLessEqualAvgPrice(storeID, skusAveragePrice)
ratio := int(math.Round(float64(count) * 100 / float64(totalCount)))
if ratio >= SaleSkuPriceRatio {
finalScore = ItemScore
finalScore = ItemTotalScore
} else {
decScore := (SaleSkuPriceRatio - ratio) / 10
finalScore = ItemScore - decScore
finalScore = ItemTotalScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
storeScoreDataWrapper.SetData(storeID, "SaleSkuPrice", finalScore)
storeScoreDataWrapper.SetData(storeID, storeName, "SaleSkuPrice", finalScore)
}
}
}
@@ -441,19 +468,19 @@ func ScoreStore(ctx *jxcontext.Context, storeIDList []int) (retVal interface{},
storeIDMap := jxutils.IntList2Map(storeIDList)
storeList = GetFilterStoreListEx(storeList, storeIDMap)
// GetAllStoreSkus(ctx, storeList)
GetAllStoreSkus(ctx, storeList)
ScoreStoreOpenTime(storeList)
// ScoreSaleSkuCount(ctx, storeList)
ScoreSaleSkuCount(ctx, storeList)
ScoreAveragePickupTime(storeList)
ScoreBadCommentOrder(storeList)
ScoreUnfinishOrder(storeList)
// ScoreAbsentGoodsOrder(storeList)
ScoreAbsentGoodsOrder(storeList)
ScorePromotionSku(storeList)
ScoreFullVendor(storeList)
ScoreStoreRange(storeList)
// ScoreSaleSkuPrice(ctx, storeList)
// InsertStoreScore()
// ClearAllStoreSkus()
ScoreSaleSkuPrice(ctx, storeList)
InsertStoreScore()
ClearAllStoreSkus()
return retVal, err
}
@@ -469,3 +496,62 @@ func ScheduleScoreStore() {
ScoreStore(jxcontext.AdminCtx, []int{})
}, scoreStoreTimeList)
}
func SplitToSingelWeekDataList(storeScoreList []*model.StoreScore) (weekDataList [][]*model.StoreScore) {
singelWeekData := []*model.StoreScore{}
count := 0
for _, value := range storeScoreList {
singelWeekData = append(singelWeekData, value)
count++
if count == WeekDayCount {
weekDataList = append(weekDataList, singelWeekData)
singelWeekData = []*model.StoreScore{}
count = 0
}
}
return weekDataList
}
func GetWeeklyStoreScore(storeID, weekIndex int) (outWeeklyStoreScoreDataList []*model.WeeklyStoreScore, err error) {
db := dao.GetDB()
storeScoreList, err := dao.GetLatestWeeklyStoreScoreList(db, storeID, 5)
if err == nil && len(storeScoreList) > 0 {
weeklyStoreScoreDataList := []*model.WeeklyStoreScore{}
weekDataList := SplitToSingelWeekDataList(storeScoreList)
for weekIndex, weekDataList := range weekDataList {
weeklyData := &model.WeeklyStoreScore{}
weeklyData.ID = weekIndex
weeklyData.ItemTotalScore = ItemTotalScore
weeklyStoreScoreDataList = append(weeklyStoreScoreDataList, weeklyData)
for dayIndex, dayData := range weekDataList {
for _, fieldName := range storeScoreFieldName {
srcFieldValue := refutil.GetObjFieldByName(dayData, fieldName).(int)
destFieldValueR := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
refutil.SetObjFieldByName(weeklyData, fieldName, destFieldValueR+srcFieldValue)
}
if dayIndex == 0 {
weeklyData.BeginTime = dayData.CreatedAt
} else if dayIndex == WeekDayCount-1 {
weeklyData.EndTime = dayData.CreatedAt
}
}
for _, fieldName := range storeScoreFieldName {
destFieldValueR := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
refutil.SetObjFieldByName(weeklyData, fieldName, int(math.Round(float64(destFieldValueR)/WeekDayCount)))
}
for _, fieldName := range storeScoreFieldName {
srcFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
destFieldValueR := refutil.GetObjFieldByName(weeklyData, "TotalScore").(int)
refutil.SetObjFieldByName(weeklyData, "TotalScore", destFieldValueR+srcFieldValue)
}
}
if weekIndex == -1 {
outWeeklyStoreScoreDataList = weeklyStoreScoreDataList
} else {
outWeeklyStoreScoreDataList = []*model.WeeklyStoreScore{weeklyStoreScoreDataList[weekIndex]}
}
}
return outWeeklyStoreScoreDataList, err
}

View File

@@ -296,7 +296,7 @@ func GetDailyFinishOrderList(db *DaoDB, storeID int) (orderList []*model.OrderPi
select t2.status_time, t1.pick_deadline
from goods_order t1
left join order_status t2 on t1.vendor_order_id = t2.vendor_order_id
where t1.jx_store_id = ? and t2.order_type = ? and t2.status = ? and DATE_FORMAT(t1.order_finished_at, '%Y-%m-%d') = DATE_FORMAT(NOW(), '%Y-%m-%d')
where t1.jx_store_id = ? and t2.order_type = ? and t2.status = ? and DATE(t1.order_finished_at) = CURDATE()
`
sqlParams := []interface{}{
storeID,
@@ -307,7 +307,7 @@ func GetDailyFinishOrderList(db *DaoDB, storeID int) (orderList []*model.OrderPi
}
func GetDailyBadCommentOrderCount(db *DaoDB, storeID int) (num int64, err error) {
sql := `select count(*) from jx_bad_comments where DATE_FORMAT(createtime, '%Y-%m-%d') = DATE_FORMAT(NOW(), '%Y-%m-%d') and jxstoreid = ?`
sql := `select count(*) from jx_bad_comments where DATE(createtime) = CURDATE() and jxstoreid = ?`
sqlParams := []interface{}{
storeID,
}
@@ -324,7 +324,7 @@ func GetDailyFinishOrderCount(db *DaoDB, storeID int) (num int64, err error) {
func GetDailyEndOrderCount(db *DaoDB, storeID int, statusList []int) (num int64, err error) {
sql := `select count(*) from goods_order
where DATE_FORMAT(order_finished_at, '%Y-%m-%d') = DATE_FORMAT(NOW(), '%Y-%m-%d')
where DATE(order_finished_at) = CURDATE()
and jx_store_id = ?
and status in (` + GenQuestionMarks(len(statusList)) + `)`
sqlParams := []interface{}{

View File

@@ -11,3 +11,48 @@ func InsertStoreScore(storeScore *model.StoreScore) error {
storeScore.CreatedAt = time.Now()
return CreateEntity(nil, storeScore)
}
func GetLatestWeeklyStoreScoreList(db *DaoDB, storeID, weekNum int) (storeScoreList []*model.StoreScore, err error) {
// sql := `
// SET @dayInWeek = IF(DAYOFWEEK(CURDATE()) - 1 = 0, 7, DAYOFWEEK(CURDATE()) - 1);
// SET @endDate = DATE_SUB(CURDATE(), INTERVAL @dayInWeek DAY);
// SET @beginData = DATE_SUB(@endDate, INTERVAL ? DAY);
// SELECT * FROM store_score
// WHERE store_id = ? AND DATE(created_at) >= @beginData AND DATE(created_at) <= @endDate ORDER BY created_at DESC
// `
sql := `
SELECT * FROM store_score WHERE store_id = ?
AND DATE(created_at) >= DATE_SUB(
DATE_SUB(
CURDATE(),
INTERVAL
IF (
DAYOFWEEK(CURDATE()) - 1 = 0,
7,
DAYOFWEEK(CURDATE()) - 1
) DAY
),
INTERVAL ? DAY
)
AND DATE(created_at) <= DATE_SUB(
CURDATE(),
INTERVAL
IF (
DAYOFWEEK(CURDATE()) - 1 = 0,
7,
DAYOFWEEK(CURDATE()) - 1
) DAY
)
ORDER BY created_at DESC
`
if weekNum <= 0 {
weekNum = 1
}
diffDays := weekNum*7 - 1
sqlParams := []interface{}{
storeID,
diffDays,
}
err = GetRows(db, &storeScoreList, sql, sqlParams)
return storeScoreList, err
}

View File

@@ -6,6 +6,7 @@ type StoreScore struct {
ID int `orm:"column(id)" json:"id"`
CreatedAt time.Time `orm:"auto_now_add;type(datetime)" json:"createdAt"`
StoreID int `orm:"column(store_id)" json:"storeID"`
StoreName string `orm:"column(store_name)" json:"storeName"`
StoreOpenTime int `orm:"column(store_open_time)" json:"storeOpenTime"`
SaleSkuCount int `orm:"column(sale_sku_count)" json:"saleSkuCount"`
@@ -18,3 +19,11 @@ type StoreScore struct {
StoreRange int `orm:"column(store_range)" json:"storeRange"`
SaleSkuPrice int `orm:"column(sale_sku_price)" json:"saleSkuPrice"`
}
type WeeklyStoreScore struct {
StoreScore
BeginTime time.Time `json:"beginTime"`
EndTime time.Time `json:"endTime"`
TotalScore int `json:"totalScore"`
ItemTotalScore int `json:"itemTotalScore"`
}

View File

@@ -334,3 +334,19 @@ func (c *TempOpController) ScoreStore() {
return retVal, "", err
})
}
// @Title 得到门店周平均分数数据
// @Description 得到门店周平均分数数据
// @Param token header string true "认证token"
// @Param storeID query int true "京西门店ID"
// @Param weekIndex query int true "周索引(起始索引为0, -1为所有周数据)"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /GetWeeklyStoreScore [get]
func (c *TempOpController) GetWeeklyStoreScore() {
c.callGetWeeklyStoreScore(func(params *tTempopGetWeeklyStoreScoreParams) (retVal interface{}, errCode string, err error) {
retVal, err = misc.GetWeeklyStoreScore(params.StoreID, params.WeekIndex)
return retVal, "", err
})
}

View File

@@ -1647,6 +1647,15 @@ func init() {
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:TempOpController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:TempOpController"],
beego.ControllerComments{
Method: "GetWeeklyStoreScore",
Router: `/GetWeeklyStoreScore`,
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:TempOpController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:TempOpController"],
beego.ControllerComments{
Method: "PrintMsg",