package statdaily import ( "context" "errors" "fmt" "stat/common/log" "stat/common/statutils" "stat/common/utils" "stat/models/accessmod" "stat/models/blocDailystatmod" "stat/models/dailystatmod" "stat/models/downloadinfo" "stat/models/rechargegamemod" "stat/models/rechargemod" "stat/models/registermod" "stat/models/syncrecharge" "stat/models/syncvip" "stat/models/versionMod" "stat/models/withdrawGameOrdermod" "strconv" "strings" "time" "go.mongodb.org/mongo-driver/bson" ) const ( AppVisitCount string = "appVisitCount" // app访问数 Day1RetainRate string = "day1RetainRate" // 次日留存率 Day3RetainRate string = "day3RetainRate" // 3日留存率 Day7RetainRate string = "day7RetainRate" // 7日留存率 RechargeAmount string = "rechargeAmount" // 充值金额 NewDirectCount string = "newDirectCount" // 直推 VipRechargeAmount string = "vipRechargeAmount" // VIP购买数 RechargeCount string = "rechargeCount" // 充值次数 GameRecharge string = "gameRecharge" // 游戏充值 LandpageClick string = "landpageClick" // 落地页下载按钮点击次数 ) func defaultTimeMap(defaultStatDate time.Time) map[string]time.Time { return map[string]time.Time{ AppVisitCount: defaultStatDate, // app访问人数 Day1RetainRate: defaultStatDate, // 次日留存率 Day3RetainRate: defaultStatDate, // 3日留存率 Day7RetainRate: defaultStatDate, // 7日留存率 RechargeAmount: defaultStatDate, // 直推充值金额 NewDirectCount: defaultStatDate, // 新增直推 VipRechargeAmount: defaultStatDate, // VIP购买数 RechargeCount: defaultStatDate, // 充值次数 GameRecharge: defaultStatDate, // 游戏充值 LandpageClick: defaultStatDate, // 落地页 } } // 获取统计方法 type StatMethod = func(ctx context.Context, start time.Time, end time.Time, appIds []int32) error // 统计方法汇总 var statMethodMap = map[string]StatMethod{ AppVisitCount: AppVisitCountMethod, // 访问数 Day1RetainRate: Day1RetainRateMethod, // 次日留存率 Day3RetainRate: Day3RetainRateMethod, // 3日留存率 Day7RetainRate: Day7RetainRateMethod, // 7日留存率 RechargeAmount: AmountMethod, // 直推充值金额 NewDirectCount: NewCountMethod, // 注册用户 VipRechargeAmount: VipRechargeAmountMethod, // VIP购买数 RechargeCount: RechargeCountMethod, // 充值次数 GameRecharge: GameRechargeMethod, // 游戏充值 LandpageClick: LandpageClickMethod, // 落地页 } // AppVisitCountMethod app访问数 func AppVisitCountMethod(ctx context.Context, start time.Time, end time.Time, appIds []int32) error { for _, appid := range appIds { stat := &statutils.Stat{} err := accessmod.VisitInfoByTimeShard(ctx, appid, start, end, utils.GlobalShardHour, func(item *accessmod.AccessMod) { client := statutils.GetClientInfo(item.SysType, item.DevType, item.DistrictCode, item.IsDirect, false, item.IsFormalUser) stat.Add(1, client) }) if err != nil { log.Error("AppVisitCountMethod:VisitInfoByTimeShard", log.E(err)) return err } //更新数据库 doc := dailystatmod.DailyStatDoc{ TotalVisitCount: stat.CountRef(), DirectVisitCount: stat.Total.Direct.CountRef(), DeductionVisitCount: stat.Total.Deduction.CountRef(), NaturalVisitCount: stat.Total.Direct.Natural.CountRef(), FissionVisitCount: stat.Total.Fission.CountRef(), TodayDistrictVisitCount: stat.Total.District.CountRef(), TodayWebVisitCount: stat.Total.Web.CountRef(), TodayNormalVisitCount: stat.Total.Normal.CountRef(), TodayIosVisitCount: stat.Ios.CountRef(), TodayAndroidVisitCount: stat.Android.CountRef(), LightVisitCount: stat.Light.CountRef(), LightDirectVisitCount: stat.Light.Total.Direct.CountRef(), LightFissionVisitCount: stat.Light.Total.Fission.CountRef(), LightDeductionVisitCount: stat.Light.Total.Deduction.CountRef(), LightNaturalVisitCount: stat.Light.Total.Direct.Natural.CountRef(), LightWebVisitCount: stat.Light.Total.Web.CountRef(), LightDistrictVisitCount: stat.Light.Total.District.CountRef(), LightNormalVisitCount: stat.Light.Total.Normal.CountRef(), TodayH5VisitCount: stat.H5.CountRef(), TodayH5PcVisitCount: stat.H5.Pc.CountRef(), TodayH5IosVisitCount: stat.H5.Ios.CountRef(), TodayH5AndroidVisitCount: stat.H5.Android.CountRef(), } err = dailystatmod.UpsertDailyStat(ctx, start, appid, doc) if err != nil { log.Error("H5appVisitCountMethod:UpsertDailyStat", log.E(err)) return err } } return nil } // Day1RetainRateMethod 次日留存率 func Day1RetainRateMethod(ctx context.Context, start time.Time, end time.Time, appIds []int32) error { for _, appid := range appIds { rate := float64(0) registerStart := utils.BeginWithTime(start.AddDate(0, 0, -1)) registerEnd := utils.EndWithTime(start.AddDate(0, 0, -1)) registerCount, err := registermod.TotalAddUserCount(ctx, appid, registerStart, registerEnd) if err != nil { log.Error("Day1RetainRateMethod s", log.E(err)) return err } VistitCount, err := accessmod.DailyUserVisitCountByRegister(ctx, appid, start, end, registerStart, registerEnd) if err != nil { log.Error("Day1RetainRateMethod DailyUserVisitCountByRegister", log.E(err)) return err } if registerCount > 0 { rate, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", 100*(float64(VistitCount)/float64(registerCount))), 64) //fmt.Println(VistitCount, registerCount, rate) } // 更新数据库 doc := dailystatmod.DailyStatDoc{ Day1RetainRate: &rate, } err = dailystatmod.UpsertDailyStat(ctx, start, appid, doc) if err != nil { log.Error("Day1RetainRateMethod UpsertDailyStat ", log.E(err)) return err } } return nil } // Day3RetainRateMethod 3日留存率 func Day3RetainRateMethod(ctx context.Context, start time.Time, end time.Time, appIds []int32) error { for _, appid := range appIds { rate := float64(0) registerStart := utils.BeginWithTime(start.AddDate(0, 0, -2)) registerEnd := utils.EndWithTime(start.AddDate(0, 0, -2)) registerCount, err := registermod.TotalAddUserCount(ctx, appid, registerStart, registerEnd) if err != nil { log.Error("Day1RetainRateMethod s", log.E(err)) return err } VistitCount, err := accessmod.DailyUserVisitCountByRegister(ctx, appid, start, end, registerStart, registerEnd) if err != nil { log.Error("Day1RetainRateMethod DailyUserVisitCountByRegister", log.E(err)) return err } if registerCount > 0 { rate, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", 100*(float64(VistitCount)/float64(registerCount))), 64) } // 更新数据库 doc := dailystatmod.DailyStatDoc{ Day3RetainRate: &rate, } err = dailystatmod.UpsertDailyStat(ctx, start, appid, doc) if err != nil { log.Error("Day3RetainRateMethod UpsertDailyStat ", log.E(err)) return err } } return nil } // Day7RetainRateMethod 7日留存率 func Day7RetainRateMethod(ctx context.Context, start time.Time, end time.Time, appIds []int32) error { for _, appid := range appIds { rate := float64(0) registerStart := utils.BeginWithTime(start.AddDate(0, 0, -6)) registerEnd := utils.EndWithTime(start.AddDate(0, 0, -6)) registerCount, err := registermod.TotalAddUserCount(ctx, appid, registerStart, registerEnd) if err != nil { log.Error("Day1RetainRateMethod s", log.E(err)) return err } VistitCount, err := accessmod.DailyUserVisitCountByRegister(ctx, appid, start, end, registerStart, registerEnd) if err != nil { log.Error("Day1RetainRateMethod DailyUserVisitCountByRegister", log.E(err)) return err } if registerCount > 0 { rate, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", 100*(float64(VistitCount)/float64(registerCount))), 64) } // 更新数据库 doc := dailystatmod.DailyStatDoc{ Day7RetainRate: &rate, } err = dailystatmod.UpsertDailyStat(ctx, start, appid, doc) if err != nil { log.Error("Day7RetainRateMethod UpsertDailyStat ", log.E(err)) return err } } return nil } // AmountMethod 直推充值金额 func AmountMethod(ctx context.Context, start time.Time, end time.Time, appIds []int32) error { for _, appid := range appIds { // 获取充值金额 itemList, err := rechargemod.TotalRechargeListV1(ctx, appid, start, end) if err != nil { log.Error("DirectAmountMethod DirectRechargeAmount ", log.E(err)) return err } stat := &statutils.Stat{} repStat := &statutils.Stat{} newStat := &statutils.Stat{} for _, item := range itemList { client := statutils.GetClientInfo(item.SysType, item.DevType, item.DistrictCode, item.IsDirect, false, item.IsFormalUser) stat.Add(item.PayMoney, client) if item.RegisterTime.After(item.SuccessAt.AddDate(0, 0, -1)) { newStat.Add(item.PayMoney, client) } if item.Repeat { repStat.Add(item.PayMoney, client) } } // 更新数据库 doc := dailystatmod.DailyStatDoc{ TotalAmount: stat.ValueRef(), SuccessRechargeOrder: stat.CountRef(), DirectAmount: stat.Total.Direct.ValueRef(), DirectAmountCount: stat.Total.Direct.CountRef(), FissionAmount: stat.Total.Fission.ValueRef(), FissionAmountCount: stat.Total.Fission.CountRef(), NaturalAmount: stat.Total.Direct.Natural.ValueRef(), NaturalAmountCount: stat.Total.Direct.Natural.CountRef(), DeductionAmount: stat.Total.Deduction.ValueRef(), DeductionAmountCount: stat.Total.Deduction.CountRef(), TodayWebRecharge: stat.Total.Web.ValueRef(), TodayDistrictRecharge: stat.Total.District.ValueRef(), TodayNormalRecharge: stat.Total.Normal.ValueRef(), TodayAndroidRecharge: stat.Android.ValueRef(), TodayIosRecharge: stat.Ios.ValueRef(), LightRechargeCount: stat.Light.CountRef(), LightDirectRechargeCount: stat.Light.Total.Direct.CountRef(), LightFissionRechargeCount: stat.Light.Total.Fission.CountRef(), LightDeductionRechargeCount: stat.Light.Total.Deduction.CountRef(), LightNaturalRechargeCount: stat.Light.Total.Direct.Natural.CountRef(), LightWebRechargeCount: stat.Light.Total.Web.CountRef(), LightDistrictRechargeCount: stat.Light.Total.District.CountRef(), LightNormalRechargeCount: stat.Light.Total.Normal.CountRef(), LightRechargeAmount: stat.Light.ValueRef(), LightDirectRechargeAmount: stat.Light.Total.Direct.ValueRef(), LightFissionRechargeAmount: stat.Light.Total.Fission.ValueRef(), LightDeductionRechargeAmount: stat.Light.Total.Deduction.ValueRef(), LightNaturalRechargeAmount: stat.Light.Total.Direct.Natural.ValueRef(), LightWebRechargeAmount: stat.Light.Total.Web.ValueRef(), LightDistrictRechargeAmount: stat.Light.Total.District.ValueRef(), LightNormalRechargeAmount: stat.Light.Total.Normal.ValueRef(), TodayH5Recharge: stat.H5.ValueRef(), TodayH5IosRecharge: stat.H5.Ios.ValueRef(), TodayH5AndroidRecharge: stat.H5.Android.ValueRef(), TodayH5PcRecharge: stat.H5.Pc.ValueRef(), NewRechargeAmount: newStat.ValueRef(), NewRechargeCount: newStat.CountRef(), RepeatAmount: repStat.ValueRef(), RepeatCount: repStat.CountRef(), } err = dailystatmod.UpsertDailyStat(ctx, start, appid, doc) if err != nil { log.Error("DirectAmountMethod UpsertDailyStat ", log.E(err)) return err } } return nil } func NewCountMethod(ctx context.Context, start time.Time, end time.Time, appIds []int32) error { for _, appid := range appIds { stat := &statutils.Stat{} userDict := make(map[uint64]bool) err := registermod.RegisterFormalsInfoByTimeShard(ctx, appid, start, end, utils.GlobalShardHour, func(item *registermod.RegisterMod) { if item.IsFormal && statutils.IsClientH5OrLight(item.SysType, item.DevType) { if _, exists := userDict[item.UserId]; !exists { userDict[item.UserId] = true client := statutils.GetClientInfo(item.SysType, item.DevType, item.DistrictCode, item.IsDirect, false, item.IsFormal) stat.Add(1, client) } } }) if err != nil { return err } err = registermod.RegisterUsersInfoByTimeShard(ctx, appid, start, end, utils.GlobalShardHour, func(item *registermod.RegisterMod) { userDict[item.UserId] = true client := statutils.GetClientInfo(item.SysType, item.DevType, item.DistrictCode, item.IsDirect, false, item.IsFormal) stat.Add(1, client) }) if err != nil { return err } doc := dailystatmod.DailyStatDoc{ NewTotalCount: stat.CountRef(), NewDirectCount: stat.Total.Direct.CountRef(), NewFissionCount: stat.Total.Fission.CountRef(), NewDeductionCount: stat.Total.Deduction.CountRef(), NewNaturalCount: stat.Total.Direct.Natural.CountRef(), NewWebCount: stat.Total.Web.CountRef(), NewDistrictCount: stat.Total.District.CountRef(), NewNormalCount: stat.Total.Normal.CountRef(), AndroidAddCount: stat.Android.CountRef(), IosAddCount: stat.Ios.CountRef(), LightAddCount: stat.Light.CountRef(), LightGuestAddCount: stat.Light.Guest.CountRef(), LightFormalAddCount: stat.Light.Formal.CountRef(), LightDirectCount: stat.Light.Total.Direct.CountRef(), LightFissionCount: stat.Light.Total.Fission.CountRef(), LightDeductionCount: stat.Light.Total.Deduction.CountRef(), LightNaturalCount: stat.Light.Total.Direct.Natural.CountRef(), LightWebCount: stat.Light.Total.Web.CountRef(), LightDistrictCount: stat.Light.Total.District.CountRef(), LightNormalCount: stat.Light.Total.Normal.CountRef(), H5AddCount: stat.H5.CountRef(), H5PcAddCount: stat.H5.Pc.CountRef(), H5IosAddCount: stat.H5.Ios.CountRef(), H5AndroidAddCount: stat.H5.Android.CountRef(), H5FormalCount: stat.H5.Formal.CountRef(), } err = dailystatmod.UpsertDailyStat(ctx, start, appid, doc) if err != nil { log.Error("NewDeductionCountMethod UpsertDailyStat ", log.E(err)) return err } } return nil } // VipRechargeAmountMethod VIP购买次数 func VipRechargeAmountMethod(ctx context.Context, start time.Time, end time.Time, appIds []int32) error { for _, appid := range appIds { money := int64(0) amount := int64(0) NewVipPayMoney := int64(0) RepeatVipMoney := int64(0) filter := bson.M{syncvip.FN.SyncVip.AppId: appid, syncvip.FN.SyncVip.SuccessAt: bson.M{"$gt": start, "$lt": end}} viporderList, serr := syncvip.FindManySyncVip(ctx, filter) if serr != nil { return errors.New(serr.Error()) } for _, viporder := range viporderList { money += viporder.Money amount += viporder.Amount if viporder.RegisterTime.After(viporder.SuccessAt.AddDate(0, 0, -1)) { NewVipPayMoney += viporder.Money } if viporder.Repeat { RepeatVipMoney += viporder.Money } } // 更新数据库 doc := dailystatmod.DailyStatDoc{ VipPayByMoney: &money, VipPayByAmount: &amount, NewVipPayMoney: &NewVipPayMoney, RepeatVipMoney: &RepeatVipMoney, } err := dailystatmod.UpsertDailyStat(ctx, start, appid, doc) if err != nil { log.Error("NewDeductionCountMethod UpsertDailyStat ", log.E(err)) return err } } return nil } // RechargeCountMethod 充值次数 func RechargeCountMethod(ctx context.Context, start time.Time, end time.Time, appIds []int32) error { for _, appid := range appIds { filter := bson.M{syncvip.FN.SyncVip.AppId: appid, syncrecharge.FN.SyncRechargeOrder.CreatedAt: bson.M{"$gt": start, "$lt": end}} total, serr := syncrecharge.CountSyncRechargeOrders(ctx, filter) if serr != nil { return errors.New(serr.Error()) } doc := dailystatmod.DailyStatDoc{ TotalRechargeOrder: &total, } err := dailystatmod.UpsertDailyStat(ctx, start, appid, doc) if err != nil { log.Error("NewDeductionCountMethod UpsertDailyStat ", log.E(err)) return err } } return nil } // GameRechargeMethod 游戏充值 func GameRechargeMethod(ctx context.Context, start time.Time, end time.Time, appIds []int32) error { for _, appid := range appIds { rechageAmount := int64(0) withdrawAmount := int64(0) withdrawList, serr := withdrawGameOrdermod.GetGameWithdrawOrder(ctx, appid, start, end) if serr != nil { return errors.New(serr.Error()) } for _, withdrawInfo := range withdrawList { withdrawAmount += withdrawInfo.PayMoney } filter := bson.M{"appId": appid, "successAt": bson.M{"$gt": start, "$lte": end}} rechageList, serr := rechargegamemod.FindManyRechargeInfo(ctx, filter) if serr != nil { return errors.New(serr.Error()) } for _, rechageInfo := range rechageList { rechageAmount += rechageInfo.PayMoney } // 更新数据库 doc := dailystatmod.DailyStatDoc{ GameRechageAmount: &rechageAmount, GameWithdrawAmount: &withdrawAmount, } err := dailystatmod.UpsertDailyStat(ctx, start, appid, doc) if err != nil { log.Error("NewDeductionCountMethod UpsertDailyStat ", log.E(err)) return err } // 更新数据库 blocDoc := blocDailystatmod.BlocDailyStatDoc{ GameRechageAmount: &rechageAmount, GameWithdrawAmount: &withdrawAmount, } err = blocDailystatmod.UpsertBlocDailyStat(ctx, start, appid, blocDoc) if err != nil { log.Error("DeductionAmountMethod UpsertDailyStat ", log.E(err)) return err } } return nil } // LandpageClickMethod 落地页访问次数 func LandpageClickMethod(ctx context.Context, start time.Time, end time.Time, appIds []int32) error { for _, appid := range appIds { downloadList, err := downloadinfo.GetAccessCountByTime(ctx, appid, start, end) if err != nil { log.Error("RunMonitor, GetAccessCountByTime", log.E(err)) return err } androidClick := int64(0) appstoreClick := int64(0) iosAtherClick := int64(0) lightClick := int64(0) for _, downloadInfo := range downloadList { if downloadInfo.SysType == "android" { androidClick += 1 } else if strings.Contains(downloadInfo.SysType, "ios") || strings.Contains(downloadInfo.SysType, "light") { if downloadInfo.PackageType == versionMod.Shop { appstoreClick += 1 } else if downloadInfo.PackageType == versionMod.Enterprise { iosAtherClick += 1 } else if downloadInfo.PackageType == versionMod.Light { lightClick += 1 } } } // 更新数据库 doc := dailystatmod.DailyStatDoc{ LandpageAndroidClick: &androidClick, LandpageIosAppstoreClick: &appstoreClick, LandpageIosAthorClick: &iosAtherClick, LandpageIosH5Click: &lightClick, } err = dailystatmod.UpsertDailyStat(ctx, start, appid, doc) if err != nil { log.Error("NewDeductionCountMethod UpsertDailyStat ", log.E(err)) return err } } return nil }