package campaignuser import ( "joybuywork/internal/consts" "joybuywork/internal/repository/cache" "joybuywork/internal/repository/model" "joybuywork/internal/repository/mtype" "joybuywork/internal/repository/withdefault" "joybuywork/internal/service/provider" "joybuywork/internal/service/provider/award" "joybuywork/internal/service/provider/fissionaction" "joybuywork/internal/service/provider/players" "joybuywork/internal/service/provider/stocks" "joybuywork/internal/utils/logic" "joybuywork/internal/utils/timez" "joybuywork/internal/utils/verify" pb "joybuywork/proto/go_proto/w_campaign_user" "joybuywork/proto/go_proto/workerr" "fmt" "strings" "time" "gits.branchcn.com/backend/microcode/plugins/lucky" "gorm.io/gen/field" ) const ( childActiveStatusWait = 1 childActiveStatusLack = 2 childActiveStatusSame = 3 ) type ChildActive struct { logic.Logic Req *pb.ChildActiveReq Res *pb.ChildActiveRes recordMap map[int32]int64 childUserUp []field.AssignExpr } func (s *ChildActive) Run() error { return logic.Run(s) } func (s *ChildActive) Exec() (err error) { cpn, user, err := s.user() if err != nil { return } reward, player, err := s.active(cpn, user) if err != nil { return } if reward == nil { s.Res.Status = childActiveStatusWait return } return s.getReward(cpn, user, reward, player) } func (s *ChildActive) user() (cpn *model.FissionCampaign, user *model.FissionUser, err error) { cpn, err = cache.NewCampaign(s.Ctx).FindById(s.Req.GetCampaignId()) if err != nil { err = s.BE().CacheError(err) return } if cpn == nil || cpn.IsDel == mtype.Yes { err = workerr.NotFound("not found cpn") return } user, err = cache.NewFissionUser(s.Ctx, s.Req.GetCampaignId()).FindById(s.Req.GetUserId()) if err != nil { err = s.BE().CacheError(err) return } if user == nil { err = workerr.NotFound("not found user") return } s.recordMap = make(map[int32]int64) return } func (s *ChildActive) active(cpn *model.FissionCampaign, user *model.FissionUser) (reward *model.FissionCampaignReward, player *model.FissionChildUser, err error) { relate, err := cache.NewCampaignChild(s.Ctx).FindByUniqIdx(cpn.ID, int8(s.Req.GetChildType())) if err != nil { err = s.BE().CacheError(err) return } if relate == nil { err = workerr.NotFound("not found child") return } child, err := cache.NewCampaign(s.Ctx).FindById(relate.ChildID) if err != nil { err = s.BE().CacheError(err) return } if child == nil { err = workerr.NotFound("not found child") return } player, err = cache.NewFissionChildUser(s.Ctx).FindByUniqIdx(user.ID, child.ID) if err != nil { err = s.BE().CacheError(err) return } if player == nil { err = workerr.NotFound("not found player") return } switch s.Req.GetChildType() { case mtype.FissionCampaignChildTypeInvite: if player.RecordID > 0 { err = s.done(cpn.ProjectID, cpn.ID, player.RecordID, user.LangMark) if err != nil { return } } return case mtype.FissionCampaignChildTypeSign: reward, err = s._sign(cpn, user, player) if err != nil { return } return case mtype.FissionCampaignChildTypeBlind: reward, err = s._lottery(cpn, user, player) if err != nil { return } return case mtype.FissionCampaignChildTypeLucky: reward, err = s._lucky(cpn, user, player) if err != nil { return } return case mtype.FissionCampaignChildTypeTask: } return } func (s *ChildActive) _sign(cpn *model.FissionCampaign, user *model.FissionUser, player *model.FissionChildUser) (reward *model.FissionCampaignReward, err error) { tz := provider.NewCampaignTZ(s.Ctx, cpn, user.LangMark) _, start, end := timez.GMTStartAndEndTs(tz.GetTz()) if verify.Inside(player.LastDone, start, end) { err = s.done(cpn.ProjectID, cpn.ID, player.RecordID, user.LangMark) if err != nil { return } return } //如果是预览用户,随机返回一个奖品 if user.IsView == mtype.Yes { m := s.GetDao().FissionCampaignReward reward, err = m.WithContext(s.Ctx).Where(m.CampaignID.Eq(player.CampaignID), m.SignDay.Eq(1), m.IsDel.Eq(mtype.No)).Take() if err != nil { err = s.BE().MysqlError(err) return } return } m := s.GetDao().FissionCampaignReward list, err := m.WithContext(s.Ctx).Where(m.CampaignID.Eq(player.CampaignID), m.IsDel.Eq(mtype.No)).Order(m.SignDay).Find() if err != nil { err = s.BE().MysqlError(err) return } var l = len(list) conf, err := cache.NewCampaignConfig(s.Ctx).FindByCampaignId(player.CampaignID) if err != nil { err = s.BE().CacheError(err) return } playerM := s.GetDao().FissionChildUser s.childUserUp = append(s.childUserUp, playerM.SignDay.Add(1)) if player.JoinTime == 0 { s.childUserUp = append(s.childUserUp, playerM.JoinTime.Value(time.Now().Unix())) } var idx int switch conf.PlayType { case mtype.FissionCampaignConfigPlayTypeSign: idx = int(player.SignDay) % l case mtype.FissionCampaignConfigPlayTypeContinue: var continueSign = player.ContinueSign + 1 if !verify.Inside(player.LastDone, start-86400, end-86400) { continueSign = 1 } s.childUserUp = append(s.childUserUp, playerM.ContinueSign.Value(continueSign)) idx = int(continueSign-1) % l default: return } reward = list[idx] s.AddAfterRun(func() (err error) { fissionaction.NewMarkPoint(s.Ctx).InApp(user).JoinChild(time.Now().Unix(), player.CampaignID, player.ChildType) fissionaction.NewMarkPoint(s.Ctx).Child(player, user).ChildSign(time.Now().Unix()) return }) return } func (s *ChildActive) _lucky(cpn *model.FissionCampaign, user *model.FissionUser, player *model.FissionChildUser) (reward *model.FissionCampaignReward, err error) { reward, err = s._lottery(cpn, user, player) if err != nil { return } if reward == nil { return } var luckyReward = player.LuckyReward if reward.IsSuper == mtype.Yes { luckyReward = "" } else { luckyReward = strings.Trim(fmt.Sprintf("%s,%d", luckyReward, reward.ID), ",") } s.childUserUp = append(s.childUserUp, s.GetDao().FissionChildUser.LuckyReward.Value(luckyReward)) return } // 抽奖 func (s *ChildActive) _lottery(cpn *model.FissionCampaign, user *model.FissionUser, player *model.FissionChildUser) (reward *model.FissionCampaignReward, err error) { tz := provider.NewCampaignTZ(s.Ctx, cpn, user.LangMark) _, start, end := timez.GMTStartAndEndTs(tz.GetTz()) if verify.Inside[int64](player.LastDone, start, end) { err = s.done(cpn.ProjectID, cpn.ID, player.RecordID, user.LangMark) if err != nil { return } return } conf, err := cache.NewCampaignConfig(s.Ctx).FindByCampaignId(player.CampaignID) if err != nil { err = s.BE().CacheError(err) return } m := s.GetDao().FissionCampaignReward rewards, err := m.WithContext(s.Ctx).Where(m.CampaignID.Eq(player.CampaignID), m.IsDel.Eq(mtype.No)).Find() if err != nil { err = s.BE().MysqlError(err) return } //如果是预览用户,随机返回一个奖品 if user.IsView == mtype.Yes { var dataMap = make(map[int64]*model.FissionCampaignReward) for _, v := range rewards { if v.Odds == 0 && conf.PlayType == mtype.FissionCampaignConfigPlayTypeRate { continue } dataMap[v.ID] = v } for _, v := range dataMap { reward = v } return } s.AddAfterRun(func() (err error) { fissionaction.NewMarkPoint(s.Ctx).InApp(user).JoinChild(time.Now().Unix(), player.CampaignID, player.ChildType) fissionaction.NewMarkPoint(s.Ctx).Child(player, user).ChildLottery(time.Now().Unix()) return }) if player.JoinTime == 0 { s.childUserUp = append(s.childUserUp, s.GetDao().FissionChildUser.JoinTime.Value(time.Now().Unix())) } var ids []int64 for _, v := range rewards { if v.PropMark == mtype.FissionCampaignRewardPropMarkChance { continue } ids = append(ids, v.ID) } stock, err := stocks.NewCampaignReward(s.Ctx, ids...) if err != nil { return } useStockMap, _ := stock.AllUseStock() var filterMap = make(map[int64]struct{}) for _, id := range player.GetLuckyReward() { filterMap[id] = struct{}{} } var hasReward bool var rewardMap = make(map[int64]*model.FissionCampaignReward) for _, v := range rewards { if v.PropMark == mtype.FissionCampaignRewardPropMarkReward && int64(v.Stock) <= useStockMap[v.ID] { continue } if _, ok := filterMap[v.ID]; ok { continue } oddo := v.Odds if conf.PlayType == mtype.FissionCampaignConfigPlayTypeRand { oddo = 1 } v.Odds = oddo rewardMap[v.ID] = v hasReward = true } //奖品都发完了 if !hasReward { s.Res.Status = childActiveStatusLack return } //获取到了奖品 for { //构建抽奖机 machine := s.lotteryMachine(rewardMap) //抽奖 lcy, _ := machine.Lottery() getReward, ok := rewardMap[lcy.Int64()] if !ok { s.Res.Status = childActiveStatusLack return } if getReward.PropMark == mtype.FissionCampaignRewardPropMarkChance { reward = getReward return } //中奖了 var check bool check, err = award.NewAwardIssVerify(s.Ctx, user, getReward).DeductStock().RuleFilter().IsOK() if err != nil { return } //扣除库存成功 if check { reward = getReward return } //这个奖品这个人不能中了 delete(rewardMap, lcy.Int64()) } } // 抽奖机 func (s *ChildActive) lotteryMachine(selection map[int64]*model.FissionCampaignReward) *lucky.Discrete { var prize []lucky.Reward for _, v := range selection { prize = append(prize, lucky.Reward{ Share: int(v.Odds), Mark: v.ID, }) } return lucky.NewDiscrete(s.Ctx, prize) } func (s *ChildActive) _rsp(reward *model.FissionCampaignReward, info provider.RewardAutoLang, record *model.FissionRewardRecord) { s.AddAfterRun(func() (err error) { res := &pb.ChildActiveRes_Record{ RewardId: reward.ID, PropMark: reward.PropMark, RewardNum: reward.RewardNum, IsSuper: int32(reward.IsSuper), Title: info.Title, KvData: make([]*pb.ChildActiveRes_KV, 0, len(info.KvData)), Img: info.ImgUrl, Contact: info.Contact, OpenToUse: info.OpenToUse, WebUrl: info.WebUrl, AppParam: info.AppParam, DyRewardType: info.DyRewardType, Id: 0, HashId: "", CustomRewardVal: "", PcParam: info.PcParam, ReceiveType: info.ReceiveType, } for _, v := range info.KvData { res.KvData = append(res.KvData, &pb.ChildActiveRes_KV{ Key: v.Key, Value: v.Value, IsShow: v.IsShow, }) } if record != nil { res.Id = record.ID res.HashId = record.HashID res.CustomRewardVal = record.CustomRewardVal res.PropMark = record.PropMark res.RewardNum = record.RewardNum } s.Res.Record = res return }) } func (s *ChildActive) getReward(cpn *model.FissionCampaign, user *model.FissionUser, reward *model.FissionCampaignReward, player *model.FissionChildUser) (err error) { if user.IsView == mtype.Yes { preward, _ := provider.NewRewards(s.Ctx, cpn.ProjectID, reward.RewardID) info, _ := preward.InfoAutoLang(reward.RewardID, user.LangMark) // 设置返回的数据 s._rsp(reward, info, nil) return } if reward.PropMark == mtype.FissionCampaignRewardPropMarkChance { switch cpn.FissionID { case consts.IdKeep: err = s._keepChance(user, reward) if err != nil { return } } } record, info, _, err := award.NewAwardReward(s.Ctx, s.GetDao(), cpn.ProjectID, user).One(reward, true, award.RewardRecordChildId(player.CampaignID)) if err != nil { return } m := s.GetDao().FissionChildUser var up = s.childUserUp up = append(up, m.LastDone.Value(record.CreatedAt), m.RewardID.Value(record.RewardID), m.RecordID.Value(record.ID)) _, err = m.WithContext(s.Ctx).Where(m.ID.Eq(player.ID)).UpdateSimple(up...) if err != nil { err = s.BE().MysqlError(err) return } var recordSource string switch player.ChildType { case mtype.FissionCampaignChildTypeLucky: recordSource = mtype.FissionChildUserRecordSourceLucky case mtype.FissionCampaignChildTypeBlind: recordSource = mtype.FissionChildUserRecordSourceBlind case mtype.FissionCampaignChildTypeSign: recordSource = mtype.FissionChildUserRecordSourceSign case mtype.FissionCampaignChildTypeInvite: case mtype.FissionCampaignChildTypeTask: } if recordSource != "" { err = s.GetDao().FissionChildUserRecord.WithContext(s.Ctx).Create(withdefault.FissionChildUserRecord(&model.FissionChildUserRecord{ PCpnID: player.PCpnID, CampaignID: player.CampaignID, UserID: player.UserID, PlayerID: player.ID, ChildType: player.ChildType, Mark: recordSource, RecordID: record.ID, })) if err != nil { err = s.BE().MysqlError(err) return } } s.AddAfterRun(func() (err error) { return cache.NewFissionChildUser(s.Ctx).Clear(player) }) // 返回数据 s._rsp(reward, info, record) fissionaction.NewMarkPoint(s.Ctx).Child(player, user).ChildGetReward(time.Now().Unix(), record.RewardID, record.ID, record.RewardType) return } func (s *ChildActive) _keepChance(user *model.FissionUser, reward *model.FissionCampaignReward) (err error) { keepDog, err := players.NewKeepDog(s.Ctx, user) if err != nil { return } return keepDog.ChildActive(reward.RewardNum, int8(s.Req.GetChildType())) } func (s *ChildActive) done(projectId, cpnId, recordId int64, langMark string) (err error) { m := s.GetDao().FissionRewardRecord.SubTable(cpnId) record, err := m.WithContext(s.Ctx).Where(m.ID.Eq(recordId)).Take() if err != nil { err = s.BE().MysqlError(err) return } preward, err := provider.NewRewards(s.Ctx, projectId, record.BaseRewardID) if err != nil { return } rewardM := s.GetDao().FissionCampaignReward reward, err := rewardM.WithContext(s.Ctx).Where(rewardM.ID.Eq(record.RewardID)).Take() if err != nil { err = s.BE().MysqlError(err) return } info, _ := preward.InfoAutoLang(reward.RewardID, langMark) s._rsp(reward, info, record) s.Res.Status = childActiveStatusSame return }