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.

5395 lines
124 KiB
Go

package service
import (
"joybuywork/internal/app"
"joybuywork/internal/consts"
"joybuywork/internal/consts/ckey"
"joybuywork/internal/plugins/jsonm"
"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"
containers "joybuywork/internal/service/containers/campaignuser"
"joybuywork/internal/service/notify"
"joybuywork/internal/service/provider"
"joybuywork/internal/service/provider/award"
"joybuywork/internal/service/provider/cachecurd"
"joybuywork/internal/service/provider/fissionaction"
"joybuywork/internal/service/provider/players"
"joybuywork/internal/service/provider/projectuser"
"joybuywork/internal/service/queue/producer"
"joybuywork/internal/service/queue/types"
"joybuywork/internal/utils"
"joybuywork/internal/utils/blink"
"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"
"errors"
"fmt"
"strings"
"time"
grds "github.com/go-redis/redis/v8"
"github.com/golang-module/carbon/v2"
deventpb "gits.branchcn.com/backend/deeplink/proto/go_proto/devent"
bi_fission_actionpb "gits.branchcn.com/backend/fissionbi/proto/go_proto/bi_fission_action"
"gits.branchcn.com/backend/microcode/plugins/derivative/lock"
"gorm.io/gen"
"gorm.io/gen/field"
)
type WCampaignUser struct {
Service
}
// List 用户列表
func (s *WCampaignUser) List(req *pb.ListReq, res *pb.ListRes) (err error) {
defer s.checkErr()
*res = pb.ListRes{}
container := new(containers.List)
{
container.Init(s.ctx)
container.Req = req
container.Res = res
}
return container.Run()
}
// Reward 用户奖励
func (s *WCampaignUser) Reward(req *pb.RewardReq, res *pb.RewardRes) (err error) {
defer s.checkErr()
*res = pb.RewardRes{}
container := new(containers.Reward)
{
container.Init(s.ctx)
container.Req = req
container.Res = res
}
return container.Run()
}
// Visit 访问活动
func (s *WCampaignUser) Visit(req *pb.VisitReq, res *pb.VisitRes) (err error) {
defer s.checkErr()
*res = pb.VisitRes{}
container := new(containers.Visit)
{
container.Init(s.ctx)
container.Req = req
container.Res = res
}
return container.Run()
}
// Play 用户活动数据
func (s *WCampaignUser) Play(req *pb.PlayReq, res *pb.PlayRes) (err error) {
defer s.checkErr()
*res = pb.PlayRes{}
container := new(containers.Play)
{
container.Init(s.ctx, logic.WithOnce(ckey.FissionUserPlayOnce(req.GetId())), logic.WithErrData(req))
container.Req = req
container.Res = res
}
return container.Run()
}
// RewardUser 中奖用户列表
func (s *WCampaignUser) RewardUser(req *pb.RewardUserReq, res *pb.RewardUserRes) (err error) {
defer s.checkErr()
*res = pb.RewardUserRes{}
container := new(containers.RewardUser)
{
container.Init(s.ctx)
container.Req = req
container.Res = res
}
return container.Run()
}
// Info 用户信息
func (s *WCampaignUser) Info(req *pb.InfoReq, res *pb.InfoRes) (err error) {
defer s.checkErr()
cpn, err := finder.Campaign(s.ctx, req.GetCampaignId(), req.GetCampaignHashId())
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, cpn.ID).FindBySubUserId(req.GetSubUserId())
if err != nil {
return s.BE().CacheError(err)
}
if user == nil {
err = workerr.NotFound("not found user")
return
}
var psuId string
if user.ParentID != 0 {
var parent *model.FissionUser
parent, err = finder.FissionUser(s.ctx, cpn.ID, user.ParentID)
if err != nil {
err = s.BE().CacheError(err)
return
}
psuId = parent.SubUserID
}
statM := s.GetDao().FissionUserStat
stat, err := statM.WithContext(s.ctx).Where(statM.UserID.Eq(user.ID)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
rewardM := s.GetDao().FissionRewardRecord.SubTable(cpn.ID)
list, err := rewardM.WithContext(s.ctx).Where(rewardM.UserID.Eq(user.ID), rewardM.Status.Eq(mtype.FissionRewardRecordStatusSuccess)).Find()
if err != nil {
return s.BE().MysqlError(err)
}
*res = pb.InfoRes{
SubUserId: user.SubUserID,
PsuId: psuId,
DirectNum: 0,
IndirectNum: 0,
Rewards: make([]*pb.InfoRes_Reward, 0, len(list)),
}
if stat != nil {
res.DirectNum = stat.DirectNum
res.IndirectNum = stat.IndirectNum
}
for _, v := range list {
res.Rewards = append(res.Rewards, &pb.InfoRes_Reward{
CreatedTime: v.CreatedAt,
Title: v.Title,
})
}
return
}
// Rank 排行榜
func (s *WCampaignUser) Rank(req *pb.RankReq, res *pb.RankRes) (err error) {
defer s.checkErr()
cpn, err := finder.Campaign(s.ctx, req.GetCampaignId(), req.GetCampaignHashId())
if err != nil {
return s.BE().CacheError(err)
}
if cpn == nil || cpn.IsDel == mtype.Yes {
err = workerr.NotFound("not found cpn")
return
}
conf, err := cache.NewCampaignConfig(s.ctx).FindByCampaignId(cpn.ID)
if err != nil {
return s.BE().CacheError(err)
}
m := s.GetDao().FissionUserStat
var order []field.Expr
var cond = []gen.Condition{
m.CampaignID.Eq(cpn.ID),
m.IsDel.Eq(mtype.No),
}
var t int32 = consts.FissionRankTypeSelfTask
switch cpn.FissionID {
case consts.IdSignIn:
t = consts.FissionRankTypeSign
order = append(order, m.SignNum.Desc(), m.SignRewardNum.Desc(), m.ID)
cond = append(cond, m.SignNum.Gt(0))
case consts.IdGrow:
t = consts.FissionRankTypeGrow
order = append(order, m.GrowNum.Desc(), m.GrowRewardNum.Desc(), m.ID)
cond = append(cond, m.GrowNum.Gt(0))
default:
switch conf.Option {
case mtype.FissionCampaignConfigTargetOptionApp:
t = utils.Ternary[int32](conf.AppEvent == mtype.FissionCampaignConfigTargetAppEventRegister, consts.FissionRankTypeRegister, consts.FissionRankTypeInstall)
case mtype.FissionCampaignConfigTargetOptionFriend:
t = consts.FissionRankTypeFriendTarget
}
if conf.Target == mtype.FissionCampaignConfigTargetUp || conf.Option == mtype.FissionCampaignConfigTargetOptionTask {
order = append(order, m.TargetNum.Desc(), m.IndirectTargetNum.Desc(), m.ID)
cond = append(cond, m.TargetNum.Gt(0))
} else {
order = append(order, m.EffectiveNum.Desc(), m.IndirectEffectiveNum.Desc(), m.ID)
cond = append(cond, m.EffectiveNum.Gt(0))
}
}
offset, limit := utils.PpDbLo(req.GetPage(), req.GetPerPage())
list, total, err := m.WithContext(s.ctx).Where(cond...).Order(order...).FindByPage(offset, limit)
if err != nil {
return s.BE().MysqlError(err)
}
*res = pb.RankRes{
List: make([]*pb.RankRes_One, 0, len(list)),
Total: total,
Type: t,
}
if total == 0 {
return
}
var userIds []int64
for _, v := range list {
userIds = append(userIds, v.UserID)
}
um := s.GetDao().FissionUser.SubTable(cpn.ID)
ul, err := um.WithContext(s.ctx).Where(um.ID.In(userIds...)).Find()
if err != nil {
return s.BE().MysqlError(err)
}
var uMap = make(map[int64]string)
for _, v := range ul {
uMap[v.ID] = v.UserMark
}
var condMap = make(map[int64][]*pb.RankRes_Cond)
if t == consts.FissionRankTypeSelfTask {
var userConds []*model.FissionUserCond
userCondM := s.GetDao().FissionUserCond
userConds, err = userCondM.WithContext(s.ctx).Where(userCondM.UserID.In(userIds...)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var userCondMap = make(map[int64]map[int64]int64)
for _, v := range userConds {
if _, ok := userCondMap[v.UserID]; !ok {
userCondMap[v.UserID] = map[int64]int64{v.CondID: v.Num}
} else {
userCondMap[v.UserID][v.CondID] = v.Num
}
}
var conds []*model.FissionCampaignCond
condM := s.GetDao().FissionCampaignCond
conds, err = condM.WithContext(s.ctx).Where(condM.CampaignID.Eq(cpn.ID)).
Where(
condM.WithContext(s.ctx).
Or(condM.IsDel.Eq(mtype.No)).
Or(condM.IsDel.Eq(mtype.Yes), condM.DelUse.Eq(mtype.Yes)),
).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
for _, id := range userIds {
for _, v := range conds {
one := &pb.RankRes_Cond{
Desc: v.Desc,
Num: 0,
}
if num, ok := userCondMap[id][v.ID]; ok {
one.Num = num
}
condMap[id] = append(condMap[id], one)
}
}
}
for _, v := range list {
one := &pb.RankRes_One{
SubUserId: uMap[v.UserID],
Conds: condMap[v.UserID],
}
switch cpn.FissionID {
case consts.IdSignIn:
one.DirectNum = v.SignRewardNum
one.IndirectNum = v.SignNum
case consts.IdGrow:
one.DirectNum = v.GrowNum
one.IndirectNum = v.GrowRewardNum
default:
if conf.Target == mtype.FissionCampaignConfigTargetUp || conf.Option == mtype.FissionCampaignConfigTargetOptionTask {
one.DirectNum = v.TargetNum
one.IndirectNum = v.IndirectTargetNum
} else {
one.DirectNum = v.EffectiveNum
one.IndirectNum = v.IndirectEffectiveNum
}
}
res.List = append(res.List, one)
}
return
}
// Lottery 活动抽奖
func (s *WCampaignUser) Lottery(req *pb.LotteryReq, res *pb.LotteryRes) (err error) {
defer s.checkErr()
*res = pb.LotteryRes{}
container := new(containers.Lottery)
{
container.Init(s.ctx, logic.WithOnce(ckey.FissionUserLotteryOnce(req.GetUserId())))
container.Req = req
container.Res = res
}
err = container.Run()
return
}
// Answer 活动答题
func (s *WCampaignUser) Answer(req *pb.AnswerReq, res *pb.AnswerRes) (err error) {
defer s.checkErr()
*res = pb.AnswerRes{}
container := new(containers.Answer)
{
container.Init(s.ctx, logic.WithOnce(ckey.FissionUserAnswerOnce(req.GetUserId())), logic.WithBp())
container.Req = req
container.Res = res
}
return container.Run()
}
// Vote 活动投票
func (s *WCampaignUser) Vote(req *pb.VoteReq, res *pb.VoteRes) (err error) {
defer s.checkErr()
*res = pb.VoteRes{}
container := new(containers.Vote)
{
container.Init(s.ctx, logic.WithOnce(ckey.FissionUserVoteOnce(req.GetUserId())))
container.Req = req
container.Res = res
}
return container.Run()
}
// Notify 客户端回调
func (s *WCampaignUser) Notify(req *pb.NotifyReq, res *pb.NotifyRes) (err error) {
defer s.checkErr()
*res = pb.NotifyRes{}
cpn, err := finder.Campaign(s.ctx, 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 := finder.FissionUser(s.ctx, cpn.ID, req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = workerr.NotFound("not found user")
return
}
m := s.GetDao().FissionRewardRecord.SubTable(cpn.ID)
record, err := m.WithContext(s.ctx).Where(m.UserID.Eq(user.ID), m.HashID.Eq(req.GetRewardHashId())).Take()
if err = dbcheck.DbError(err); err != nil {
return s.BE().MysqlError(err)
}
if record == nil {
return workerr.NotFound("reward not found")
}
// 不是待发送的就不用发送
if record.Status != mtype.FissionRewardRecordStatusWait {
return
}
_, err = m.WithContext(s.ctx).Where(m.ID.Eq(record.ID)).UpdateSimple(m.Status.Value(mtype.FissionRewardRecordStatusSuccess))
if err != nil {
return s.BE().MysqlError(err)
}
ntfM := s.GetDao().FissionNotify
ntf := withdefault.FissionNotify(&model.FissionNotify{
CampaignID: user.CampaignID,
RecordID: record.ID,
NotifyType: mtype.FissionNotifyTypeClient,
NotifyURL: "",
Token: "",
Body: req.GetBody(),
PushNum: record.RewardNum,
IsOk: mtype.Yes,
})
err = ntfM.WithContext(s.ctx).Create(ntf)
if err != nil {
return s.BE().MysqlError(err)
}
respM := s.GetDao().FissionNotifyResp
err = respM.WithContext(s.ctx).Create(withdefault.FissionNotifyResp(&model.FissionNotifyResp{
NotifyID: ntf.ID,
Resp: req.GetResp(),
}))
if err != nil {
return s.BE().MysqlError(err)
}
return
}
// AcceptReward 领取奖品
func (s *WCampaignUser) AcceptReward(req *pb.AcceptRewardReq, res *pb.AcceptRewardRes) (err error) {
defer s.checkErr()
*res = pb.AcceptRewardRes{}
cpn, err := finder.Campaign(s.ctx, 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
}
m := s.GetDao().FissionRewardRecord.SubTable(cpn.ID)
reward, err := m.WithContext(s.ctx).Where(m.HashID.Eq(req.GetRewardHashId()), m.CampaignID.Eq(cpn.ID)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if reward == nil {
err = workerr.NotFound("not found reward")
return
}
// 不是待发送的就不用发送
if reward.Status != mtype.FissionRewardRecordStatusWait {
return
}
userId, userRewardId := reward.UserID, reward.ID
// 没有回调就通知回调
producer.NewCampaignNotice(s.ctx).CampaignRewardNotify(types.CampaignRewardNotify{
CampaignId: cpn.ID,
UserId: userId,
UserRewardId: userRewardId,
})
return
}
// TargetRule 达标规则
func (s *WCampaignUser) TargetRule(req *pb.TargetRuleReq, res *pb.TargetRuleRes) (err error) {
defer s.checkErr()
m := s.GetDao().FissionUser.SubTable(req.GetCampaignId())
offset, limit := utils.PpDbLo(req.GetPage(), req.GetPerPage())
list, total, err := m.WithContext(s.ctx).Where(
m.CampaignID.Eq(req.GetCampaignId()),
m.ParentID.Eq(req.GetUserId()),
m.ParentID.Gt(0),
).FindByPage(offset, limit)
if err != nil {
return s.BE().MysqlError(err)
}
if total == 0 {
return
}
var userIds []int64
var userCondMap = make(map[int64]map[int64]int64)
for _, v := range list {
if _, ok := userCondMap[v.ID]; !ok {
userIds = append(userIds, v.ID)
userCondMap[v.ID] = map[int64]int64{}
}
}
userCondM := s.GetDao().FissionUserCond
userConds, err := userCondM.WithContext(s.ctx).Where(userCondM.UserID.In(userIds...)).Find()
if err != nil {
return s.BE().MysqlError(err)
}
for _, v := range userConds {
userCondMap[v.UserID][v.CondID] = v.Num
}
statM := s.GetDao().FissionUserStat
stat, err := statM.WithContext(s.ctx).Where(statM.UserID.Eq(req.GetUserId())).Take()
if err = dbcheck.DbError(err); err != nil {
return s.BE().MysqlError(err)
}
*res = pb.TargetRuleRes{
List: make([]*pb.TargetRuleRes_One, 0, len(list)),
Total: total,
TargetNum: 0,
}
if stat != nil {
var cpn *model.FissionCampaign
cpn, err = finder.Campaign(s.ctx, req.GetCampaignId())
if err != nil {
err = s.BE().CacheError(err)
return
}
switch cpn.FissionID {
case consts.IdReferral, consts.IdWinTogether:
res.TargetNum = stat.EffectiveNum
default:
res.TargetNum = stat.TargetNum
}
}
condM := s.GetDao().FissionCampaignCond
conds, err := condM.WithContext(s.ctx).Where(condM.CampaignID.Eq(req.GetCampaignId())).Find()
if err != nil {
return s.BE().MysqlError(err)
}
for _, v := range list {
one := &pb.TargetRuleRes_One{
SubUserId: utils.Ternary(v.SubUserID == "", v.DeviceID, v.SubUserID),
Cond: make([]*pb.TargetRuleRes_Cond, 0, len(conds)),
}
for _, cond := range conds {
one.Cond = append(one.Cond, &pb.TargetRuleRes_Cond{
Desc: cond.Desc,
Num: userCondMap[v.ID][cond.ID],
CondId: cond.ID,
})
}
res.List = append(res.List, one)
}
return
}
// Task 我的任务
func (s *WCampaignUser) Task(req *pb.TaskReq, res *pb.TaskRes) (err error) {
defer s.checkErr()
*res = pb.TaskRes{}
container := new(containers.Task)
{
container.Init(s.ctx)
container.Req = req
container.Res = res
}
return container.Run()
}
// Resend 补发奖品
func (s *WCampaignUser) Resend(req *pb.ResendReq, res *pb.ResendRes) (err error) {
defer s.checkErr()
lc := app.NewRedisLock(s.ctx, ckey.FissionRewardResendOnce(req.GetRewardHashId()), lock.SetExpire(20*time.Second))
if !lc.SoftLock() {
return workerr.BusyError
}
defer lc.Release()
cpn, err := finder.Campaign(s.ctx, req.GetCampaignHashId())
if err != nil {
return s.BE().CacheError(err)
}
m := s.GetDao().FissionRewardRecord.SubTable(cpn.ID)
record, err := m.WithContext(s.ctx).Where(m.HashID.Eq(req.GetRewardHashId())).Take()
if err = dbcheck.DbError(err); err != nil {
return s.BE().MysqlError(err)
}
if record == nil {
return workerr.NotFound("not found record")
}
if record.Status != mtype.FissionRewardRecordStatusFail {
switch record.Status {
case mtype.FissionRewardRecordStatusWait:
if record.CreatedAt+consts.DaySec > time.Now().Unix() {
return s.BE().VerifyError("can not resend")
}
default:
return s.BE().VerifyError("can not resend")
}
}
reward, err := cache.NewReward(s.ctx).FindById(record.BaseRewardID)
if err != nil {
return s.BE().CacheError(err)
}
if reward == nil || reward.ReceiveType != mtype.RewardReceiveTypeNotify {
return
}
url, err := cache.NewNotifyURL(s.ctx).FindById(reward.URLID)
if err != nil {
return
}
user, err := finder.FissionUser(s.ctx, cpn.ID, record.UserID)
if err != nil {
return s.BE().CacheError(err)
}
var parentSubUserId string
if user.ParentID > 0 {
var parent *model.FissionUser
parent, err = finder.FissionUser(s.ctx, cpn.ID, user.ParentID)
if err != nil {
return s.BE().CacheError(err)
}
parentSubUserId = parent.SubUserID
}
project, err := finder.Project(s.ctx, cpn.ProjectID)
if err != nil {
return s.BE().CacheError(err)
}
_ = notify.Reward{
CampaignId: record.CampaignID,
RewardId: record.ID,
UserId: user.ID,
ParentId: user.ParentID,
CampaignHashId: cpn.HashID,
RewardHashId: record.HashID,
KvData: reward.GetJustKvData(),
RewardType: record.RewardType,
RewardTitle: record.Title,
RewardNum: record.RewardNum,
SubUserId: user.SubUserID,
ParentSubUserId: parentSubUserId,
Lang: utils.STernary[string](user.UserLang, "", user.LangMark),
Title: cpn.Title,
MallRecordId: record.MallRecordID,
}.Send(s.ctx, url.URL, project.NotifyToken, project.PushLadder, url.GetHeaders())
record, err = m.WithContext(s.ctx).Where(m.HashID.Eq(req.GetRewardHashId())).Take()
if err = dbcheck.DbError(err); err != nil {
return s.BE().MysqlError(err)
}
*res = pb.ResendRes{
Status: int32(record.Status),
FailType: record.FailType,
FailMsg: record.FailMsg,
}
return
}
// DynamicLink 获取用户动态链接
func (s *WCampaignUser) DynamicLink(req *pb.DynamicLinkReq, res *pb.DynamicLinkRes) (err error) {
defer s.checkErr()
*res = pb.DynamicLinkRes{}
container := new(containers.DynamicLink)
{
container.Init(s.ctx)
container.Req = req
container.Res = res
}
return container.Run()
}
// DylinkShow 获取用户动态链接详情
func (s *WCampaignUser) DylinkShow(req *pb.DylinkShowReq, res *pb.DylinkShowRes) (err error) {
defer s.checkErr()
m := s.GetDao().FissionUserDylink
lk, err := m.WithContext(s.ctx).Where(m.HashID.Eq(req.GetHashId())).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
params := lk.GetParams()
*res = pb.DylinkShowRes{
MediaType: params.MediaType,
ImageText: nil,
}
switch params.MediaType {
case mtype.FissionUserDyLinkMediaTypeImgText:
for _, text := range params.ImageText {
res.ImageText = append(res.ImageText, &pb.DylinkShowRes_ImageText{
NickName: text.NickName,
Avatar: text.Avatar,
Title: text.Title,
Desc: text.Desc,
Image: text.Image,
})
}
}
return
}
// SignIn 我的签到板
func (s *WCampaignUser) SignIn(req *pb.SignInReq, res *pb.SignInRes) (err error) {
defer s.checkErr()
*res = pb.SignInRes{}
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = workerr.NotFound("not found user")
return
}
player, err := players.NewSign(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
playerData, err := player.SignBoard(req.GetPageType(), req.GetNowMouth())
if err != nil {
return
}
*res = pb.SignInRes{
SignDate: make([]*pb.SignInRes_SignDate, 0, len(playerData.SignDate)),
NowMouth: playerData.NowMouth,
CycleDate: make([]*pb.SignInRes_CycleDate, 0, len(playerData.CycleDate)),
}
for _, v := range playerData.SignDate {
res.SignDate = append(res.SignDate, &pb.SignInRes_SignDate{
Y: v.Y,
M: v.M,
D: v.D,
SignIn: v.SignIn,
Ban: v.Ban,
RewardId: v.RewardId,
Open: v.Open,
NowWeek: v.NowWeek,
NowDay: v.NowDay,
LastMiss: v.LastMiss,
NowMouth: v.NowMouth,
})
}
for _, v := range playerData.CycleDate {
res.CycleDate = append(res.CycleDate, &pb.SignInRes_CycleDate{
SignTime: v.SignTime,
SignIn: v.SignIn,
NowDay: v.NowDay,
RewardId: v.RewardId,
RewardImg: v.RewardImg,
RewardTitle: v.RewardTitle,
IsSuper: v.IsSuper,
Y: v.Y,
M: v.M,
D: v.D,
})
}
return
}
// Sign 签到
func (s *WCampaignUser) Sign(req *pb.SignReq, res *pb.SignRes) (err error) {
defer s.checkErr()
lc := app.NewRedisLock(s.ctx, ckey.FissionUserSignOnce(req.GetUserId()))
defer lc.Release()
if !lc.SoftLock() {
err = workerr.OnceLockError
return
}
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil {
return
}
sign, err := players.NewSign(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
status, reward, err := sign.SignIn(req.GetSignDate())
if err != nil {
return
}
*res = pb.SignRes{
FailType: status,
}
if reward != nil {
*res = pb.SignRes{
FailType: status,
HasReward: true,
RewardTitle: reward.RewardTitle,
RewardNum: reward.RewardNum,
ImgUrl: reward.ImgUrl,
RewardId: reward.RewardId,
ReceiveType: reward.ReceiveType,
KvData: make([]*pb.SignRes_KV, 0, len(reward.KvData)),
Contact: reward.Contact,
}
for _, v := range reward.KvData {
res.KvData = append(res.KvData, &pb.SignRes_KV{
Key: v.Key,
Value: v.Value,
})
}
}
return
}
// DiceMap 大富翁地图
func (s *WCampaignUser) DiceMap(req *pb.DiceMapReq, res *pb.DiceMapRes) (err error) {
defer s.checkErr()
cpn, err := finder.Campaign(s.ctx, req.GetCampaignId())
if err != nil {
err = s.BE().CacheError(err)
return
}
user, err := finder.FissionUser(s.ctx, cpn.ID, req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = workerr.NotFound("please login")
return
}
dice, err := players.NewDice(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
maps, err := dice.DiceMap(req.GetMapHashId(), req.GetGoShowStep(), req.GetPrefixStep())
if err != nil {
return
}
*res = pb.DiceMapRes{
List: make([]*pb.DiceMapRes_One, 0, len(maps)),
}
for _, v := range maps {
res.List = append(res.List, &pb.DiceMapRes_One{
MapHashId: v.MapHashId,
MarkType: v.MarkType,
RewardTitle: v.RewardTitle,
ImgUrl: v.ImgUrl,
RewardId: v.RewardId,
})
}
return
}
// Dice 大富翁骰子
func (s *WCampaignUser) Dice(req *pb.DiceReq, res *pb.DiceRes) (err error) {
defer s.checkErr()
lc := app.NewRedisLock(s.ctx, ckey.FissionDiceOnce(req.GetUserId()))
defer lc.Release()
if !lc.SoftLock() {
return workerr.OnceLockError
}
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil {
return
}
dice, err := players.NewDice(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
var rollRes players.RollRes
switch req.GetMark() {
case mtype.FissionDicePropMarkFixedRoll:
rollRes, err = dice.FixRoll(req.GetVal())
if err != nil {
return
}
default:
rollRes, err = dice.Roll()
if err != nil {
return
}
}
*res = pb.DiceRes{
FailType: rollRes.FailType,
MapHashId: rollRes.MapHashId,
RollNum: rollRes.RollNum,
MarkType: rollRes.MarkType,
RewardTitle: rollRes.RewardTitle,
ImgUrl: rollRes.ImgUrl,
IsIntact: rollRes.IsIntact,
Lack: rollRes.Lack,
RewardId: rollRes.RewardId,
}
return
}
// Grow 成长生命体
func (s *WCampaignUser) Grow(req *pb.GrowReq, res *pb.GrowRes) (err error) {
defer s.checkErr()
lifeM := s.GetDao().FissionGrowLife
life, err := lifeM.WithContext(s.ctx).Where(lifeM.UserID.Eq(req.GetUserId()), lifeM.IsGrow.Eq(mtype.Yes)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if life == nil {
*res = pb.GrowRes{
GetGrow: true,
}
return
}
cpn, err := cache.NewCampaign(s.ctx).FindById(req.GetCampaignId())
if err != nil {
err = s.BE().CacheError(err)
return
}
tz := provider.NewCampaignTZ(s.ctx, cpn, req.GetLangMark())
now, die := timez.GMTTime(tz.GetTz()), timez.GMTTime(tz.GetTz(), life.DieTime)
if life.IsDie == mtype.No && die.Before(now) {
err = cmm.NewCMM(s.ctx, s.GetDao()).LifeStatus(life, true, 0)
if err != nil {
return
}
life.IsDie = mtype.Yes
}
*res = pb.GrowRes{
GetGrow: false,
Title: life.Title,
Step: life.Step,
Num: life.Num,
WillDie: die.Before(now.AddDate(0, 0, 1)),
IsDie: life.IsDie == mtype.Yes,
MaxLv: false,
RewardTitle: "",
RewardUrl: "",
RewardId: 0,
}
stepM := s.GetDao().FissionCampaignGrowStep
step, err := stepM.WithContext(s.ctx).Where(stepM.CampaignID.Eq(life.CampaignID), stepM.Step.Eq(life.Step+1), stepM.IsDel.Eq(mtype.No)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if step != nil {
res.LvUpNum = step.Num
res.DiffP = utils.PercentNoZero(life.Num, step.Num)
return
}
recordM := s.GetDao().FissionRewardRecord.SubTable(cpn.ID)
record, err := recordM.WithContext(s.ctx).Where(
recordM.ID.Eq(life.RecordID),
).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if record == nil {
return
}
if record.FailType == mtype.FissionRewardRecordFailTypeCli && record.FailMsg == mtype.FissionRewardRecordFailTypeCliLackMsg {
res.Lack = true
}
res.WillDie = false
res.IsDie = false
res.MaxLv = true
res.RewardTitle = record.Title
res.RewardUrl = record.ImgURL
res.RewardId = record.RewardID
return
}
// GetGrow 领养生命体
func (s *WCampaignUser) GetGrow(req *pb.GetGrowReq, res *pb.GetGrowRes) (err error) {
defer s.checkErr()
playerM := s.GetDao().FissionGrow
player, err := playerM.WithContext(s.ctx).Where(playerM.UserID.Eq(req.GetUserId())).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if player == nil {
err = workerr.NotFound("not found player")
return
}
lifeM := s.GetDao().FissionGrowLife
growing, err := lifeM.WithContext(s.ctx).Where(lifeM.UserID.Eq(player.UserID), lifeM.IsGrow.Eq(mtype.Yes)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
// 没有死亡,没有到最高等级,不重新领取
if growing != nil && growing.IsDie == mtype.No && growing.RecordID == 0 {
return
}
confM := s.GetDao().FissionCampaignGrow
conf, err := confM.WithContext(s.ctx).Where(confM.CampaignID.Eq(player.CampaignID)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if conf == nil {
err = workerr.NotFound("not found grow conf")
return
}
rewardM := s.GetDao().FissionCampaignReward
reward, err := rewardM.WithContext(s.ctx).Where(
rewardM.CampaignID.Eq(player.CampaignID),
rewardM.RewardType.Eq(mtype.FissionCampaignRewardTypeApp),
rewardM.IsDel.Eq(mtype.No),
).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if reward == nil {
return
}
defer func() {
if err != nil {
return
}
cpn, _ := cache.NewCampaign(s.ctx).FindById(player.CampaignID)
if cpn != nil && cpn.ReportType == mtype.FissionCampaignReportTypeNew {
user, _ := cache.NewFissionUser(s.ctx, cpn.ID).FindById(player.UserID)
fissionaction.NewMarkPoint(s.ctx).InApp(user).Grow(time.Now().Unix(), reward.ID)
}
}()
lc := app.NewRedisLock(s.ctx, ckey.FissionGrowGetOnce(req.GetUserId()))
defer lc.Release()
if !lc.SoftLock() {
return
}
tx := s.GetDao().Begin()
defer func() {
if err != nil {
_ = tx.Rollback()
return
}
_ = tx.Commit()
}()
lifeTx := tx.FissionGrowLife
_, err = lifeTx.WithContext(s.ctx).Where(lifeTx.UserID.Eq(player.UserID), lifeTx.IsGrow.Eq(mtype.Yes)).UpdateSimple(lifeTx.IsGrow.Value(mtype.No))
if err != nil {
err = s.BE().MysqlError(err)
return
}
err = lifeTx.WithContext(s.ctx).Create(withdefault.FissionGrowLife(&model.FissionGrowLife{
UserID: player.UserID,
CampaignID: player.CampaignID,
Title: req.GetTitle(),
Num: 0,
Step: 0,
DieTime: carbon.Now().AddHours(int(conf.DieHour)).Timestamp(),
IsGrow: mtype.Yes,
RewardID: reward.ID,
}))
if err != nil {
err = s.BE().MysqlError(err)
return
}
recordM := tx.FissionGrowRecord
err = recordM.WithContext(s.ctx).Create(withdefault.FissionGrowRecord(&model.FissionGrowRecord{
UserID: player.UserID,
CampaignID: player.CampaignID,
Mark: mtype.FissionGrowRecordGetGrow,
VarData: "",
}))
if err != nil {
err = s.BE().MysqlError(err)
return
}
statTx := tx.FissionUserStat
_, err = statTx.WithContext(s.ctx).Where(statTx.UserID.Eq(player.UserID)).UpdateSimple(statTx.GrowNum.Add(1))
if err != nil {
err = s.BE().MysqlError(err)
return
}
*res = pb.GetGrowRes{}
return
}
// Feed 饲养生命体
func (s *WCampaignUser) Feed(req *pb.FeedReq, res *pb.FeedRes) (err error) {
defer s.checkErr()
*res = pb.FeedRes{}
container := new(containers.Feed)
{
container.Init(s.ctx, logic.WithOnce(ckey.FissionGrowFeedOnce(req.GetUserId())), logic.WithTran())
container.Req = req
container.Res = res
}
return container.Run()
}
// GetFeed 领取饲养道具
func (s *WCampaignUser) GetFeed(req *pb.GetFeedReq, res *pb.GetFeedRes) (err error) {
defer s.checkErr()
*res = pb.GetFeedRes{}
lc := app.NewRedisLock(s.ctx, ckey.FissionGrowGetFeedOnce(req.GetUserId(), req.GetMark()))
defer lc.Release()
if !lc.SoftLock() {
return
}
playerM := s.GetDao().FissionGrow
player, err := playerM.WithContext(s.ctx).Where(playerM.UserID.Eq(req.GetUserId())).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if player == nil {
err = workerr.NotFound("not found player")
return
}
confM := s.GetDao().FissionCampaignGrow
conf, err := confM.WithContext(s.ctx).Where(confM.CampaignID.Eq(player.CampaignID)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if conf == nil {
err = workerr.NotFound("not found grow conf")
return
}
if req.GetMark() != "auto" {
return
}
now := carbon.Now()
next := carbon.CreateFromTimestamp(player.PropsTime)
if next.Gt(now) {
return
}
_, err = playerM.WithContext(s.ctx).Where(playerM.ID.Eq(player.ID)).UpdateSimple(
playerM.GrowNum.Add(conf.AutoNum),
playerM.AutoNum.Add(conf.AutoNum),
playerM.PropsTime.Value(now.AddHours(int(conf.AutoHour)).Timestamp()),
)
if err != nil {
err = s.BE().MysqlError(err)
return
}
return
}
// GrowRecord 成长记录
func (s *WCampaignUser) GrowRecord(req *pb.GrowRecordReq, res *pb.GrowRecordRes) (err error) {
defer s.checkErr()
cpn, err := cache.NewCampaign(s.ctx).FindById(req.GetCampaignId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if cpn == nil || cpn.FissionID != consts.IdGrow {
return
}
user, err := finder.FissionUser(s.ctx, cpn.ID, req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
return
}
tz := provider.NewCampaignTZ(s.ctx, cpn, user.LangMark)
var date = carbon.Now().Timestamp()
if req.GetDate() != "" {
date = timez.GMTCarbon(tz.GetTz()).Parse(req.GetDate()).StartOfDay().Timestamp()
}
recordM := s.GetDao().FissionGrowRecord
records, err := recordM.WithContext(s.ctx).Where(
recordM.UserID.Eq(req.GetUserId()),
recordM.CreatedAt.Lt(date),
).Limit(20).Order(recordM.CreatedAt.Desc(), recordM.ID.Desc()).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
l := len(records)
if l == 0 {
return
}
type DateGroup struct {
idx int
data []*pb.GrowRecordRes_Record
}
var lastRecord *model.FissionGrowRecord
var idx int
var dateMap = make(map[string]*DateGroup)
for i, v := range records {
ct := timez.GMTCarbon(tz.GetTz()).CreateFromTimestamp(v.CreatedAt)
sd := ct.Format(consts.Ymd_)
d := &pb.GrowRecordRes_Record{
Mark: v.Mark,
His: ct.Format(consts.His_),
VarData: nil,
}
for _, kv := range v.GetVarData() {
d.VarData = append(d.VarData, &pb.GrowRecordRes_KV{
Key: kv.Key,
Value: kv.Value,
IdMark: kv.IdMark,
})
}
_, ok := dateMap[sd]
if !ok {
dateMap[sd] = &DateGroup{
idx: idx,
data: []*pb.GrowRecordRes_Record{d},
}
idx++
} else {
dateMap[sd].data = append(dateMap[sd].data, d)
}
if i == l-1 {
lastRecord = v
}
}
if lastRecord == nil {
return
}
var ld = timez.GMTCarbon(tz.GetTz()).CreateFromTimestamp(lastRecord.CreatedAt)
sd := ld.Format(consts.Ymd_)
var list []*model.FissionGrowRecord
list, err = recordM.WithContext(s.ctx).Where(
recordM.UserID.Eq(req.GetUserId()),
recordM.ID.Lt(lastRecord.ID),
recordM.CreatedAt.Lte(ld.EndOfDay().Timestamp()),
).Order(recordM.CreatedAt.Desc()).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
for _, v := range list {
ct := timez.GMTCarbon(tz.GetTz()).CreateFromTimestamp(v.CreatedAt)
d := &pb.GrowRecordRes_Record{
Mark: v.Mark,
His: ct.Format(consts.His_),
VarData: nil,
}
for _, kv := range v.GetVarData() {
d.VarData = append(d.VarData, &pb.GrowRecordRes_KV{
Key: kv.Key,
Value: kv.Value,
IdMark: kv.IdMark,
})
}
dateMap[sd].data = append(dateMap[sd].data, d)
}
*res = pb.GrowRecordRes{
List: make([]*pb.GrowRecordRes_One, len(dateMap)),
}
for d, v := range dateMap {
res.List[v.idx] = &pb.GrowRecordRes_One{
Date: d,
Records: v.data,
}
}
return
}
// ContentLink 内容链接
func (s *WCampaignUser) ContentLink(req *pb.ContentLinkReq, res *pb.ContentLinkRes) (err error) {
defer s.checkErr()
cpn, err := cache.NewCampaign(s.ctx).FindById(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 := finder.FissionUser(s.ctx, cpn.ID, req.GetUserId())
if err != nil {
err = s.be.CacheError(err)
return
}
ct, err := cmm.NewCMM(s.ctx, s.dao).CreateContentLink(user, req.GetMarkId(), req.GetMark())
if err != nil {
return
}
if ct.LinkURL != "" && user.ShareLink != ct.LinkURL {
userM := s.dao.FissionUser
_, err = userM.WithContext(s.ctx).Where(userM.ID.Eq(user.ID)).UpdateSimple(userM.ShareLink.Value(ct.LinkURL))
if err != nil {
err = s.be.MysqlError(err)
return
}
userMs := s.dao.FissionUser.SubTable(user.CampaignID)
_, err = userMs.WithContext(s.ctx).Where(userMs.ID.Eq(user.ID)).UpdateSimple(userMs.ShareLink.Value(ct.LinkURL))
if err != nil {
err = s.be.MysqlError(err)
return
}
_ = cache.NewFissionUser(s.ctx, user.CampaignID).Clear(user)
}
*res = pb.ContentLinkRes{
LinkUrl: ct.LinkURL,
}
return
}
// LinkContent 链接内容
func (s *WCampaignUser) LinkContent(req *pb.LinkContentReq, res *pb.LinkContentRes) (err error) {
defer s.checkErr()
m := s.GetDao().FissionUserCtlink
ct, err := m.WithContext(s.ctx).Where(m.HashID.Eq(req.GetCtId())).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if ct == nil {
return
}
user, err := finder.FissionUser(s.ctx, ct.CampaignID, ct.UserID)
if err != nil {
err = s.be.CacheError(err)
return
}
cpn, err := cache.NewCampaign(s.ctx).FindById(ct.CampaignID)
if err != nil {
err = s.be.CacheError(err)
return
}
*res = pb.LinkContentRes{
Mark: ct.Mark,
}
switch ct.Mark {
case mtype.FissionUserCtLinkMarkQa:
qam := s.GetDao().LibraryQa
var qa *model.LibraryQa
qa, err = qam.WithContext(s.ctx).Where(qam.ID.Eq(ct.MarkID)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if qa == nil {
res.Qa = &pb.LinkContentRes_Qa{HomeShare: true}
return
}
optionM := s.GetDao().LibraryQaOption
var options []*model.LibraryQaOption
options, err = optionM.WithContext(s.ctx).Where(optionM.QaID.Eq(qa.ID), optionM.IsDel.Eq(mtype.No)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
res.Qa = &pb.LinkContentRes_Qa{
Id: qa.ID,
HashId: qa.HashID,
Mark: qa.Mark,
Title: qa.Title,
CoverUrl: qa.CoverURL,
LinkUrl: qa.LinkURL,
Options: make([]*pb.LinkContentRes_Option, 0, len(options)),
AnswerMark: qa.AnswerMark,
}
for _, v := range options {
res.Qa.Options = append(res.Qa.Options, &pb.LinkContentRes_Option{
Id: v.ID,
Title: v.Title,
ImgUrl: v.ImgURL,
})
}
return
case mtype.FissionUserCtLinkMarkBallot:
rewardM := s.GetDao().FissionCampaignReward
var reward *model.FissionCampaignReward
reward, err = rewardM.WithContext(s.ctx).Where(rewardM.ID.Eq(ct.MarkID)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if reward == nil {
return
}
preward, _ := provider.NewRewards(s.ctx, cpn.ProjectID, reward.RewardID)
info := preward.AutoLang(reward.RewardID, user.LangMark)
res.Ballot = &pb.LinkContentRes_Ballot{
Id: reward.ID,
Title: info.Title,
ImgUrl: info.ImgUrl,
}
return
case mtype.FissionUserCtLinkMarkChop:
rewardM := s.GetDao().FissionCampaignReward
var rewards []*model.FissionCampaignReward
rewards, err = rewardM.WithContext(s.ctx).Where(rewardM.CampaignID.Eq(ct.CampaignID), rewardM.IsDel.Eq(mtype.No)).Find()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
res.Chop = &pb.LinkContentRes_Chop{
Rewards: make([]*pb.LinkContentRes_ChopReward, 0, len(rewards)),
}
var bids []int64
for _, v := range rewards {
bids = append(bids, v.RewardID)
}
preward, _ := provider.NewRewards(s.ctx, cpn.ProjectID, bids...)
for _, v := range rewards {
info := preward.AutoLang(v.RewardID, user.LangMark)
res.Chop.Rewards = append(res.Chop.Rewards, &pb.LinkContentRes_ChopReward{
Title: info.Title,
ImgUrl: info.ImgUrl,
Selected: v.ID == ct.MarkID,
Id: v.ID,
})
}
return
}
return
}
// ChopSelect 选择砍一刀奖品
func (s *WCampaignUser) ChopSelect(req *pb.ChopSelectReq, res *pb.ChopSelectRes) (err error) {
defer s.checkErr()
user, err := finder.FissionUser(s.ctx, req.GetCampaignId(), req.GetUserId())
if err != nil {
err = s.be.CacheError(err)
return
}
chop, err := players.NewChop(s.ctx, user)
if err != nil {
return
}
err = chop.SelectReward(req.GetRewardId())
if err != nil {
return
}
*res = pb.ChopSelectRes{}
return
}
// ChopReselect 重选砍一刀奖品
func (s *WCampaignUser) ChopReselect(req *pb.ChopReselectReq, res *pb.ChopReselectRes) (err error) {
defer s.checkErr()
user, err := finder.FissionUser(s.ctx, req.GetCampaignId(), req.GetUserId())
if err != nil {
err = s.be.CacheError(err)
return
}
chop, err := players.NewChop(s.ctx, user)
if err != nil {
return
}
err = chop.Reselect()
if err != nil {
return
}
canSelect, err := chop.ExistSelectReward()
if err != nil {
return
}
*res = pb.ChopReselectRes{
RewardNone: !canSelect,
}
return
}
// ChopHelp 砍一刀助力记录
func (s *WCampaignUser) ChopHelp(req *pb.ChopHelpReq, res *pb.ChopHelpRes) (err error) {
defer s.checkErr()
playerM := s.GetDao().FissionChop
player, err := playerM.WithContext(s.ctx).Where(playerM.UserID.Eq(req.GetUserId())).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if player == nil {
err = workerr.NotFound("not found player")
return
}
if player.ChopRewardID == 0 {
return
}
m := s.GetDao().FissionChopHelp
var cond = []gen.Condition{
m.UserID.Eq(player.UserID),
m.ChopRewardID.Eq(player.ChopRewardID),
}
offset, limit := utils.PpDbLo(req.GetPage(), req.GetPerPage())
list, total, err := m.WithContext(s.ctx).Where(cond...).Order(m.ID.Desc()).FindByPage(offset, limit)
if err != nil {
return s.BE().MysqlError(err)
}
*res = pb.ChopHelpRes{
List: make([]*pb.ChopHelpRes_One, 0, len(list)),
Total: total,
}
if total == 0 {
return
}
for _, v := range list {
res.List = append(res.List, &pb.ChopHelpRes_One{
Id: v.ID,
Mark: v.Mark,
Percent: v.Percent,
CreatedTime: v.CreatedAt,
})
}
return
}
// LevelList 用户等级列表
func (s *WCampaignUser) LevelList(req *pb.LevelListReq, res *pb.LevelListRes) (err error) {
defer s.checkErr()
project, err := finder.Project(s.ctx, req.GetProjectHashId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if project == nil {
return
}
m := s.GetDao().FissionUserLevel
list, err := m.WithContext(s.ctx).Where(m.ProjectID.Eq(project.ID), m.DeletedAt.Eq(0)).Order(m.ID).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
*res = pb.LevelListRes{
List: make([]*pb.LevelListRes_One, 0, len(list)),
}
var ids []int64
for _, v := range list {
ids = append(ids, v.ID)
}
type Num struct {
LevelId int64
Num int64
}
var num []*Num
relateM := s.GetDao().FissionUserLevelRelated
err = relateM.WithContext(s.ctx).
Select(relateM.LevelID, relateM.ID.Count().As("num")).
Where(relateM.LevelID.In(ids...), relateM.CancelTime.Eq(0)).
Group(relateM.LevelID).
Scan(&num)
if err != nil {
err = s.BE().MysqlError(err)
return
}
var numMap = map[int64]int64{}
for _, v := range num {
numMap[v.LevelId] = v.Num
}
for _, v := range list {
res.List = append(res.List, &pb.LevelListRes_One{
Id: v.ID,
Title: v.Title,
Mark: v.Mark,
CreatedAt: v.CreatedAt,
Num: numMap[v.ID],
})
}
return
}
// LevelStore 创建用户等级
func (s *WCampaignUser) LevelStore(req *pb.LevelStoreReq, res *pb.LevelStoreRes) (err error) {
defer s.checkErr()
project, err := finder.Project(s.ctx, req.GetProjectHashId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if project == nil {
err = workerr.NotFound("not found project")
return
}
lc := app.NewRedisLock(s.ctx, ckey.FissionUserLevelOperateOnce(project.ID, req.GetMark())).Lock()
defer lc.Release()
if lc.Error() != nil {
err = workerr.BusyError
return
}
m := s.GetDao().FissionUserLevel
exist, err := m.WithContext(s.ctx).Where(m.ProjectID.Eq(project.ID), m.Mark.Eq(req.GetMark()), m.DeletedAt.Eq(0)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if exist != nil {
err = s.BE().VerifyError("level exist")
return
}
err = m.WithContext(s.ctx).Create(withdefault.FissionUserLevel(&model.FissionUserLevel{
ProjectID: project.ID,
Mark: req.GetMark(),
Title: req.GetTitle(),
}))
if err != nil {
err = s.BE().MysqlError(err)
return
}
*res = pb.LevelStoreRes{}
return
}
// LevelEdit 更新用户等级
func (s *WCampaignUser) LevelEdit(req *pb.LevelEditReq, res *pb.LevelEditRes) (err error) {
defer s.checkErr()
m := s.GetDao().FissionUserLevel
c := cache.NewFissionUserLevel(s.ctx)
lv, err := c.FindById(req.GetId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if lv == nil || lv.DeletedAt > 0 {
err = workerr.NotFound("not found user level")
return
}
lc := app.NewRedisLock(s.ctx, ckey.FissionUserLevelOperateOnce(lv.ProjectID, req.GetMark())).Lock()
defer lc.Release()
if lc.Error() != nil {
err = workerr.BusyError
return
}
exist, err := m.WithContext(s.ctx).Where(m.ProjectID.Eq(lv.ProjectID), m.Mark.Eq(req.GetMark()), m.DeletedAt.Eq(0), m.ID.Neq(lv.ID)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if exist != nil {
err = s.BE().VerifyError("level exist")
return
}
_, err = m.WithContext(s.ctx).Where(m.ID.Eq(lv.ID)).UpdateSimple(m.Title.Value(req.GetTitle()), m.Mark.Value(req.GetMark()))
if err != nil {
err = s.BE().MysqlError(err)
return
}
_ = c.Clear(lv)
*res = pb.LevelEditRes{}
return
}
// LevelDestroy 删除用户等级
func (s *WCampaignUser) LevelDestroy(req *pb.LevelDestroyReq, res *pb.LevelDestroyRes) (err error) {
defer s.checkErr()
m := s.GetDao().FissionUserLevel
c := cache.NewFissionUserLevel(s.ctx)
lv, err := c.FindById(req.GetId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if lv == nil || lv.DeletedAt > 0 {
return
}
_, err = m.WithContext(s.ctx).Where(m.ID.Eq(lv.ID)).UpdateSimple(m.DeletedAt.Value(time.Now().Unix()))
if err != nil {
err = s.BE().MysqlError(err)
return
}
_ = c.Clear(lv)
*res = pb.LevelDestroyRes{}
return
}
// ProjectList 项目参与用户列表
func (s *WCampaignUser) ProjectList(req *pb.ProjectListReq, res *pb.ProjectListRes) (err error) {
defer s.checkErr()
project, err := finder.Project(s.ctx, req.GetProjectHashId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if project == nil || project.IsDel == mtype.Yes {
return
}
m := s.GetDao().FissionCampaign
list, err := m.WithContext(s.ctx).Where(m.ProjectID.Eq(project.ID), m.IsDel.Eq(mtype.No)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
if len(list) == 0 {
return
}
var cpnMap = make(map[int64]*model.FissionCampaign)
var ids []int64
for _, v := range list {
cpnMap[v.ID] = v
ids = append(ids, v.ID)
}
userM := s.GetDao().FissionUser
var cond = []gen.Condition{
userM.IsDel.Eq(mtype.No),
userM.IsView.Eq(mtype.No),
userM.CampaignID.In(ids...),
userM.SubUserID.Neq(""),
}
if req.GetStart() > 0 {
cond = append(cond, userM.CreatedAt.Gte(req.GetStart()))
}
if req.GetEnd() > 0 {
cond = append(cond, userM.CreatedAt.Lte(req.GetEnd()))
}
offset, limit := utils.PpDbLo(req.GetPage(), req.GetPerPage())
userList, total, err := userM.WithContext(s.ctx).Where(cond...).Order(userM.ID).FindByPage(offset, limit)
if err != nil {
return s.BE().MysqlError(err)
}
if total == 0 {
return
}
*res = pb.ProjectListRes{
List: make([]*pb.ProjectListRes_One, 0, len(userList)),
Total: total,
}
var shareCond = make(map[int64][]string)
var userIds = make([]int64, 0, len(list))
for _, v := range userList {
userIds = append(userIds, v.ID)
shareCond[v.CampaignID] = append(shareCond[v.CampaignID], fmt.Sprint(v.ID))
}
statM := s.GetDao().FissionUserStat
stats, err := statM.WithContext(s.ctx).Where(statM.UserID.In(userIds...)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var statMap = make(map[int64]*model.FissionUserStat, len(stats))
for _, v := range stats {
statMap[v.UserID] = v
}
for _, v := range userList {
one := &pb.ProjectListRes_One{
Id: v.ID,
SubUserId: v.SubUserID,
HashId: v.HashID,
CampaignTitle: cpnMap[v.CampaignID].Title,
CampaignHashId: cpnMap[v.CampaignID].HashID,
CreatedAt: v.CreatedAt,
EffectNum: 0,
IsNew: int32(v.IsNew),
HelpStatus: 0,
}
if v.ParentID > 0 {
one.HelpStatus = utils.Ternary[int32](v.IsHelp == mtype.Yes, 1, 2)
}
if stat, ok := statMap[v.ID]; ok {
one.EffectNum = stat.EffectiveNum
}
res.List = append(res.List, one)
}
return
}
// FinishStep 完成现金抽奖阶段
func (s *WCampaignUser) FinishStep(req *pb.FinishStepReq, res *pb.FinishStepRes) (err error) {
defer s.checkErr()
lc := app.NewRedisLock(s.ctx, ckey.FissionUserFinishStepOnce(req.GetUserId()))
defer lc.Release()
if !lc.SoftLock() {
err = workerr.BusyError
return
}
cpn, err := cache.NewCampaign(s.ctx).FindById(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, cpn.ID).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = workerr.NotFound("not found user")
return
}
cash, err := players.NewCash(s.ctx, user)
if err != nil {
return
}
*res = pb.FinishStepRes{}
switch req.GetStep() {
case mtype.FissionCashNextStepOpenGift:
res.OpenBox, res.LeftBox, res.RightBox, err = cash.OpenGift()
return
case mtype.FissionCashNextStepTriggerShare:
return cash.TriggerShare()
case mtype.FissionCashNextStepShowReward:
return cash.ShowReward()
case mtype.FissionCashNextStepLastSpin:
return cash.LastSpin()
default:
return
}
}
// Spin 现金转盘抽奖
func (s *WCampaignUser) Spin(req *pb.SpinReq, res *pb.SpinRes) (err error) {
defer s.checkErr()
lc := app.NewRedisLock(s.ctx, ckey.FissionUserSpinOnce(req.GetUserId()))
defer lc.Release()
if !lc.SoftLock() {
err = workerr.BusyError
return
}
cpn, err := cache.NewCampaign(s.ctx).FindById(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, cpn.ID).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = workerr.NotFound("not found user")
return
}
var id int64
var failType int32
switch cpn.FissionID {
case consts.IdGold:
var gold *players.Gold
gold, err = players.NewGold(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
id, failType, err = gold.Spin()
if err != nil {
return
}
default:
var cash *players.Cash
cash, err = players.NewCash(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
id, failType, err = cash.Spin()
if err != nil {
return
}
}
*res = pb.SpinRes{
Id: id,
FailType: failType,
}
return
}
// CashRecords 现金转盘记录
func (s *WCampaignUser) CashRecords(req *pb.CashRecordsReq, res *pb.CashRecordsRes) (err error) {
defer s.checkErr()
cpn, err := cache.NewCampaign(s.ctx).FindById(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, cpn.ID).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = workerr.NotFound("not found user")
return
}
cash, err := players.NewCash(s.ctx, user)
if err != nil {
return
}
player := cash.GetPlayer()
if !verify.InArray(req.GetType(), mtype.FissionCashRecordTypeInvite, mtype.FissionCashRecordTypeEnergy, mtype.FissionCashRecordTypeCash) {
return
}
offset, limit := utils.PpDbLo(req.GetPage(), req.GetPerPage())
recordM := s.GetDao().FissionCashRecord
list, total, err := recordM.WithContext(s.ctx).
Where(recordM.CashID.Eq(player.ID), recordM.Type.Eq(int8(req.GetType()))).
Order(recordM.CreatedAt.Desc(), recordM.ID.Desc()).
FindByPage(offset, limit)
if err != nil {
err = s.BE().MysqlError(err)
return
}
if len(list) == 0 {
return
}
*res = pb.CashRecordsRes{
List: make([]*pb.CashRecordsRes_One, 0, len(list)),
Total: total,
}
switch req.GetType() {
case mtype.FissionCashRecordTypeInvite:
var inviteIds []int64
for _, v := range list {
inviteIds = append(inviteIds, v.GetDataInvite().UserId)
}
var users []*model.FissionUser
userM := s.GetDao().FissionUser.SubTable(cpn.ID)
users, err = userM.WithContext(s.ctx).Where(userM.ID.In(inviteIds...)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var userMap = make(map[int64]string)
for _, v := range users {
userMap[v.ID] = v.UserMark
}
for _, v := range list {
invite := v.GetDataInvite()
res.List = append(res.List, &pb.CashRecordsRes_One{
SubUserId: userMap[invite.UserId],
CreatedAt: v.CreatedAt,
IsHelp: invite.Help,
})
}
case mtype.FissionCashRecordTypeCash:
for _, v := range list {
cashData := v.GetDataCash()
res.List = append(res.List, &pb.CashRecordsRes_One{
TitleMark: cashData.TitleMark,
CreatedAt: v.CreatedAt,
DecOrAdd: cashData.DecOrAdd,
Val: cashData.Cash,
})
}
case mtype.FissionCashRecordTypeEnergy:
for _, v := range list {
data := v.GetDataEnergy()
res.List = append(res.List, &pb.CashRecordsRes_One{
TitleMark: data.TitleMark,
CreatedAt: v.CreatedAt,
DecOrAdd: data.DecOrAdd,
Val: data.Energy,
})
}
default:
}
return
}
// MixReward 合成奖品
func (s *WCampaignUser) MixReward(req *pb.MixRewardReq, res *pb.MixRewardRes) (err error) {
defer s.checkErr()
if !app.NewRedisLock(s.ctx, ckey.FissionUserMixReward(req.GetUserId())).SoftLock() {
return workerr.OnceLockError
}
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil {
return
}
dice, err := players.NewDice(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
reward, err := dice.MixReward(req.GetRewardId())
if err != nil {
return
}
*res = pb.MixRewardRes{
Lack: reward.Lack,
RewardId: reward.RewardId,
RewardTitle: reward.RewardTitle,
ImgUrl: reward.ImgUrl,
ReceiveType: reward.ReceiveType,
KvData: make([]*pb.MixRewardRes_KV, 0, len(reward.KvData)),
Contact: reward.Contact,
RewardHashId: reward.RewardHashId,
OpenToUse: reward.OpenToUse,
WebUrl: reward.WebUrl,
AppParam: reward.AppParam,
PcParam: reward.PcParam,
}
return
}
// DiceRecord 骰子记录
func (s *WCampaignUser) DiceRecord(req *pb.DiceRecordReq, res *pb.DiceRecordRes) (err error) {
defer s.checkErr()
*res = pb.DiceRecordRes{}
container := new(containers.DiceRecord)
{
container.Init(s.ctx)
container.Req = req
container.Res = res
}
return container.Run()
}
// RewardForm 奖品需要填写的表单
func (s *WCampaignUser) RewardForm(req *pb.RewardFormReq, res *pb.RewardFormRes) (err error) {
defer s.checkErr()
cpn, err := finder.Campaign(s.ctx, req.GetCampaignId(), req.GetCampaignHashId())
if err != nil {
return
}
if cpn == nil {
err = workerr.NotFound("not found cpn")
return
}
m := s.GetDao().FissionRewardRecord.SubTable(cpn.ID)
record, err := m.WithContext(s.ctx).Where(m.HashID.Eq(req.GetRewardHashId())).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if record == nil {
err = workerr.NotFound("not found record")
return
}
user, err := finder.FissionUser(s.ctx, record.CampaignID, record.UserID)
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = workerr.NotFound("not found user")
return
}
if record.Status == mtype.FissionRewardRecordStatusSubmitForm {
rfm := s.GetDao().FissionRewardRecordForm
var recordForm *model.FissionRewardRecordForm
recordForm, err = rfm.WithContext(s.ctx).Where(rfm.RecordID.Eq(record.ID)).Take()
if err != nil {
err = s.BE().MysqlError(err)
return
}
items := recordForm.GetItems()
var form *model.Form
form, err = cache.NewForm(s.ctx).FindById(recordForm.FormID)
if err != nil {
err = s.BE().CacheError(err)
return
}
*res = pb.RewardFormRes{
IsSubmit: true,
Title: form.Title,
Items: make([]*pb.RewardFormRes_Item, 0, len(items)),
Id: record.ID,
RewardId: record.RewardID,
}
for _, item := range items {
res.Items = append(res.Items, &pb.RewardFormRes_Item{
Name: item.Name,
Key: item.Key,
Value: item.Value,
})
}
return
}
breward, err := cache.NewReward(s.ctx).FindById(record.BaseRewardID)
if err != nil {
err = s.BE().CacheError(err)
return
}
if breward.ReceiveType != mtype.RewardReceiveTypeForm {
return
}
form, err := cache.NewForm(s.ctx).FindById(breward.FormID)
if err != nil {
err = s.BE().CacheError(err)
return
}
items := form.GetItems()
*res = pb.RewardFormRes{
IsSubmit: false,
Title: form.Title,
Items: make([]*pb.RewardFormRes_Item, 0, len(items)),
Id: record.ID,
RewardId: record.RewardID,
}
for _, v := range items {
res.Items = append(res.Items, &pb.RewardFormRes_Item{
Name: v.GetTranName(req.GetLangMark()),
Key: v.Name,
Value: "",
})
}
return
}
// SubmitForm 提交表单
func (s *WCampaignUser) SubmitForm(req *pb.SubmitFormReq, res *pb.SubmitFormRes) (err error) {
defer s.checkErr()
m := s.GetDao().FissionRewardRecord.SubTable(req.GetCampaignId())
record, err := m.WithContext(s.ctx).Where(m.HashID.Eq(req.GetRewardHashId())).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if record == nil {
err = workerr.NotFound("not found record")
return
}
switch record.Status {
case mtype.FissionRewardRecordStatusSubmitForm:
*res = pb.SubmitFormRes{
FailType: 1,
}
return
case mtype.FissionRewardRecordStatusFail:
*res = pb.SubmitFormRes{
FailType: 3,
}
return
default:
}
breward, err := cache.NewReward(s.ctx).FindById(record.BaseRewardID)
if err != nil {
err = s.BE().CacheError(err)
return
}
if breward.ReceiveType != mtype.RewardReceiveTypeForm {
*res = pb.SubmitFormRes{
FailType: 3,
}
return
}
form, err := cache.NewForm(s.ctx).FindById(breward.FormID)
if err != nil {
err = s.BE().CacheError(err)
return
}
var items = form.GetItems()
var itemMap = make(map[string]struct{})
for _, item := range form.GetItems() {
itemMap[item.Name] = struct{}{}
}
var submitItems = make([]*mtype.SubmitFormItem, 0, len(items))
for _, v := range req.GetItems() {
if _, ok := itemMap[v.GetKey()]; !ok {
continue
}
submitItems = append(submitItems, &mtype.SubmitFormItem{
Name: v.GetName(),
Key: v.GetKey(),
Value: v.GetValue(),
})
}
recordForm := withdefault.FissionRewardRecordForm(&model.FissionRewardRecordForm{
CampaignID: record.CampaignID,
RecordID: record.ID,
FormID: form.ID,
Items: "",
})
recordForm.SetItems(submitItems)
err = s.GetDao().FissionRewardRecordForm.WithContext(s.ctx).Create(recordForm)
if err != nil {
err = s.BE().MysqlError(err)
return
}
_, err = m.WithContext(s.ctx).Where(m.ID.Eq(record.ID)).UpdateSimple(m.Status.Value(mtype.FissionRewardRecordStatusSubmitForm))
if err != nil {
err = s.BE().MysqlError(err)
return
}
user, _ := cache.NewFissionUser(s.ctx, record.CampaignID).FindById(record.UserID)
if user != nil {
fissionaction.NewMarkPoint(s.ctx).InApp(user).FormSubmit(time.Now().Unix(), record.RewardID, record.ID)
}
return
}
// GetAdsUrl 广告停留回传
func (s *WCampaignUser) GetAdsUrl(req *pb.GetAdsUrlReq, res *pb.GetAdsUrlRes) (err error) {
defer s.checkErr()
m := s.GetDao().FissionCampaignCond
cond, err := m.WithContext(s.ctx).Where(m.ID.Eq(req.GetCondId())).Take()
if err != nil {
err = s.BE().MysqlError(err)
return
}
if cond == nil {
err = workerr.NotFound("not found cond")
return
}
user, err := finder.FissionUser(s.ctx, cond.CampaignID, req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = workerr.NotFound("not found user")
return
}
ad, err := cache.NewProjectAd(s.ctx).FindByProjectId(cond.ProjectID)
if err != nil {
err = s.BE().CacheError(err)
return
}
if ad == nil || ad.OpenAd == mtype.No {
err = workerr.NotFound("not open ad")
return
}
eventVal := fmt.Sprint(cond.WatchSec)
jt := time.Now().Unix()
token := app.Encode(user.HashID, cond.Event, cond.EventKey, eventVal, jt)
err = app.Redis.Set(s.ctx, ckey.FissionUserAdsOnce(token), fmt.Sprint(cond.ID), consts.TimeDay)
if err != nil {
err = s.BE().RedisError(err)
return
}
if cond.AdsStrategyID != "" {
*res = pb.GetAdsUrlRes{
Url: blink.NewAdsJump(cond.AdsStrategyID, blink.SetAdsJumpLg(user.LangMark)).Link(),
Token: token,
UserHashId: user.HashID,
Event: cond.Event,
EventKey: cond.EventKey,
EventVal: eventVal,
JumpTime: jt,
}
return
}
act, host, uri := app.AdsRandOne(ad.AdStatus == mtype.ProjectAdStatusProd, ad.ProjectID)
*res = pb.GetAdsUrlRes{
Url: fmt.Sprintf("%s%s", host, uri),
Token: token,
UserHashId: user.HashID,
Event: cond.Event,
EventKey: cond.EventKey,
EventVal: eventVal,
JumpTime: jt,
AdG: &pb.GetAdsUrlRes_AdG{
Adc: act,
GaShowId: ad.GaShowID,
GaEmbedId: ad.GaEmbedID,
GaDoubleId: ad.GaDoubleID,
},
}
return
}
// AdsStay 广告停留回传
func (s *WCampaignUser) AdsStay(req *pb.AdsStayReq, res *pb.AdsStayRes) (err error) {
defer s.checkErr()
if !app.TokenOk(req.GetToken(), req.GetUserHashId(), req.GetEvent(), req.GetEventKey(), req.GetEventVal(), req.GetJumpTime()) {
err = s.BE().VerifyError("params error")
return
}
key := ckey.FissionUserAdsOnce(req.GetToken())
defer func() {
if err == nil {
_ = app.Redis.Del(s.ctx, key)
}
}()
nd := time.Now().Unix() - req.GetJumpTime()
st := utils.StrToInt64(req.GetEventVal())
if nd < st {
sl := int32(st - nd)
*res = pb.AdsStayRes{
StayLave: utils.Ternary[int32](sl < 0, 0, sl),
}
return
}
condId, err := app.Redis.Cache.Get(s.ctx, key).Int64()
if !errors.Is(err, grds.Nil) && err != nil {
err = s.BE().CacheError(err)
return
}
if errors.Is(err, grds.Nil) || condId == 0 {
err = nil
return
}
cond, err := cache.NewCampaignCond(s.ctx).FindById(condId)
if err != nil {
err = s.BE().CacheError(err)
return
}
if cond == nil {
return
}
user, err := finder.FissionUser(s.ctx, cond.CampaignID, req.GetUserHashId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = workerr.NotFound("not found user")
return
}
cpn, err := cache.NewCampaign(s.ctx).FindById(user.CampaignID)
if err != nil {
err = s.BE().CacheError(err)
return
}
if cpn == nil || cpn.IsDel == mtype.Yes || !verify.InArray(cpn.Status, mtype.FissionCampaignStatusPubPre, mtype.FissionCampaignStatusPub) {
err = workerr.CEndError
return
}
producer.NewCampaignNotice(s.ctx).ValidEvents(types.ValidEvents{
UserId: user.ID,
NewUser: false,
BehaviorTime: time.Now().Unix(),
NoticeType: types.NoticeTypeCustom,
Event: req.GetEvent(),
EventData: []types.EventData{
{
EventKey: req.GetEventKey(),
EventVal: "1",
},
},
EventType: mtype.FissionCampaignCondEventTypeAds,
AdsCondId: condId,
CampaignId: cpn.ID,
})
*res = pb.AdsStayRes{
Done: true,
}
return
}
// ClueNotified 通知信息已经被接收
func (s *WCampaignUser) ClueNotified(req *pb.ClueNotifiedReq, res *pb.ClueNotifiedRes) (err error) {
defer s.checkErr()
provider.NewFissionClue(s.ctx, req.GetUserId()).Notified()
*res = pb.ClueNotifiedRes{}
return
}
// ChangeUserLevel 修改用户等级
func (s *WCampaignUser) ChangeUserLevel(req *pb.ChangeUserLevelReq, res *pb.ChangeUserLevelRes) (err error) {
defer s.checkErr()
m := s.GetDao().FissionCampaign
list, err := m.WithContext(s.ctx).
Where(
m.ProjectID.Eq(req.GetProjectId()),
m.Status.In(mtype.FissionCampaignStatusPub, mtype.FissionCampaignStatusPubPre),
).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
if len(list) == 0 {
return
}
var ids []int64
var cpnMap = make(map[int64]*model.FissionCampaign, len(list))
for _, v := range list {
ids = append(ids, v.ID)
cpnMap[v.ID] = v
}
confM := s.GetDao().FissionCampaignConfig
confList, err := confM.WithContext(s.ctx).Where(confM.CampaignID.In(ids...)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
if len(confList) == 0 {
return
}
cc1 := cache.NewFissionUserAttr(s.ctx)
for _, v := range confList {
cc := cache.NewFissionUser(s.ctx, v.CampaignID)
var user *model.FissionUser
user, err = cc.FindBySubUserId(req.GetSubUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
continue
}
uct, _ := cmm.NewCMM(s.ctx, s.GetDao()).UserCampaignType(cpnMap[v.CampaignID], v, "", req.GetUserLevel(), "")
setLv := strings.Split(req.GetUserLevel(), ",")
userM := s.GetDao().FissionUser
_, err = userM.WithContext(s.ctx).Where(userM.ID.Eq(user.ID)).UpdateSimple(
userM.LevelMark.Value(req.GetUserLevel()),
userM.UserLevel.Value(uct.LevelId),
userM.UserLevelMark.Value(uct.LevelMark),
userM.FixedUserLevel.Value(mtype.Yes),
)
if err != nil {
err = s.BE().MysqlError(err)
return
}
userMs := s.GetDao().FissionUser.SubTable(user.CampaignID)
_, err = userMs.WithContext(s.ctx).Where(userMs.ID.Eq(user.ID)).UpdateSimple(
userMs.LevelMark.Value(req.GetUserLevel()),
userMs.UserLevel.Value(uct.LevelId),
userMs.UserLevelMark.Value(uct.LevelMark),
userMs.FixedUserLevel.Value(mtype.Yes),
)
if err != nil {
err = s.BE().MysqlError(err)
return
}
_ = cc.Clear(user)
attrVal := utils.Ternary[string](verify.InArray[string](uct.LevelMark, setLv...), uct.LevelMark, setLv[0])
var attr *model.FissionUserAttr
attr, err = cache.NewFissionUserAttr(s.ctx).FindByUniqIdx(user.ID, mtype.FissionUserAttrMarkUserLv, cache.WithNilSet(func() ([]byte, error) {
pAttr := withdefault.FissionUserAttr(&model.FissionUserAttr{
CampaignID: user.CampaignID,
UserID: user.ID,
Attr: mtype.FissionUserAttrMarkUserLv,
Value: attrVal,
Values: req.GetUserLevel(),
})
err = s.GetDao().FissionUserAttr.WithContext(s.ctx).Create(pAttr)
if err != nil {
return nil, err
}
return jsonm.Marshal(pAttr)
}))
if err != nil {
err = s.BE().CacheError(err)
return
}
// 如果没更新,或者平台是其他,就不用处理了
if attrVal == attr.Value {
continue
}
vals := attr.GetValues()
for _, lv := range setLv {
if !verify.InArray(lv, vals...) {
vals = append(vals, lv)
}
}
attrM := s.GetDao().FissionUserAttr
_, err = attrM.WithContext(s.ctx).Where(attrM.ID.Eq(attr.ID)).UpdateSimple(
attrM.Value.Value(attrVal),
attrM.Values.Value(strings.Join(vals, ",")),
)
if err != nil {
err = s.BE().MysqlError(err)
return
}
_ = cc1.Clear(attr)
}
*res = pb.ChangeUserLevelRes{}
return
}
// ChopReward 砍一刀可选奖品
func (s *WCampaignUser) ChopReward(req *pb.ChopRewardReq, res *pb.ChopRewardRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = workerr.NotFound("not found user")
return
}
rewards, err := cmm.NewCMM(s.ctx, s.GetDao()).UserAppReward(user)
if err != nil {
return
}
var bRewardIds []int64
var limitIds []int64
for _, reward := range rewards {
if reward.HasRule == mtype.Yes {
limitIds = append(limitIds, reward.ID)
}
bRewardIds = append(bRewardIds, reward.RewardID)
}
prewards, _ := provider.NewRewards(s.ctx, 0, bRewardIds...)
if len(limitIds) == 0 {
*res = pb.ChopRewardRes{
Rewards: make([]*pb.ChopRewardRes_Reward, 0, len(rewards)),
}
for _, reward := range rewards {
info, _ := prewards.InfoAutoLang(reward.RewardID, user.LangMark)
res.Rewards = append(res.Rewards, &pb.ChopRewardRes_Reward{
Id: reward.ID,
Title: info.Title,
ImgUrl: info.ImgUrl,
})
}
return
}
ruleM := s.GetDao().FissionCampaignRewardRule
rules, err := ruleM.WithContext(s.ctx).Where(ruleM.CampaignID.Eq(user.CampaignID), ruleM.RewardID.In(limitIds...)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var ruleMap = make(map[int64]*model.FissionCampaignRewardRule, len(rules))
for _, rule := range rules {
ruleMap[rule.RewardID] = rule
}
type rewardGet struct {
RewardId int64 `json:"reward_id"`
Num int32 `json:"num"`
}
var gets []*rewardGet
chopRewardM := s.GetDao().FissionChopReward
err = chopRewardM.WithContext(s.ctx).
Select(chopRewardM.ID.Count().As("num"), chopRewardM.RewardID).
Where(chopRewardM.UserID.Eq(user.ID), chopRewardM.RecordID.Gt(0)).
Group(chopRewardM.RewardID).
Scan(&gets)
if err != nil {
err = s.BE().MysqlError(err)
return
}
var filterMap = make(map[int64]struct{})
for _, v := range gets {
if rule, ok := ruleMap[v.RewardId]; ok && rule.CampaignLimit <= v.Num {
filterMap[v.RewardId] = struct{}{}
}
}
*res = pb.ChopRewardRes{}
for _, reward := range rewards {
if _, ok := filterMap[reward.ID]; ok {
continue
}
info, _ := prewards.InfoAutoLang(reward.RewardID, user.LangMark)
res.Rewards = append(res.Rewards, &pb.ChopRewardRes_Reward{
Id: reward.ID,
Title: info.Title,
ImgUrl: info.ImgUrl,
})
}
return
}
// HelpPercent 助力进度
func (s *WCampaignUser) HelpPercent(req *pb.HelpPercentReq, res *pb.HelpPercentRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
*res = pb.HelpPercentRes{}
chop, err := players.NewChop(s.ctx, user)
if err != nil {
return
}
res.IsFix, res.OldPercent, res.AddPercent = chop.HelpClue()
return
}
// InvokeCond 触发前置条件
func (s *WCampaignUser) InvokeCond(req *pb.InvokeCondReq, res *pb.InvokeCondRes) (err error) {
defer s.checkErr()
user, err := finder.FissionUser(s.ctx, req.GetCampaignId(), req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
m := s.GetDao().FissionUserPreCond
pre, err := m.WithContext(s.ctx).Select(m.ID).Where(m.UserID.Eq(user.ID), m.PreCond.Eq(req.GetPreCond())).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
taskM := s.GetDao().FissionCampaignTask
task, err := taskM.WithContext(s.ctx).Where(
taskM.CampaignID.Eq(user.CampaignID),
taskM.PreCond.Eq(req.GetPreCond()),
taskM.IsDel.Eq(mtype.No),
).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if task == nil {
return
}
if pre == nil && verify.InArray(task.PreCond, mtype.FissionCampaignTaskPreCondClickIcon, mtype.FissionCampaignTaskPreCondWait30s) {
pre = withdefault.FissionUserPreCond(&model.FissionUserPreCond{
CampaignID: user.CampaignID,
UserID: user.ID,
PreCond: task.PreCond,
ExpiredAt: time.Now().Add(time.Duration(task.ExpiredMin) * time.Minute).Unix(),
})
err = m.WithContext(s.ctx).Create(pre)
if err != nil {
err = s.BE().MysqlError(err)
return
}
}
if pre == nil {
return
}
condId := utils.FissionCampaignTaskMarkCondOneCondId(task.TaskMark)
cond, err := cache.NewCampaignCond(s.ctx).FindById(condId)
if err != nil {
err = s.BE().CacheError(err)
return
}
cpn, err := cache.NewCampaign(s.ctx).FindById(cond.CampaignID)
if err != nil {
err = s.BE().CacheError(err)
return
}
// 用户当前语言是配置的语言
var condLangMap = make(map[int64]*mtype.LangCond)
if verify.InArray(user.LangMark, cpn.GetLangMarks()...) {
lang, err1 := cache.NewCampaignLang(s.ctx).FindByCampaignId(user.CampaignID, user.LangMark)
if err1 != nil {
err = s.BE().CacheError(err1)
return
}
if lang != nil {
for _, v := range lang.GetConds() {
condLangMap[v.CondId] = v
}
}
}
var condExtra = make(map[string]*deventpb.GetCustomEventListRes_Info)
eventRes, _ := app.NewDeepLinkEvent().GetCustomEventList(s.ctx, &deventpb.GetCustomEventListReq{
ProjectId: cpn.ProjectID,
EventKeyList: []string{cond.Event},
LangMark: user.LangMark,
})
for _, v := range eventRes.GetList() {
condExtra[v.GetEventKey()] = v
}
*res = pb.InvokeCondRes{
Id: cond.ID,
Desc: cond.Desc,
IfCond: int32(cond.IfCond),
Event: cond.Event,
EventKey: cond.EventKey,
EventVal: cond.EventVal,
TaskChance: task.Chance,
WebUrl: cond.WebURL,
AppParam: cond.ExtraParam,
EventType: int32(cond.EventType),
ViewType: int32(cond.ViewType),
GoShow: int32(cond.GoShow),
AdsStrategyId: cond.AdsStrategyID,
IsSuper: int32(cond.IsSuper),
HasPre: int32(task.HasPre),
Reward: nil,
PropMark: task.PropMark,
ExpiredSec: pre.ExpiredAt - time.Now().Unix(),
PcParam: cond.PcParam,
}
if condLang, ok := condLangMap[cond.ID]; ok {
res.Desc = condLang.Desc
}
if cond.OpenJump == mtype.Yes {
if condLang, ok := condLangMap[cond.ID]; ok {
res.WebUrl = condLang.WebURL
res.AppParam = condLang.ExtraParam
res.PcParam = condLang.ExtraParam
}
} else {
if param, ok := condExtra[cond.Event]; ok {
res.WebUrl = param.WebUrl
res.AppParam = param.ExtraParam
res.PcParam = param.PcParam
}
}
if task.RewardID == 0 {
return
}
rewardM := s.GetDao().FissionCampaignReward
reward, err := rewardM.WithContext(s.ctx).Where(rewardM.ID.Eq(task.RewardID)).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
if reward == nil {
return
}
bewards, err := provider.NewRewards(s.ctx, cpn.ProjectID, reward.RewardID)
if err != nil {
return
}
info := bewards.AutoLang(reward.RewardID, user.LangMark)
res.Reward = &pb.InvokeCondRes_Reward{
Id: reward.ID,
Title: info.Title,
ImgUrl: info.ImgUrl,
}
return
}
// KeepReward 激励养成可选奖品
func (s *WCampaignUser) KeepReward(req *pb.KeepRewardReq, res *pb.KeepRewardRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = workerr.NotFound("not found user")
return
}
rewards, err := cmm.NewCMM(s.ctx, s.GetDao()).UserAppReward(user)
if err != nil {
return
}
var rewardIds, bRewardIds, limitIds []int64
for _, reward := range rewards {
if reward.HasRule == mtype.Yes {
limitIds = append(limitIds, reward.ID)
}
bRewardIds = append(bRewardIds, reward.RewardID)
rewardIds = append(rewardIds, reward.ID)
}
hmap, err := cachecurd.NewHMap(s.ctx, ckey.FissionKeepRewardSelectedUser(user.CampaignID), cachecurd.SetKeepRewardSelectBuild(user.CampaignID))
if err != nil {
return
}
selectReward, _ := hmap.Int64ToInt64()
var useStock = make(map[int64]int64, len(rewardIds))
for _, id := range rewardIds {
useStock[id] = selectReward[id]
}
prewards, _ := provider.NewRewards(s.ctx, 0, bRewardIds...)
if len(limitIds) == 0 {
*res = pb.KeepRewardRes{
Rewards: make([]*pb.KeepRewardRes_Reward, 0, len(rewards)),
}
for _, reward := range rewards {
var status int32
if int64(reward.Stock) <= useStock[reward.ID] {
status = 2
}
info := prewards.AutoLang(reward.RewardID, user.LangMark)
res.Rewards = append(res.Rewards, &pb.KeepRewardRes_Reward{
Id: reward.ID,
Title: info.Title,
ImgUrl: info.ImgUrl,
Num: useStock[reward.ID],
Status: status,
})
}
return
}
ruleM := s.GetDao().FissionCampaignRewardRule
rules, err := ruleM.WithContext(s.ctx).Where(ruleM.CampaignID.Eq(user.CampaignID), ruleM.RewardID.In(limitIds...)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var ruleMap = make(map[int64]*model.FissionCampaignRewardRule, len(rules))
for _, rule := range rules {
ruleMap[rule.RewardID] = rule
}
type rewardGet struct {
RewardId int64 `json:"reward_id"`
Num int32 `json:"num"`
}
var gets []*rewardGet
keepM := s.GetDao().FissionKeep
err = keepM.WithContext(s.ctx).
Select(keepM.ID.Count().As("num"), keepM.RewardID).
Where(keepM.UserID.Eq(user.ID)).
Group(keepM.RewardID).
Scan(&gets)
if err != nil {
err = s.BE().MysqlError(err)
return
}
var filterMap = make(map[int64]struct{})
for _, v := range gets {
if rule, ok := ruleMap[v.RewardId]; ok && rule.CampaignLimit <= v.Num {
filterMap[v.RewardId] = struct{}{}
}
}
*res = pb.KeepRewardRes{}
for _, reward := range rewards {
var status int32
if _, ok := filterMap[reward.ID]; ok {
status = 3
} else if int64(reward.Stock) <= useStock[reward.ID] {
status = 2
}
info := prewards.AutoLang(reward.RewardID, user.LangMark)
res.Rewards = append(res.Rewards, &pb.KeepRewardRes_Reward{
Id: reward.ID,
Title: info.Title,
ImgUrl: info.ImgUrl,
Num: useStock[reward.ID],
Status: status,
})
}
return
}
// KeepSelect 选择激励养成奖品
func (s *WCampaignUser) KeepSelect(req *pb.KeepSelectReq, res *pb.KeepSelectRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
keepDog, err := players.NewKeepDog(s.ctx, user)
if err != nil {
return
}
status, err := keepDog.RewardSelect(req.GetRewardId())
if err != nil {
return
}
*res = pb.KeepSelectRes{
Status: status,
}
return
}
// KeepCollect 激励养成收集一级道具
func (s *WCampaignUser) KeepCollect(req *pb.KeepCollectReq, res *pb.KeepCollectRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
lc := app.NewRedisLock(s.ctx, ckey.FissionUserKeepDoingOnce(user.ID)).Lock()
defer lc.Release()
if lc.Error() != nil {
err = lc.Error()
return
}
keepDog, err := players.NewKeepDog(s.ctx, user)
if err != nil {
return
}
num, gets, err := keepDog.Collect()
if err != nil {
return
}
*res = pb.KeepCollectRes{
Gets: make([]*pb.KeepCollectRes_Reward, 0, len(gets)),
Num: num,
}
for _, get := range gets {
res.Gets = append(res.Gets, &pb.KeepCollectRes_Reward{
RewardType: get.RewardType,
Chance: get.Chance,
RewardId: get.RewardId,
RewardTitle: get.RewardTitle,
RewardImg: get.RewardImg,
Lack: get.Lack,
LastReward: get.LastReward,
ReceiveType: get.ReceiveType,
})
}
return
}
// KeepFeed 激励养成收集一级道具
func (s *WCampaignUser) KeepFeed(req *pb.KeepFeedReq, res *pb.KeepFeedRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
lc := app.NewRedisLock(s.ctx, ckey.FissionUserKeepDoingOnce(user.ID)).Lock()
defer lc.Release()
if lc.Error() != nil {
err = lc.Error()
return
}
keepDog, err := players.NewKeepDog(s.ctx, user)
if err != nil {
return
}
status, addPercent, err := keepDog.Feed()
if err != nil {
return
}
*res = pb.KeepFeedRes{
Status: status,
AddPercent: addPercent,
}
return
}
// MachineSave 激励养成保存机器道具
func (s *WCampaignUser) MachineSave(req *pb.MachineSaveReq, res *pb.MachineSaveRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
keepDog, err := players.NewKeepDog(s.ctx, user)
if err != nil {
return
}
err = keepDog.MachineSave(req.GetNum())
if err != nil {
return
}
*res = pb.MachineSaveRes{}
return
}
// MachineRecycle 激励养成保存机器道具
func (s *WCampaignUser) MachineRecycle(req *pb.MachineRecycleReq, res *pb.MachineRecycleRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
keepDog, err := players.NewKeepDog(s.ctx, user)
if err != nil {
return
}
limit, getNum, err := keepDog.MachineRecycle(req.GetNum())
if err != nil {
return
}
conf := keepDog.GetConf()
*res = pb.MachineRecycleRes{
MachineLimit: limit,
NextFull: time.Now().Add(time.Duration(conf.OfflineMin)*time.Minute).Unix() - time.Now().Unix(),
GetNum: getNum,
}
return
}
// GetPropFeed 收喂养次数的道具
func (s *WCampaignUser) GetPropFeed(req *pb.GetPropFeedReq, res *pb.GetPropFeedRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
keepDog, err := players.NewKeepDog(s.ctx, user)
if err != nil {
return
}
num, err := keepDog.GetPropFeed()
if err != nil {
return
}
*res = pb.GetPropFeedRes{
Num: num,
}
return
}
// KeepLog 激励养成记录
func (s *WCampaignUser) KeepLog(req *pb.KeepLogReq, res *pb.KeepLogRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
keepDog, err := players.NewKeepDog(s.ctx, user)
if err != nil {
return
}
player := keepDog.GetPlayer()
m := s.GetDao().FissionKeepLog
var cond = []gen.Condition{
m.KeepID.Eq(player.ID),
}
if len(req.GetType()) > 0 {
var ts = make([]int8, 0, len(req.GetType()))
for _, v := range req.GetType() {
ts = append(ts, int8(v))
}
cond = append(cond, m.Type.In(ts...))
}
offset, limit := utils.PpDbLo(req.GetPage(), req.GetPerPage())
list, total, err := m.WithContext(s.ctx).Where(cond...).Order(m.CreatedAt.Desc()).FindByPage(offset, limit)
if err != nil {
err = s.BE().MysqlError(err)
return
}
*res = pb.KeepLogRes{
List: make([]*pb.KeepLogRes_One, 0, len(list)),
Total: total,
}
for _, v := range list {
res.List = append(res.List, &pb.KeepLogRes_One{
Type: int32(v.Type),
Source: v.Source,
Val: v.Val,
CreatedAt: v.CreatedAt,
})
}
return
}
// KeepReselect 激励养成重新选择
func (s *WCampaignUser) KeepReselect(req *pb.KeepReselectReq, res *pb.KeepReselectRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
keepDog, err := players.NewKeepDog(s.ctx, user)
if err != nil {
return
}
status, err := keepDog.Reselect()
if err != nil {
return
}
*res = pb.KeepReselectRes{
Status: status,
}
return
}
// KeepGuide 激励养成指引
func (s *WCampaignUser) KeepGuide(req *pb.KeepGuideReq, res *pb.KeepGuideRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
keepDog, err := players.NewKeepDog(s.ctx, user)
if err != nil {
return
}
reward, err := keepDog.Guided()
if err != nil {
return
}
*res = pb.KeepGuideRes{
RewardType: reward.RewardType,
Chance: reward.Chance,
RewardId: reward.RewardId,
RewardTitle: reward.RewardTitle,
RewardImg: reward.RewardImg,
Lack: reward.Lack,
ReceiveType: reward.ReceiveType,
}
return
}
// KeepFirstInvite 激励养成首邀状态
func (s *WCampaignUser) KeepFirstInvite(req *pb.KeepFirstInviteReq, res *pb.KeepFirstInviteRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
cpn, err := cache.NewCampaign(s.ctx).FindById(user.CampaignID)
if err != nil {
err = s.BE().CacheError(err)
return
}
tz := provider.NewCampaignTZ(s.ctx, cpn, user.LangMark)
start, _ := timez.GMTTimeStart(tz.GetTz())
keepDog, err := players.NewKeepDog(s.ctx, user)
if err != nil {
return
}
status, err := keepDog.GetStatus()
if err != nil {
return
}
conf := keepDog.GetConf()
*res = pb.KeepFirstInviteRes{
OpenInvite: int32(conf.OpenInvite),
DayFirstInvite: status.DayFirstInvite,
DayFirstFeed: status.DayFirstFeed,
ExpiredSec: start.Unix() - time.Now().Unix() + 86400,
}
return
}
// Child 子活动信息
func (s *WCampaignUser) Child(req *pb.ChildReq, res *pb.ChildRes) (err error) {
defer s.checkErr()
*res = pb.ChildRes{}
container := new(containers.Child)
{
container.Init(s.ctx, logic.WithErrData(req))
container.Req = req
container.Res = res
}
return container.Run()
}
// ChildActive 参与子活动
func (s *WCampaignUser) ChildActive(req *pb.ChildActiveReq, res *pb.ChildActiveRes) (err error) {
defer s.checkErr()
*res = pb.ChildActiveRes{}
container := new(containers.ChildActive)
{
container.Init(s.ctx, logic.WithErrData(req))
container.Req = req
container.Res = res
}
return container.Run()
}
// GoldFinishStep 完成金币任务阶段
func (s *WCampaignUser) GoldFinishStep(req *pb.GoldFinishStepReq, res *pb.GoldFinishStepRes) (err error) {
defer s.checkErr()
lc := app.NewRedisLock(s.ctx, ckey.FissionUserFinishStepOnce(req.GetUserId()))
defer lc.Release()
if !lc.SoftLock() {
err = workerr.BusyError
return
}
cpn, err := cache.NewCampaign(s.ctx).FindById(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, cpn.ID).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = workerr.NotFound("not found user")
return
}
*res = pb.GoldFinishStepRes{}
gold, err := players.NewGold(s.ctx, user)
if err != nil {
return
}
switch req.GetStep() {
case mtype.FissionGoldNextStepOpenGift:
res.OpenBox, res.LeftBox, res.RightBox, err = gold.OpenGift()
return
case mtype.FissionGoldNextStepTriggerShare:
return gold.TriggerShare()
case mtype.FissionGoldNextStepShowReward:
return gold.ShowReward()
case mtype.FissionGoldNextStepLastSpin:
return gold.LastSpin()
case mtype.FissionGoldNextStepGoldRain:
return gold.GoldRain()
default:
return
}
}
// GoldNotify 金币获取通知
func (s *WCampaignUser) GoldNotify(req *pb.GoldNotifyReq, res *pb.GoldNotifyRes) (err error) {
defer s.checkErr()
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
*res = pb.GoldNotifyRes{}
gold, err := players.NewGold(s.ctx, user)
if err != nil {
return
}
res.OldGold, res.AddGold = gold.Clue()
return
}
// GoldRecord 金币获取记录
func (s *WCampaignUser) GoldRecord(req *pb.GoldRecordReq, res *pb.GoldRecordRes) (err error) {
defer s.checkErr()
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil {
return
}
gold, err := players.NewGold(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
player := gold.GetPlayer()
m := s.GetDao().FissionGoldLog
offset, limit := utils.PpDbLo(req.GetPage(), req.GetPerPage())
list, count, err := m.WithContext(s.ctx).
Where(m.CampaignID.Eq(cpn.ID), m.GoldID.Eq(player.ID), m.Type.Eq(mtype.FissionGoldLogTypeDoTask)).
Order(m.CreatedAt.Desc()).
FindByPage(offset, limit)
if err != nil {
err = s.BE().MysqlError(err)
return
}
*res = pb.GoldRecordRes{
List: make([]*pb.GoldRecordRes_One, 0, len(list)),
Total: count,
}
var condIds []int64
var condMap = make(map[int64]string)
for _, v := range list {
val := v.GetVal()
if _, ok := condMap[val.CondId]; !ok {
condIds = append(condIds, val.CondId)
condMap[val.CondId] = ""
}
}
langTitle, err := provider.NewLangTitle(s.ctx, cpn, user.LangMark)
if err != nil {
return
}
condMap, err = langTitle.GetCondTitle(condIds...)
if err != nil {
return
}
for _, v := range list {
val := v.GetVal()
title, ok := condMap[val.CondId]
one := &pb.GoldRecordRes_One{
Title: title,
GoldNum: val.Chance,
CreatedAt: v.CreatedAt,
Mark: utils.Ternary[string](ok, "record:completed_task", "record:completed_task_none"),
}
if verify.InArray[string](v.Source, mtype.FissionLogSourceInstall, mtype.FissionLogSourceRegister) {
one.Mark = "record:completed_invite_task"
}
res.List = append(res.List, one)
}
return
}
// Deduct 扣除积分
func (s *WCampaignUser) Deduct(req *pb.DeductReq, res *pb.DeductRes) (err error) {
defer s.checkErr()
lc := app.NewRedisLock(s.ctx, ckey.FissionCoinChangeLock(req.GetUserId()))
defer lc.Release()
if !lc.SoftLock() {
err = workerr.OnceLockError
return
}
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
player, err := players.NewCoin(s.ctx, user)
if err != nil {
return
}
useNum, status, err := player.Deduct()
if err != nil {
return
}
playerStatus, err := player.GetStatus()
if err != nil {
return
}
*res = pb.DeductRes{
Status: status,
Total: playerStatus.AllCoin,
UseNum: useNum,
GetCoin: playerStatus.GetCoin,
OpenSec: playerStatus.OpenSec,
}
return
}
// Gain 领取积分
func (s *WCampaignUser) Gain(req *pb.GainReq, res *pb.GainRes) (err error) {
defer s.checkErr()
lc := app.NewRedisLock(s.ctx, ckey.FissionCoinChangeLock(req.GetUserId()))
defer lc.Release()
if !lc.SoftLock() {
err = workerr.OnceLockError
return
}
user, err := cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
player, err := players.NewCoin(s.ctx, user)
if err != nil {
return
}
getCoin, status, err := player.Gain()
if err != nil {
return
}
*res = pb.GainRes{
Status: status,
GetCoin: getCoin,
}
return
}
// CoinRecord 金币池记录
func (s *WCampaignUser) CoinRecord(req *pb.CoinRecordReq, res *pb.CoinRecordRes) (err error) {
defer s.checkErr()
cpn, err := finder.Campaign(s.ctx, req.GetCampaignId(), req.GetCampaignHashId())
if err != nil {
err = s.BE().CacheError(err)
return
}
m := s.GetDao().FissionCoinLog
var cond = []gen.Condition{
m.CampaignID.Eq(cpn.ID),
}
var userMap = make(map[int64]string)
if req.GetUserId() > 0 {
var user *model.FissionUser
user, err = cache.NewFissionUser(s.ctx, cpn.ID).FindById(req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
return
}
cond = append(cond, m.UserID.Eq(user.ID))
userMap[user.ID] = user.SubUserID
}
if req.GetSubUserId() != "" {
var user *model.FissionUser
user, err = cache.NewFissionUser(s.ctx, cpn.ID).FindBySubUserId(req.GetSubUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
return
}
cond = append(cond, m.UserID.Eq(user.ID))
userMap[user.ID] = user.SubUserID
}
if len(req.GetType()) > 0 {
var status = make([]int8, 0, len(req.GetType()))
for _, v := range req.GetType() {
status = append(status, int8(v))
}
cond = append(cond, m.Type.In(status...))
}
if req.GetSceneId() > 0 {
cond = append(cond, m.SceneID.Eq(req.GetSceneId()))
}
if req.GetSource() != "" {
cond = append(cond, m.Source.Eq(req.GetSource()))
}
tz := utils.STernary[int32](req.GetTOffset(), consts.DefaultTz, cpn.TOffset)
if req.GetStart() > 0 {
cond = append(cond, m.CreatedAt.Gte(timez.GMT(req.GetStart(), tz)))
}
if req.GetEnd() > 0 {
cond = append(cond, m.CreatedAt.Lte(timez.GMT(req.GetEnd(), tz)))
}
offset, limit := utils.PpDbLo(req.GetPage(), req.GetPerPage())
list, count, err := m.WithContext(s.ctx).
Where(cond...).
Order(m.CreatedAt.Desc()).
FindByPage(offset, limit)
if err != nil {
err = s.BE().MysqlError(err)
return
}
sceneM := s.GetDao().FissionCoinScene
scenes, err := sceneM.WithContext(s.ctx).Where(sceneM.CampaignID.Eq(cpn.ID)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
gmt := utils.Ternary[string](cpn.TOffset < 0, fmt.Sprint(cpn.TOffset), fmt.Sprintf("+%d", cpn.TOffset))
var titleMap = make(map[int64]string, len(scenes))
for _, v := range scenes {
day, _, _ := timez.GMTStartAndEndTs(cpn.TOffset, v.OpenTime)
titleMap[v.ID] = fmt.Sprintf("%s(GMT%s)", day, gmt)
}
if req.GetUserId() == 0 && req.GetSubUserId() == "" {
var userId []int64
for _, v := range list {
if _, ok := userMap[v.UserID]; !ok {
userId = append(userId, v.UserID)
}
}
userM := s.GetDao().FissionUser.SubTable(cpn.ID)
var users []*model.FissionUser
users, err = userM.WithContext(s.ctx).Where(userM.ID.In(userId...)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
for _, v := range users {
userMap[v.ID] = v.SubUserID
}
}
*res = pb.CoinRecordRes{
List: make([]*pb.CoinRecordRes_One, 0, len(list)),
Total: count,
}
for _, v := range list {
val := v.GetVal()
res.List = append(res.List, &pb.CoinRecordRes_One{
Id: v.ID,
Type: int32(v.Type),
CreatedAt: v.CreatedAt,
Source: v.Source,
Num: val.CoinNum,
SubUserId: userMap[v.UserID],
Title: titleMap[v.SceneID],
})
}
return
}
// ChildList 子活动用户列表
func (s *WCampaignUser) ChildList(req *pb.ChildListReq, res *pb.ChildListRes) (err error) {
defer s.checkErr()
*res = pb.ChildListRes{}
container := new(containers.ChildList)
{
container.Init(s.ctx, logic.WithErrData(req))
container.Req = req
container.Res = res
}
return container.Run()
}
// ReceiveReward 领取奖励
func (s *WCampaignUser) ReceiveReward(req *pb.ReceiveRewardReq, res *pb.ReceiveRewardRes) (err error) {
defer s.checkErr()
lc := app.NewRedisLock(s.ctx, ckey.FissionReceiveRewardLock(req.GetUserId(), req.GetTaskId()))
defer lc.Release()
if !lc.SoftLock() {
err = workerr.OnceLockError
return
}
m := s.GetDao().FissionUserTaskReward
list, err := m.WithContext(s.ctx).Where(
m.UserID.Eq(req.GetUserId()),
m.TaskID.Eq(req.GetTaskId()),
m.ReceiveTime.Eq(0),
).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
if len(list) == 0 {
return
}
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil {
return
}
var reward *award.RewardRes
var chance int32
switch cpn.FissionID {
case consts.IdPrizeWheel:
var player *players.Wheel
player, err = players.NewWheel(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
chance, reward, err = player.ReceiveReward(list...)
if err != nil {
return
}
case consts.IdBlindBox:
var player *players.Blind
player, err = players.NewBlind(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
chance, reward, err = player.ReceiveReward(list...)
if err != nil {
return
}
case consts.IdLuckyGrid:
var player *players.Grid
player, err = players.NewGrid(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
chance, reward, err = player.ReceiveReward(list...)
if err != nil {
return
}
case consts.IdFlip:
var player *players.Flip
player, err = players.NewFlip(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
chance, reward, err = player.ReceiveReward(list...)
if err != nil {
return
}
case consts.IdSlotMachine:
var player *players.Slot
player, err = players.NewSlot(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
chance, reward, err = player.ReceiveReward(list...)
if err != nil {
return
}
case consts.IdKeep:
var player *players.KeepDog
player, err = players.NewKeepDog(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
chance, reward, err = player.ReceiveReward(list...)
if err != nil {
return
}
case consts.IdVs:
var player *players.Vs
player, err = players.NewVs(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
chance, reward, err = player.ReceiveReward(list...)
if err != nil {
return
}
case consts.IdGashapon:
var player *players.Gashapon
player, err = players.NewGashapon(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
chance, reward, err = player.ReceiveReward(list...)
case consts.IdPrizeAnswer, consts.IdQa, consts.IdQaAudio, consts.IdQaVideo:
var player *players.Qa
player, err = players.NewQa(s.ctx, user, cpn.FissionID, players.SetCpn(cpn))
if err != nil {
return
}
chance, reward, err = player.ReceiveReward(list...)
if err != nil {
return
}
default:
return s.BE().VerifyError("Not supported")
}
*res = pb.ReceiveRewardRes{
PropMark: mtype.FissionCampaignRewardPropMarkChance,
Chance: chance,
Reward: nil,
}
if reward != nil {
res.PropMark = reward.Reward.PropMark
res.Reward = &pb.ReceiveRewardRes_Reward{
HashId: reward.Record.HashID,
Title: reward.Info.Title,
Img: reward.Info.ImgUrl,
JumpUrl: "",
KvData: nil,
ReceiveType: reward.Info.ReceiveType,
Contact: reward.Info.Contact,
CreatedAt: reward.Record.CreatedAt,
OpenToUse: reward.Info.OpenToUse,
WebUrl: reward.Info.WebUrl,
AppParam: reward.Info.AppParam,
PcParam: reward.Info.PcParam,
Lack: utils.Ternary[int32](reward.Record.FailMsg == mtype.FissionRewardRecordFailTypeCliLackMsg, 1, 0),
RewardNum: reward.Record.RewardNum,
}
for _, v := range reward.Info.KvData {
res.Reward.KvData = append(res.Reward.KvData, &pb.ReceiveRewardRes_KV{
Key: v.Key,
Value: v.Value,
IsShow: v.IsShow,
})
}
}
return
}
// LotteryLog 抽奖玩法日志
func (s *WCampaignUser) LotteryLog(req *pb.LotteryLogReq, res *pb.LotteryLogRes) (err error) {
defer s.checkErr()
*res = pb.LotteryLogRes{}
container := new(containers.LotteryLog)
{
container.Init(s.ctx)
container.Req = req
container.Res = res
}
return container.Run()
}
// UserList 活动用户数据
func (s *WCampaignUser) UserList(req *pb.UserListReq, res *pb.UserListRes) (err error) {
defer s.checkErr()
m := s.GetDao().FissionUser.SubTable(req.GetCampaignId())
var idsGroup = utils.Groups[int64](req.GetIds(), 200)
var list []*model.FissionUser
for _, ids := range idsGroup {
var parts []*model.FissionUser
parts, err = m.WithContext(s.ctx).Where(m.ID.In(ids...)).Find()
if err != nil {
return
}
list = append(list, parts...)
}
*res = pb.UserListRes{
List: make([]*pb.UserListRes_One, 0, len(list)),
}
for _, v := range list {
res.List = append(res.List, &pb.UserListRes_One{
Id: v.ID,
HashId: v.HashID,
SubUserId: v.SubUserID,
DeviceId: v.DeviceID,
})
}
return
}
// CashAgain 现金大抽奖再玩一次
func (s *WCampaignUser) CashAgain(req *pb.CashAgainReq, res *pb.CashAgainRes) (err error) {
defer s.checkErr()
user, err := finder.FissionUser(s.ctx, req.GetCampaignId(), req.GetUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
err = s.BE().VerifyError("not found user")
return
}
cash, err := players.NewCash(s.ctx, user)
if err != nil {
return
}
err = cash.Again()
if err != nil {
return
}
*res = pb.CashAgainRes{}
return
}
// MarkLevel 用户等级标识列表
func (s *WCampaignUser) MarkLevel(req *pb.MarkLevelReq, res *pb.MarkLevelRes) (err error) {
defer s.checkErr()
project, err := finder.Project(s.ctx, req.GetProjectId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if project == nil {
return
}
m := s.GetDao().FissionUserLevel
list, err := m.WithContext(s.ctx).Where(
m.ProjectID.Eq(project.ID),
m.Mark.In(req.GetMarks()...),
m.DeletedAt.Eq(0),
).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
*res = pb.MarkLevelRes{
List: make([]*pb.MarkLevelRes_One, 0, len(list)),
}
for _, v := range list {
res.List = append(res.List, &pb.MarkLevelRes_One{
Id: v.ID,
Title: v.Title,
Mark: v.Mark,
})
}
return
}
// DiceCollect 用户手机碎片
func (s *WCampaignUser) DiceCollect(req *pb.DiceCollectReq, res *pb.DiceCollectRes) (err error) {
defer s.checkErr()
cpn, err := finder.Campaign(s.ctx, req.GetCampaignHashId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if cpn == nil {
return
}
user, err := finder.FissionUser(s.ctx, cpn.ID, req.GetHashId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user == nil {
return
}
collectM := s.GetDao().FissionDiceCollect
collects, err := collectM.WithContext(s.ctx).Where(collectM.UserID.Eq(user.ID)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var collectMap = make(map[int64]*model.FissionDiceCollect)
for _, v := range collects {
collectMap[v.RewardID] = v
}
rewards, err := cmm.NewCMM(s.ctx, s.GetDao()).UserAppReward(user)
if err != nil {
return
}
var brIds []int64
for _, v := range rewards {
brIds = append(brIds, v.RewardID)
}
rewardM := s.GetDao().Reward
rewardList, err := rewardM.WithContext(s.ctx).Where(rewardM.ID.In(brIds...)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var rewardTitle = make(map[int64]string, len(rewardList))
for _, v := range rewardList {
rewardTitle[v.ID] = v.RewardTitle
}
for _, reward := range rewards {
one := &pb.DiceCollectRes_One{
RewardId: reward.ID,
Num: 0,
CollectNum: reward.CollectNum,
Title: rewardTitle[reward.RewardID],
MixNum: 0,
MaxNum: reward.CollectNum,
}
rule := reward.GetCollectRule()
if rule.Open == mtype.Yes {
one.MaxNum = rule.InitCollect
}
if collect, ok := collectMap[reward.ID]; ok {
one.Num = collect.Num
one.MixNum = collect.IntactNum
if rule.Open == mtype.Yes {
one.MaxNum = rule.InitCollect * collect.SignNum
}
}
res.List = append(res.List, one)
}
return
}
// ClientReward 用户手机碎片
func (s *WCampaignUser) ClientReward(req *pb.ClientRewardReq, res *pb.ClientRewardRes) (err error) {
defer s.checkErr()
var userId = req.GetUserId()
var projectId, cpnId int64
if req.GetPorjectHashId() != "" {
var project *model.Project
project, err = finder.Project(s.ctx, req.GetPorjectHashId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if project != nil {
projectId = project.ID
}
}
if req.GetCampaignUserId() != 0 {
var user *model.FissionUser
user, err = cache.NewFissionUser(s.ctx, req.GetCampaignId()).FindById(req.GetCampaignUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
if user != nil {
userId = user.SubUserID
var cpn *model.FissionCampaign
cpn, err = finder.Campaign(s.ctx, user.CampaignID)
if err != nil {
err = s.BE().CacheError(err)
return
}
if cpn != nil {
projectId = cpn.ProjectID
cpnId = cpn.ID
}
}
}
m := s.GetDao().FissionClientReward
var cond = []gen.Condition{
m.UserID.Eq(userId),
m.ReceiveAt.Eq(0),
}
if projectId > 0 {
cond = append(cond, m.ProjectID.Eq(projectId))
}
if cpnId > 0 {
cond = append(cond, m.CampaignID.Eq(cpnId))
}
*res = pb.ClientRewardRes{
Rewards: make([]*pb.ClientRewardRes_Reward, 0, 20),
}
var rewardMap = make(map[int64]*model.Reward)
var list []*model.FissionClientReward
err = m.WithContext(s.ctx).Where(cond...).FindInBatches(&list, 200, func(tx gen.Dao, batch int) error {
var ids []int64
var recordIds []int64
for _, v := range list {
ids = append(ids, v.ID)
recordIds = append(recordIds, v.RecordID)
}
recordM := s.GetDao().FissionRewardRecord
records, err1 := recordM.WithContext(s.ctx).Where(recordM.ID.In(recordIds...)).Find()
if err1 != nil {
return s.BE().MysqlError(err)
}
var rewardIds []int64
for _, record := range records {
if _, ok := rewardMap[record.BaseRewardID]; !ok {
rewardMap[record.BaseRewardID] = nil
rewardIds = append(rewardIds, record.BaseRewardID)
}
}
if len(rewardIds) > 0 {
rewardM := s.GetDao().Reward
var rewards []*model.Reward
rewards, err = rewardM.WithContext(s.ctx).Where(rewardM.ID.In(rewardIds...)).Find()
if err != nil {
return s.BE().MysqlError(err)
}
for _, reward := range rewards {
rewardMap[reward.ID] = reward
}
}
for _, record := range records {
one := &pb.ClientRewardRes_Reward{
HashId: record.HashID,
CreatedAt: record.CreatedAt,
KvData: make([]*pb.ClientRewardRes_KV, 0),
}
if reward, ok := rewardMap[record.BaseRewardID]; ok {
for _, kv := range reward.GetKvData() {
one.KvData = append(one.KvData, &pb.ClientRewardRes_KV{
Key: kv.Key,
Value: kv.Value,
})
}
}
res.Rewards = append(res.Rewards, one)
}
_, err = recordM.WithContext(s.ctx).Where(recordM.ID.In(recordIds...)).UpdateSimple(recordM.Status.Value(mtype.FissionRewardRecordStatusSuccess))
if err != nil {
return s.BE().MysqlError(err)
}
subM := s.GetDao().FissionRewardRecord.SubTable(cpnId)
_, err = subM.WithContext(s.ctx).Where(subM.ID.In(recordIds...)).UpdateSimple(subM.Status.Value(mtype.FissionRewardRecordStatusSuccess))
if err != nil {
return s.BE().MysqlError(err)
}
_, err = m.WithContext(s.ctx).Where(m.ID.In(ids...)).UpdateSimple(m.ReceiveAt.Value(time.Now().Unix()))
if err != nil {
return s.BE().MysqlError(err)
}
return nil
})
if err != nil {
err = s.BE().MysqlError(err)
return
}
return
}
// PointsUse 积分兑换
func (s *WCampaignUser) PointsUse(req *pb.PointsUseReq, res *pb.PointsUseRes) (err error) {
defer s.checkErr()
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil {
return
}
var status int32
switch cpn.FissionID {
case consts.IdPrizeWheel:
var player *players.Wheel
player, err = players.NewWheel(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
status, err = player.PointsUse()
case consts.IdDice:
var player *players.Dice
player, err = players.NewDice(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
status, err = player.PointsUse()
case consts.IdGashapon:
var player *players.Gashapon
player, err = players.NewGashapon(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
status, err = player.PointsUse()
default:
return s.BE().VerifyError("Not supported")
}
*res = pb.PointsUseRes{
Status: status,
}
return
}
// Chat Ai聊天
func (s *WCampaignUser) Chat(req *pb.ChatReq, res *pb.ChatRes) (err error) {
defer s.checkErr()
*res = pb.ChatRes{}
container := new(containers.Chat)
{
container.Init(s.ctx)
container.Req = req
container.Res = res
}
return container.Run()
}
// ChatList Ai聊天
func (s *WCampaignUser) ChatList(req *pb.ChatListReq, res *pb.ChatListRes) (err error) {
defer s.checkErr()
*res = pb.ChatListRes{}
container := new(containers.ChatList)
{
container.Init(s.ctx)
container.Req = req
container.Res = res
}
return container.Run()
}
// ScheduleList 赛程信息
func (s *WCampaignUser) ScheduleList(req *pb.ScheduleListReq, res *pb.ScheduleListRes) (err error) {
defer s.checkErr()
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil {
return
}
player, err := players.NewVs(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
schedules, err := player.Schedules(req.GetTabType())
if err != nil {
return
}
var list = make([]*pb.ScheduleListRes_One, 0, len(schedules))
for _, schedule := range schedules {
one := &pb.ScheduleListRes_One{
Id: schedule.Id,
Desc: schedule.Desc,
VsImg: schedule.VsImg,
VsDate: schedule.VsDate,
VsTz: schedule.VsTz,
VoteCountdown: schedule.VoteCountdown,
Status: schedule.Status,
WinType: schedule.WinType,
WinTeamId: schedule.WinTeamId,
Teams: make([]*pb.ScheduleListRes_Team, 0, len(schedule.Teams)),
UserVote: nil,
Reward: nil,
Votes: make([]*pb.ScheduleListRes_Vote, 0, len(schedule.Votes)),
OtherVote: schedule.OtherVote,
Scores: make([]*pb.ScheduleListRes_Score, 0, len(schedule.Scores)),
OpenOdds: schedule.OpenOdds,
OddsLeft: schedule.OddsLeft,
OddsRight: schedule.OddsRight,
OddsDraw: schedule.OddsDraw,
}
if schedule.UserVote != nil {
one.UserVote = &pb.ScheduleListRes_UserVote{
UserWinType: schedule.UserVote.UserWinType,
UserWinTeamId: schedule.UserVote.UserWinTeamId,
IsWin: schedule.UserVote.IsWin,
VoteNum: schedule.UserVote.VoteNum,
}
}
for _, team := range schedule.Teams {
one.Teams = append(one.Teams, &pb.ScheduleListRes_Team{
Id: team.Id,
Name: team.Name,
LogoImg: team.LogoImg,
Score: team.Score,
})
}
for _, vote := range schedule.Votes {
one.Votes = append(one.Votes, &pb.ScheduleListRes_Vote{
WinType: vote.WinType,
WinTeamId: vote.WinTeamId,
Num: vote.Num,
})
}
for _, score := range schedule.Scores {
one.Scores = append(one.Scores, &pb.ScheduleListRes_Score{
TeamId: score.TeamId,
Score: score.Score,
})
}
if reward := schedule.Reward; reward != nil {
one.Reward = &pb.ScheduleListRes_Reward{
RewardId: reward.Id,
PropMark: reward.PropMark,
Title: reward.Title,
Img: reward.Img,
KvData: make([]*pb.ScheduleListRes_KV, 0, len(reward.KvData)),
ReceiveType: reward.ReceiveType,
Contact: reward.Contact,
OpenToUse: reward.OpenToUse,
WebUrl: reward.WebUrl,
AppParam: reward.AppParam,
PcParam: reward.PcParam,
PropNum: reward.PropNum,
}
for _, kv := range reward.KvData {
one.Reward.KvData = append(one.Reward.KvData, &pb.ScheduleListRes_KV{
Key: kv.Key,
Value: kv.Value,
IsShow: kv.IsShow,
})
}
}
list = append(list, one)
}
*res = pb.ScheduleListRes{
List: list,
}
return
}
// MallList 用户商城奖品列表
func (s *WCampaignUser) MallList(req *pb.MallListReq, res *pb.MallListRes) (err error) {
defer s.checkErr()
*res = pb.MallListRes{}
container := new(containers.MallList)
{
container.Init(s.ctx)
container.Req = req
container.Res = res
}
return container.Run()
}
// Exchange 商城奖品兑换
func (s *WCampaignUser) Exchange(req *pb.ExchangeReq, res *pb.ExchangeRes) (err error) {
defer s.checkErr()
*res = pb.ExchangeRes{}
container := new(containers.Exchange)
{
container.Init(s.ctx, logic.WithTran())
container.Req = req
container.Res = res
}
return container.Run()
}
// VoteList 投票列表
func (s *WCampaignUser) VoteList(req *pb.VoteListReq, res *pb.VoteListRes) (err error) {
defer s.checkErr()
cpn, user, err := s.CpnAndUserStr(req.GetCampaignHashId(), req.GetUserHashId())
if err != nil {
return
}
m := s.GetDao().FissionVsVote
votes, err := m.WithContext(s.ctx).Where(
m.CampaignID.Eq(cpn.ID),
m.UserID.Eq(user.ID),
).Order(m.ID.Desc()).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
teamM := s.GetDao().FissionCampaignVsTeam
teams, err := teamM.WithContext(s.ctx).Where(
teamM.CampaignID.Eq(cpn.ID),
).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var teamMap = make(map[int64]*pb.VoteListRes_Team, len(teams))
for _, team := range teams {
teamMap[team.ID] = &pb.VoteListRes_Team{
Id: team.ID,
Name: team.Name,
LogoImg: team.LogoImg,
}
}
var scheduleIds []int64
for _, vote := range votes {
scheduleIds = append(scheduleIds, vote.ScheduleID)
}
scheduleM := s.GetDao().FissionCampaignVsSchedule
schedules, err := scheduleM.WithContext(s.ctx).Where(
scheduleM.ID.In(scheduleIds...),
).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var scheduleTeamMap = make(map[int64][]*pb.VoteListRes_Team, len(schedules))
for _, schedule := range schedules {
for _, id := range schedule.GetVsTeamIds() {
scheduleTeamMap[schedule.ID] = append(scheduleTeamMap[schedule.ID], teamMap[id])
}
}
*res = pb.VoteListRes{
List: make([]*pb.VoteListRes_One, 0, len(votes)),
}
for _, vote := range votes {
res.List = append(res.List, &pb.VoteListRes_One{
Id: vote.ID,
Teams: scheduleTeamMap[vote.ScheduleID],
WinType: int32(vote.WinType),
WinTeamId: vote.WinTeamID,
FreeVote: vote.FreeVote,
PointVote: vote.PointVote,
})
}
return
}
// VsTipReward 接收投票结果
func (s *WCampaignUser) VsTipReward(req *pb.VsTipRewardReq, res *pb.VsTipRewardRes) (err error) {
defer s.checkErr()
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil {
return
}
player, err := players.NewVs(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
err = player.TipReward()
if err != nil {
return
}
*res = pb.VsTipRewardRes{}
return
}
// UnoRandCard uno随机牌
func (s *WCampaignUser) UnoRandCard(req *pb.UnoRandCardReq, res *pb.UnoRandCardRes) (err error) {
defer s.checkErr()
*res = pb.UnoRandCardRes{}
container := new(containers.UnoRandCard)
{
container.Init(s.ctx, logic.WithTran(), logic.WithOnce(ckey.FissionUserUnoRandCardOnce(req.GetUserId())))
container.Req = req
container.Res = res
}
return container.Run()
}
// UnoClaim uno领取牌奖励
func (s *WCampaignUser) UnoClaim(req *pb.UnoClaimReq, res *pb.UnoClaimRes) (err error) {
defer s.checkErr()
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil {
return
}
player, err := players.NewUno(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
status, info, record, err := player.Claim(req.GetColorMark())
if err != nil {
return
}
*res = pb.UnoClaimRes{
Status: status,
}
if record != nil {
res.Id = record.ID
res.HashId = record.HashID
res.RewardId = record.RewardID
res.Title = info.Title
res.ImgUrl = info.ImgUrl
res.KvData = make([]*pb.UnoClaimRes_KV, 0, len(info.KvData))
res.ReceiveType = info.ReceiveType
res.Contact = info.Contact
res.OpenToUse = info.OpenToUse
res.CustomRewardVal = record.CustomRewardVal
res.WebUrl = info.WebUrl
res.AppParam = info.AppParam
res.PcParam = info.PcParam
for _, kv := range info.KvData {
res.KvData = append(res.KvData, &pb.UnoClaimRes_KV{
Key: kv.Key,
Value: kv.Value,
IsShow: kv.IsShow,
})
}
}
return
}
// UnoCard uno卡牌
func (s *WCampaignUser) UnoCard(req *pb.UnoCardReq, res *pb.UnoCardRes) (err error) {
defer s.checkErr()
cpn, user, err := s.CpnAndUserStr(req.GetCampaignHashId(), req.GetUserHashId())
if err != nil {
return
}
m := s.GetDao().FissionUnoCollect
list, err := m.WithContext(s.ctx).Where(m.UserID.Eq(user.ID)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var collectMap = make(map[string]*model.FissionUnoCollect, len(list))
for _, v := range list {
collectMap[v.Mark] = v
}
groupM := s.GetDao().FissionCampaignUnoGroup
groups, err := groupM.WithContext(s.ctx).Where(groupM.CampaignID.Eq(cpn.ID)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
*res = pb.UnoCardRes{
List: make([]*pb.UnoCardRes_One, 0, len(list)),
}
for _, v := range groups {
one := &pb.UnoCardRes_One{
Id: v.ID,
Mark: v.Mark,
LimitNum: 9,
}
if collect, ok := collectMap[v.Mark]; ok {
one.PreIntactNum = collect.PreIntactNum
one.IntactNum = collect.IntactNum
one.CardInfo = collect.GetCardInfo()
if v.OpenRule == mtype.Yes {
rule := v.GetLimitRule()
one.LimitNum = rule.InitNum + rule.AddNum*(collect.SignNum/rule.SignDay)
if one.LimitNum > 9 {
one.LimitNum = 9
}
}
}
res.List = append(res.List, one)
}
return
}
// Show 用户详情
func (s *WCampaignUser) Show(req *pb.ShowReq, res *pb.ShowRes) (err error) {
defer s.checkErr()
cpn, user, err := s.CpnAndUserStr(req.GetCampaignHashId(), req.GetUserHashId())
if err != nil {
return
}
attr := provider.NewFissionUserAttr(s.ctx, user)
platform, err := attr.GetAttr(mtype.FissionUserAttrMarkPlatform)
if err != nil {
return
}
var oss string
var os string
if platform != nil {
os = platform.Value
oss = platform.Values
}
lang, _ := attr.GetAttr(mtype.FissionUserAttrMarkLang)
var langMarks []string
if lang != nil {
langMarks = lang.GetValues()
}
lv, _ := attr.GetAttr(mtype.FissionUserAttrMarkUserLv)
var lvMarks string
if lv != nil {
lvMarks = lv.Values
}
lastView, err := app.NewFissionBiFissionAction().FindLast(s.ctx, &bi_fission_actionpb.FindLastReq{
CampaignId: cpn.ID,
Type: mtype.FissionActionTypeView,
UserMark: fmt.Sprint(user.ID),
})
if err != nil {
return
}
*res = pb.ShowRes{
Id: user.ID,
HashId: user.HashID,
UserId: user.SubUserID,
DeviceId: user.DeviceID,
CreatedAt: user.CreatedAt,
Source: int32(user.Source),
LangMark: user.LangMark,
LangMarks: langMarks,
LvMark: user.LevelMark,
LvMarks: lvMarks,
Os: os,
Oss: oss,
JoinAt: user.JoinAt,
JoinAtLast: lastView.GetActionTime(),
Tz: cpn.TOffset,
}
return
}
// EventFirstVisit 首次访问活动
func (s *WCampaignUser) EventFirstVisit(req *pb.EventFirstVisitReq, res *pb.EventFirstVisitRes) (err error) {
defer s.checkErr()
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil {
return
}
var rewards []*players.EventReward
switch cpn.FissionID {
case consts.IdVs:
var player *players.Vs
player, err = players.NewVs(s.ctx, user, players.SetCpn(cpn))
if err != nil {
return
}
rewards, err = player.FirstVisit()
if err != nil {
return
}
}
*res = pb.EventFirstVisitRes{
Rewards: make([]*pb.EventFirstVisitRes_EventReward, 0, len(rewards)),
}
for _, v := range rewards {
var reward *pb.EventFirstVisitRes_Reward
if verify.InArray[string](v.PropMark, mtype.FissionCampaignRewardPropMarkPoint, mtype.FissionCampaignRewardPropMarkReward) {
record, info := v.Reward.Record, v.Reward.Info
reward = &pb.EventFirstVisitRes_Reward{
Id: record.ID,
HashId: record.HashID,
RewardId: record.RewardID,
RewardNum: record.RewardNum,
Title: record.Title,
ImgUrl: record.ImgURL,
KvData: make([]*pb.EventFirstVisitRes_KV, 0, len(info.KvData)),
ReceiveType: info.ReceiveType,
Contact: info.Contact,
CustomRewardVal: record.CustomRewardVal,
WebUrl: info.WebUrl,
AppParam: info.AppParam,
PcParam: info.PcParam,
}
for _, kv := range info.KvData {
reward.KvData = append(reward.KvData, &pb.EventFirstVisitRes_KV{
Key: kv.Key,
Value: kv.Value,
IsShow: kv.IsShow,
})
}
}
res.Rewards = append(res.Rewards, &pb.EventFirstVisitRes_EventReward{
PropMark: v.PropMark,
Reward: reward,
Chance: v.Chance,
})
}
return
}
// FindByUniq 通过唯一键找用户id
func (s *WCampaignUser) FindByUniq(req *pb.FindByUniqReq, res *pb.FindByUniqRes) (err error) {
defer s.checkErr()
c := cache.NewFissionUser(s.ctx, req.GetCampaignId())
var user *model.FissionUser
if req.GetSubUserId() != "" {
user, err = c.FindBySubUserId(req.GetSubUserId())
if err != nil {
err = s.BE().CacheError(err)
return
}
}
if req.GetDeviceId() != "" {
user, err = c.FindBySubUserId(req.GetDeviceId())
if err != nil {
err = s.BE().CacheError(err)
return
}
}
var id int64
if user != nil {
id = user.ID
}
*res = pb.FindByUniqRes{
Id: id,
}
return
}
// TaskTip 任务提示
func (s *WCampaignUser) TaskTip(req *pb.TaskTipReq, res *pb.TaskTipRes) (err error) {
defer s.checkErr()
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil || cpn == nil || user == nil {
return
}
list, err := players.GetTaskTip(s.ctx, user.ID)
if err != nil {
return
}
*res = pb.TaskTipRes{
Rewards: make([]*pb.TaskTipRes_EventReward, 0),
L: int32(len(list)),
}
var hasCoin bool
var recordIds []int64
for _, v := range list {
if v.PropMark == mtype.FissionCampaignRewardPropMarkPoint {
hasCoin = true
}
if v.RecordId > 0 {
recordIds = append(recordIds, v.RecordId)
}
}
var recordMap = make(map[int64]*model.FissionRewardRecord)
var preward *provider.Rewards
if len(recordIds) > 0 {
m := s.GetDao().FissionRewardRecord.SubTable(req.GetCampaignId())
var records []*model.FissionRewardRecord
records, err = m.WithContext(s.ctx).Where(m.ID.In(recordIds...)).Find()
if err != nil {
return
}
var bIds []int64
var bMap = make(map[int64]struct{})
for _, v := range records {
recordMap[v.ID] = v
if _, ok := bMap[v.BaseRewardID]; !ok && v.BaseRewardID > 0 {
bIds = append(bIds, v.BaseRewardID)
bMap[v.BaseRewardID] = struct{}{}
}
}
if len(bIds) > 0 {
preward, err = provider.NewRewards(s.ctx, cpn.ProjectID, bIds...)
if err != nil {
return
}
}
}
var title, imgUrl string
if hasCoin {
title, imgUrl, _, err = cmm.NewCMM(s.ctx, s.GetDao()).GetCoinInfo(cpn.ProjectID, user.LangMark)
if err != nil {
return
}
}
for _, v := range list {
switch v.PropMark {
case mtype.FissionCampaignRewardPropMarkChance:
res.Rewards = append(res.Rewards, &pb.TaskTipRes_EventReward{
PropMark: v.PropMark,
Reward: nil,
Chance: v.Chance,
})
case mtype.FissionCampaignRewardPropMarkReward:
r := recordMap[v.RecordId]
info, _ := preward.InfoAutoLang(r.BaseRewardID, user.LangMark)
var kv = make([]*pb.TaskTipRes_KV, 0, len(info.KvData))
for _, d := range info.KvData {
kv = append(kv, &pb.TaskTipRes_KV{
Key: d.Key,
Value: d.Value,
IsShow: d.IsShow,
})
}
res.Rewards = append(res.Rewards, &pb.TaskTipRes_EventReward{
PropMark: v.PropMark,
Reward: &pb.TaskTipRes_Reward{
Id: r.ID,
HashId: r.HashID,
RewardId: r.RewardID,
RewardNum: r.RewardNum,
Title: info.Title,
ImgUrl: info.ImgUrl,
KvData: kv,
ReceiveType: info.ReceiveType,
Contact: info.Contact,
CustomRewardVal: r.CustomRewardVal,
WebUrl: info.WebUrl,
AppParam: info.AppParam,
PcParam: info.PcParam,
},
Chance: v.Chance,
})
case mtype.FissionCampaignRewardPropMarkPoint:
r := recordMap[v.RecordId]
res.Rewards = append(res.Rewards, &pb.TaskTipRes_EventReward{
PropMark: v.PropMark,
Reward: &pb.TaskTipRes_Reward{
Id: r.ID,
HashId: r.HashID,
RewardId: r.RewardID,
RewardNum: r.RewardNum,
Title: title,
ImgUrl: imgUrl,
},
Chance: r.RewardNum,
})
}
}
return
}
// TaskTipOk 任务提示完成
func (s *WCampaignUser) TaskTipOk(req *pb.TaskTipOkReq, res *pb.TaskTipOkRes) (err error) {
defer s.checkErr()
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil || cpn == nil || user == nil {
return
}
players.DelTaskTip(s.ctx, user.ID, req.GetL())
*res = pb.TaskTipOkRes{}
return
}
// CoinLog 金币日志
func (s *WCampaignUser) CoinLog(req *pb.CoinLogReq, res *pb.CoinLogRes) (err error) {
defer s.checkErr()
cpn, user, err := s.CpnAndUser(req.GetCampaignId(), req.GetUserId())
if err != nil || cpn == nil || user == nil {
return
}
if user.SubUserID == "" {
return
}
pu, err := projectuser.NewProjectUser(s.ctx, projectuser.WithInit(cpn.ProjectID, user.SubUserID))
if err != nil {
return
}
m := s.GetDao().ProjectUserCoinRecord
var cond = []gen.Condition{
m.UserID.Eq(pu.GetProjectUser().ID),
m.Source.Eq(mtype.ProjectUserCoinSourceCampaign),
m.SourceID.Eq(cpn.ID),
m.CreatedAt.Gt(cpn.StartTime),
}
if req.GetType() > 0 {
cond = append(cond, m.Type.Eq(int8(req.GetType())))
}
o, l := utils.PpDbLo(req.GetPage(), req.GetPerPage())
list, total, err := m.WithContext(s.ctx).Where(cond...).Order(m.ID.Desc()).FindByPage(o, l)
if err != nil {
err = s.BE().MysqlError(err)
return
}
if total == 0 {
return
}
*res = pb.CoinLogRes{
List: make([]*pb.CoinLogRes_One, 0, len(list)),
Total: total,
}
for _, v := range list {
res.List = append(res.List, &pb.CoinLogRes_One{
CreatedAt: v.CreatedAt,
Mark: fmt.Sprintf("coin_log:%s", v.Mark),
Num: v.Num,
Type: int32(v.Type),
})
}
return
}
// AnswerHistory 答题历史
func (s *WCampaignUser) AnswerHistory(req *pb.AnswerHistoryReq, res *pb.AnswerHistoryRes) (err error) {
defer s.checkErr()
cpn, err := cache.NewCampaign(s.ctx).FindById(req.GetCampaignId())
if err != nil || cpn == nil {
return
}
rewardM := s.GetDao().FissionRewardRecord.SubTable(cpn.ID)
reward, err := rewardM.WithContext(s.ctx).Where(rewardM.CampaignID.Eq(cpn.ID), rewardM.HashID.Eq(req.GetRewardHashId())).Take()
if err = dbcheck.DbError(err); err != nil {
err = s.BE().MysqlError(err)
return
}
answers := reward.GetAnswer()
var qid []int64
var selectMap = make(map[int64]map[int64]struct{})
for _, v := range answers {
qid = append(qid, v.QID)
if _, ok := selectMap[v.QID]; !ok {
selectMap[v.QID] = make(map[int64]struct{})
}
for _, a := range v.AID {
selectMap[v.QID][a] = struct{}{}
}
}
m := s.GetDao().LibraryQa
qa, err := m.WithContext(s.ctx).Where(m.ID.In(qid...)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var qMap = make(map[int64]*model.LibraryQa)
for _, v := range qa {
qMap[v.ID] = v
}
optionM := s.GetDao().LibraryQaOption
options, err := optionM.WithContext(s.ctx).Where(optionM.QaID.In(qid...), optionM.IsDel.Eq(mtype.No)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
var qaMap = make(map[int64][]*model.LibraryQaOption)
for _, option := range options {
qaMap[option.QaID] = append(qaMap[option.QaID], option)
}
*res = pb.AnswerHistoryRes{
List: make([]*pb.AnswerHistoryRes_One, 0, len(qid)),
}
for _, v := range answers {
q, ok := qMap[v.QID]
if !ok {
continue
}
one := &pb.AnswerHistoryRes_One{
Id: q.ID,
HashId: q.HashID,
Mark: q.Mark,
Title: q.Title,
CoverUrl: q.CoverURL,
LinkUrl: q.LinkURL,
ExplainText: q.ExplainText,
ExplainImg: q.ExplainImg,
Options: make([]*pb.AnswerHistoryRes_Option, 0, len(qaMap[v.QID])),
AnswerMark: q.AnswerMark,
SelectOptionId: v.AID,
}
for _, opt := range qaMap[v.QID] {
one.Options = append(one.Options, &pb.AnswerHistoryRes_Option{
Id: opt.ID,
Title: opt.Title,
ImgUrl: opt.ImgURL,
IsRight: int32(opt.IsRight),
})
}
res.List = append(res.List, one)
}
return
}