go-common/app/job/main/growup/service/creative_activity.go
2019-04-22 18:49:16 +08:00

449 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<RequireValue,可以直接break
if up.ItemVal < ac.RequireValue {
break
}
bonusUp = append(bonusUp, up)
}
} else if ac.WinType == 2 {
// 去掉item为0的up
for i := 0; i < len(upList); i++ {
if upList[i].ItemVal == 0 {
upList = upList[:i]
break
}
}
if len(upList) > 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
}