You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

381 lines
9.5 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}