|
|
package campaignnotice
|
|
|
|
|
|
import (
|
|
|
"joybuywork/internal/app"
|
|
|
"joybuywork/internal/consts"
|
|
|
"joybuywork/internal/consts/ckey"
|
|
|
"joybuywork/internal/repository/cache"
|
|
|
"joybuywork/internal/repository/dbcheck"
|
|
|
"joybuywork/internal/repository/finder"
|
|
|
"joybuywork/internal/repository/model"
|
|
|
"joybuywork/internal/repository/mtype"
|
|
|
"joybuywork/internal/repository/withdefault"
|
|
|
"joybuywork/internal/service/cmm"
|
|
|
"joybuywork/internal/service/provider"
|
|
|
"joybuywork/internal/service/provider/fissionaction"
|
|
|
"joybuywork/internal/service/queue/producer"
|
|
|
"joybuywork/internal/service/queue/types"
|
|
|
"joybuywork/internal/utils"
|
|
|
"joybuywork/internal/utils/logic"
|
|
|
"joybuywork/internal/utils/verify"
|
|
|
"joybuywork/proto/go_proto/workerr"
|
|
|
"fmt"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"time"
|
|
|
|
|
|
"gits.branchcn.com/backend/microcode/plugins/derivative/lock"
|
|
|
"gorm.io/gen/field"
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
campaignNoticeEtNone = iota // 无效用户
|
|
|
campaignNoticeEtInvite // 邀请有效
|
|
|
campaignNoticeEtSelf // 自身完成有效任务
|
|
|
campaignNoticeEtParent // 上级完成有效任务
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
campaignNoticeResTypeNone = iota
|
|
|
campaignNoticeResTypeNotNext // 没有下一级
|
|
|
campaignNoticeResTypeLack // 库存不足
|
|
|
)
|
|
|
|
|
|
type Notice struct {
|
|
|
logic.Logic
|
|
|
|
|
|
Req *types.CampaignNotice
|
|
|
|
|
|
//项目id
|
|
|
projectId int64
|
|
|
|
|
|
//活动hash_id
|
|
|
cpnHashId string
|
|
|
|
|
|
//父级的统计
|
|
|
pStat *model.FissionUserStat
|
|
|
|
|
|
expTime time.Duration // 归档结束用来当缓存过期时间
|
|
|
|
|
|
resendReg bool // 重新触发注册事件
|
|
|
}
|
|
|
|
|
|
func (s *Notice) Exec() (err error) {
|
|
|
cpn, err := s.campaign()
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
parent, err := s.parent()
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
user, parent, newUser, err := s.user(cpn, parent)
|
|
|
if err != nil || user == nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if cpn.ReportType == mtype.FissionCampaignReportTypeNew {
|
|
|
var dems []fissionaction.CusDem
|
|
|
if s.Req.WebChannelId > 0 {
|
|
|
dems = append(dems, fissionaction.SetChannelId(s.Req.WebChannelId))
|
|
|
}
|
|
|
switch s.Req.NoticeType {
|
|
|
case types.NoticeTypeOpen:
|
|
|
s.MP().InApp(user, dems...).AppOpen(s.Req.BehaviorTime, s.Req.Ip, s.Req.Os, s.Req.OsVersion, s.Req.DeviceModel, newUser)
|
|
|
case types.NoticeTypeInstall:
|
|
|
if s.Req.NoticeTag == types.NoticeTagWeb {
|
|
|
s.MP().InApp(user, dems...).WebFirstOpen(s.Req.BehaviorTime, s.Req.Ip, s.Req.Os, s.Req.OsVersion, s.Req.DeviceModel, newUser)
|
|
|
} else {
|
|
|
s.MP().InApp(user, dems...).AppInstall(s.Req.BehaviorTime, s.Req.Ip, s.Req.Os, s.Req.OsVersion, s.Req.DeviceModel, newUser)
|
|
|
}
|
|
|
|
|
|
case types.NoticeTypeRegister:
|
|
|
s.MP().InApp(user).AppRegister(s.Req.BehaviorTime, s.Req.Ip, s.Req.Os, s.Req.OsVersion, s.Req.DeviceModel, newUser)
|
|
|
case types.NoticeTypeCustom:
|
|
|
case types.NoticeTypePay:
|
|
|
s.MP().InApp(user).Pay(s.Req.BehaviorTime, s.Req.PurchasesData)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if cpn.Target == mtype.FissionCampaignConfigTargetAdsGame || s.change(cpn, user, parent, newUser) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
et, targetNum, setHelp, err := s.effective(cpn, user, parent, newUser)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if et == campaignNoticeEtSelf {
|
|
|
err = s.targetStatNum(user, targetNum) // 自己的达标数
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
} else {
|
|
|
err = s.parentStatNum(parent, newUser, setHelp, et, targetNum)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
switch et {
|
|
|
case campaignNoticeEtInvite: // 好友有效
|
|
|
err = s.game(cpn, user, parent)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
case campaignNoticeEtSelf: // 自己完成任务有效
|
|
|
err = s.selfGame(cpn, user, targetNum)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
case campaignNoticeEtParent: // 上级完成任务有效
|
|
|
err = s.selfGame(cpn, parent, targetNum)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 活动数据
|
|
|
func (s *Notice) campaign() (cpn *model.FissionCampaign, err error) {
|
|
|
cpn, err = finder.Campaign(s.Ctx, s.Req.CampaignId)
|
|
|
if err != nil {
|
|
|
err = s.BE().CacheError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if cpn == nil || cpn.IsDel == mtype.Yes {
|
|
|
err = workerr.NotFound("not found cpn")
|
|
|
return
|
|
|
}
|
|
|
|
|
|
s.projectId = cpn.ProjectID
|
|
|
s.cpnHashId = cpn.HashID
|
|
|
s.expTime = provider.NewCampaignTZ(s.Ctx, cpn, s.Req.Lang).EndTime().Sub(time.Now())
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 找父亲
|
|
|
func (s *Notice) parent() (parent *model.FissionUser, err error) {
|
|
|
if s.Req.ParentId == "" {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
fuCache := cache.NewFissionUser(s.Ctx, s.Req.CampaignId)
|
|
|
parent, err = fuCache.FindBySubUserId(s.Req.ParentId)
|
|
|
if err != nil {
|
|
|
err = s.BE().CacheError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 通过用户唯一标识找参与用户
|
|
|
func (s *Notice) _findByUserMark(cpnId int64, uct consts.CampaignUserType) (user *model.FissionUser, err error) {
|
|
|
if !verify.InArray(s.Req.NoticeType, types.NoticeTypeInstall, types.NoticeTypeOpen) || s.Req.UserMark == "" {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
id, _ := app.Redis.Cache.Get(s.Ctx, ckey.FissionUserUniqMark(cpnId, s.Req.UserMark)).Int64()
|
|
|
if id == 0 {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
user, err = cache.NewFissionUser(s.Ctx, cpnId).FindById(id)
|
|
|
if err != nil {
|
|
|
err = s.BE().CacheError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if user == nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
ms := s.GetDao().FissionUser.SubTable(cpnId)
|
|
|
m := s.GetDao().FissionUser
|
|
|
var upData []field.AssignExpr
|
|
|
var upDataMs []field.AssignExpr
|
|
|
// 没绑定device_id就绑定
|
|
|
if user.DeviceID == "" && s.Req.DeviceId != "" {
|
|
|
upData = append(upData, m.DeviceID.Value(s.Req.DeviceId))
|
|
|
upDataMs = append(upDataMs, ms.DeviceID.Value(s.Req.DeviceId))
|
|
|
user.DeviceID = s.Req.DeviceId
|
|
|
}
|
|
|
|
|
|
// 没绑定user_id就绑定
|
|
|
if user.SubUserID == "" && s.Req.UserId != "" {
|
|
|
upData = append(upData, m.SubUserID.Value(s.Req.UserId), m.UserMark.Value(s.Req.UserId))
|
|
|
upDataMs = append(upDataMs, ms.SubUserID.Value(s.Req.UserId), ms.UserMark.Value(s.Req.UserId))
|
|
|
user.SubUserID = s.Req.UserId
|
|
|
}
|
|
|
|
|
|
if user.LangMark != s.Req.Lang {
|
|
|
upData = append(upData, m.LangMark.Value(s.Req.Lang), m.UserLang.Value(uct.LangMark))
|
|
|
upDataMs = append(upDataMs, ms.LangMark.Value(s.Req.Lang), ms.UserLang.Value(uct.LangMark))
|
|
|
user.LangMark, user.UserLang = s.Req.Lang, uct.LangMark
|
|
|
}
|
|
|
|
|
|
// 更换匹配中的用户等级
|
|
|
if user.UserLevel != uct.LevelId && user.FixedUserLevel == mtype.No {
|
|
|
upData = append(upData, m.UserLevelMark.Value(uct.LevelMark), m.UserLevel.Value(uct.LevelId))
|
|
|
upDataMs = append(upDataMs, ms.UserLevelMark.Value(uct.LevelMark), ms.UserLevel.Value(uct.LevelId))
|
|
|
user.UserLevelMark = uct.LevelMark
|
|
|
user.UserLevel = uct.LevelId
|
|
|
}
|
|
|
|
|
|
lvMark := strings.Join(s.Req.UserLv, ",")
|
|
|
if user.LevelMark != lvMark {
|
|
|
upData = append(upData, m.LevelMark.Value(lvMark))
|
|
|
upDataMs = append(upDataMs, ms.LevelMark.Value(lvMark))
|
|
|
user.LevelMark = lvMark
|
|
|
}
|
|
|
|
|
|
if len(upData) > 0 {
|
|
|
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(user.ID)).UpdateSimple(upData...)
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
_, err = ms.WithContext(s.Ctx).Where(ms.ID.Eq(user.ID)).UpdateSimple(upDataMs...)
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
_ = cache.NewFissionUser(s.Ctx, cpnId).Clear(user)
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 通过user_id找参与用户
|
|
|
func (s *Notice) _findByOwnerId(uct consts.CampaignUserType) (user *model.FissionUser, err error) {
|
|
|
if s.Req.UserId == "" {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
fuCache := cache.NewFissionUser(s.Ctx, s.Req.CampaignId)
|
|
|
user, err = fuCache.FindBySubUserId(s.Req.UserId)
|
|
|
if err != nil {
|
|
|
err = s.BE().CacheError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if user == nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
ms := s.GetDao().FissionUser.SubTable(user.CampaignID)
|
|
|
m := s.GetDao().FissionUser
|
|
|
var upData []field.AssignExpr
|
|
|
var upDataMs []field.AssignExpr
|
|
|
// 没绑定device_id就绑定
|
|
|
if user.DeviceID == "" && s.Req.DeviceId != "" {
|
|
|
upData = append(upData, m.DeviceID.Value(s.Req.DeviceId))
|
|
|
upDataMs = append(upDataMs, ms.DeviceID.Value(s.Req.DeviceId))
|
|
|
user.DeviceID = s.Req.DeviceId
|
|
|
}
|
|
|
|
|
|
// 没绑定user_id就绑定
|
|
|
if user.SubUserID == "" && s.Req.UserId != "" {
|
|
|
upData = append(upData, m.SubUserID.Value(s.Req.UserId), m.UserMark.Value(s.Req.UserId))
|
|
|
upDataMs = append(upDataMs, ms.SubUserID.Value(s.Req.UserId), ms.UserMark.Value(s.Req.UserId))
|
|
|
user.SubUserID = s.Req.UserId
|
|
|
}
|
|
|
|
|
|
if user.LangMark != s.Req.Lang {
|
|
|
upData = append(upData, m.LangMark.Value(s.Req.Lang), m.UserLang.Value(uct.LangMark))
|
|
|
upDataMs = append(upDataMs, ms.LangMark.Value(s.Req.Lang), ms.UserLang.Value(uct.LangMark))
|
|
|
user.LangMark, user.UserLang = s.Req.Lang, uct.LangMark
|
|
|
}
|
|
|
|
|
|
// 更换匹配中的用户等级
|
|
|
if user.UserLevel != uct.LevelId && user.FixedUserLevel == mtype.No {
|
|
|
upData = append(upData, m.UserLevelMark.Value(uct.LevelMark), m.UserLevel.Value(uct.LevelId))
|
|
|
upDataMs = append(upDataMs, ms.UserLevelMark.Value(uct.LevelMark), ms.UserLevel.Value(uct.LevelId))
|
|
|
user.UserLevelMark = uct.LevelMark
|
|
|
user.UserLevel = uct.LevelId
|
|
|
}
|
|
|
|
|
|
lvMark := strings.Join(s.Req.UserLv, ",")
|
|
|
if user.LevelMark != lvMark {
|
|
|
upData = append(upData, m.LevelMark.Value(lvMark))
|
|
|
upDataMs = append(upDataMs, ms.LevelMark.Value(lvMark))
|
|
|
user.LevelMark = lvMark
|
|
|
}
|
|
|
|
|
|
if len(upData) > 0 {
|
|
|
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(user.ID)).UpdateSimple(upData...)
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
_, err = ms.WithContext(s.Ctx).Where(ms.ID.Eq(user.ID)).UpdateSimple(upDataMs...)
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
_ = fuCache.Clear(user)
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 通过device找活动的参与用户
|
|
|
func (s *Notice) _findByDeviceId(uct consts.CampaignUserType) (user *model.FissionUser, err error) {
|
|
|
if s.Req.DeviceId == "" {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
fuCache := cache.NewFissionUser(s.Ctx, s.Req.CampaignId)
|
|
|
user, err = fuCache.FindByDeviceId(s.Req.DeviceId)
|
|
|
if err != nil {
|
|
|
err = s.BE().CacheError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if user == nil || user.SubUserID == s.Req.UserId {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 如果同一个设备多个用户,就当成一个新用户处理吧
|
|
|
if user.SubUserID != "" && s.Req.UserId != "" {
|
|
|
return nil, nil
|
|
|
}
|
|
|
|
|
|
ms := s.GetDao().FissionUser.SubTable(user.CampaignID)
|
|
|
m := s.GetDao().FissionUser
|
|
|
var upData []field.AssignExpr
|
|
|
var upDataMs []field.AssignExpr
|
|
|
// 没绑定device_id就绑定
|
|
|
if user.DeviceID == "" && s.Req.DeviceId != "" {
|
|
|
upData = append(upData, m.DeviceID.Value(s.Req.DeviceId))
|
|
|
upDataMs = append(upDataMs, ms.DeviceID.Value(s.Req.DeviceId))
|
|
|
user.DeviceID = s.Req.DeviceId
|
|
|
}
|
|
|
|
|
|
// 没绑定user_id就绑定
|
|
|
if user.SubUserID == "" && s.Req.UserId != "" {
|
|
|
upData = append(upData, m.SubUserID.Value(s.Req.UserId), m.UserMark.Value(s.Req.UserId))
|
|
|
upDataMs = append(upDataMs, ms.SubUserID.Value(s.Req.UserId), ms.UserMark.Value(s.Req.UserId))
|
|
|
user.SubUserID = s.Req.UserId
|
|
|
}
|
|
|
|
|
|
if user.LangMark != s.Req.Lang {
|
|
|
upData = append(upData, m.LangMark.Value(s.Req.Lang), m.UserLang.Value(uct.LangMark))
|
|
|
upDataMs = append(upDataMs, ms.LangMark.Value(s.Req.Lang), ms.UserLang.Value(uct.LangMark))
|
|
|
user.LangMark, user.UserLang = s.Req.Lang, uct.LangMark
|
|
|
}
|
|
|
|
|
|
// 更换匹配中的用户等级
|
|
|
if user.UserLevel != uct.LevelId && user.FixedUserLevel == mtype.No {
|
|
|
upData = append(upData, m.UserLevelMark.Value(uct.LevelMark), m.UserLevel.Value(uct.LevelId))
|
|
|
upDataMs = append(upDataMs, ms.UserLevelMark.Value(uct.LevelMark), ms.UserLevel.Value(uct.LevelId))
|
|
|
user.UserLevelMark = uct.LevelMark
|
|
|
user.UserLevel = uct.LevelId
|
|
|
}
|
|
|
|
|
|
lvMark := strings.Join(s.Req.UserLv, ",")
|
|
|
if user.LevelMark != lvMark {
|
|
|
upData = append(upData, m.LevelMark.Value(lvMark))
|
|
|
upDataMs = append(upDataMs, ms.LevelMark.Value(lvMark))
|
|
|
user.LevelMark = lvMark
|
|
|
}
|
|
|
|
|
|
if len(upData) > 0 {
|
|
|
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(user.ID)).UpdateSimple(upData...)
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
_, err = ms.WithContext(s.Ctx).Where(ms.ID.Eq(user.ID)).UpdateSimple(upDataMs...)
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
_ = fuCache.Clear(user)
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 参与用户
|
|
|
func (s *Notice) user(cpn *model.FissionCampaign, parent *model.FissionUser) (user, bindParent *model.FissionUser, newUser bool, err error) {
|
|
|
return provider.NewFissionUser(s.Ctx, cpn, nil).NotifyUser(
|
|
|
s.Req.BehaviorTime,
|
|
|
s.Req.NoticeType,
|
|
|
s.Req.IsInstall,
|
|
|
s.Req.NoticeTag,
|
|
|
s.Req.UserMark,
|
|
|
s.Req.UserId,
|
|
|
s.Req.DeviceId,
|
|
|
strings.Join(s.Req.UserLv, ","),
|
|
|
s.Req.Lang,
|
|
|
s.platform(),
|
|
|
s.Req.CustomParam,
|
|
|
s.Req.WebChannelId,
|
|
|
s.Req.ChannelId,
|
|
|
s.expTime,
|
|
|
parent,
|
|
|
)
|
|
|
}
|
|
|
|
|
|
func (s *Notice) platform() string {
|
|
|
platform, dm := strings.ToLower(s.Req.Os), strings.ToLower(s.Req.DeviceModel)
|
|
|
if platform == "macos" {
|
|
|
platform = consts.PlatformIOS
|
|
|
}
|
|
|
|
|
|
if verify.InArray(platform, consts.PlatformAndroid, consts.PlatformIOS, consts.PlatformWeb) {
|
|
|
// 创建一些可变更的属性
|
|
|
if platform == consts.PlatformIOS && dm == consts.PlatformIPad {
|
|
|
platform = consts.PlatformIPad
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return platform
|
|
|
}
|
|
|
|
|
|
func (s *Notice) effective(cpn *model.FissionCampaign, user, parent *model.FissionUser, newUser bool) (et int, targetNum int32, setHelp bool, err error) {
|
|
|
conf, err := cache.NewCampaignConfig(s.Ctx).FindByCampaignId(user.CampaignID)
|
|
|
if err != nil {
|
|
|
err = s.BE().CacheError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 设置用户助力成功,仅当首次完成的触发条件的时候会执行
|
|
|
defer func() {
|
|
|
if parent != nil && user.IsHelp == mtype.No && et != campaignNoticeEtNone {
|
|
|
userMs := s.GetDao().FissionUser.SubTable(cpn.ID)
|
|
|
res, err1 := userMs.WithContext(s.Ctx).Where(
|
|
|
userMs.ID.Eq(user.ID),
|
|
|
userMs.IsHelp.Eq(mtype.No),
|
|
|
).UpdateSimple(userMs.IsHelp.Value(mtype.Yes))
|
|
|
if err1 != nil {
|
|
|
err = s.BE().MysqlError(err1)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
_ = cache.NewFissionUser(s.Ctx, cpn.ID).Clear(user)
|
|
|
|
|
|
setHelp = res.RowsAffected > 0
|
|
|
}
|
|
|
|
|
|
langTitle, _ := provider.NewLangTitle(s.Ctx, cpn, user.LangMark)
|
|
|
|
|
|
pageTitle, _ := langTitle.GetPageTitle()
|
|
|
|
|
|
// 助力成功回调
|
|
|
if setHelp {
|
|
|
switch s.Req.NoticeType {
|
|
|
case types.NoticeTypeInstall:
|
|
|
producer.NewOplatformOther(s.Ctx).OpoCampaignHelpOk(types.OpoCampaignHelpOk{
|
|
|
ProjectId: cpn.ProjectID,
|
|
|
CampaignHashId: cpn.HashID,
|
|
|
CampaignTitle: cpn.Title,
|
|
|
PageTitle: pageTitle,
|
|
|
HelperUserId: user.SubUserID,
|
|
|
HelperDeviceId: user.DeviceID,
|
|
|
BeHelperUserId: parent.SubUserID,
|
|
|
BeHelperDeviceId: parent.DeviceID,
|
|
|
Source: types.HelpSourceInstall,
|
|
|
KvData: make([]*types.KV, 0),
|
|
|
}, producer.SetHeaderLang(user.LangMark))
|
|
|
case types.NoticeTypeRegister:
|
|
|
producer.NewOplatformOther(s.Ctx).OpoCampaignHelpOk(types.OpoCampaignHelpOk{
|
|
|
ProjectId: cpn.ProjectID,
|
|
|
CampaignHashId: cpn.HashID,
|
|
|
CampaignTitle: cpn.Title,
|
|
|
PageTitle: pageTitle,
|
|
|
HelperUserId: user.SubUserID,
|
|
|
HelperDeviceId: user.DeviceID,
|
|
|
BeHelperUserId: parent.SubUserID,
|
|
|
BeHelperDeviceId: parent.DeviceID,
|
|
|
Source: types.HelpSourceRegister,
|
|
|
KvData: make([]*types.KV, 0),
|
|
|
}, producer.SetHeaderLang(user.LangMark))
|
|
|
case types.NoticeTypeCustom:
|
|
|
var kv = make([]*types.KV, 0, len(s.Req.EventData))
|
|
|
for _, v := range s.Req.EventData {
|
|
|
kv = append(kv, &types.KV{
|
|
|
Event: s.Req.Event,
|
|
|
Key: v.EventKey,
|
|
|
Value: v.EventVal,
|
|
|
})
|
|
|
}
|
|
|
producer.NewOplatformOther(s.Ctx).OpoCampaignHelpOk(types.OpoCampaignHelpOk{
|
|
|
ProjectId: cpn.ProjectID,
|
|
|
CampaignHashId: cpn.HashID,
|
|
|
CampaignTitle: cpn.Title,
|
|
|
PageTitle: pageTitle,
|
|
|
HelperUserId: user.SubUserID,
|
|
|
HelperDeviceId: user.DeviceID,
|
|
|
BeHelperUserId: parent.SubUserID,
|
|
|
BeHelperDeviceId: parent.DeviceID,
|
|
|
Source: types.HelpSourceCustom,
|
|
|
KvData: kv,
|
|
|
}, producer.SetHeaderLang(user.LangMark))
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
if cpn.FissionID == consts.IdSignIn {
|
|
|
if parent == nil { // 没有上级不处理
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if s.Req.NoticeType == types.NoticeTypeInstall {
|
|
|
et = utils.Ternary[int](newUser, campaignNoticeEtInvite, campaignNoticeEtNone)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
switch conf.Option {
|
|
|
case mtype.FissionCampaignConfigTargetOptionApp:
|
|
|
if parent == nil { // 没有上级不处理
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if conf.AppEvent == mtype.FissionCampaignConfigTargetAppEventInstall && s.Req.NoticeType == types.NoticeTypeInstall {
|
|
|
et = utils.Ternary[int](newUser, campaignNoticeEtInvite, campaignNoticeEtNone)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if conf.AppEvent == mtype.FissionCampaignConfigTargetAppEventRegister && s.Req.NoticeType == types.NoticeTypeRegister && user.IsHelp == mtype.No {
|
|
|
|
|
|
// 防止并发操作
|
|
|
once := app.Redis.Cache.SetNX(s.Ctx, ckey.FissionRegisterOnce(user.ID), s.Req.BehaviorTime, 20*time.Second).Val()
|
|
|
et = utils.Ternary[int](once, campaignNoticeEtInvite, campaignNoticeEtNone)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
return
|
|
|
case mtype.FissionCampaignConfigTargetOptionFriend:
|
|
|
if parent == nil || len(s.Req.EventData) == 0 { // 没有上级不处理
|
|
|
return
|
|
|
}
|
|
|
targetNum, err = s._eventEffective(user, conf.BothType)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 如果是老带新和一起赢奖励,那么一个用户达标只能算一次助力成功
|
|
|
if verify.InArray(cpn.FissionID, consts.IdWinTogether, consts.IdReferral) {
|
|
|
if targetNum > 0 && user.IsHelp == mtype.No {
|
|
|
once := app.Redis.Cache.SetNX(s.Ctx, ckey.FissionEventEffectiveOnce(user.ID), s.Req.BehaviorTime, 20*time.Second).Val()
|
|
|
et = utils.Ternary[int](once, campaignNoticeEtInvite, campaignNoticeEtNone)
|
|
|
return
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
et = utils.Ternary[int](targetNum > 0, campaignNoticeEtParent, campaignNoticeEtNone)
|
|
|
return
|
|
|
case mtype.FissionCampaignConfigTargetOptionSelf, mtype.FissionCampaignConfigTargetOptionUse:
|
|
|
if len(s.Req.EventData) == 0 {
|
|
|
return
|
|
|
}
|
|
|
targetNum, err = s._eventEffective(user, conf.BothType)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
et = utils.Ternary[int](targetNum > 0, campaignNoticeEtSelf, campaignNoticeEtNone)
|
|
|
return
|
|
|
case mtype.FissionCampaignConfigTargetOptionTask:
|
|
|
if len(s.Req.EventData) == 0 {
|
|
|
return
|
|
|
}
|
|
|
targetNum, err = s._eventEffective(user, conf.BothType)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 事件触发是否有效,返回达标次数
|
|
|
func (s *Notice) _eventEffective(user *model.FissionUser, bothType int8) (targetNum int32, err error) {
|
|
|
//自定义事件处理逻辑
|
|
|
m := s.GetDao().FissionCampaignCond
|
|
|
conds, err := m.WithContext(s.Ctx).Where(m.CampaignID.Eq(user.CampaignID), m.IsDel.Eq(mtype.No)).Find()
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if len(conds) == 0 {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 用户只能同时存在一个计算有效
|
|
|
lc := app.NewRedisLock(s.Ctx, ckey.FissionCustomEffectiveOnce(user.ID)).Lock()
|
|
|
defer lc.Release()
|
|
|
if lc.Error() != nil {
|
|
|
err = workerr.BusyError
|
|
|
return
|
|
|
}
|
|
|
|
|
|
var target = make(map[int64]*utils.CondTotalFinishRes) // 完成的任务
|
|
|
var condValMap = make(map[int64]*model.FissionCampaignCond) // 条件id对应的任务数据
|
|
|
var condMap = make(map[string][]*model.FissionCampaignCond) // event+key对应的条件数据集合
|
|
|
for _, cond := range conds {
|
|
|
key := fmt.Sprintf("%s_%s", cond.Event, cond.EventKey)
|
|
|
condMap[key] = append(condMap[key], cond)
|
|
|
target[cond.ID] = nil // 默认任务条件都没有完成
|
|
|
condValMap[cond.ID] = cond
|
|
|
}
|
|
|
|
|
|
cm := cmm.NewCMM(s.Ctx, s.GetDao())
|
|
|
// 只获取活动相关的条件
|
|
|
var condTotal = make(map[int64]string) // 条件累计数据
|
|
|
var records []*model.FissionUserCondRecord
|
|
|
for _, v := range s.Req.EventData {
|
|
|
key := fmt.Sprintf("%s_%s", s.Req.Event, v.EventKey)
|
|
|
eCond, ok := condMap[key] // 找到event+key对应的条件数据集合
|
|
|
if !ok { // 如果找不到就不是我们想要的自定义事件
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
for _, cond := range eCond {
|
|
|
|
|
|
if !cm.EventCanTotal(cond, user.SubUserID, 0, user.JoinAt, s.Req.BehaviorTime) {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
switch cond.IfCond {
|
|
|
case mtype.FissionCampaignCondIfCondTotal:
|
|
|
if total, ok1 := condTotal[cond.ID]; ok1 { // 如果存在当前条件的数据就累加
|
|
|
condTotal[cond.ID] = utils.StrAdd(total, v.EventVal)
|
|
|
} else {
|
|
|
condTotal[cond.ID] = v.EventVal
|
|
|
}
|
|
|
|
|
|
records = append(records, withdefault.FissionUserCondRecord(&model.FissionUserCondRecord{
|
|
|
CampaignID: user.CampaignID,
|
|
|
UserID: user.ID,
|
|
|
CondID: cond.ID,
|
|
|
Val: v.EventVal,
|
|
|
IsUse: mtype.Yes, // 因为累加过了,所以要标识为已使用
|
|
|
BehaviorTime: s.Req.BehaviorTime,
|
|
|
}))
|
|
|
|
|
|
s.condFinish(user.ID, cond.ID, v.EventVal)
|
|
|
|
|
|
case mtype.FissionCampaignCondIfCondEq:
|
|
|
if cond.EventVal == v.EventVal { // 等式下,必须要值相等才成立条件
|
|
|
if total, ok1 := condTotal[cond.ID]; ok1 { // 如果存在当前条件的数据就累加
|
|
|
condTotal[cond.ID] = utils.StrAdd(total, v.EventVal)
|
|
|
} else {
|
|
|
condTotal[cond.ID] = v.EventVal
|
|
|
}
|
|
|
records = append(records, withdefault.FissionUserCondRecord(&model.FissionUserCondRecord{
|
|
|
CampaignID: user.CampaignID,
|
|
|
UserID: user.ID,
|
|
|
CondID: cond.ID,
|
|
|
Val: v.EventVal,
|
|
|
BehaviorTime: s.Req.BehaviorTime,
|
|
|
}))
|
|
|
|
|
|
s.condFinish(user.ID, cond.ID, v.EventVal)
|
|
|
}
|
|
|
case mtype.FissionCampaignCondIfCondGte:
|
|
|
if utils.NumberStrCompareGte(v.EventVal, cond.EventVal) { // 大于等于下,必须要值大于等于才成立条件
|
|
|
if total, ok1 := condTotal[cond.ID]; ok1 { // 如果存在当前条件的数据就累加
|
|
|
condTotal[cond.ID] = utils.StrAdd(total, v.EventVal)
|
|
|
} else {
|
|
|
condTotal[cond.ID] = v.EventVal
|
|
|
}
|
|
|
records = append(records, withdefault.FissionUserCondRecord(&model.FissionUserCondRecord{
|
|
|
CampaignID: user.CampaignID,
|
|
|
UserID: user.ID,
|
|
|
CondID: cond.ID,
|
|
|
Val: v.EventVal,
|
|
|
BehaviorTime: s.Req.BehaviorTime,
|
|
|
}))
|
|
|
|
|
|
s.condFinish(user.ID, cond.ID, v.EventVal)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 没有完成的条件肯定不会触发有效的
|
|
|
if len(records) == 0 {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
ucrM := s.GetDao().FissionUserCondRecord
|
|
|
|
|
|
// 先去找还被计算的记录
|
|
|
ucr, err := ucrM.WithContext(s.Ctx).Where(ucrM.UserID.Eq(user.ID), ucrM.IsUse.Eq(mtype.No)).Find()
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 把新创建的记录入库
|
|
|
err = ucrM.WithContext(s.Ctx).Create(records...)
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 找到条件总揽
|
|
|
fucM := s.GetDao().FissionUserCond
|
|
|
fuc, err := fucM.WithContext(s.Ctx).Where(fucM.UserID.Eq(user.ID)).Find()
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 把总揽条件构建一个map
|
|
|
var uCondMap = make(map[int64]*model.FissionUserCond)
|
|
|
for _, uCond := range fuc {
|
|
|
uCondMap[uCond.CondID] = uCond
|
|
|
if total, ok1 := condTotal[uCond.CondID]; ok1 { // 这里要把之前累计的都放到累计map上
|
|
|
condTotal[uCond.CondID] = utils.StrAdd(total, uCond.Total)
|
|
|
} else {
|
|
|
condTotal[uCond.CondID] = uCond.Total
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var incCond = make(map[int64]int64) // 完成次数需要+1的总揽数据
|
|
|
for _, record := range records {
|
|
|
cond := condValMap[record.CondID]
|
|
|
|
|
|
info, ok := uCondMap[cond.ID]
|
|
|
|
|
|
if !ok {
|
|
|
info = withdefault.FissionUserCond(&model.FissionUserCond{
|
|
|
CampaignID: user.CampaignID,
|
|
|
UserID: user.ID,
|
|
|
CondID: record.CondID,
|
|
|
})
|
|
|
|
|
|
err = fucM.WithContext(s.Ctx).Create(info)
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
uCondMap[cond.ID] = info
|
|
|
}
|
|
|
|
|
|
switch cond.IfCond {
|
|
|
case mtype.FissionCampaignCondIfCondEq, mtype.FissionCampaignCondIfCondGte:
|
|
|
incCond[info.ID]++
|
|
|
}
|
|
|
}
|
|
|
|
|
|
for condId, total := range condTotal {
|
|
|
cond := condValMap[condId]
|
|
|
if cond.IfCond != mtype.FissionCampaignCondIfCondTotal {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
info := uCondMap[cond.ID]
|
|
|
|
|
|
if utils.NumberStrCompareGte(total, cond.EventVal) { // 这里代表完成了一次累计任务,要重新开始累计
|
|
|
res := utils.CondTotalFinishNum(total, cond.EventVal)
|
|
|
|
|
|
// 处理值问题
|
|
|
_, err = fucM.WithContext(s.Ctx).
|
|
|
Where(fucM.ID.Eq(info.ID)).
|
|
|
UpdateSimple(fucM.Num.Add(int64(res.Num)), fucM.CountNum.Add(int64(res.Num)), fucM.Total.Value(res.Remain))
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
target[cond.ID] = res
|
|
|
uCondMap[cond.ID].CountNum += int64(res.Num)
|
|
|
} else { // 这里是没有完成累计任务,记录最新的累计值
|
|
|
_, err = fucM.WithContext(s.Ctx).Where(fucM.ID.Eq(info.ID)).UpdateSimple(fucM.Total.Value(total))
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 完成的任务数
|
|
|
if len(incCond) > 0 {
|
|
|
for id, num := range incCond {
|
|
|
_, err = fucM.WithContext(s.Ctx).Where(fucM.ID.Eq(id)).UpdateSimple(fucM.Num.Add(num))
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 整合新的和旧的所有没有计算的记录
|
|
|
for _, v := range ucr {
|
|
|
records = append(records, v)
|
|
|
}
|
|
|
|
|
|
if len(records) == 0 {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 把计算完毕的记录都标识成已计算,下一次就不找这些数据
|
|
|
var useRecord []int64
|
|
|
var countMap = make(map[int32][]int64)
|
|
|
defer func() {
|
|
|
if targetNum == 0 {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if len(countMap) > 0 {
|
|
|
for k, v := range countMap {
|
|
|
_, err = fucM.WithContext(s.Ctx).Where(fucM.ID.In(v...)).UpdateSimple(fucM.CountNum.Sub(int64(k)))
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if len(useRecord) > 0 {
|
|
|
_, err = ucrM.WithContext(s.Ctx).Where(ucrM.ID.In(useRecord...)).UpdateSimple(ucrM.IsUse.Value(mtype.Yes))
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
// 分条件计算
|
|
|
switch bothType {
|
|
|
case mtype.FissionCampaignConfigTargetBothTypeOne:
|
|
|
// 达标统计
|
|
|
var condStat []int64
|
|
|
for _, v := range records {
|
|
|
cond, ok := condValMap[v.CondID]
|
|
|
if !ok {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
switch cond.IfCond {
|
|
|
case mtype.FissionCampaignCondIfCondGte, mtype.FissionCampaignCondIfCondEq:
|
|
|
targetNum++
|
|
|
useRecord = append(useRecord, v.ID)
|
|
|
condStat = append(condStat, cond.ID)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
for condId, res := range target {
|
|
|
if res == nil || res.Num <= 0 {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
targetNum += res.Num
|
|
|
|
|
|
// 这个事件完成的次数
|
|
|
for i := 0; i < int(res.Num); i++ {
|
|
|
condStat = append(condStat, condId)
|
|
|
}
|
|
|
|
|
|
countMap[res.Num] = append(countMap[res.Num], uCondMap[condId].ID)
|
|
|
}
|
|
|
|
|
|
// 达标统计
|
|
|
if len(condStat) > 0 {
|
|
|
producer.NewCampaignNotice(s.Ctx).CampaignTargetStat(types.CampaignTargetStat{
|
|
|
CampaignId: user.CampaignID,
|
|
|
UserId: user.ID,
|
|
|
CondIds: condStat,
|
|
|
FinishTime: s.Req.BehaviorTime,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
return
|
|
|
case mtype.FissionCampaignConfigTargetBothTypeAll:
|
|
|
var groupIdx = make(map[int64]int)
|
|
|
var groupFinish = make(map[int]map[int64]int64)
|
|
|
|
|
|
// 完成任务分组
|
|
|
for _, v := range records {
|
|
|
cond, ok := condValMap[v.CondID]
|
|
|
if !ok {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
switch cond.IfCond {
|
|
|
case mtype.FissionCampaignCondIfCondGte, mtype.FissionCampaignCondIfCondEq:
|
|
|
idx := groupIdx[v.CondID]
|
|
|
_, ok1 := groupFinish[idx]
|
|
|
if !ok1 {
|
|
|
groupFinish[idx] = make(map[int64]int64)
|
|
|
}
|
|
|
|
|
|
groupFinish[idx][v.CondID] = v.ID
|
|
|
groupIdx[v.CondID]++
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var useCount []int64
|
|
|
for condId := range target {
|
|
|
fuc1, ok1 := uCondMap[condId]
|
|
|
if !ok1 {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
for i := 0; i < int(fuc1.CountNum); i++ {
|
|
|
idx := groupIdx[condId]
|
|
|
_, ok2 := groupFinish[idx]
|
|
|
if !ok2 {
|
|
|
groupFinish[idx] = make(map[int64]int64)
|
|
|
}
|
|
|
|
|
|
groupFinish[idx][condId] = 0
|
|
|
groupIdx[condId]++
|
|
|
}
|
|
|
useCount = append(useCount, fuc1.ID)
|
|
|
}
|
|
|
|
|
|
var condStat []int64
|
|
|
for _, cond := range conds {
|
|
|
condStat = append(condStat, cond.ID)
|
|
|
}
|
|
|
|
|
|
for _, v := range groupFinish {
|
|
|
if len(v) != len(conds) {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
for _, recordId := range v {
|
|
|
|
|
|
if recordId > 0 {
|
|
|
useRecord = append(useRecord, recordId)
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
targetNum++
|
|
|
|
|
|
producer.NewCampaignNotice(s.Ctx).CampaignTargetStat(types.CampaignTargetStat{
|
|
|
CampaignId: user.CampaignID,
|
|
|
UserId: user.ID,
|
|
|
CondIds: condStat,
|
|
|
FinishTime: s.Req.BehaviorTime,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
if len(useCount) > 0 {
|
|
|
countMap[targetNum] = useCount
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func (s *Notice) condFirst(userId, condId int64) (yes bool, err error) {
|
|
|
key := ckey.FissionUserCondFirst(userId, condId)
|
|
|
|
|
|
exist, err := app.Redis.Exists(s.Ctx, key)
|
|
|
if err != nil {
|
|
|
err = s.BE().RedisError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if exist {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
yes = app.Redis.Cache.SetNX(s.Ctx, key, 1, s.expTime).Val()
|
|
|
if !yes {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
m := s.GetDao().FissionUserCondRecord
|
|
|
record, err := m.WithContext(s.Ctx).Where(m.UserID.Eq(userId), m.CondID.Eq(condId)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
return record == nil, nil
|
|
|
}
|
|
|
|
|
|
// 完成事件
|
|
|
func (s *Notice) condFinish(userId, condId int64, total string) {
|
|
|
val, _ := strconv.ParseFloat(total, 64)
|
|
|
first, _ := s.condFirst(userId, condId)
|
|
|
producer.NewCampaignNotice(s.Ctx).CampaignCondStat(types.CampaignCondStat{
|
|
|
UserId: userId,
|
|
|
CondId: condId,
|
|
|
Total: val,
|
|
|
BehaviorTime: s.Req.BehaviorTime,
|
|
|
First: first,
|
|
|
Event: s.Req.Event,
|
|
|
EventData: s.Req.EventData,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 邀请目标人数换活动机会数 (使用:大转盘、盲盒、九宫格、老虎机、赛事竞猜、签到)
|
|
|
func (s *Notice) _targetToChance(userId int64, taskChance, targetNum, chance int32) (fnh int32, err error) {
|
|
|
//获取到当前的任务次数,需要完成多少轮任务
|
|
|
oldNum := taskChance / chance
|
|
|
|
|
|
num, err := s._statDirectNum(userId)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//当前可计算完成任务的人数
|
|
|
nowInvite := int32(num) - (oldNum * targetNum)
|
|
|
|
|
|
//当前完成的次数
|
|
|
fnh = nowInvite / targetNum
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 统计有效邀请人数
|
|
|
func (s *Notice) _statDirectNum(userId int64) (num int64, err error) {
|
|
|
key := ckey.FissionUserInviteStat(userId)
|
|
|
|
|
|
if app.Redis.Cache.Exists(s.Ctx, key).Val() == 0 {
|
|
|
//锁住计算获得的人次
|
|
|
lc := app.NewRedisLock(s.Ctx, ckey.ForLock(key), lock.SetExpire(5*time.Second)).Lock()
|
|
|
defer lc.Release()
|
|
|
if lc.Error() != nil {
|
|
|
err = workerr.BusyError
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if app.Redis.Cache.Exists(s.Ctx, key).Val() == 0 {
|
|
|
num = app.Redis.Cache.IncrBy(s.Ctx, key, s.pStat.EffectiveNum).Val()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//当前邀请人数+1
|
|
|
num = app.Redis.Cache.Incr(s.Ctx, key).Val()
|
|
|
app.Redis.Cache.Expire(s.Ctx, key, 2*time.Hour)
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 玩法数据处理
|
|
|
func (s *Notice) game(cpn *model.FissionCampaign, user, parent *model.FissionUser) (err error) {
|
|
|
|
|
|
switch cpn.FissionID {
|
|
|
case consts.IdPrizeQuiz: //有奖竞猜
|
|
|
return s.prizeQuiz(cpn, user, parent)
|
|
|
case consts.IdPrizeAnswer, consts.IdQa, consts.IdQaVideo, consts.IdQaAudio: //趣味问答
|
|
|
return s.prizeAnswer(user, parent)
|
|
|
case consts.IdSignIn: //签到
|
|
|
return s.sign(user, parent)
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 有奖竞猜
|
|
|
func (s *Notice) prizeQuiz(cpn *model.FissionCampaign, user, parent *model.FissionUser) (err error) {
|
|
|
m := s.GetDao().FissionCampaignQuiz
|
|
|
fcq, err := m.WithContext(s.Ctx).Where(m.CampaignID.Eq(cpn.ID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
fqM := s.GetDao().FissionQuiz
|
|
|
pqUser, err := fqM.WithContext(s.Ctx).Where(fqM.UserID.Eq(user.ID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if pqUser == nil {
|
|
|
//创建用户的赛事竞猜玩法数据
|
|
|
err = fqM.WithContext(s.Ctx).Create(withdefault.FissionQuiz(&model.FissionQuiz{
|
|
|
UserID: user.ID,
|
|
|
CampaignID: user.CampaignID,
|
|
|
Chance: fcq.InitChance,
|
|
|
}))
|
|
|
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//防止并发获取投票次数
|
|
|
lc := app.NewRedisLock(s.Ctx, ckey.FissionParentInviteOnce(parent.ID), lock.SetExpire(5*time.Second)).Lock()
|
|
|
defer lc.Release()
|
|
|
if lc.Error() != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//是新用户,完成目标
|
|
|
ppqUser, err := fqM.WithContext(s.Ctx).Where(fqM.UserID.Eq(parent.ID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if ppqUser == nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//默认一人给一次
|
|
|
var fnh int32 = 1
|
|
|
|
|
|
//添加机会数
|
|
|
defer func() {
|
|
|
if err != nil || fnh == 0 {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
addChance := fnh * fcq.Chance
|
|
|
_, err = fqM.WithContext(s.Ctx).Where(fqM.ID.Eq(ppqUser.ID)).UpdateSimple(fqM.Chance.Add(addChance))
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}()
|
|
|
|
|
|
//目标数小于,直接一个因为这里就是一个人进来的
|
|
|
if fcq.TargetNum <= 1 {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//如果多人给一次,借助redis.incr来记录一下
|
|
|
fnh, err = s._targetToChance(
|
|
|
parent.ID,
|
|
|
ppqUser.TaskChance,
|
|
|
fcq.TargetNum,
|
|
|
fcq.Chance,
|
|
|
)
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func (s *Notice) prizeAnswer(user *model.FissionUser, parent *model.FissionUser) (err error) {
|
|
|
m := s.GetDao().FissionCampaignQa
|
|
|
qa, err := m.WithContext(s.Ctx).Where(m.CampaignID.Eq(user.CampaignID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//看看有没有活动用户数据
|
|
|
fqM := s.GetDao().FissionQa
|
|
|
player, err := fqM.WithContext(s.Ctx).Where(fqM.UserID.Eq(user.ID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if player == nil {
|
|
|
//创建用户的玩法用户数据
|
|
|
err = fqM.WithContext(s.Ctx).Create(withdefault.FissionQa(&model.FissionQa{
|
|
|
UserID: user.ID,
|
|
|
CampaignID: user.CampaignID,
|
|
|
Chance: qa.InitChance,
|
|
|
}))
|
|
|
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//防止并发获取答题次数
|
|
|
lc := app.NewRedisLock(s.Ctx, ckey.FissionParentInviteOnce(parent.ID), lock.SetExpire(5*time.Second)).Lock()
|
|
|
defer lc.Release()
|
|
|
if lc.Error() != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//是新用户,完成目标
|
|
|
pPlayer, err := fqM.WithContext(s.Ctx).Where(fqM.UserID.Eq(parent.ID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if pPlayer == nil {
|
|
|
pPlayer = withdefault.FissionQa(&model.FissionQa{
|
|
|
UserID: parent.ID,
|
|
|
CampaignID: parent.CampaignID,
|
|
|
Chance: qa.InitChance,
|
|
|
})
|
|
|
|
|
|
//这里是防止后面有一些需求,导致上级用户可以不进入活动页面页能拉新的情况,不让一般都不会走进来这个if
|
|
|
if err = fqM.WithContext(s.Ctx).Create(pPlayer); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//假设邀请了完成了一次获取抽奖机会的任务
|
|
|
var fnh int32 = 1
|
|
|
|
|
|
//添加机会数
|
|
|
defer func() {
|
|
|
if err != nil || fnh == 0 {
|
|
|
return
|
|
|
}
|
|
|
addChance := fnh * qa.Chance
|
|
|
_, err = fqM.WithContext(s.Ctx).Where(fqM.ID.Eq(pPlayer.ID)).UpdateSimple(
|
|
|
fqM.Chance.Add(addChance),
|
|
|
fqM.TaskChance.Add(addChance),
|
|
|
)
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}()
|
|
|
|
|
|
//目标数小于等于1,直接当完成,因为这里就是一个人进来的
|
|
|
if qa.TargetNum <= 1 {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//如果多人给一次,借助redis.incr来记录一下
|
|
|
fnh, err = s._targetToChance(
|
|
|
pPlayer.UserID,
|
|
|
pPlayer.TaskChance,
|
|
|
qa.TargetNum,
|
|
|
qa.Chance,
|
|
|
)
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func (s *Notice) selfGame(cpn *model.FissionCampaign, user *model.FissionUser, targetNum int32) (err error) {
|
|
|
switch cpn.FissionID {
|
|
|
case consts.IdPrizeQuiz: //有奖竞猜
|
|
|
return s.selfPrizeQuiz(user, targetNum)
|
|
|
case consts.IdPrizeAnswer, consts.IdQa, consts.IdQaVideo, consts.IdQaAudio: //趣味问答
|
|
|
return s.selfPrizeAnswer(user, targetNum)
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func (s *Notice) selfPrizeQuiz(user *model.FissionUser, targetNum int32) (err error) {
|
|
|
m := s.GetDao().FissionCampaignQuiz
|
|
|
conf, err := m.WithContext(s.Ctx).Where(m.CampaignID.Eq(user.CampaignID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//看看有没有活动用户数据
|
|
|
playerM := s.GetDao().FissionQuiz
|
|
|
player, err := playerM.WithContext(s.Ctx).Where(playerM.UserID.Eq(user.ID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
var chance = conf.Chance * targetNum
|
|
|
|
|
|
if player == nil {
|
|
|
//创建用户的玩法用户数据
|
|
|
err = playerM.WithContext(s.Ctx).Create(withdefault.FissionQuiz(&model.FissionQuiz{
|
|
|
UserID: user.ID,
|
|
|
CampaignID: user.CampaignID,
|
|
|
Chance: conf.InitChance + chance,
|
|
|
TaskChance: chance,
|
|
|
}))
|
|
|
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
_, err = playerM.WithContext(s.Ctx).Where(playerM.ID.Eq(player.ID)).UpdateSimple(playerM.TaskChance.Add(chance), playerM.Chance.Add(chance))
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func (s *Notice) selfPrizeAnswer(user *model.FissionUser, targetNum int32) (err error) {
|
|
|
m := s.GetDao().FissionCampaignQa
|
|
|
conf, err := m.WithContext(s.Ctx).Where(m.CampaignID.Eq(user.CampaignID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//看看有没有活动用户数据
|
|
|
playerM := s.GetDao().FissionQa
|
|
|
player, err := playerM.WithContext(s.Ctx).Where(playerM.UserID.Eq(user.ID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
var chance = conf.Chance * targetNum
|
|
|
|
|
|
if player == nil {
|
|
|
//创建用户的玩法用户数据
|
|
|
err = playerM.WithContext(s.Ctx).Create(withdefault.FissionQa(&model.FissionQa{
|
|
|
UserID: user.ID,
|
|
|
CampaignID: user.CampaignID,
|
|
|
Chance: conf.InitChance + chance,
|
|
|
TaskChance: chance,
|
|
|
}))
|
|
|
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
_, err = playerM.WithContext(s.Ctx).Where(playerM.ID.Eq(player.ID)).UpdateSimple(playerM.TaskChance.Add(chance), playerM.Chance.Add(chance))
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 上级统计数据
|
|
|
func (s *Notice) parentStatNum(parent *model.FissionUser, newUser, setHelp bool, et int, targetNum int32) (err error) {
|
|
|
if parent == nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
m := s.GetDao().FissionUserStat
|
|
|
|
|
|
var userIds = []int64{parent.ID}
|
|
|
if parent.ParentID > 0 {
|
|
|
userIds = append(userIds, parent.ParentID)
|
|
|
}
|
|
|
|
|
|
stat, err := m.WithContext(s.Ctx).Where(m.UserID.Eq(parent.ID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
return s.BE().MysqlError(err)
|
|
|
}
|
|
|
|
|
|
s.pStat = stat
|
|
|
|
|
|
// 直接要更新的数据, 间接要更新的数据
|
|
|
var upData, indirectData []field.AssignExpr
|
|
|
if newUser {
|
|
|
upData = append(upData, m.DirectNum.Add(1))
|
|
|
if parent.ParentID > 0 {
|
|
|
indirectData = append(indirectData, m.IndirectNum.Add(1))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 当前用户变成助力成功
|
|
|
if setHelp {
|
|
|
upData = append(upData, m.EffectiveNum.Add(1))
|
|
|
if parent.ParentID > 0 {
|
|
|
indirectData = append(indirectData, m.IndirectEffectiveNum.Add(1))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 达标数+1
|
|
|
if et != 0 {
|
|
|
upData = append(upData, m.TargetNum.Add(int64(targetNum)))
|
|
|
if parent.ParentID > 0 {
|
|
|
indirectData = append(indirectData, m.IndirectTargetNum.Add(int64(targetNum)))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 直接数据更新
|
|
|
if len(upData) > 0 {
|
|
|
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(stat.ID)).UpdateSimple(upData...)
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 间接数据更新
|
|
|
if len(indirectData) > 0 {
|
|
|
_, err = m.WithContext(s.Ctx).Where(m.UserID.Eq(parent.ParentID)).UpdateSimple(indirectData...)
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 达标数统计
|
|
|
func (s *Notice) targetStatNum(user *model.FissionUser, targetNum int32) (err error) {
|
|
|
|
|
|
m := s.GetDao().FissionUserStat
|
|
|
|
|
|
// 直接达标数
|
|
|
_, err = m.WithContext(s.Ctx).Where(m.UserID.Eq(user.ID)).UpdateSimple(m.TargetNum.Add(int64(targetNum)))
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 间接达标数
|
|
|
if user.ParentID > 0 {
|
|
|
_, err = m.WithContext(s.Ctx).Where(m.UserID.Eq(user.ParentID)).UpdateSimple(m.IndirectTargetNum.Add(int64(targetNum)))
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
func (s *Notice) sign(user *model.FissionUser, parent *model.FissionUser) (err error) {
|
|
|
m := s.GetDao().FissionCampaignSign
|
|
|
fcs, err := m.WithContext(s.Ctx).Where(m.CampaignID.Eq(user.CampaignID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//看看有没有活动用户数据
|
|
|
playerM := s.GetDao().FissionSign
|
|
|
player, err := playerM.WithContext(s.Ctx).Where(playerM.UserID.Eq(user.ID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if player == nil {
|
|
|
//创建用户的玩法用户数据
|
|
|
err = playerM.WithContext(s.Ctx).Create(withdefault.FissionSign(&model.FissionSign{
|
|
|
UserID: user.ID,
|
|
|
CampaignID: user.CampaignID,
|
|
|
}))
|
|
|
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//防止并发获取骰子次数
|
|
|
lc := app.NewRedisLock(s.Ctx, ckey.FissionParentInviteOnce(parent.ID), lock.SetExpire(5*time.Second)).Lock()
|
|
|
defer lc.Release()
|
|
|
if lc.Error() != nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//是新用户,完成目标
|
|
|
pfb, err := playerM.WithContext(s.Ctx).Where(playerM.UserID.Eq(parent.ID)).Take()
|
|
|
if err = dbcheck.DbError(err); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if pfb == nil {
|
|
|
pfb = withdefault.FissionSign(&model.FissionSign{
|
|
|
UserID: parent.ID,
|
|
|
CampaignID: parent.CampaignID,
|
|
|
})
|
|
|
|
|
|
//这里是防止后面有一些需求,导致上级用户可以不进入活动页面页能拉新的情况,不让一般都不会走进来这个if
|
|
|
if err = playerM.WithContext(s.Ctx).Create(pfb); err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if fcs.HasCard == mtype.No {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//假设邀请了完成了一次获取补签卡机会的任务
|
|
|
var fnh int32 = 1
|
|
|
|
|
|
//添加机会数
|
|
|
defer func() {
|
|
|
if err != nil || fnh == 0 {
|
|
|
return
|
|
|
}
|
|
|
addChance := fnh
|
|
|
_, err = playerM.WithContext(s.Ctx).Where(playerM.ID.Eq(pfb.ID)).UpdateSimple(
|
|
|
playerM.CardNum.Add(addChance),
|
|
|
playerM.TaskCard.Add(addChance),
|
|
|
)
|
|
|
if err != nil {
|
|
|
err = s.BE().MysqlError(err)
|
|
|
return
|
|
|
}
|
|
|
}()
|
|
|
|
|
|
//目标数小于等于1,直接当完成,因为这里就是一个人进来的
|
|
|
if fcs.InviteNum <= 1 {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
//如果多人给一次,借助redis.incr来记录一下
|
|
|
fnh, err = s._targetToChance(
|
|
|
pfb.UserID,
|
|
|
pfb.TaskCard,
|
|
|
fcs.InviteNum,
|
|
|
1,
|
|
|
)
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 切换处理方式
|
|
|
func (s *Notice) change(cpn *model.FissionCampaign, user *model.FissionUser, parent *model.FissionUser, newUser bool) (ok bool) {
|
|
|
if !consts.NewEventCpn(cpn.FissionID) {
|
|
|
return false
|
|
|
}
|
|
|
|
|
|
switch s.Req.NoticeType {
|
|
|
case types.NoticeTypeInstall, types.NoticeTypeRegister, types.NoticeTypeOpen:
|
|
|
if parent == nil {
|
|
|
return
|
|
|
}
|
|
|
producer.NewCampaignNotice(s.Ctx).ValidEvents(types.ValidEvents{
|
|
|
UserId: user.ID,
|
|
|
NewUser: newUser,
|
|
|
BehaviorTime: s.Req.BehaviorTime,
|
|
|
NoticeType: s.Req.NoticeType,
|
|
|
CampaignId: s.Req.CampaignId,
|
|
|
ParentId: user.ParentID,
|
|
|
})
|
|
|
|
|
|
if s.resendReg {
|
|
|
producer.NewCampaignNotice(s.Ctx).ValidEvents(types.ValidEvents{
|
|
|
UserId: user.ID,
|
|
|
NewUser: false,
|
|
|
BehaviorTime: user.RegisterAt,
|
|
|
NoticeType: types.NoticeTypeRegister,
|
|
|
CampaignId: user.CampaignID,
|
|
|
ParentId: user.ParentID,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
case types.NoticeTypeCustom, types.NoticeTypePay:
|
|
|
if user == nil {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
var eventType int32 = mtype.FissionCampaignCondEventTypeCustom
|
|
|
if s.Req.NoticeType == types.NoticeTypePay {
|
|
|
eventType = mtype.FissionCampaignCondEventTypeStandard
|
|
|
}
|
|
|
|
|
|
producer.NewCampaignNotice(s.Ctx).ValidEvents(types.ValidEvents{
|
|
|
UserId: user.ID,
|
|
|
NewUser: newUser,
|
|
|
BehaviorTime: s.Req.BehaviorTime,
|
|
|
NoticeType: s.Req.NoticeType,
|
|
|
Event: s.Req.Event,
|
|
|
EventData: s.Req.EventData,
|
|
|
EventType: eventType,
|
|
|
CampaignId: s.Req.CampaignId,
|
|
|
ParentId: user.ParentID,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
return true
|
|
|
}
|