bilibili-backup/app/admin/main/growup/service/activity.go
2019-04-22 02:59:20 +00:00

435 lines
13 KiB
Go

package service
import (
"bytes"
"context"
"fmt"
"sort"
"strconv"
"time"
"go-common/app/admin/main/growup/model"
"go-common/library/database/sql"
"go-common/library/log"
xtime "go-common/library/time"
)
const (
_activityNotStart = iota
_activityStart
_activityEnd
)
// AddActivity add creative activity
func (s *Service) AddActivity(c context.Context, ac *model.CActivity, creator string) (err error) {
ac.Creator = creator
_, err = s.dao.GetActivityByName(c, ac.Name)
if err == sql.ErrNoRows {
err = s.insertActivity(c, ac, "", true)
return
}
if err != nil {
log.Error("s.dao.GetActivityByName error(%v)", err)
return
}
err = fmt.Errorf("activity has exist")
return
}
func actQueyStmt(name, sort string) string {
query := ""
if name != "" {
query = fmt.Sprintf("WHERE name = '%s'", name)
}
if sort != "" {
query += " ORDER BY "
query += sort
}
return query
}
// ListActivity list activity by query
func (s *Service) ListActivity(c context.Context, name string, from, limit int, sort string) (acs []*model.CActivity, total int, err error) {
query := actQueyStmt(name, sort)
total, err = s.dao.ActivityCount(c, query)
if err != nil {
log.Error("s.dao.ActivityCount error(%v)", err)
return
}
acs, err = s.dao.GetActivities(c, query, from, limit)
if err != nil {
log.Error("s.dao.GetActivities error(%v)", err)
return
}
if len(acs) == 0 {
return
}
ids := make([]int64, len(acs))
for i := 0; i < len(acs); i++ {
ids[i] = acs[i].ID
}
bonus, err := s.getActivityBonus(c, ids)
if err != nil {
log.Error("s.getActivityBonus error(%v)", err)
return
}
now := xtime.Time(time.Now().Unix())
for _, ac := range acs {
if now < ac.SignUpStart {
ac.State = _activityNotStart
} else if now >= ac.SignUpStart && now <= ac.BonusTime {
ac.State = _activityStart
} else if now > ac.BonusTime {
ac.State = _activityEnd
}
ac.BonusMoney = bonus[ac.ID]
ac.Enrolment, err = s.dao.UpActivityStateCount(c, ac.ID, []int64{1, 2, 3})
if err != nil {
log.Error("s.dao.UpActivityStateCount error(%v)", err)
return
}
ac.WinNum, err = s.dao.UpActivityStateCount(c, ac.ID, []int64{2, 3})
if err != nil {
log.Error("s.dao.UpActivityStateCount error(%v)", err)
return
}
}
return
}
func checkSignUp(oldAc, newAc *model.CActivity) bool {
if oldAc.SignedStart != newAc.SignedStart ||
oldAc.SignedEnd != newAc.SignedEnd ||
oldAc.SignUp != newAc.SignUp ||
oldAc.SignUpStart != newAc.SignUpStart {
return false
}
return true
}
func checkWin(oldAc, newAc *model.CActivity) bool {
if oldAc.Object != newAc.Object ||
oldAc.UploadStart != newAc.UploadStart ||
oldAc.UploadEnd != newAc.UploadEnd ||
oldAc.WinType != newAc.WinType ||
oldAc.RequireItems != newAc.RequireItems ||
oldAc.RequireValue != newAc.RequireValue ||
oldAc.StatisticsStart != newAc.StatisticsStart {
return false
}
return true
}
func checkBonus(oldAc, newAc *model.CActivity) bool {
if oldAc.BonusType != newAc.BonusType ||
oldAc.BonusTime != newAc.BonusTime {
return false
}
return true
}
func checkProgress(oldAc, newAc *model.CActivity) bool {
if oldAc.ProgressFrequency != newAc.ProgressFrequency ||
oldAc.UpdatePage != newAc.UpdatePage ||
oldAc.ProgressStart != newAc.ProgressStart ||
oldAc.ProgressSync != newAc.ProgressSync {
return false
}
return true
}
func checkOpenBonus(oldAc, newAc *model.CActivity) bool {
if oldAc.BonusQuery != newAc.BonusQuery ||
oldAc.BonusQuerStart != newAc.BonusQuerStart {
return false
}
return true
}
// UpdateActivity update creative activity
func (s *Service) UpdateActivity(c context.Context, newAc *model.CActivity) (err error) {
acs, _, err := s.ListActivity(c, newAc.Name, 0, 1, "")
if err != nil {
log.Error("s.ListActivity error(%v)", err)
return
}
if len(acs) == 0 {
err = fmt.Errorf("activity(%s) not exist", newAc.Name)
return
}
old := acs[0]
// 报名标准
signUpStr := "signed_start=VALUES(signed_start),signed_end=VALUES(signed_end),sign_up=VALUES(sign_up),sign_up_start=VALUES(sign_up_start)"
// 中奖标准
winStr := "object=VALUES(object),upload_start=VALUES(upload_start),upload_end=VALUES(upload_end),win_type=VALUES(win_type),require_items=VALUES(require_items),require_value=VALUES(require_value),statistics_start=VALUES(statistics_start),statistics_end=VALUES(statistics_end)"
// 奖金设置
bonusStr := "bonus_type=VALUES(bonus_type),bonus_time=VALUES(bonus_time)"
// 进展同步
progressStr := "progress_frequency=VALUES(progress_frequency),update_page=VALUES(update_page),progress_start=VALUES(progress_start),progress_end=VALUES(progress_end),progress_sync=VALUES(progress_sync)"
// 开奖查询
openBonusStr := "bonus_query=VALUES(bonus_query),bonus_query_start=VALUES(bonus_query_start),bonus_query_end=VALUES(bonus_query_end)"
// others
otherStr := "background=VALUES(background),win_desc=VALUES(win_desc),unwin_desc=VALUES(unwin_desc),details=VALUES(details)"
var (
update = ""
updateBonus = false
now = xtime.Time(time.Now().Unix())
)
switch {
case now < old.SignUpStart:
// 报名未时间开始
update = fmt.Sprintf("%s,%s,%s,%s,%s,%s,sign_up_end=VALUES(sign_up_end)", signUpStr, winStr, bonusStr, progressStr, openBonusStr, otherStr)
updateBonus = true
case now >= old.SignUpStart && now <= old.SignUpEnd && now < old.ProgressStart:
// 报名已开始未结束,进展同步未开始
if !checkSignUp(old, newAc) || !checkWin(old, newAc) || !checkBonus(old, newAc) {
err = fmt.Errorf("报名已开始,无法修改报名、中奖、奖金相关内容,请检查修改项")
return
}
update = fmt.Sprintf("sign_up_end=VALUES(sign_up_end),%s,%s,%s", progressStr, openBonusStr, otherStr)
case now > old.SignUpEnd && now >= old.ProgressStart && now <= old.ProgressEnd:
// 报名已结束,进展同步开始未结束
if !checkSignUp(old, newAc) || !checkWin(old, newAc) || !checkBonus(old, newAc) || !checkProgress(old, newAc) {
err = fmt.Errorf("报名已结束,进展同步开始未结束,无法修改报名、中奖、奖金、进展相关内容,请检查修改项")
return
}
update = fmt.Sprintf("progress_end=VALUES(progress_end),%s,%s", openBonusStr, otherStr)
case now > old.ProgressEnd && now < old.BonusQueryEnd:
// 进展同步已结束,开奖查询未结束
if !checkSignUp(old, newAc) || !checkWin(old, newAc) || !checkBonus(old, newAc) || !checkProgress(old, newAc) || !checkOpenBonus(old, newAc) || old.ProgressEnd != newAc.ProgressEnd {
err = fmt.Errorf("进展同步已结束,开奖查询未结束,无法修改报名、中奖、奖金、进展、开奖相关内容,请检查修改项")
return
}
update = fmt.Sprintf("bonus_query_end=VALUES(bonus_query_end),%s", otherStr)
default:
err = fmt.Errorf("不符合任何修改时间段,没有任何修改")
return
}
update = fmt.Sprintf("ON DUPLICATE KEY UPDATE %s", update)
err = s.insertActivity(c, newAc, update, updateBonus)
return
}
func (s *Service) getActivityBonus(c context.Context, ids []int64) (bm map[int64][]int64, err error) {
bm = make(map[int64][]int64)
bonus, err := s.dao.GetActivityBonus(c, ids)
if err != nil {
return
}
sort.Slice(bonus, func(i, j int) bool {
return bonus[i].Rank < bonus[j].Rank
})
for i := 0; i < len(bonus); i++ {
id := bonus[i].ID
if _, ok := bm[id]; !ok {
bm[id] = make([]int64, 0)
}
bm[id] = append(bm[id], bonus[i].Money)
}
return
}
func (s *Service) insertActivity(c context.Context, ac *model.CActivity, updateVal string, updateBonus bool) (err error) {
tx, err := s.dao.BeginTran(c)
if err != nil {
log.Error("s.dao.BeginTran error(%v)", err)
return
}
// insert activity
if _, err = s.dao.TxInsertActivity(tx, ac, updateVal); err != nil {
log.Error("s.dao.TxInsertActivity error(%v)", err)
return
}
id, err := s.dao.TxGetActivityByName(tx, ac.Name)
if err != nil {
log.Error("s.dao.GetActivityByName error(%v)", err)
return
}
// is update bonus
if updateBonus && len(ac.BonusMoney) > 0 {
bonus := make([]*model.BonusRank, 0)
if ac.WinType == 1 {
bonus = append(bonus, &model.BonusRank{ID: id, Rank: 0, Money: ac.BonusMoney[0]})
} else if ac.WinType == 2 {
for i := 0; i < len(ac.BonusMoney); i++ {
bonus = append(bonus, &model.BonusRank{ID: id, Rank: i + 1, Money: ac.BonusMoney[i]})
}
}
// insert bonus money
if err = s.txInsertActivityBonus(tx, bonus); err != nil {
log.Error("s.TxInsertBonusRank error(%v)", err)
return
}
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error")
}
return
}
func (s *Service) txInsertActivityBonus(tx *sql.Tx, bonus []*model.BonusRank) (err error) {
var buf bytes.Buffer
for _, row := range bonus {
buf.WriteString("(")
buf.WriteString(strconv.FormatInt(row.ID, 10))
buf.WriteByte(',')
buf.WriteString(strconv.Itoa(row.Rank))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(row.Money, 10))
buf.WriteString(")")
buf.WriteByte(',')
}
if buf.Len() > 0 {
buf.Truncate(buf.Len() - 1)
}
vals := buf.String()
buf.Reset()
_, err = s.dao.TxInsertActivityBonusBatch(tx, vals)
return
}
// ListActivitySignUp list activity who sign up
func (s *Service) ListActivitySignUp(c context.Context, activityID int64, from, limit int) (ups []*model.UpActivity, total int, err error) {
total, err = s.dao.UpActivityStateCount(c, activityID, []int64{1, 2, 3})
if err != nil {
log.Error("s.dao.UpActivityStateCount error(%v)", err)
return
}
ups, err = s.dao.ListUpActivity(c, activityID, from, limit)
if err != nil {
log.Error("s.dao.ListUpActivity error(%v)", err)
}
return
}
// ListActivityWinners list activity winners
func (s *Service) ListActivityWinners(c context.Context, activityID, mid int64, from, limit int) (ups []*model.UpActivity, total int, err error) {
total, err = s.dao.UpActivityStateCount(c, activityID, []int64{2, 3})
if err != nil {
log.Error("s.dao.UpActivityStateCount error(%v)", err)
return
}
ups, err = s.dao.ListUpActivitySuccess(c, activityID, mid, from, limit)
if err != nil {
log.Error("s.dao.ListUpActivity error(%v)", err)
return
}
if mid != 0 {
total = len(ups)
}
return
}
// ActivityAward activity award
func (s *Service) ActivityAward(c context.Context, activityID int64, activityName string, date, statisticsEnd xtime.Time, creator string) (err error) {
if xtime.Time(time.Now().Unix()) <= statisticsEnd {
err = fmt.Errorf("统计阶段未结束,不能发奖")
return
}
ups, err := s.listUpActivity(c, activityID)
if err != nil {
log.Error("s.listUpActivity error(%v)", err)
return
}
if len(ups) == 0 {
return
}
rankMID := make(map[int][]int64)
rankMoney := make(map[int]int64)
for _, up := range ups {
if up.State != 2 {
continue
}
rank := up.Rank
rankMoney[rank] = up.Bonus
if _, ok := rankMID[rank]; !ok {
rankMID[rank] = make([]int64, 0)
}
rankMID[rank] = append(rankMID[rank], up.MID)
}
// insert to tag
tx, err := s.dao.BeginTran(c)
if err != nil {
log.Error("s.dao.BeginTran error(%v)", err)
return
}
for rank, money := range rankMoney {
mids, ok := rankMID[rank]
if !ok || len(mids) == 0 {
continue
}
tagName := fmt.Sprintf("act-%s-%d", activityName, rank)
err = s.addActivityUpTag(tx, money, creator, tagName, mids, date)
if err != nil {
log.Error("s.addActivityUpTag error(%v)", err)
return
}
// update mids state
if _, err = s.dao.TxUpdateUpActivityState(tx, activityID, mids, 2, 3); err != nil {
tx.Rollback()
log.Error("s.dao.TxUpdateUpActivityState error(%v)", err)
return
}
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error(%v)", err)
}
return
}
func (s *Service) addActivityUpTag(tx *sql.Tx, money int64, creator, tagName string, mids []int64, date xtime.Time) (err error) {
tag := &model.TagInfo{
Tag: tagName,
Creator: creator,
Dimension: 1,
StartTime: date,
EndTime: date,
AdjustType: 1,
Ratio: int(money),
UploadStartTime: date,
UploadEndTime: date,
}
if _, err = s.dao.TxInsertTag(tx, tag); err != nil {
tx.Rollback()
log.Error("s.dao.TxInsertTag error(%v)", err)
return
}
tagID, err := s.dao.TxGetTagInfoByName(tx, tagName, 1, 0, 0)
if err != nil {
tx.Rollback()
log.Error("s.dao.TxGetTagInfoByName error(%v)", err)
return
}
for _, mid := range mids {
_, err = s.dao.TxInsertTagUpInfo(tx, tagID, mid, 0)
if err != nil {
tx.Rollback()
log.Error("s.dao.TxInsertTagUpInfo error(%v)", err)
return
}
}
return
}
func (s *Service) listUpActivity(c context.Context, activityID int64) (ups []*model.UpActivity, err error) {
from, limit := 0, 2000
ups = make([]*model.UpActivity, 0)
for {
var up []*model.UpActivity
up, err = s.dao.ListUpActivity(c, activityID, from, limit)
if err != nil {
return
}
ups = append(ups, up...)
if len(up) < limit {
break
}
from += limit
}
return
}