|
|
package containers
|
|
|
|
|
|
import (
|
|
|
"joybuywork/internal/app"
|
|
|
"joybuywork/internal/repository/cache"
|
|
|
"joybuywork/internal/repository/dao"
|
|
|
"joybuywork/internal/repository/dbcheck"
|
|
|
"joybuywork/internal/repository/finder"
|
|
|
"joybuywork/internal/repository/model"
|
|
|
"joybuywork/internal/repository/mtype"
|
|
|
"joybuywork/internal/repository/withdefault"
|
|
|
"joybuywork/internal/service/provider"
|
|
|
"joybuywork/internal/service/provider/stocks"
|
|
|
"joybuywork/internal/service/queue/producer"
|
|
|
"joybuywork/internal/service/queue/types"
|
|
|
"joybuywork/internal/utils"
|
|
|
"joybuywork/internal/utils/logic"
|
|
|
"fmt"
|
|
|
"sync"
|
|
|
"time"
|
|
|
|
|
|
"github.com/panjf2000/ants/v2"
|
|
|
"gorm.io/gen"
|
|
|
"gorm.io/gorm/clause"
|
|
|
)
|
|
|
|
|
|
type userTypeWinner struct {
|
|
|
userIds []int64
|
|
|
thank, reward *model.FissionCampaignReward
|
|
|
thankInfo, rewardInfo provider.RewardAutoLang
|
|
|
}
|
|
|
|
|
|
type CampaignQuizOpen struct {
|
|
|
logic.Logic
|
|
|
|
|
|
ntf chan []*model.FissionQuizReward
|
|
|
|
|
|
cpnId int64
|
|
|
}
|
|
|
|
|
|
func (s *CampaignQuizOpen) Run() error {
|
|
|
return logic.Run(s)
|
|
|
}
|
|
|
|
|
|
func (s *CampaignQuizOpen) Exec() (err error) {
|
|
|
m := s.GetDao().FissionCampaignQuiz
|
|
|
|
|
|
var cpnIds []int64
|
|
|
err = m.WithContext(s.Ctx).Where(m.OpenPrize.Lte(time.Now().Unix()), m.OpenType.Eq(mtype.FissionCampaignQuizOpenTypeWait)).Pluck(m.CampaignID, &cpnIds)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if len(cpnIds) == 0 {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
defer wg.Wait()
|
|
|
|
|
|
gop, _ := ants.NewPool(50)
|
|
|
defer gop.Release()
|
|
|
|
|
|
for _, v := range cpnIds {
|
|
|
wg.Add(1)
|
|
|
cpnId := v
|
|
|
_ = gop.Submit(func() {
|
|
|
defer wg.Done()
|
|
|
defer app.TryCatch(s.Ctx, fmt.Sprintf("竞猜开奖,活动id[%d]", cpnId))
|
|
|
|
|
|
err = s.open(cpnId)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
})
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func (s *CampaignQuizOpen) open(cpnId int64) (err error) {
|
|
|
//活动数据
|
|
|
cpn, err := finder.Campaign(s.Ctx, cpnId)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//活动配置数据
|
|
|
fcqM := dao.FissionCampaignQuiz
|
|
|
fcq, err := fcqM.WithContext(s.Ctx).Where(fcqM.CampaignID.Eq(cpnId)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//活动奖品数据
|
|
|
rewardM := dao.FissionCampaignReward
|
|
|
rewards, err := rewardM.WithContext(s.Ctx).Where(rewardM.CampaignID.Eq(cpnId), rewardM.IsDel.Eq(mtype.No)).Find()
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if len(rewards) == 0 {
|
|
|
//设置成已开奖
|
|
|
app.FeishuNormalSend("活动[%d],没有奖品开奖", cpnId)
|
|
|
err = s.setOpen(fcq)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
var utRewardMap = make(map[string][]*model.FissionCampaignReward)
|
|
|
var brIds []int64
|
|
|
for _, v := range rewards {
|
|
|
brIds = append(brIds, v.RewardID)
|
|
|
key := fmt.Sprintf("%s_%d", v.LangMark, v.LevelID)
|
|
|
utRewardMap[key] = append(utRewardMap[key], v)
|
|
|
}
|
|
|
|
|
|
prewards, err := provider.NewRewards(s.Ctx, cpn.ProjectID, brIds...)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 赢家的数据,是否可以开奖
|
|
|
winMap, open, err := s.winMap(cpnId, fcq)
|
|
|
if err != nil || !open {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//活动配置数据
|
|
|
conf, err := cache.NewCampaignConfig(s.Ctx).FindByCampaignId(cpnId)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
var userRewardMap = make(map[string]*userTypeWinner)
|
|
|
var list []*model.FissionUser
|
|
|
m, quizM := s.GetDao().FissionUser.SubTable(cpn.ID), s.GetDao().FissionQuiz
|
|
|
_ = m.WithContext(s.Ctx).
|
|
|
Join(quizM, quizM.UserID.EqCol(m.ID)).
|
|
|
Where(m.CampaignID.Eq(cpn.ID), quizM.OptionID.Gt(0)).
|
|
|
FindInBatches(&list, 200, func(tx gen.Dao, batch int) error {
|
|
|
for _, v := range list {
|
|
|
|
|
|
wnk := fmt.Sprintf("%s_%d", v.UserLang, v.UserLevel)
|
|
|
winner, ok := userRewardMap[wnk]
|
|
|
if !ok {
|
|
|
winner = &userTypeWinner{
|
|
|
userIds: []int64{v.ID},
|
|
|
thank: nil,
|
|
|
reward: nil,
|
|
|
}
|
|
|
|
|
|
var setRewards []*model.FissionCampaignReward
|
|
|
switch conf.RewardGroup {
|
|
|
case mtype.FissionRewardGroupNormal:
|
|
|
setRewards = utRewardMap["_0"]
|
|
|
case mtype.FissionRewardGroupUserLevel:
|
|
|
setRewards = utRewardMap[fmt.Sprintf("_%d", v.UserLevel)]
|
|
|
case mtype.FissionRewardGroupLang:
|
|
|
setRewards = utRewardMap[fmt.Sprintf("%s_0", v.UserLang)]
|
|
|
case mtype.FissionRewardGroupLangAndUserLevel:
|
|
|
setRewards = utRewardMap[fmt.Sprintf("%s_%d", v.UserLang, v.UserLevel)]
|
|
|
}
|
|
|
|
|
|
for _, reward := range setRewards {
|
|
|
info, _ := prewards.InfoAutoLang(reward.RewardID, v.LangMark)
|
|
|
if reward.IsThank == mtype.Yes {
|
|
|
winner.thank = reward
|
|
|
winner.thankInfo = info
|
|
|
} else {
|
|
|
winner.reward = reward
|
|
|
winner.rewardInfo = info
|
|
|
}
|
|
|
}
|
|
|
|
|
|
userRewardMap[wnk] = winner
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
userRewardMap[wnk].userIds = append(userRewardMap[wnk].userIds, v.ID)
|
|
|
|
|
|
}
|
|
|
return nil
|
|
|
})
|
|
|
|
|
|
for _, winner := range userRewardMap {
|
|
|
err = s.winner(cpnId, winner, winMap)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//设置成已开奖
|
|
|
err = s.setOpen(fcq)
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func (s *CampaignQuizOpen) setOpen(fcq *model.FissionCampaignQuiz) (err error) {
|
|
|
//设置成已开奖
|
|
|
fcqM := dao.FissionCampaignQuiz
|
|
|
_, err = fcqM.WithContext(s.Ctx).Where(fcqM.ID.Eq(fcq.ID)).UpdateSimple(fcqM.OpenType.Value(mtype.FissionCampaignQuizOpenTypeOpen))
|
|
|
if err != nil {
|
|
|
return s.BE().MysqlError(err)
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func (s *CampaignQuizOpen) winMap(cpnId int64, fcq *model.FissionCampaignQuiz) (winMap map[int64]struct{}, open bool, err error) {
|
|
|
//选项数据
|
|
|
fcqM := s.GetDao().FissionCampaignQuiz
|
|
|
optionM := dao.FissionCampaignQuizOption
|
|
|
winMap = make(map[int64]struct{})
|
|
|
if fcq.RewardRule == mtype.FissionCampaignQuizRewardRuleVote {
|
|
|
|
|
|
//对选项排序,并且要找有投票的数据
|
|
|
options, frr := optionM.WithContext(s.Ctx).
|
|
|
Where(
|
|
|
optionM.CampaignID.Eq(cpnId),
|
|
|
optionM.IsDel.Eq(mtype.No),
|
|
|
optionM.VoteNum.Gt(0),
|
|
|
).
|
|
|
Order(optionM.VoteNum.Desc(), optionM.ID).
|
|
|
Find()
|
|
|
if frr != nil {
|
|
|
err = s.BE().MysqlError(frr)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//没有投票选项就不会发奖
|
|
|
if len(options) == 0 {
|
|
|
//设置成已开奖
|
|
|
_, err = fcqM.WithContext(s.Ctx).Where(fcqM.ID.Eq(fcq.ID)).UpdateSimple(fcqM.OpenType.Value(mtype.FissionCampaignQuizOpenTypeNone))
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
|
|
|
l := len(options)
|
|
|
//因为排序了,所以第一个肯定是赢的
|
|
|
winMap[options[0].ID] = struct{}{}
|
|
|
//看看后面的有没有和赢的相同票数,就一齐赢
|
|
|
for i := 1; i < l; i++ {
|
|
|
if options[0].VoteNum != options[i].VoteNum {
|
|
|
break
|
|
|
}
|
|
|
winMap[options[i].ID] = struct{}{}
|
|
|
}
|
|
|
} else {
|
|
|
option, frr := optionM.WithContext(s.Ctx).
|
|
|
Where(
|
|
|
optionM.CampaignID.Eq(cpnId),
|
|
|
optionM.IsDel.Eq(mtype.No),
|
|
|
optionM.IsRight.Eq(mtype.Yes),
|
|
|
).
|
|
|
Take()
|
|
|
if err = dbcheck.DbError(frr); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//还没设置正确答案就退出,等下一次开奖
|
|
|
if option == nil {
|
|
|
return
|
|
|
}
|
|
|
winMap[option.ID] = struct{}{}
|
|
|
}
|
|
|
|
|
|
return winMap, true, nil
|
|
|
}
|
|
|
|
|
|
func (s *CampaignQuizOpen) winner(cpnId int64, winner *userTypeWinner, winMap map[int64]struct{}) (err error) {
|
|
|
|
|
|
reward, thank := winner.reward, winner.thank
|
|
|
rewardInfo, thankInfo := winner.rewardInfo, winner.thankInfo
|
|
|
idGroups := utils.Groups(winner.userIds, 200)
|
|
|
|
|
|
m := s.GetDao().FissionQuiz
|
|
|
for _, ids := range idGroups {
|
|
|
var list []*model.FissionQuiz
|
|
|
list, err = m.WithContext(s.Ctx).Where(m.UserID.In(ids...)).Find()
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
if len(list) == 0 {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
var add []*model.FissionRewardRecord
|
|
|
var winnerIds []int64
|
|
|
var winnerMap = make(map[int64]struct{})
|
|
|
for _, player := range list {
|
|
|
if _, ok := winMap[player.OptionID]; ok {
|
|
|
winnerMap[player.UserID] = struct{}{}
|
|
|
winnerIds = append(winnerIds, player.ID)
|
|
|
|
|
|
add = append(add, withdefault.FissionRewardRecord(&model.FissionRewardRecord{
|
|
|
CampaignID: player.CampaignID,
|
|
|
UserID: player.UserID,
|
|
|
RewardID: reward.ID,
|
|
|
Title: rewardInfo.Title,
|
|
|
ImgURL: rewardInfo.ImgUrl,
|
|
|
RewardType: reward.RewardType,
|
|
|
RewardNum: reward.RewardNum,
|
|
|
Step: reward.Step,
|
|
|
IsThank: reward.IsThank,
|
|
|
Status: mtype.FissionRewardRecordStatusWait,
|
|
|
FailType: "",
|
|
|
FailMsg: "",
|
|
|
BaseRewardID: reward.RewardID,
|
|
|
}))
|
|
|
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
add = append(add, withdefault.FissionRewardRecord(&model.FissionRewardRecord{
|
|
|
CampaignID: player.CampaignID,
|
|
|
UserID: player.UserID,
|
|
|
RewardID: thank.ID,
|
|
|
Title: thankInfo.Title,
|
|
|
ImgURL: thankInfo.ImgUrl,
|
|
|
RewardType: thank.RewardType,
|
|
|
RewardNum: thank.RewardNum,
|
|
|
Step: thank.Step,
|
|
|
IsThank: thank.IsThank,
|
|
|
Status: mtype.FissionRewardRecordStatusWait,
|
|
|
FailType: "",
|
|
|
FailMsg: "",
|
|
|
BaseRewardID: thank.RewardID,
|
|
|
}))
|
|
|
}
|
|
|
|
|
|
if len(add) == 0 {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//改成赢的状态
|
|
|
if len(winnerIds) > 0 {
|
|
|
_, err = m.WithContext(s.Ctx).Where(m.ID.In(winnerIds...)).UpdateSimple(m.IsWin.Value(mtype.Yes))
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
fqrM := dao.FissionRewardRecord
|
|
|
_ = fqrM.WithContext(s.Ctx).Clauses(clause.Insert{
|
|
|
Modifier: "IGNORE",
|
|
|
}).CreateInBatches(add, 200)
|
|
|
|
|
|
fqrMs := dao.FissionRewardRecord.SubTable(cpnId)
|
|
|
_ = fqrMs.WithContext(s.Ctx).Clauses(clause.Insert{
|
|
|
Modifier: "IGNORE",
|
|
|
}).CreateInBatches(add, 200)
|
|
|
|
|
|
var useStock = make(map[int64]int64)
|
|
|
for _, record := range add {
|
|
|
if record.ID == 0 {
|
|
|
continue
|
|
|
}
|
|
|
producer.NewCampaignNotice(s.Ctx).CampaignRewardNotify(types.CampaignRewardNotify{
|
|
|
CampaignId: record.CampaignID,
|
|
|
UserId: record.UserID,
|
|
|
UserRewardId: record.ID,
|
|
|
})
|
|
|
useStock[record.RewardID]++
|
|
|
}
|
|
|
|
|
|
for rewardId, num := range useStock {
|
|
|
stock, _ := stocks.NewCampaignReward(s.Ctx, rewardId)
|
|
|
_ = stock.AddUseStock(num)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|