package campaignstat import ( "joybuywork/internal/consts" "joybuywork/internal/repository/cache" "joybuywork/internal/repository/finder" "joybuywork/internal/repository/model" "joybuywork/internal/repository/mtype" "joybuywork/internal/service/provider" "joybuywork/internal/utils" "joybuywork/internal/utils/logic" pb "joybuywork/proto/go_proto/w_campaign_stat" "joybuywork/proto/go_proto/workerr" "fmt" "github.com/golang-module/carbon/v2" ) // 展示类型(1-活动访问,2-达标条件,3-签到) const ( statCampaignShowTypeVisit = iota + 1 statCampaignShowTypeCond statCampaignShowTypeSign statCampaignShowTypeGrow ) type Campaign struct { logic.Logic Req *pb.CampaignReq Res *pb.CampaignRes conf *model.FissionCampaignConfig } func (s *Campaign) Run() error { return logic.Run(s) } func (s *Campaign) Exec() (err error) { cpn, err := s.campaign() if err != nil { return } start, end, statType := s.statParams(cpn) err = s.line(cpn, start, end, statType) if err != nil { return } err = s.change(cpn, start, end) if err != nil { return } return } // 活动数据 func (s *Campaign) campaign() (cpn *model.FissionCampaign, err error) { cpn, err = finder.Campaign(s.Ctx, s.Req.GetCampaignHashId()) if err != nil { err = s.BE().CacheError(err) return } if cpn == nil || cpn.IsDel == mtype.Yes { return nil, workerr.NotFound("campaign not found") } return } // 统计参数 func (s *Campaign) statParams(cpn *model.FissionCampaign) (start, end carbon.Carbon, statType int8) { start = utils.Ternary(s.Req.GetStartTime() != 0, carbon.CreateFromTimestamp(s.Req.GetStartTime()), carbon.Now().StartOfDay()) end = utils.Ternary(s.Req.GetEndTime() != 0, carbon.CreateFromTimestamp(s.Req.GetEndTime()), carbon.Now()) statType = mtype.FissionTotalCycleTypeHour if start.AddDay().Lt(end) { statType = mtype.FissionTotalCycleTypeDay } // 自定义事件的统计标识 conf, err := cache.NewCampaignConfig(s.Ctx).FindByCampaignId(cpn.ID) if err != nil { err = s.BE().CacheError(err) return } s.conf = conf switch cpn.FissionID { case consts.IdSignIn: s.Res.ShowType = statCampaignShowTypeSign case consts.IdGrow: s.Res.ShowType = statCampaignShowTypeGrow default: s.Res.ShowType = utils.Ternary[int32](conf.Option == mtype.FissionCampaignConfigTargetOptionApp, statCampaignShowTypeVisit, statCampaignShowTypeCond) } s.Res.ReportUser = &pb.CampaignRes_Report{} s.Res.ReportNum = &pb.CampaignRes_Report{} return } // 线数据 func (s *Campaign) line(cpn *model.FissionCampaign, start, end carbon.Carbon, statType int8) (err error) { marks, markName, err := s.lineMark(cpn) if err != nil { return } m := s.GetDao().FissionTotalCycle list, err := m.WithContext(s.Ctx). Where( m.StatTime.Gte(start.Timestamp()), m.StatTime.Lte(end.Timestamp()), m.CampaignID.Eq(cpn.ID), m.StatType.Eq(statType), m.Mark.In(marks...), ).Find() var x []string var xMap = make(map[string]int) switch statType { case mtype.FissionTotalCycleTypeHour: hours := utils.BetweenHour(start, end) x = make([]string, 0, len(hours)) for k, v := range hours { key := fmt.Sprintf("%dh", v) x = append(x, key) xMap[key] = k } case mtype.FissionTotalCycleTypeDay: x = utils.BetweenDay(start, end) for k, v := range x { xMap[v] = k } } //人数 xLen := len(x) var nf, unf = "num", "user_num" var lineMap = make(map[string]map[string]*pb.CampaignRes_Y) for _, mark := range marks { t := utils.BehaviorMarkToType(mark) lineMap[mark] = map[string]*pb.CampaignRes_Y{ nf: { Type: t, Name: markName[mark], Data: make([]int64, xLen), }, unf: { Type: t, Name: markName[mark], Data: make([]int64, xLen), }, } } for _, v := range list { var idx int var t = carbon.CreateFromTimestamp(v.StatTime) switch statType { case mtype.FissionTotalCycleTypeHour: idx = xMap[fmt.Sprintf("%dh", t.Hour())] case mtype.FissionTotalCycleTypeDay: idx = xMap[t.ToShortDateString()] } lineMap[v.Mark][nf].Data[idx] = v.Num lineMap[v.Mark][unf].Data[idx] = v.UserNum } // 即时数据 pTotal := provider.NewFissionBehaviorTotal(s.Ctx, cpn.ID) var immNum, immUserNum map[string]int64 var immIdx int now := carbon.Now() switch statType { case mtype.FissionTotalCycleTypeHour: if now.StartOfDay().Eq(start.StartOfDay()) { // 当天的某一个小时 immIdx = xMap[fmt.Sprintf("%dh", now.Hour())] immNum, immUserNum, err = pTotal.CycleHour(now, marks...) if err != nil { return } } case mtype.FissionTotalCycleTypeDay: if end.Gte(now) { // 如果结束时间大于当前时间 dayStr := now.ToShortDateString() immIdx = xMap[dayStr] immNum, immUserNum, err = pTotal.CycleDay(now, marks...) if err != nil { return } } } for k, v := range immNum { lineMap[k][nf].Data[immIdx] = v } for k, v := range immUserNum { lineMap[k][unf].Data[immIdx] = v } s.AddAfterRun(func() (err error) { s.Res.X = x for _, v := range marks { s.Res.ReportNum.Y = append(s.Res.ReportNum.Y, lineMap[v][nf]) s.Res.ReportUser.Y = append(s.Res.ReportUser.Y, lineMap[v][unf]) } return }) return } func (s *Campaign) lineMark(cpn *model.FissionCampaign) (marks []string, markName map[string]string, err error) { switch cpn.FissionID { case consts.IdSignIn: marks = []string{ mtype.FissionBehaviorMarkSign, mtype.FissionBehaviorMarkSignTarget, } return case consts.IdGrow: marks = []string{ mtype.FissionBehaviorMarkView, mtype.FissionBehaviorMarkGrow, } return } marks = []string{ mtype.FissionBehaviorMarkView, mtype.FissionBehaviorMarkClickShare, } if s.conf.Option == mtype.FissionCampaignConfigTargetOptionApp && s.conf.AppEvent == mtype.FissionCampaignConfigTargetAppEventRegister { marks = append(marks, mtype.FissionBehaviorMarkAppRegister) } else { marks = append(marks, mtype.FissionBehaviorMarkAppInstall) } markName = make(map[string]string) if s.conf.Option != mtype.FissionCampaignConfigTargetOptionApp { condM := s.GetDao().FissionCampaignCond var conds []*model.FissionCampaignCond conds, err = condM.WithContext(s.Ctx).Where(condM.CampaignID.Eq(cpn.ID)). Where( condM.WithContext(s.Ctx). Or(condM.IsDel.Eq(mtype.No)). Or(condM.IsDel.Eq(mtype.Yes), condM.DelUse.Eq(mtype.Yes)), ).Find() if err != nil { err = s.BE().MysqlError(err) return } for _, cond := range conds { mark := utils.BehaviorFormatMark(mtype.FissionBehaviorTypeFinishCond, cond.ID) marks = append(marks, mark) markName[mark] = cond.Event } marks = append(marks, mtype.FissionBehaviorMarkFinishTask) } return } func (s *Campaign) change(cpn *model.FissionCampaign, start, end carbon.Carbon) (err error) { total := provider.NewFissionBehaviorTotal(s.Ctx, cpn.ID) var ( viewUser = total.UserNumType(mtype.FissionBehaviorTypeView, start, end) //活动页面访问人数 viewNum = total.NumType(mtype.FissionBehaviorTypeView, start, end) //活动页面访问次数 clickPlayUser = total.UserNumType(mtype.FissionBehaviorTypeClickPlay, start, end) //活动按钮点击人数 clickPlayNum = total.NumType(mtype.FissionBehaviorTypeClickPlay, start, end) //活动按钮点击次数 clickShareUser = total.UserNumType(mtype.FissionBehaviorTypeClickShare, start, end) //活动分享按钮点击人数 clickShareNum = total.NumType(mtype.FissionBehaviorTypeClickShare, start, end) //活动分享按钮点击次数 clickMediaUser = total.UserNumType(mtype.FissionBehaviorTypeClickMedia, start, end) //活动社媒点击人数 clickMediaNum = total.NumType(mtype.FissionBehaviorTypeClickMedia, start, end) //活动社媒点击次数 finishTaskUser = total.UserNumType(mtype.FissionBehaviorTypeFinishTask, start, end) //活动完成目标人数 finishTaskNum = total.NumType(mtype.FissionBehaviorTypeFinishTask, start, end) //活动完成目标次数 signUser = total.UserNumType(mtype.FissionBehaviorTypeSign, start, end) //活动签到人数 signNum = total.NumType(mtype.FissionBehaviorTypeSign, start, end) //活动签到次数 signTargetUser = total.UserNumType(mtype.FissionBehaviorTypeSignTarget, start, end) //活动签到达标人数 signTargetNum = total.NumType(mtype.FissionBehaviorTypeSignTarget, start, end) //活动签到达标次数 growOkUser = total.UserNumType(mtype.FissionBehaviorTypeGrow, start, end) //领养人数 growOkNum = total.NumType(mtype.FissionBehaviorTypeGrow, start, end) //领养次数 ) s.AddAfterRun(func() (err error) { s.Res.ReportNum.TargetNum = finishTaskNum s.Res.ReportUser.TargetNum = finishTaskUser s.Res.ReportNum.ViewNum = viewNum s.Res.ReportUser.ViewNum = viewUser s.Res.ReportNum.SignNum = signNum s.Res.ReportUser.SignNum = signUser s.Res.ReportNum.Change = utils.PercentNoZero(clickShareNum+clickMediaNum, viewNum) s.Res.ReportUser.Change = utils.PercentNoZero(clickShareUser+clickMediaUser, viewUser) s.Res.ReportNum.Fun = utils.PercentNoZero(clickPlayNum, viewNum) s.Res.ReportUser.Fun = utils.PercentNoZero(clickPlayUser, viewUser) s.Res.ReportNum.Target = utils.PercentNoZero(finishTaskNum, viewNum) s.Res.ReportUser.Target = utils.PercentNoZero(finishTaskUser, viewUser) s.Res.ReportNum.Sign = utils.PercentNoZero(signTargetNum, signNum) s.Res.ReportUser.Sign = utils.PercentNoZero(signTargetUser, signUser) s.Res.ReportNum.Grow = utils.PercentNoZero(growOkNum, viewNum) s.Res.ReportUser.Grow = utils.PercentNoZero(growOkUser, viewUser) return }) return }