go-common/app/job/main/growup/service/creative_activity.go

449 lines
11 KiB
Go
Raw Normal View History

2019-04-22 10:49:16 +00:00
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
}