package service import ( "bytes" "context" "fmt" "sort" "strconv" "strings" "time" "go-common/app/job/main/growup/model" "go-common/library/log" xtime "go-common/library/time" "go-common/library/xstr" ) const ( _like = "1" _share = "2" _play = "3" _reply = "4" _dm = "5" ) // CreativeActivity creative activity job func (s *Service) CreativeActivity(c context.Context, date time.Time) (err error) { activities, err := s.dao.GetCActivities(c) if err != nil { log.Error("s.dao.GetCActivities error(%v)", err) return } // get signed up ups, err := s.signed(c, int64(_dbLimit)) if err != nil { log.Error("s.signed error(%v)", err) return } now := xtime.Time(date.Unix()) // calculate activity within the statistical period for _, ac := range activities { if now >= ac.StatisticsStart && now <= ac.StatisticsEnd { log.Info("calculate ac: %d", ac.ID) err = s.handleActivity(c, ac, ups, date) if err != nil { log.Error("s.handleActivity error(%v)", err) return } } } return } func (s *Service) handleActivity(c context.Context, ac *model.CActivity, upInfo map[int64]*model.UpInfoVideo, date time.Time) (err error) { // 获取已报名并且在签约时间内的up主, signedUps, err := s.getSignedUps(c, ac, upInfo) if err != nil { log.Error("s.getSignedUps error(%v)", err) return } // 获取活动稿件点赞、分享、播放、评论、弹幕 archiveInfo, err := s.getArchiveInfo(c, ac.ID) if err != nil { log.Error("s.getArchiveInfo error(%v)", err) return } if len(archiveInfo) == 0 { log.Info("activity(%d) get 0 archiveInfo", ac.ID) return } log.Info("get %d archiveInfo", len(archiveInfo)) fmt.Printf("get %d archiveInfo\n", len(archiveInfo)) // 获取在投稿时间内的稿件 avs, err := s.getAvsUpload(c, signedUps) if err != nil { log.Error("s.getAvsByMID error(%v)", err) return } if len(avs) == 0 { log.Info("activity(%d) get 0 av", ac.ID) return } log.Info("get %d archives", len(avs)) fmt.Printf("get %d archives\n", len(avs)) // 筛选在签约时间内的稿件 handleActivityAvs(signedUps, avs, ac) for _, u := range signedUps { // 获取up主对应稿件要求的和 err = s.getUpStatisData(c, u, ac, date, archiveInfo) if err != nil { log.Error("s.getUpData error(%v)", err) return } } // 计算中奖up主 upBonus, err := s.calUpWin(c, signedUps, ac) if err != nil { log.Error("s.calUpBonus error(%v)", err) return } err = s.updateUpActivity(c, ac.ID, upBonus) if err != nil { log.Error("s.updateUpActivity error(%v)", err) } return } func (s *Service) calUpWin(c context.Context, ups map[int64]*model.UpActivity, ac *model.CActivity) (bonusUp []*model.UpActivity, err error) { activityBonus, err := s.dao.GetActivityBonus(c, ac.ID) if err != nil { log.Error("s.dao.GetActivityBonus error(%v)", err) return } bonusUp = make([]*model.UpActivity, 0) var ( upList = make([]*model.UpActivity, len(ups)) index int ) for _, up := range ups { upList[index] = up index++ } sort.Slice(upList, func(i, j int) bool { return upList[i].ItemVal > upList[j].ItemVal }) // 1:达标型 2:排序型 if ac.WinType == 1 { for _, up := range upList { // uplist经过ItemVal,所以如果有ItemVal int(ac.RequireValue) { upList = upList[:int(ac.RequireValue)] } bonusUp = upList } if len(bonusUp) == 0 { return } // 计算up主奖金 calUpBonus(bonusUp, activityBonus, ac.BonusType, ac.WinType) return } // cal ups bonus func calUpBonus(bonusUp []*model.UpActivity, activityBonus map[int64]int64, bonusType, winType int) (err error) { // 中奖类型 1:达标型 2:排序型 // 奖金类型 1:平分 2:各得 if winType == 1 { money, ok := activityBonus[0] if !ok { err = fmt.Errorf("活动奖金设置错误:达标型未设置金额") return } if bonusType == 1 { money = money / int64(len(bonusUp)) } for _, up := range bonusUp { up.Bonus = money up.Rank = 0 if up.State < 2 { // 中奖 up.State = 2 up.SuccessTime = xtime.Time(time.Now().Unix()) } } } else if winType == 2 { other := len(activityBonus) otherMoney, ok := activityBonus[int64(other)] if !ok { err = fmt.Errorf("活动奖金设置错误:排序型没有其他金额") return } for i := 0; i < len(bonusUp); i++ { var ( rank = i + 1 money int64 ok bool ) if rank >= other { money = otherMoney } else { money, ok = activityBonus[int64(rank)] if !ok { err = fmt.Errorf("活动奖金设置错误:没有名次金额") return } } if money == 0 { continue } bonusUp[i].Bonus = money bonusUp[i].Rank = i + 1 if bonusUp[i].State < 2 { // 中奖 bonusUp[i].State = 2 bonusUp[i].SuccessTime = xtime.Time(time.Now().Unix()) } } } return } func (s *Service) getUpStatisData(c context.Context, up *model.UpActivity, ac *model.CActivity, date time.Time, archiveInfo map[int64]map[int]*model.ArchiveStat) (err error) { if len(up.AIDs) == 0 { return } avItem := make([]*model.AvItem, 0) aIDs := up.AIDs for _, avID := range aIDs { // 稿件统计数据: 计算当天的和 - 统计开始前一天的和 var itemSumStart, itemSumEnd int64 itemSumEnd, err = s.getAvStatisState(c, avID, ac, archiveInfo, 2) if err != nil { log.Error("s.getAvStatisState error(%v)", err) return } itemSumStart, err = s.getAvStatisState(c, avID, ac, archiveInfo, 1) if err != nil { log.Error("s.getAvStatisState error(%v)", err) return } itemSum := itemSumEnd - itemSumStart if itemSum > 0 { avItem = append(avItem, &model.AvItem{ AvID: avID, Value: itemSum, }) } } if len(avItem) == 0 { return } sort.Slice(avItem, func(i, j int) bool { return avItem[i].Value > avItem[j].Value }) // 1:uid 2 avid if ac.Object == 1 { up.AIDs = make([]int64, 0) for _, av := range avItem { if len(up.AIDs) < 5 { up.AIDs = append(up.AIDs, av.AvID) } up.ItemVal += av.Value } up.AIDNum = int64(len(avItem)) } else if ac.Object == 2 { up.AIDs = []int64{avItem[0].AvID} up.ItemVal = avItem[0].Value up.AIDNum = 1 } return } func (s *Service) getAvStatisState(c context.Context, avID int64, ac *model.CActivity, archiveInfo map[int64]map[int]*model.ArchiveStat, state int) (sum int64, err error) { if _, ok := archiveInfo[avID]; !ok { return } stat, ok := archiveInfo[avID][state] if !ok { return } requireItems := strings.Split(ac.RequireItems, ",") for _, item := range requireItems { switch item { case _like: sum += stat.Like case _share: sum += stat.Share case _play: sum += stat.Play case _reply: sum += stat.Reply case _dm: sum += stat.Dm } } return } func handleActivityAvs(ups map[int64]*model.UpActivity, avs []*model.AvUpload, ac *model.CActivity) { for _, av := range avs { if !(av.UploadTime >= ac.UploadStart && av.UploadTime <= ac.UploadEnd) { continue } if _, ok := ups[av.MID]; ok { if len(ups[av.MID].AIDs) == 0 { ups[av.MID].AIDs = make([]int64, 0) } ups[av.MID].AIDs = append(ups[av.MID].AIDs, av.AvID) } } } func (s *Service) getAvsUpload(c context.Context, ups map[int64]*model.UpActivity) (avs []*model.AvUpload, err error) { avs = make([]*model.AvUpload, 0) var id int64 for { var av []*model.AvUpload av, err = s.dao.GetAvUploadByMID(c, id, _dbLimit) if err != nil { return } avs = append(avs, av...) if len(av) < _dbLimit { break } id = av[len(av)-1].ID } return } func (s *Service) getArchiveInfo(c context.Context, activityID int64) (archives map[int64]map[int]*model.ArchiveStat, err error) { archives = make(map[int64]map[int]*model.ArchiveStat) // map[av_id][state]*model.ArchiveStat var id int64 for { var arch []*model.ArchiveStat arch, err = s.dao.GetArchiveInfo(c, activityID, id, _dbLimit) if err != nil { return } for _, a := range arch { if _, ok := archives[a.AvID]; !ok { archives[a.AvID] = make(map[int]*model.ArchiveStat) } archives[a.AvID][a.State] = a } if len(arch) < _dbLimit { break } id = arch[len(arch)-1].ID } return } func (s *Service) getSignedUps(c context.Context, ac *model.CActivity, upInfo map[int64]*model.UpInfoVideo) (signedUps map[int64]*model.UpActivity, err error) { signedUps = make(map[int64]*model.UpActivity) // if need sign up if ac.SignUp == 1 { var ups []*model.UpActivity ups, err = s.dao.ListUpActivity(c, ac.ID) if err != nil { return } for _, up := range ups { if info, ok := upInfo[up.MID]; ok && info.SignedAt >= ac.SignedStart && info.SignedAt <= ac.SignedEnd { signedUps[up.MID] = up } } } else { for _, info := range upInfo { if info.SignedAt >= ac.SignedStart && info.SignedAt <= ac.SignedEnd { signedUps[info.MID] = &model.UpActivity{MID: info.MID, ActivityID: ac.ID, State: 1, Nickname: info.Nickname} } } } return } func (s *Service) updateUpActivity(c context.Context, id int64, upBonus []*model.UpActivity) (err error) { // 更新所有之前获奖up主为已报名 // update state 2->1 将所有状态设置为已报名 _, err = s.dao.UpdateUpActivityState(c, id, 2, 1) if err != nil { log.Error("s.dao.UpdateUpActivityState error(%v)", err) return } if len(upBonus) > 0 { _, err = s.insertUpActivityBatch(c, upBonus) if err != nil { log.Error("s.insertUpActivity error(%v)", err) } } return } func (s *Service) insertUpActivityBatch(c context.Context, ups []*model.UpActivity) (rows int64, err error) { insert := make([]*model.UpActivity, _dbBatchSize) insertIndex := 0 for _, up := range ups { insert[insertIndex] = up insertIndex++ if insertIndex >= _dbBatchSize { _, err = s.insertUpActivity(c, insert[:insertIndex]) if err != nil { return } insertIndex = 0 } } if insertIndex > 0 { _, err = s.insertUpActivity(c, insert[:insertIndex]) } return } func assembleUpActivity(ups []*model.UpActivity) (vals string) { var buf bytes.Buffer for _, row := range ups { buf.WriteString("(") buf.WriteString(strconv.FormatInt(row.MID, 10)) buf.WriteByte(',') buf.WriteString("\"" + row.Nickname + "\"") buf.WriteByte(',') buf.WriteString(strconv.FormatInt(row.ActivityID, 10)) buf.WriteByte(',') buf.WriteString("'" + xstr.JoinInts(row.AIDs) + "'") buf.WriteByte(',') buf.WriteString(strconv.FormatInt(row.AIDNum, 10)) buf.WriteByte(',') buf.WriteString(strconv.Itoa(row.Rank)) buf.WriteByte(',') buf.WriteString(strconv.FormatInt(row.Bonus, 10)) buf.WriteByte(',') buf.WriteString(strconv.Itoa(row.State)) buf.WriteByte(',') buf.WriteString("'" + row.SuccessTime.Time().Format("2006-01-02 15:04:05") + "'") buf.WriteString(")") buf.WriteByte(',') } if buf.Len() > 0 { buf.Truncate(buf.Len() - 1) } vals = buf.String() buf.Reset() return } func (s *Service) insertUpActivity(c context.Context, ups []*model.UpActivity) (rows int64, err error) { vals := assembleUpActivity(ups) rows, err = s.dao.InsertUpActivityBatch(c, vals) return }