package players import ( "context" "joybuywork/internal/app" "joybuywork/internal/consts" "joybuywork/internal/consts/ckey" "joybuywork/internal/plugins/jsonm" "joybuywork/internal/repository/cache" "joybuywork/internal/repository/dao" "joybuywork/internal/repository/dbcheck" "joybuywork/internal/repository/model" "joybuywork/internal/repository/mtype" "joybuywork/internal/repository/withdefault" "joybuywork/internal/service/provider/award" "joybuywork/internal/utils" "time" "gits.branchcn.com/backend/joybuywork/proto/go_proto/workerr" ) // Quiz 赛事竞猜交互逻辑 type Quiz struct { Player player *model.FissionQuiz conf *model.FissionCampaignQuiz fissionPlayerSetInitOnceKey string } func NewQuiz(ctx context.Context, user *model.FissionUser, opts ...Option) (player *Quiz, err error) { player = &Quiz{} err = player.Init(ctx, user, consts.IdPrizeQuiz, opts...) if err != nil { return } err = player.initPlayer() if err != nil { return } return } // ReceiveReward 手动领取奖励 func (s *Quiz) ReceiveReward(taskRewards ...*model.FissionUserTaskReward) (chance int32, reward *award.RewardRes, err error) { err = s._receiveReward(taskRewards, func(tasks []*model.FissionCampaignTask, records []*award.RewardRes) error { chance, err = s.taskFinish(tasks, false) if err != nil { return err } if len(records) == 0 { return nil } reward = records[0] return nil }) if err != nil { return } return } // FinishTask 完成任务 func (s *Quiz) FinishTask(tasks ...*model.FissionCampaignTask) (err error) { _, err = s.taskFinish(tasks, true) if err != nil { return } return } // 完成任务 func (s *Quiz) taskFinish(tasks []*model.FissionCampaignTask, checkManual bool) (chance int32, err error) { player := s.GetPlayer() var logs []*model.FissionQuizLog for _, task := range tasks { if checkManual && task.AwardMode == mtype.FissionCampaignTaskAwardModeManual { continue } switch task.PropMark { case mtype.FissionCampaignTaskPropMarkChance: chance += task.Chance } val, _ := jsonm.MarshalToString(mtype.QuizLogVal{ TaskId: task.ID, VoteNum: task.Chance, }) log := withdefault.FissionQuizLog(&model.FissionQuizLog{ UserID: player.UserID, CampaignID: player.CampaignID, QuizID: player.ID, Type: mtype.FissionQuizLogTypeAdd, Val: val, }) switch task.TaskType { case mtype.FissionCampaignTaskTypeRegister: log.Source = mtype.FissionLogSourceRegister case mtype.FissionCampaignTaskTypeInstall: log.Source = mtype.FissionLogSourceInstall case mtype.FissionCampaignTaskTypeCondAll: log.Source = utils.Ternary[string](task.AwardMode == mtype.FissionCampaignTaskAwardModeManual, mtype.FissionLogSourceManualCondAll, mtype.FissionLogSourceCondAll) case mtype.FissionCampaignTaskTypeCondOne: log.Source = utils.Ternary[string](task.AwardMode == mtype.FissionCampaignTaskAwardModeManual, mtype.FissionLogSourceManualCondOne, mtype.FissionLogSourceCondOne) } logs = append(logs, log) } if chance == 0 { return } m := s.GetDao().FissionQuiz _, err = m.WithContext(s.Ctx).Where(m.ID.Eq(player.ID)).UpdateSimple(m.TaskChance.Add(chance), m.Chance.Add(chance)) if err != nil { return } err = s._addLog(logs...) if err != nil { return } return } func (s *Quiz) Vote(optionId int64, voteNum int32) (err error) { player, conf := s.GetPlayer(), s.GetConf() if conf.OpenPrize <= time.Now().Unix() { err = workerr.CVoteEndError return } if player.Chance < voteNum { return workerr.CChanceNoneError } var optId = player.OptionID optionM := s.GetDao().FissionCampaignQuizOption //如果原来没选,就设置一个 if optId == 0 { var option *model.FissionCampaignQuizOption option, err = optionM.WithContext(s.Ctx).Where(optionM.ID.Eq(optionId), optionM.CampaignID.Eq(player.CampaignID), optionM.IsDel.Eq(mtype.No)).Take() if err = dbcheck.DbError(err); err != nil { return s.BE().MysqlError(err) } if option == nil { return workerr.NotFound("not found opt") } optId = option.ID } if voteNum > 0 { _, err = optionM.WithContext(s.Ctx).Where(optionM.ID.Eq(optId)).UpdateSimple(optionM.VoteNum.Add(int64(voteNum))) if err != nil { return s.BE().MysqlError(err) } } playerM := s.GetDao().FissionQuiz _, err = playerM.WithContext(s.Ctx).Where(playerM.ID.Eq(player.ID)).UpdateSimple(playerM.Chance.Sub(voteNum), playerM.OptionID.Value(optId)) if err != nil { return s.BE().MysqlError(err) } val, _ := jsonm.MarshalToString(mtype.QuizLogVal{ VoteNum: voteNum, OptionId: optId, }) log := withdefault.FissionQuizLog(&model.FissionQuizLog{ UserID: player.UserID, CampaignID: player.CampaignID, QuizID: player.ID, Type: mtype.FissionQuizLogTypeDecr, Source: mtype.FissionLogSourceVote, Val: val, }) err = s._addLog(log) if err != nil { return } return } // SetInit 获得初始次数 func (s *Quiz) SetInit() (err error) { player, conf := s.GetPlayer(), s.GetConf() if player.SetInit == mtype.Yes || conf.InitChance == 0 { return } key := s.fissionPlayerSetInitOnceKey if !app.NewRedisLock(s.Ctx, key).SoftLock() { return } m := s.GetDao().FissionQuiz _, err = m.WithContext(s.Ctx).Where(m.ID.Eq(player.ID)).UpdateSimple(m.SetInit.Value(mtype.Yes), m.Chance.Add(conf.InitChance)) if err != nil { err = s.BE().MysqlError(err) return } val, _ := jsonm.MarshalToString(mtype.QuizLogVal{ VoteNum: conf.InitChance, }) log := withdefault.FissionQuizLog(&model.FissionQuizLog{ UserID: player.UserID, CampaignID: player.CampaignID, QuizID: player.ID, Type: mtype.FissionQuizLogTypeAdd, Source: mtype.FissionLogSourceInit, Val: val, }) err = s._addLog(log) if err != nil { return } s.player.Chance += conf.InitChance return } // GetConf 获取玩法配置 func (s *Quiz) GetConf() *model.FissionCampaignQuiz { if s.conf == nil { s.conf, _ = cache.NewCampaignQuiz(s.Ctx).FindByCampaignId(s.user.CampaignID) } return s.conf } // GetPlayer 获取玩家基础数据 func (s *Quiz) GetPlayer() *model.FissionQuiz { return s.player } // 玩家 func (s *Quiz) initPlayer() (err error) { player, err := s._dbFirst() if err != nil { return } defer func() { if err != nil { return } s.player = player s.fissionPlayerSetInitOnceKey = ckey.FissionPlayerSetInitOnce(player.UserID) }() if player != nil { return } player, err = s.firstOrCreate() if err != nil { return } return } // 创建玩家基础数据 func (s *Quiz) firstOrCreate() (player *model.FissionQuiz, err error) { lc := app.NewFollower(s.Ctx, ckey.FissionUserCreatePlayerOnce(s.user.ID)).Lock() defer lc.Release() if lc.Error() != nil { err = lc.Error() return } player, err = s._dbFirst() if err != nil { return } if player != nil { return } return s.createPlayer() } // 数据库查询 func (s *Quiz) _dbFirst() (*model.FissionQuiz, error) { playerM := dao.FissionQuiz player, err := playerM.WithContext(s.Ctx).Where(playerM.UserID.Eq(s.user.ID)).Take() if err = dbcheck.DbError(err); err != nil { return nil, s.BE().MysqlError(err) } return player, nil } // 创建一个玩家 func (s *Quiz) createPlayer() (player *model.FissionQuiz, err error) { playerM := dao.FissionQuiz player = withdefault.FissionQuiz(&model.FissionQuiz{ CampaignID: s.user.CampaignID, UserID: s.user.ID, }) err = playerM.WithContext(s.Ctx).Create(player) if err != nil { err = s.BE().MysqlError(err) return } return } func (s *Quiz) _addLog(logs ...*model.FissionQuizLog) (err error) { err = s.GetDao().FissionQuizLog.WithContext(s.Ctx).Create(logs...) if err != nil { err = s.BE().MysqlError(err) return } return }