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.

371 lines
9.2 KiB
Go

package award
import (
"context"
"joybuywork/internal/repository/dao"
"joybuywork/internal/repository/model"
"joybuywork/internal/repository/mtype"
"joybuywork/internal/repository/withdefault"
"joybuywork/internal/service/cmm"
"joybuywork/internal/service/provider"
"joybuywork/internal/service/provider/fissionaction"
"joybuywork/internal/service/provider/projectuser"
"joybuywork/internal/service/queue/producer"
"joybuywork/internal/service/queue/types"
"joybuywork/internal/utils/logic"
"joybuywork/internal/utils/merr"
"joybuywork/internal/utils/verify"
"fmt"
)
type RecordOption func(record *model.FissionRewardRecord)
// RewardRecordStatus 设置状态
func RewardRecordStatus(status int8, failType, failMsg string) RecordOption {
return func(record *model.FissionRewardRecord) {
record.Status = status
record.FailType = failType
record.FailMsg = failMsg
}
}
// RewardRecordAnswer 设置题答题目
func RewardRecordAnswer(answer string, score int32) RecordOption {
return func(record *model.FissionRewardRecord) {
record.Answer = answer
record.Score = score
}
}
// RewardRecordChildId 设置子活动
func RewardRecordChildId(childId int64) RecordOption {
return func(record *model.FissionRewardRecord) {
record.ChildID = childId
}
}
type Reward struct {
logic.Context
user *model.FissionUser
projectId int64
coinInfo struct {
Title string
ImgURL string
RewardTitle string
}
async []func()
}
// NewAwardReward 奖品发放验证
func NewAwardReward(ctx context.Context, dao *dao.Query, projectId int64, user *model.FissionUser) *Reward {
award := &Reward{
user: user,
projectId: projectId,
}
award.Init(ctx, dao, merr.NewBE(ctx))
return award
}
// RewardIdsBatch 通过奖品id扣除奖品
func (s *Reward) RewardIdsBatch(rewardIds []int64, sync bool) (res []*RewardRes, async []func(), err error) {
m := s.GetDao().FissionCampaignReward
rewards, err := m.WithContext(s.Ctx).Where(m.ID.In(rewardIds...)).Find()
if err != nil {
err = s.BE().MysqlError(err)
return
}
if len(rewards) == 0 {
return
}
var rewardMap = make(map[int64]*model.FissionCampaignReward)
for _, v := range rewards {
rewardMap[v.ID] = v
}
var sendRewards = make([]*model.FissionCampaignReward, 0, len(rewardIds))
for _, v := range rewardIds {
reward, has := rewardMap[v]
if !has {
continue
}
sendRewards = append(sendRewards, reward)
}
if len(sendRewards) == 0 {
return
}
return s.DeductStockBatch(sendRewards, sync)
}
// DeductStockOne 扣除单个缓存
func (s *Reward) DeductStockOne(reward *model.FissionCampaignReward, sync bool) (record *model.FissionRewardRecord, info provider.RewardAutoLang, async []func(), err error) {
res, async, err := s.DeductStockBatch([]*model.FissionCampaignReward{reward}, sync)
if err != nil {
return
}
return res[0].Record, res[0].Info, async, nil
}
// DeductStockBatch 扣除缓存的批量处理
func (s *Reward) DeductStockBatch(rewards []*model.FissionCampaignReward, sync bool) (res []*RewardRes, async []func(), err error) {
var addRewards = make([]*RewardOne, 0, len(rewards))
for _, reward := range rewards {
ok, err1 := NewAwardIssVerify(s.Ctx, s.user, reward).DeductStock().IsOK()
if err1 != nil {
err = err1
return
}
var opts []RecordOption
if !ok {
opts = append(opts, RewardRecordStatus(
mtype.FissionRewardRecordStatusFail,
mtype.FissionRewardRecordFailTypeCli,
mtype.FissionRewardRecordFailTypeCliLackMsg,
))
}
addRewards = append(addRewards, &RewardOne{
Reward: reward,
Opts: opts,
})
}
return s.Batch(addRewards, sync)
}
// One 创建用户奖品
func (s *Reward) One(reward *model.FissionCampaignReward, sync bool, opts ...RecordOption) (record *model.FissionRewardRecord, info provider.RewardAutoLang, async []func(), err error) {
var one = &RewardOne{
Reward: reward,
Opts: opts,
}
res, async, err := s.Batch([]*RewardOne{one}, sync)
if err != nil {
return
}
return res[0].Record, res[0].Info, async, nil
}
type RewardOne struct {
Reward *model.FissionCampaignReward
Opts []RecordOption
}
type RewardRes struct {
Record *model.FissionRewardRecord
Info provider.RewardAutoLang
Reward *model.FissionCampaignReward
}
// Batch 批量创建用户奖品
func (s *Reward) Batch(rewards []*RewardOne, sync bool) (res []*RewardRes, async []func(), err error) {
if len(rewards) == 0 {
return
}
user := s.user
var brIds []int64
for _, reward := range rewards {
if reward.Reward.RewardID == 0 {
continue
}
brIds = append(brIds, reward.Reward.RewardID)
}
var preward *provider.Rewards
if len(brIds) > 0 {
preward, err = provider.NewRewards(s.Ctx, s.projectId, brIds...)
if err != nil {
return
}
}
res = make([]*RewardRes, 0, len(rewards))
var records = make([]*model.FissionRewardRecord, 0, len(rewards))
for _, one := range rewards {
reward := one.Reward
record := withdefault.FissionRewardRecord(&model.FissionRewardRecord{
CampaignID: user.CampaignID,
UserID: user.ID,
RewardID: reward.ID,
RewardType: reward.RewardType,
RewardNum: reward.RewardNum,
Step: reward.Step,
IsThank: reward.IsThank,
BaseRewardID: reward.RewardID,
PropMark: reward.PropMark,
})
if verify.InArray[string](reward.PropMark, mtype.FissionCampaignRewardPropMarkChance, mtype.FissionCampaignRewardPropMarkPoint) || reward.RewardID < 0 {
record.Status = mtype.FissionRewardRecordStatusSuccess
}
if reward.RewardType == mtype.FissionCampaignRewardTypeChild {
record.ChildID = reward.CampaignID
}
for _, opt := range one.Opts {
opt(record)
}
var info provider.RewardAutoLang
if reward.PropMark == mtype.FissionCampaignRewardPropMarkPoint {
info.Title, info.ImgUrl, info.RewardTitle, _ = s.getCoinInfo(user.LangMark)
} else if reward.RewardID != 0 && preward != nil {
info, _ = preward.InfoAutoLang(reward.RewardID, user.LangMark)
}
record.Title, record.ImgURL = info.Title, info.ImgUrl
records = append(records, record)
res = append(res, &RewardRes{
Record: nil,
Info: info,
Reward: reward,
})
}
m := s.GetDao().FissionRewardRecord
err = m.WithContext(s.Ctx).Create(records...)
if err != nil {
err = s.BE().MysqlError(err)
return
}
sm := s.GetDao().FissionRewardRecord.SubTable(user.CampaignID)
err = sm.WithContext(s.Ctx).Create(records...)
if err != nil {
err = s.BE().MysqlError(err)
return
}
var earnCoin []*projectuser.EarnCoinParam
for k, record := range records {
res[k].Record = record
switch record.PropMark {
case mtype.FissionCampaignRewardPropMarkPoint:
var operate = mtype.ProjectUserCoinAddReward
switch res[k].Reward.RewardType {
case mtype.FissionCampaignRewardTypeTask:
operate = mtype.ProjectUserCoinAddTask
}
earnCoin = append(earnCoin, &projectuser.EarnCoinParam{
CoinNum: record.RewardNum,
IsExpired: res[k].Reward.IsExpired(),
ExpiredAt: res[k].Reward.ExpiredAt(),
Source: mtype.ProjectUserCoinSourceCampaign,
SourceID: record.CampaignID,
SourceData: map[string]string{
"reward_id": fmt.Sprintf("%d", record.RewardID),
"record_id": fmt.Sprintf("%d", record.ID),
},
Operate: operate,
})
default:
s.notify(record, res[k].Info)
}
s.markPoint(record)
}
if len(earnCoin) > 0 {
var pu *projectuser.ProjectUser
pu, err = projectuser.NewProjectUser(s.Ctx, projectuser.WithInit(s.projectId, s.user.SubUserID))
if err != nil {
return
}
err = pu.EarnCoin(earnCoin...)
if err != nil {
return
}
}
if sync {
for _, do := range s.async {
do()
}
return
}
async = s.async
return
}
// 回调
func (s *Reward) notify(record *model.FissionRewardRecord, info provider.RewardAutoLang) {
if record.Status != mtype.FissionRewardRecordStatusWait || record.PropMark == mtype.FissionCampaignRewardPropMarkChance {
return
}
if info.ReceiveType == mtype.RewardReceiveTypeClient {
_ = s.GetDao().FissionClientReward.WithContext(s.Ctx).Create(withdefault.FissionClientReward(&model.FissionClientReward{
UserID: s.user.SubUserID,
ProjectID: s.projectId,
CampaignID: s.user.CampaignID,
RecordID: record.ID,
CreatedAt: record.CreatedAt,
}))
return
}
s.async = append(s.async, func() {
producer.NewCampaignNotice(s.Ctx).CampaignRewardNotify(types.CampaignRewardNotify{
CampaignId: s.user.CampaignID,
UserId: s.user.ID,
UserRewardId: record.ID,
})
producer.CheckRewardPush(s.Ctx, 60, types.DelayCommonCheckRewardPush{
CampaignId: s.user.CampaignID,
UserId: s.user.ID,
UserRewardId: record.ID,
BaseRewardId: record.BaseRewardID,
})
})
}
// 埋点
func (s *Reward) markPoint(record *model.FissionRewardRecord) {
s.async = append(s.async, func() {
fissionaction.NewMarkPoint(s.Ctx).InApp(s.user).Reward(record.CreatedAt, record.RewardID, record.ID, record.ChildID, record.RewardType, record.RewardNum)
})
}
func (s *Reward) getCoinInfo(langMark string) (title, imgUrl, rewardTitle string, err error) {
if s.coinInfo.Title != "" {
return s.coinInfo.Title, s.coinInfo.ImgURL, s.coinInfo.RewardTitle, nil
}
s.coinInfo.Title, s.coinInfo.ImgURL, s.coinInfo.RewardTitle, err = cmm.NewCMM(s.Ctx, s.GetDao()).GetCoinInfo(s.projectId, langMark)
if err != nil {
return
}
return s.coinInfo.Title, s.coinInfo.ImgURL, s.coinInfo.RewardTitle, nil
}