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.

1146 lines
26 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 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/cmm"
"joybuywork/internal/service/provider"
"joybuywork/internal/service/provider/award"
"joybuywork/internal/service/provider/projectuser"
"joybuywork/internal/utils"
"joybuywork/internal/utils/timez"
"joybuywork/internal/utils/verify"
"math"
"strconv"
"time"
"gits.branchcn.com/backend/microcode/plugins/derivative/lock"
"gorm.io/gen/field"
)
const (
voteOk = iota
voteEnd // 非投票时间无法投票
voteLack // 投票机会不足
votePointLack // 积分不足
voteLimit // 投票已达最大次数
voteFail // 投票失败
voteNotSameTeam // 不能投同队伍
)
type Vs struct {
Player
player *model.FissionV
conf *model.FissionCampaignV
fissionPlayerSetInitOnceKey string
}
func NewVs(ctx context.Context, user *model.FissionUser, opts ...Option) (player *Vs, err error) {
player = &Vs{}
err = player.Init(ctx, user, consts.IdVs, opts...)
if err != nil {
return
}
err = player.initPlayer()
if err != nil {
return
}
return
}
func (s *Vs) Exchange(item *model.RedeemMallItem) (err error) {
player := s.GetPlayer()
val, _ := jsonm.MarshalToString(mtype.VsLogVal{
PointsNum: item.CoinNum,
MallId: item.MallID,
MallItemId: item.ID,
})
log := withdefault.FissionVsLog(&model.FissionVsLog{
UserID: player.UserID,
CampaignID: player.CampaignID,
VsID: player.ID,
Type: mtype.FissionVsLogTypeExchange,
Source: mtype.FissionLogSourceExchange,
Val: val,
})
err = s._addLog(log)
if err != nil {
return
}
vsM := s.GetDao().FissionV
_, err = vsM.WithContext(s.Ctx).Where(vsM.ID.Eq(player.ID)).UpdateSimple(vsM.CoinUse.Add(item.CoinNum))
if err != nil {
err = s.BE().MysqlError(err)
return
}
return
}
func (s *Vs) FirstVisit() (rewards []*EventReward, err error) {
ok, rewards, err := s.eventOk(mtype.FissionCampaignEventMarkFirstVisit)
if err != nil || !ok {
return
}
player := s.GetPlayer()
var chance int32
var point int32
var logs = make([]*model.FissionVsLog, 0, len(rewards))
for _, v := range rewards {
var val string
var t int8
switch v.PropMark {
case mtype.FissionCampaignRewardPropMarkPoint:
t = mtype.FissionVsLogTypeAddPoint
val, _ = jsonm.ToObjString(mtype.VsLogVal{
PointsNum: v.Chance,
})
point += v.Chance
case mtype.FissionCampaignRewardPropMarkReward:
t = mtype.FissionVsLogTypeReward
val, _ = jsonm.ToObjString(mtype.VsLogVal{
RewardId: v.Reward.Record.RewardID,
RecordId: v.Reward.Record.ID,
})
case mtype.FissionCampaignRewardPropMarkChance:
t = mtype.FissionVsLogTypeAddVote
val, _ = jsonm.ToObjString(mtype.VsLogVal{
Chance: v.Chance,
})
chance++
}
logs = append(logs, withdefault.FissionVsLog(&model.FissionVsLog{
UserID: player.UserID,
CampaignID: player.CampaignID,
VsID: player.ID,
Type: t,
Source: mtype.FissionLogSourceFirstVisit,
Val: val,
}))
}
err = s._addLog(logs...)
if err != nil {
return
}
if chance > 0 || point > 0 {
m := s.GetDao().FissionV
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(player.ID)).UpdateSimple(m.Chance.Add(chance), m.CoinGet.Add(point))
if err != nil {
err = s.BE().MysqlError(err)
return
}
}
return
}
func (s *Vs) TipReward() (err error) {
player := s.GetPlayer()
var ids []int64
m := s.GetDao().FissionVsVoteSettlement
err = m.WithContext(s.Ctx).Select(m.ID).Where(m.VsID.Eq(player.ID), m.TipAt.Eq(0)).Pluck(m.ID, &ids)
if err != nil {
err = s.BE().MysqlError(err)
return
}
if len(ids) == 0 {
return
}
_, err = m.WithContext(s.Ctx).Where(m.ID.In(ids...)).UpdateColumnSimple(m.TipAt.Value(time.Now().Unix()))
if err != nil {
err = s.BE().MysqlError(err)
return
}
return
}
func (s *Vs) SettlementReward(settlement *model.FissionVsVoteSettlement) (rewards []*Reward, err error) {
player := s.GetPlayer()
if settlement.AcceptAt > 0 {
if settlement.TipAt > 0 {
return
}
m := s.GetDao().FissionRewardRecord
records, err1 := m.WithContext(s.Ctx).Where(m.ID.In(settlement.GetRecordIds()...)).Find()
if err1 != nil {
err1 = s.BE().MysqlError(err1)
return
}
var brMap = make(map[int64]struct{})
var brIds []int64
for _, record := range records {
if _, ok := brMap[record.BaseRewardID]; !ok && record.BaseRewardID > 0 {
brIds = append(brIds, record.BaseRewardID)
}
}
preward, err1 := provider.NewRewards(s.Ctx, s.cpn.ProjectID, brIds...)
if err1 != nil {
err = err1
return
}
rewards = make([]*Reward, 0, len(records))
for _, record := range records {
switch record.PropMark {
case mtype.FissionCampaignRewardPropMarkReward:
info, _ := preward.InfoAutoLang(record.BaseRewardID, s.user.LangMark)
rewards = append(rewards, &Reward{
Id: record.RewardID,
PropMark: record.PropMark,
Title: info.Title,
Img: info.ImgUrl,
KvData: info.KvData,
ReceiveType: info.ReceiveType,
Contact: info.Contact,
OpenToUse: info.OpenToUse,
WebUrl: info.WebUrl,
AppParam: info.AppParam,
PcParam: info.PcParam,
PropNum: record.RewardNum,
RewardHashId: record.HashID,
})
case mtype.FissionCampaignRewardPropMarkPoint:
rewards = append(rewards, &Reward{
Id: record.RewardID,
PropMark: record.PropMark,
Title: record.Title,
Img: record.ImgURL,
PropNum: record.RewardNum,
RewardHashId: record.HashID,
})
}
}
return
}
lc := app.NewRedisLock(s.Ctx, ckey.FissionVoteAcceptOnce(settlement.ID), lock.SetExpire(10*time.Second))
defer lc.Release()
if !lc.SoftLock() {
return
}
m := s.GetDao().FissionVsVote
vote, err := m.WithContext(s.Ctx).Where(m.ID.Eq(settlement.VoteID)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if vote == nil {
return
}
scheduleM := s.GetDao().FissionCampaignVsSchedule
schedule, err := scheduleM.WithContext(s.Ctx).Where(scheduleM.ID.Eq(vote.ScheduleID)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if schedule == nil {
return
}
rewardM := s.GetDao().FissionCampaignReward
reward, err := rewardM.WithContext(s.Ctx).Where(rewardM.ID.Eq(schedule.RewardID)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if reward == nil {
return
}
odds, _ := strconv.ParseFloat(settlement.Odds, 64)
if reward.PropMark == mtype.FissionCampaignTaskPropMarkPoint && odds != 1 {
rewardNum := int32(math.Floor(float64(reward.RewardNum) * odds))
reward.RewardNum = rewardNum
}
var num = vote.FreeVote + vote.PointVote
var accepts = make([]*model.FissionCampaignReward, 0)
for i := 0; i < int(num); i++ {
accepts = append(accepts, reward)
}
res, _, err := award.NewAwardReward(s.Ctx, s.GetDao(), s.cpn.ProjectID, s.user).DeductStockBatch(accepts, true)
if err != nil {
return
}
var coinGet int32
var recordIds []int64
rewards = make([]*Reward, 0, len(res))
for _, v := range res {
record := v.Record
info := v.Info
rewards = append(rewards, &Reward{
Id: record.RewardID,
PropMark: record.PropMark,
Title: info.Title,
Img: info.ImgUrl,
KvData: info.KvData,
ReceiveType: info.ReceiveType,
Contact: info.Contact,
OpenToUse: info.OpenToUse,
WebUrl: info.WebUrl,
AppParam: info.AppParam,
PcParam: info.PcParam,
PropNum: record.RewardNum,
RewardHashId: record.HashID,
})
recordIds = append(recordIds, record.ID)
if s.GetConf().ClaimType != mtype.FissionCampaignVsClaimTypeAuto {
s.appTrack().VsAcceptReward(record.CreatedAt, schedule.ID, record.RewardID, record.ID)
}
if record.PropMark == mtype.FissionCampaignRewardPropMarkPoint {
coinGet += record.RewardNum
}
}
idStr, _ := jsonm.ToSliceString(recordIds)
sltM := s.GetDao().FissionVsVoteSettlement
_, err = sltM.WithContext(s.Ctx).Where(sltM.ID.Eq(settlement.ID)).UpdateColumnSimple(
sltM.AcceptAt.Value(time.Now().Unix()),
sltM.RecordIds.Value(idStr),
)
if err != nil {
err = s.BE().MysqlError(err)
return
}
if coinGet > 0 {
playerM := s.GetDao().FissionV
_, err = playerM.WithContext(s.Ctx).Where(playerM.ID.Eq(player.ID)).UpdateColumnSimple(playerM.CoinGet.Add(coinGet))
if err != nil {
err = s.BE().MysqlError(err)
return
}
}
val, _ := jsonm.MarshalToString(mtype.VsLogVal{
RewardId: reward.ID,
ScheduleId: settlement.ScheduleID,
Odds: settlement.Odds,
Num: num,
})
log := withdefault.FissionVsLog(&model.FissionVsLog{
UserID: player.UserID,
CampaignID: player.CampaignID,
VsID: player.ID,
Type: mtype.FissionVsLogTypeSettlement,
Source: mtype.FissionLogSourceSettlement,
Val: val,
})
err = s._addLog(log)
if err != nil {
return
}
return
}
// ReceiveReward 手动领取奖励
func (s *Vs) 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 *Vs) FinishTask(tasks ...*model.FissionCampaignTask) (err error) {
_, err = s.taskFinish(tasks, true)
if err != nil {
return
}
return
}
// 完成任务
func (s *Vs) taskFinish(tasks []*model.FissionCampaignTask, checkManual bool) (chance int32, err error) {
player := s.GetPlayer()
var coinGet int32
var logs []*model.FissionVsLog
for _, task := range tasks {
if checkManual && task.AwardMode == mtype.FissionCampaignTaskAwardModeManual {
continue
}
var val string
var t int8
switch task.PropMark {
case mtype.FissionCampaignTaskPropMarkChance:
chance += task.Chance
val, _ = jsonm.MarshalToString(mtype.VsLogVal{
TaskId: task.ID,
Chance: task.Chance,
})
t = mtype.FissionVsLogTypeAddVote
case mtype.FissionCampaignTaskPropMarkPoint:
val, _ = jsonm.MarshalToString(mtype.VsLogVal{
TaskId: task.ID,
PointsNum: task.Chance,
})
t = mtype.FissionVsLogTypeAddPoint
coinGet += task.Chance
case mtype.FissionCampaignTaskPropMarkReward:
val, _ = jsonm.MarshalToString(mtype.VsLogVal{
TaskId: task.ID,
RewardId: task.RewardID,
})
t = mtype.FissionVsLogTypeReward
}
log := withdefault.FissionVsLog(&model.FissionVsLog{
UserID: player.UserID,
CampaignID: player.CampaignID,
VsID: player.ID,
Type: t,
Source: "",
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 || coinGet > 0 {
m := s.GetDao().FissionV
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(player.ID)).UpdateSimple(m.Chance.Add(chance), m.CoinGet.Add(coinGet))
if err != nil {
return
}
}
err = s._addLog(logs...)
if err != nil {
return
}
return
}
func (s *Vs) Vote(scheduleId, teamId int64) (status int32, err error) {
s.Tran()
defer func() {
s.TranCommit(err)
}()
player, conf := s.GetPlayer(), s.GetConf()
scheduleM := s.GetDao().FissionCampaignVsSchedule
schedule, err := scheduleM.WithContext(s.Ctx).Where(scheduleM.ID.Eq(scheduleId)).Take()
if err != nil {
err = s.BE().MysqlError(err)
return
}
if schedule.GetStatus() != mtype.FissionCampaignVsScheduleStatusVote {
return voteEnd, nil
}
var winType int8 = mtype.FissionCampaignVsScheduleWinTypeWin
if teamId == 0 {
if !verify.InArray[string](mtype.FissionCampaignVsScheduleOtherVoteDraw, schedule.GetOtherVote()...) {
return voteFail, nil
}
winType = mtype.FissionCampaignVsScheduleWinTypeDraw
}
m := s.GetDao().FissionVsVote
vote, err := m.WithContext(s.Ctx).Where(m.VsID.Eq(player.ID), m.ScheduleID.Eq(scheduleId)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if vote == nil {
vote = withdefault.FissionVsVote(&model.FissionVsVote{
CampaignID: player.CampaignID,
UserID: player.UserID,
VsID: player.ID,
ScheduleID: scheduleId,
WinType: winType,
WinTeamID: teamId,
IsWin: 0,
})
err = m.WithContext(s.Ctx).Create(vote)
if err != nil {
err = s.BE().MysqlError(err)
return
}
defer func() {
if status != voteOk {
_, _ = m.WithContext(s.Ctx).Delete(vote)
}
}()
}
if vote.WinType != winType || vote.WinTeamID != teamId || (teamId > 0 && !verify.InArray[int64](teamId, schedule.GetVsTeamIds()...)) {
return voteNotSameTeam, nil
}
if vote.FreeVote+vote.PointVote >= conf.EachLimitNum {
return voteLimit, nil
}
if player.Chance > 0 {
val, _ := jsonm.MarshalToString(mtype.VsLogVal{
Chance: 1,
ScheduleId: scheduleId,
WinType: winType,
WinTeamId: teamId,
})
log := withdefault.FissionVsLog(&model.FissionVsLog{
UserID: player.UserID,
CampaignID: player.CampaignID,
VsID: player.ID,
Type: mtype.FissionVsLogTypeVote,
Source: mtype.FissionLogSourceVote,
Val: val,
})
err = s._addLog(log)
if err != nil {
return
}
vsM := s.GetDao().FissionV
_, err = vsM.WithContext(s.Ctx).Where(vsM.ID.Eq(player.ID)).UpdateSimple(vsM.Chance.Sub(1))
if err != nil {
err = s.BE().MysqlError(err)
return
}
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(vote.ID)).UpdateColumnSimple(m.FreeVote.Add(1))
if err != nil {
err = s.BE().MysqlError(err)
return
}
err = s._voteAdd()
if err != nil {
return
}
s.appTrack().VsVote(time.Now().Unix(), scheduleId, int32(winType), teamId)
return voteOk, nil
}
if conf.OpenPoint == mtype.No {
return voteLack, nil
}
pu, err := projectuser.NewProjectUser(s.Ctx,
projectuser.WithInit(s.cpn.ProjectID, s.user.SubUserID),
projectuser.WithDao(s.GetDao()),
)
if err != nil {
return
}
ok, err := pu.Deduct(mtype.ProjectUserCoinUseSourceCampaign, mtype.ProjectUserCoinDerVote, player.CampaignID, conf.PointsNum)
if err != nil {
return
}
if !ok {
s.Rollback("项目用户积分不足")
return voteLack, nil
}
val, _ := jsonm.MarshalToString(mtype.VsLogVal{
Chance: 1,
ScheduleId: scheduleId,
WinType: winType,
WinTeamId: teamId,
PointsNum: conf.PointsNum,
})
log := withdefault.FissionVsLog(&model.FissionVsLog{
UserID: player.UserID,
CampaignID: player.CampaignID,
VsID: player.ID,
Type: mtype.FissionVsLogTypeVote,
Source: mtype.FissionLogSourceVote,
Val: val,
})
err = s._addLog(log)
if err != nil {
return
}
vsM := s.GetDao().FissionV
_, err = vsM.WithContext(s.Ctx).Where(vsM.ID.Eq(player.ID)).UpdateSimple(vsM.CoinUse.Add(conf.PointsNum))
if err != nil {
err = s.BE().MysqlError(err)
return
}
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(vote.ID)).UpdateColumnSimple(m.PointVote.Add(1))
if err != nil {
err = s.BE().MysqlError(err)
return
}
err = s._voteAdd()
if err != nil {
return
}
s.appTrack().PointsUse(time.Now().Unix(), conf.PointsNum)
s.appTrack().VsVote(time.Now().Unix(), scheduleId, int32(winType), teamId)
return voteOk, nil
}
type Schedule struct {
Id int64
Desc string
VsImg string
VsDate string
VsTz int32
VoteCountdown int64
Status int32
OpenOdds int32
OddsLeft string
OddsRight string
OddsDraw string
WinType int32
WinTeamId int64
Scores []*Score
OtherVote []string
Teams []*Team
UserVote *UserVote
Reward *Reward
Votes []*Vote
}
type Score struct {
TeamId int64
Score string
}
type UserVote struct {
UserWinType int32
UserWinTeamId int64
IsWin bool
VoteNum int32
}
type Team struct {
Id int64
Name string
LogoImg string
Score string
}
type Reward struct {
Id int64
PropMark string
Title string
Img string
KvData []*mtype.RewardKV
ReceiveType int32
Contact string //联系方式
OpenToUse int32 //开启去使用(0-否,1-是)
WebUrl string //Web端的跳转地址
AppParam string //App端的跳转参数
PcParam string //pc端的跳转参数
PropNum int32
RewardHashId string //领取的用户奖品hash_id
}
type Vote struct {
WinType int32 `json:"win_type"`
WinTeamId int64 `json:"win_team_id"`
Num int64 `json:"num"`
}
func (s *Vs) Schedules(tabType int32) (list []*Schedule, err error) {
player, conf := s.GetPlayer(), s.GetConf()
teamM := s.GetDao().FissionCampaignVsTeam
teams, err := teamM.WithContext(s.Ctx).Where(teamM.CampaignID.Eq(s.user.CampaignID)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var teamMap = make(map[int64]*model.FissionCampaignVsTeam, len(teams))
for _, v := range teams {
teamMap[v.ID] = v
}
voteM := s.GetDao().FissionVsVote
votes, err := voteM.WithContext(s.Ctx).Where(
voteM.CampaignID.Eq(s.user.CampaignID),
voteM.VsID.Eq(player.ID),
).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var voteMap = make(map[int64]*model.FissionVsVote, len(votes))
for _, v := range votes {
voteMap[v.ScheduleID] = v
}
scheduleM := s.GetDao().FissionCampaignVsSchedule
schedules, err := scheduleM.WithContext(s.Ctx).Where(
scheduleM.CampaignID.Eq(player.CampaignID),
scheduleM.VsAt.Gt(0),
).Order(scheduleM.VsAt.Asc()).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var rewardIds []int64
for _, v := range schedules {
rewardIds = append(rewardIds, v.RewardID)
}
rewardM := s.GetDao().FissionCampaignReward
rewards, err := rewardM.WithContext(s.Ctx).Where(rewardM.ID.In(rewardIds...)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var hasPoint bool
var brdIds []int64
var brdMap = make(map[int64]struct{})
for _, v := range rewards {
if _, ok := brdMap[v.RewardID]; !ok && v.RewardID > 0 {
brdIds = append(brdIds, v.RewardID)
}
if v.PropMark == mtype.FissionCampaignRewardPropMarkPoint {
hasPoint = true
}
}
preward, err := provider.NewRewards(s.Ctx, s.cpn.ProjectID, brdIds...)
if err != nil {
return
}
var title, imgUrl string
if hasPoint {
title, imgUrl, _, err = cmm.NewCMM(s.Ctx, s.GetDao()).GetCoinInfo(s.cpn.ProjectID, s.user.LangMark)
if err != nil {
return
}
}
var rewardMap = make(map[int64]*Reward, len(rewards))
for _, reward := range rewards {
one := &Reward{
Id: reward.ID,
PropMark: reward.PropMark,
Title: title,
Img: imgUrl,
KvData: nil,
ReceiveType: 0,
Contact: "",
OpenToUse: 0,
WebUrl: "",
AppParam: "",
PcParam: "",
PropNum: reward.RewardNum,
}
if reward.PropMark == mtype.FissionCampaignRewardPropMarkReward {
info, _ := preward.InfoAutoLang(reward.RewardID, s.user.LangMark)
one.Title = info.Title
one.Img = info.ImgUrl
one.KvData = info.KvData
one.ReceiveType = info.ReceiveType
one.Contact = info.Contact
one.OpenToUse = info.OpenToUse
one.WebUrl = info.WebUrl
one.AppParam = info.AppParam
one.PcParam = info.PcParam
}
rewardMap[reward.ID] = one
}
var scheduleLang = make(map[int64]*mtype.VsSchedulePkTeam)
if verify.InArray[string](s.user.LangMark, s.cpn.GetLangMarks()[1:]...) {
var lang *model.FissionCampaignLang
lang, err = cache.NewCampaignLang(s.Ctx).FindByCampaignId(player.CampaignID, s.user.LangMark)
if err != nil {
err = s.BE().CacheError(err)
return
}
for _, v := range lang.GetVs() {
for _, pk := range v.PkTeams {
scheduleLang[pk.Id] = pk
}
}
}
var fn = func(v *model.FissionCampaignVsSchedule) {
slt := v.GetSettlement()
scoreMap := make(map[int64]string, len(slt.Scores))
for _, v := range slt.Scores {
scoreMap[v.TeamId] = v.Score
}
one := &Schedule{
Id: v.ID,
Desc: v.Desc,
VsImg: v.VsImg,
VsDate: timez.GMTTime(conf.VsTz, v.VsAt).Format(timez.PointYmdHi),
VsTz: conf.VsTz,
VoteCountdown: v.VoteEnd - time.Now().Unix(),
Status: v.GetStatus(),
OpenOdds: int32(v.OpenOdds),
OddsLeft: v.OddsLeft,
OddsRight: v.OddsRight,
OddsDraw: v.OddsDraw,
WinType: slt.WinType,
WinTeamId: slt.WinTeamId,
Scores: make([]*Score, 0, len(slt.Scores)),
OtherVote: v.GetOtherVote(),
Teams: make([]*Team, 0, len(v.GetVsTeamIds())),
UserVote: nil,
Reward: rewardMap[v.RewardID],
Votes: nil,
}
for _, v := range slt.Scores {
one.Scores = append(one.Scores, &Score{
TeamId: v.TeamId,
Score: v.Score,
})
}
if vote, ok := voteMap[v.ID]; ok {
one.UserVote = &UserVote{
UserWinType: int32(vote.WinType),
UserWinTeamId: vote.WinTeamID,
IsWin: vote.IsWin == mtype.Yes,
VoteNum: vote.FreeVote + vote.PointVote,
}
}
for _, teamId := range v.GetVsTeamIds() {
two := &Team{
Id: teamId,
}
if team, ok := teamMap[teamId]; ok {
two.Name = team.Name
two.LogoImg = team.LogoImg
two.Score = scoreMap[teamId]
}
one.Teams = append(one.Teams, two)
}
if lang, ok := scheduleLang[v.ID]; ok && lang != nil {
one.Desc = lang.Desc
one.VsImg = lang.VsImg
for i, v := range lang.Teams {
if v.Id > 0 {
one.Teams[i].Name = v.Name
one.Teams[i].LogoImg = v.LogoImg
}
}
}
one.Votes, err = s._voteNum(v.ID)
if err != nil {
return
}
list = append(list, one)
}
for _, v := range schedules {
if tabType == 1 && !verify.InArray[int32](v.GetStatus(), mtype.FissionCampaignVsScheduleStatusVote, mtype.FissionCampaignVsScheduleStatusRunning) {
continue
}
_, ok := voteMap[v.ID]
if tabType == 3 && !ok {
continue
}
fn(v)
}
if len(list) > 0 || tabType != 1 {
return
}
l := len(schedules)
for i := l; i > 0; i-- {
one := schedules[i-1]
if one.IsSettlement == mtype.Yes {
fn(one)
break
}
}
return
}
// SetInit 获得初始次数
func (s *Vs) 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().FissionV
_, 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.VsLogVal{
Chance: conf.InitChance,
})
log := withdefault.FissionVsLog(&model.FissionVsLog{
UserID: player.UserID,
CampaignID: player.CampaignID,
VsID: player.ID,
Type: mtype.FissionVsLogTypeAddVote,
Source: mtype.FissionLogSourceInit,
Val: val,
})
err = s._addLog(log)
if err != nil {
return
}
s.player.Chance += conf.InitChance
return
}
// GetConf 获取玩法配置
func (s *Vs) GetConf() *model.FissionCampaignV {
if s.conf == nil {
s.conf, _ = cache.NewCampaignVs(s.Ctx).FindByCampaignId(s.user.CampaignID)
}
return s.conf
}
// GetPlayer 获取玩家基础数据
func (s *Vs) GetPlayer() *model.FissionV {
return s.player
}
// 玩家
func (s *Vs) 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 *Vs) firstOrCreate() (player *model.FissionV, 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 *Vs) _dbFirst() (*model.FissionV, error) {
playerM := dao.FissionV
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 *Vs) createPlayer() (player *model.FissionV, err error) {
playerM := dao.FissionV
player = withdefault.FissionVs(&model.FissionV{
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 *Vs) _addLog(logs ...*model.FissionVsLog) (err error) {
err = s.GetDao().FissionVsLog.WithContext(s.Ctx).Create(logs...)
if err != nil {
err = s.BE().MysqlError(err)
return
}
return
}
func (s *Vs) _voteNum(scheduleId int64) (votes []*Vote, err error) {
m := s.GetDao().FissionVsVote
voteNumField := field.NewUnsafeFieldRaw("free_vote + point_vote")
err = m.WithContext(s.Ctx).
Select(m.WinType, m.WinTeamID, voteNumField.Sum().As("num")).
Where(m.ScheduleID.Eq(scheduleId)).
Group(m.WinType, m.WinTeamID).
Scan(&votes)
if err != nil {
err = s.BE().MysqlError(err)
return
}
return
}
func (s *Vs) _voteAdd() (err error) {
m := s.GetDao().FissionV
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(s.GetPlayer().ID)).UpdateSimple(m.VoteNum.Add(1))
if err != nil {
err = s.BE().MysqlError(err)
return
}
s.player.VoteNum++
return
}