449 lines
11 KiB
Go
449 lines
11 KiB
Go
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
|
||
}
|