You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
448 lines
11 KiB
448 lines
11 KiB
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 |
|
}
|
|
|