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.

567 lines
14 KiB
Go

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
}