Files
rootandClaude Opus 5 8679200f41 Initial commit
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 13:57:10 +08:00

1163 lines
33 KiB
Go

package taskser
import (
"91porn-server/models/v/taskrecordmod"
"91porn-server/web/webg"
"errors"
"fmt"
"strconv"
"time"
"go.mongodb.org/mongo-driver/bson"
"91porn-server/app/appg"
"91porn-server/common/constant/redisconst"
"91porn-server/common/db"
"91porn-server/common/log"
"91porn-server/common/stderr"
"91porn-server/common/timeutil"
"91porn-server/models/l/adsclicklogmod"
"91porn-server/models/l/userdailytasklogmod"
"91porn-server/models/v/dailytaskmod"
"91porn-server/models/v/oncetaskmod"
"91porn-server/models/v/prizemod"
"91porn-server/models/v/proxymod"
"91porn-server/models/v/taskmod"
"91porn-server/models/v/txnmod"
"91porn-server/models/v/usermod"
"go.mongodb.org/mongo-driver/bson/primitive"
)
/*
// 获取任务
func GetTaskList(uid uint64) (out TaskResponse, code stderr.Code) {
var (
louFengIsReceive bool
now time.Time = time.Now()
consumerFeedbackTask Config = Config{
BoonType: taskmod.ConsumerFeedback,
Status: UnDone,
}
)
out.JewelBoxDetails.List = make([]Config, 0)
out.TaskList = make([]Config, 0)
// 获取用户签到信息
signInfo, err := taskrecordmod.GetByUID(uid)
if err != nil {
code = stderr.ErrDbQueryError
return
}
// 异常判定
if signInfo == nil {
code = stderr.ErrInvalidRequest
return
}
// 获取奖品列表
prizes, err := prizemod.GetPrizeList()
if err != nil {
code = stderr.ErrDbQueryError
return
}
// 获取任务配置
list, err := taskmod.ConfigList()
if err != nil {
code = stderr.ErrDbQueryError
return
}
for _, v := range list {
switch v.Type {
case taskmod.JewelBox:
taskConfig := Config{
ID: v.ID,
Prizes: getPrizeList(v.Prizes, prizes),
FinishCondition: v.FinishCondition,
Title: v.Title,
Desc: v.Desc,
Status: UnDone,
BoonType: v.Type,
}
// 达到领取条件
if signInfo.CurrentValue >= v.FinishCondition {
// 已领取
taskConfig.Status = Finish
if signInfo.HasReceived(v.ID, taskrecordmod.JewelBox) {
taskConfig.Status = Receive
}
taskConfig.FinishValue = v.FinishCondition
} else {
taskConfig.FinishValue = signInfo.CurrentValue
if out.JewelBoxDetails.TotalValue < taskConfig.FinishCondition {
out.JewelBoxDetails.TotalValue = taskConfig.FinishCondition
}
}
out.JewelBoxDetails.List = append(out.JewelBoxDetails.List, taskConfig)
case taskmod.ConsumerFeedback:
consumerFeedbackTask.ID = v.ID
consumerFeedbackTask.Prizes = getPrizeList(v.Prizes, prizes)
consumerFeedbackTask.FinishCondition = v.FinishCondition
consumerFeedbackTask.Title = v.Title
consumerFeedbackTask.Desc = v.Desc
if !louFengIsReceive {
louFengIsReceive = true
// 统计今日楼凤消费
totalAmount, _, err := txnmod.GetIncomeByType(uid, txnmod.LouFeng,
timeutil.BeginningOfDay(now), timeutil.BeginningOfDay(now.AddDate(0, 0, 1)))
if err != nil {
code = stderr.ErrDbQueryError
return
}
consumerFeedbackTask.FinishValue = -int64(totalAmount)
}
// 任务记录刷新
if !signInfo.ConsumerFeedbackReceiveTime.After(timeutil.BeginningOfDay(now)) {
signInfo, err = taskrecordmod.ConsumerFeedbackReset(uid)
if err != nil {
code = stderr.ErrDbQueryError
return
}
}
if consumerFeedbackTask.FinishValue >= v.FinishCondition && !signInfo.HasReceived(v.ID, taskrecordmod.ConsumerFeedback) {
consumerFeedbackTask.Status = Finish
}
}
}
if len(out.JewelBoxDetails.List) > 0 && signInfo != nil {
out.JewelBoxDetails.Value = signInfo.CurrentValue
}
if !consumerFeedbackTask.ID.IsZero() {
out.TaskList = append(out.TaskList, consumerFeedbackTask)
}
code = stderr.Success
return
}
*/
/*
func GetTaskDetails(uid uint64, boonType int) (out TaskDetailsResponse, code stderr.Code) {
now := time.Now()
// 获取配置列表
taskDetail, err := taskmod.GetConfigListByType(taskmod.ConfigType(boonType))
if err != nil {
return out, stderr.ErrDbQueryError
}
// 获取奖品列表
prizes, err := prizemod.GetPrizeList()
if err != nil {
return out, stderr.ErrDbQueryError
}
//查询用户签到信息
taskInfo, err := taskrecordmod.GetByUID(uid)
if err != nil {
return out, stderr.ErrDbQueryError
}
// 新增用户任务记录
if taskInfo == nil {
taskInfo, err = taskrecordmod.AddTaskRecord(uid)
if err != nil {
return out, stderr.ErrDbQueryError
}
}
switch taskmod.ConfigType(boonType) {
case taskmod.ConsumerFeedback:
// 统计今日楼凤消费
totalAmount, _, err := txnmod.GetIncomeByType(uid, txnmod.LouFeng,
timeutil.BeginningOfDay(now), timeutil.BeginningOfDay(now.AddDate(0, 0, 1)))
if err != nil {
code = stderr.ErrDbQueryError
return
}
out.Value = -int64(totalAmount)
default:
code = stderr.ErrInvalidRequest
return
}
sort.Slice(taskDetail, func(i, j int) bool { // 按照赠送门槛逆序,保证游戏用户能领取游戏充值的游戏币最多的礼物
return taskDetail[i].FinishCondition > taskDetail[j].FinishCondition
})
out.TaskList = make([]Config, len(taskDetail))
for i, v := range taskDetail {
taskConfig := Config{
ID: v.ID,
Prizes: getPrizeList(v.Prizes, prizes),
FinishCondition: v.FinishCondition,
Title: v.Title,
Desc: v.Desc,
Status: UnDone,
BoonType: v.Type,
}
if out.Value > taskConfig.FinishCondition { // 充值/消费金额满足礼物要求
switch v.Type {
case taskmod.ConsumerFeedback: // 楼凤消费礼物可以同时领取多个
taskConfig.Status = Finish
if taskInfo.HasReceived(v.ID, taskrecordmod.ConfigType(v.Type)) {
taskConfig.Status = Receive
}
}
}
out.TaskList[i] = taskConfig
}
return out, stderr.Success
}
*/
/*
// 领取福利
func GetBoon(ctx context.Context, uid uint64, configID string, boonType int) stderr.Code {
var (
now time.Time = time.Now()
transType txnmod.TransType
)
id, err := primitive.ObjectIDFromHex(configID)
if err != nil {
return stderr.ErrParamError
}
// 获取任务配置
configInfo, err := taskmod.GetConfigByID(id)
if err != nil {
return stderr.ErrDbQueryError
}
// 异常判定 配置关闭后请求/配置ID不正确
if configInfo == nil || configInfo.Type != taskmod.ConfigType(boonType) {
log.InfoX(ctx, "配置关闭后请求/配置ID不正确")
return stderr.ErrInvalidRequest
}
// 获取任务记录
taskInfo, err := taskrecordmod.GetByUID(uid)
if err != nil {
return stderr.ErrDbQueryError
}
// 异常判定 不满足领取条件用户不会请求该接口
if taskInfo == nil {
log.InfoX(ctx, "不满足领取条件用户不会请求该接口")
return stderr.ErrInvalidRequest
}
switch taskmod.ConfigType(boonType) {
case taskmod.JewelBox:
// 领取条件判定
if taskInfo.CurrentValue < configInfo.FinishCondition {
log.InfoX(ctx, "领取条件判定")
return stderr.ErrInvalidRequest
}
transType = txnmod.JewelBoxBoon
case taskmod.ConsumerFeedback:
// 统计今日楼凤消费
totalAmount, _, err := txnmod.GetIncomeByType(uid, txnmod.LouFeng,
timeutil.BeginningOfDay(now), timeutil.BeginningOfDay(now.AddDate(0, 0, 1)))
if err != nil {
return stderr.ErrDbQueryError
}
if -totalAmount < float64(configInfo.FinishCondition) {
log.InfoX(ctx, "消费回馈(站群)领取条件不足")
return stderr.ErrInvalidRequest
}
transType = txnmod.LouFengConsumerRebate
default:
return stderr.ErrParamError
}
// 异常判定 重复领取
for _, v := range taskInfo.JewelBoxRecord {
if v == id {
return stderr.ErrDbQueryError
}
}
// 获取奖品列表
prizes, err := prizemod.GetPrizeListByIDs(configInfo.Prizes)
if err != nil {
return stderr.ErrDbQueryError
}
// 奖励发放
hanlders := make([]prizemod.PrizeHanlder, 0, len(prizes))
var transactionLogs []txnmod.TransactionLog
var gameHanlder, addGoldHanlder prizemod.PrizeHanlder
for _, v := range prizes {
hanlder, err := prizemod.Run(uid, *v, transType)
if err != nil {
return stderr.ErrDbQueryError
}
switch v.Type {
case prizemod.Gold:
addGoldHanlder = hanlder
hanlders = append(hanlders, hanlder)
default:
hanlders = append(hanlders, hanlder)
transactionLogs = append(transactionLogs, hanlder.GetTransactionLog()...)
}
}
if err = appg.VideoDB.Trans(func(t *db.MongoTool) error {
if err = taskrecordmod.BoonRecordUpdate(t, uid, id, taskrecordmod.ConfigType(boonType)); err != nil {
return err
}
for _, v := range hanlders {
if err = v.Run(t); err != nil {
return err
}
}
if addGoldHanlder != nil {
transactionLogs = append(transactionLogs, addGoldHanlder.GetTransactionLog()...)
}
if len(transactionLogs) > 0 {
if err = txnmod.InsertManyTransactionLog(t, transactionLogs); err != nil {
return err
}
}
// 特殊处理棋牌金币增加
if gameHanlder != nil {
if err = gameHanlder.Run(t); err != nil {
return err
}
}
return nil
}); err != nil {
return stderr.ErrDbTransError
}
return stderr.Success
}
*/
func GetDailyTask(uid uint64) ([]DailyTaskResponse, stderr.Code, string) {
tasks, err := dailytaskmod.GetUserDailyTasks(nil)
if err != nil {
return nil, stderr.ErrDbQueryError, ""
}
tasksLen := len(tasks)
if tasksLen == 0 {
return nil, stderr.Success, ""
}
dtrs := make([]DailyTaskResponse, tasksLen)
for i, task := range tasks {
dtrs[i] = DailyTaskResponse{
ID: task.ID,
Title: task.Title,
Img: task.Img,
Type: task.Type,
Desc: task.Desc,
Link: task.Link,
Status: 0,
}
today := timeutil.BeginningOfDay(time.Now())
item, err := taskrecordmod.GetUserRecordByTime(uid, task.ID, today)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;查询用户领取金币任务信息异常:%v", uid, err))
return nil, stderr.ErrDbQueryError, ""
}
if item != nil && !item.ID.IsZero() {
dtrs[i].Status = item.Status
}
//if task.Type == dailytaskmod.DailyUserLogin || task.Type == dailytaskmod.DailyComment || task.Type == dailytaskmod.DailyPublish ||
// task.Type == dailytaskmod.DailyTaskTypeAdsClick || task.Type == dailytaskmod.DailyTaskTypeUserInvite {
// today := timeutil.BeginningOfDay(time.Now())
// item, err := taskrecordmod.GetUserRecordByTime(uid, task.ID, today)
// if err != nil {
// log.Error(fmt.Sprintf("用户ID:%d;查询用户领取金币任务信息异常:%v", uid, err))
// return nil, stderr.ErrDbQueryError, ""
// }
// if item != nil && !item.ID.IsZero() {
// dtrs[i].Status = item.Status
// }
//}
}
return dtrs, stderr.Success, ""
}
func mergePidsAndTrimRepeat(ids1, ids2 []primitive.ObjectID) []primitive.ObjectID {
ids1Len := len(ids1)
ids2Len := len(ids2)
if ids1Len == 0 {
return ids2
}
if ids2Len == 0 {
return ids1
}
newIds := make([]primitive.ObjectID, 0, ids1Len+ids2Len)
for _, v := range append(ids1, ids2...) {
found := false
for _, vv := range newIds {
if v == vv {
found = true
break
}
}
if found {
continue
}
newIds = append(newIds, v)
}
return newIds
}
func CompleteDailyTask(t *db.MongoTool, uid uint64, taskType dailytaskmod.DailyTaskTypeEnum) error {
today := timeutil.BeginOfToday()
cacheKey := redisconst.DailyTaskCacheKey(uid, taskType, today)
redisCli := appg.Redis
if redisCli == nil {
redisCli = webg.Redis
}
if redisCli.Exists(cacheKey) {
return nil // 今日已完成
}
// 获取每日任务
task, err := dailytaskmod.GetUserDailyTaskByType(nil, taskType)
if err != nil {
return stderr.ErrDbQueryError
}
if task == nil || task.ID.IsZero() {
return errors.New("daily task is null")
}
// 判断今日是否已完成
item, err := taskrecordmod.GetUserRecordByTime(uid, task.ID, today)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;获取今日任务完成记录异常:%v", uid, err))
return stderr.ErrDbQueryError
}
if item == nil || item.ID.IsZero() {
var tType taskrecordmod.TaskType
switch taskType {
case dailytaskmod.DailyTaskTypeAdsClick:
tType = taskrecordmod.DailyTaskTypeAdsClick
case dailytaskmod.DailyTaskTypeUserInvite:
tType = taskrecordmod.DailyTaskTypeUserInvite
case dailytaskmod.DailyUserLogin:
tType = taskrecordmod.DailyUserLogin
case dailytaskmod.CommentSetGod:
tType = taskrecordmod.DailyTaskCommentSetGod
case dailytaskmod.DailyDoCollect:
tType = taskrecordmod.DailyDoCollect
case dailytaskmod.DailyPublish:
tType = taskrecordmod.DailyPublish
case dailytaskmod.DailyUnlockByGold:
tType = taskrecordmod.DailyUnlockByGold
case dailytaskmod.DailyComment:
tType = taskrecordmod.DailyComment
default:
return errors.New("不支持的任务类型")
}
// 更新今日任务记录
now := time.Now()
filter := bson.M{"uid": uid, "recordTime": today, "taskId": task.ID}
cond := bson.M{
"uid": uid,
"recordTime": today,
"taskId": task.ID,
"type": taskrecordmod.DailyTask,
"taskType": tType,
"status": taskrecordmod.UnReceived,
"updateTime": now,
"createTime": now,
}
if err := taskrecordmod.InsertTask(nil, filter, cond); err != nil {
return err
}
}
// 缓存标识,以免重复查询
_ = redisCli.Set(cacheKey, 1, time.Hour*24)
return nil
}
func GetDailyTaskBoon(uid uint64, taskId primitive.ObjectID) error {
redisKey := redisconst.GetUserDailyTaskRewardLockKey(uid, taskId.String())
success, err := appg.Redis.Setnx_NewOK(redisKey, "1", redisconst.GetUserDailyTaskRewardLockExpired())
if err != nil {
return err
}
if !success {
return errors.New("请求过于频繁, 请稍后再试")
}
defer func() { _, _ = appg.Redis.Del(redisKey) }()
task, err := dailytaskmod.GetUserDailyTaskByID(nil, taskId)
if err != nil {
return err
}
var transType txnmod.TransType
switch task.Type {
case dailytaskmod.DailyTaskTypeAdsClick:
transType = txnmod.DailyTaskAdsClick
case dailytaskmod.DailyTaskTypeUserInvite:
transType = txnmod.DailyTaskUserInvite
}
return appg.VideoDB.Trans(func(t *db.MongoTool) error {
prizeIDs, err := getDailyRewards(t, uid, task)
if err != nil {
return err
}
if len(prizeIDs) == 0 {
return nil
}
// 获取奖品
return getPrizes(t, uid, prizeIDs, transType)
})
}
func getDailyRewards(t *db.MongoTool, uid uint64, task *dailytaskmod.DailyTask) ([]primitive.ObjectID, error) {
if task == nil {
return nil, nil
}
taskDetailLen := len(task.Detail)
if taskDetailLen == 0 {
return nil, nil
}
count, err := getUserDailyCountByMongo(uid, task.Type) // 每日已完成数量(已点击次数, 已邀请人数等)
if err != nil {
return nil, err
}
finishCount, err := getUserDailyFinish(t, uid, task.Type) // 每日已领取奖励次数
if err != nil {
return nil, err
}
if finishCount >= uint64(len(task.Detail)) {
return nil, nil
}
var rewards []primitive.ObjectID
var completeTime uint64
for i, detail := range task.Detail {
if uint64(i) < finishCount { // 已完成过的不要重复领奖
count -= detail.FinishCondition
continue
}
if count < detail.FinishCondition {
break
}
count -= detail.FinishCondition
completeTime++
rewards = append(rewards, detail.Prizes...)
}
if err := userdailytasklogmod.CompleteDailyTask(uid, int64(task.Type), completeTime); err != nil {
return nil, err
}
go func() {
redisKey := redisconst.GetUserDailyTaskRewardTimeKey(uid, int64(task.Type))
_ = appg.Redis.Set(redisKey, finishCount+completeTime, redisconst.GetUserDailyTaskExpired())
}()
return rewards, nil
}
// 获取用户每日数量(广告点击数, 用户邀请数等)
func getUserDailyCount(uid uint64, taskType dailytaskmod.DailyTaskTypeEnum) (uint64, stderr.Code, string) {
count, err := getUserDailyCountByRedis(uid, taskType)
if err == nil {
return count, stderr.Success, ""
}
count, err = getUserDailyCountByMongo(uid, taskType)
if err != nil {
return 0, stderr.ErrDbQueryError, ""
}
return count, stderr.Success, ""
}
func getUserDailyCountByRedis(uid uint64, taskType dailytaskmod.DailyTaskTypeEnum) (uint64, error) {
redisKey := redisconst.GetUserDailyTaskCountKey(uid, int64(taskType))
ct, err := appg.Redis.Get(redisKey)
if err != nil {
return 0, err
}
if ct == nil || *ct == "" {
return 0, errors.New("daily task count not found in redis")
}
return strconv.ParseUint(*ct, 10, 0)
}
func getUserDailyCountByMongo(uid uint64, taskType dailytaskmod.DailyTaskTypeEnum) (uint64, error) {
redisKey := redisconst.GetUserDailyTaskCountKey(uid, int64(taskType))
switch taskType {
case dailytaskmod.DailyTaskTypeAdsClick: // 每日广告点击
count, err := adsclicklogmod.GetDailyClickCount(uid)
if err != nil {
return 0, err
}
go func() { _ = appg.Redis.Set(redisKey, count, redisconst.GetUserDailyTaskExpired()) }()
return count, nil
case dailytaskmod.DailyTaskTypeUserInvite: // 每日邀请
now := time.Now()
count, err := proxymod.CountByUIDAndTime(uid, time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local))
if err != nil {
return 0, err
}
go func() { _ = appg.Redis.Set(redisKey, count, redisconst.GetUserDailyTaskExpired()) }()
return uint64(count), nil
default:
return 0, nil
}
}
// 获取用户每日完成任务次数
func getUserDailyFinish(t *db.MongoTool, uid uint64, taskType dailytaskmod.DailyTaskTypeEnum) (uint64, error) {
redisKey := redisconst.GetUserDailyTaskRewardTimeKey(uid, int64(taskType))
ct, redisErr := appg.Redis.Get(redisKey)
if redisErr == nil && ct != nil && *ct != "" {
if count, err := strconv.ParseUint(*ct, 10, 0); err == nil {
return count, nil
}
}
switch taskType {
case dailytaskmod.DailyTaskTypeAdsClick, dailytaskmod.DailyTaskTypeUserInvite: // 每日广告点击或每日邀请
finishCount, err := userdailytasklogmod.GetUserFinishCount(uid, taskType)
if err != nil {
return 0, err
}
go func() { _ = appg.Redis.Set(redisKey, finishCount, redisconst.GetUserDailyTaskExpired()) }()
return finishCount, nil
default:
return 0, nil
}
}
func GetOnceTask(uid uint64) ([]OnceTaskResponse, stderr.Code, string) {
tasks, err := oncetaskmod.GetOnceTaskValid(nil)
if err != nil {
return nil, stderr.ErrDbQueryError, ""
}
tasksLen := len(tasks)
if tasksLen == 0 {
return nil, stderr.Success, ""
}
dtrs := make([]OnceTaskResponse, tasksLen)
for i, task := range tasks {
dtrs[i] = OnceTaskResponse{
ID: task.ID,
Title: task.Title,
Img: task.Img,
Type: task.Type,
Status: 0,
Desc: task.Desc,
Link: task.Link,
}
if task.Type == oncetaskmod.Download {
dtrs[i].Status, _ = taskrecordmod.IsDownloadTaskComplete(nil, uid, task.ID)
} else {
hasComplete, _ := taskrecordmod.IsOnceTaskComplete(nil, uid, task.ID)
if hasComplete {
dtrs[i].Status = taskrecordmod.Received
}
}
//taskRecord, err := taskrecordmod.GetUserTaskRecordByUid(uid, taskrecordmod.OnceTask, task.ID)
//if err != nil {
// continue
//}
//if taskRecord == nil || taskRecord.ID.IsZero() {
// continue
//}
//dtrs[i].Status = taskRecord.Status
}
return dtrs, stderr.Success, ""
}
// GetGrowthTask 获取成长任务
func GetGrowthTask(uid uint64) ([]*GrowthTaskResponse, stderr.Code, string) {
list, err := taskmod.ConfigList()
if err != nil {
return nil, stderr.ErrDbQueryError, ""
}
res := []*GrowthTaskResponse{}
for _, v := range list {
item := &GrowthTaskResponse{
ID: v.ID,
Type: int(v.Type),
Title: v.Title,
Img: v.Img,
SubTitle: v.Desc,
}
res = append(res, item)
if len(v.Detail) == 0 {
continue
}
// 获取任务完成记录
taskRecord, err := taskrecordmod.GetUserTask(uid, v.ID)
if err != nil {
continue
}
if taskRecord.Stage < len(v.Detail) {
item.SubTitle = v.Detail[taskRecord.Stage].SubTitle
item.Status = taskRecord.Status
} else {
item.Status = taskrecordmod.Received // 已经超过最后一个阶段,直接展示已领取
}
}
return res, stderr.Success, ""
}
func hasFinishOneceTaskByRedis(uid uint64, taskType oncetaskmod.OnceTaskTypeEnum) (bool, error) {
redisKey := redisconst.GetUserOnceTaskCompleteKey(uid, int64(taskType))
ct, err := appg.Redis.Get(redisKey)
if err != nil {
return false, err
}
if ct == nil || *ct == "" {
return false, errors.New("not found in redis")
}
return *ct == "1", nil
}
func hasFinishOnceTaskByMongo(uid uint64, taskId primitive.ObjectID) (bool, error) {
u, err := taskrecordmod.GetByUID(uid)
if err != nil {
return false, err
}
if u == nil {
return false, nil
}
for _, v := range u.OnceTask {
if v == taskId {
return true, nil
}
}
return false, nil
}
func CompleteGrowthTask(uid uint64, configType taskmod.ConfigType, progress int64) {
// 获取该任务
taskList, err := taskmod.GetConfigListByType(configType)
if err != nil {
log.Error("CompleteGrowthTask taskmod.GetConfigListByType", log.E(err))
return
}
if len(taskList) == 0 {
return
}
task := taskList[0]
if len(task.Detail) == 0 {
return
}
// 获取该任务的完成进度
taskRecord, err := taskrecordmod.GetUserTask(uid, task.ID)
if err != nil {
log.Error("CompleteGrowthTask taskrecordmod.GetUserTaskRecordByUid", log.E(err))
return
}
// 如果是待领取或者是已领取的情况,则直接返回
if taskRecord.Status > 0 {
return
}
// 已经没有下一阶段
if taskRecord.Stage >= len(task.Detail) {
return
}
if progress < int64(task.Detail[taskRecord.Stage].FinishCondition) {
return
}
taskRecord.Status = taskrecordmod.UnReceived // 修改为待领取状态
filter := bson.M{
"uid": uid,
"taskId": task.ID,
}
updateData := bson.M{
"$set": bson.M{
"status": taskRecord.Status,
"updateTime": time.Now(),
},
"$setOnInsert": bson.M{
"uid": uid,
"taskId": task.ID,
"createTime": time.Now(),
},
}
err = taskrecordmod.UpsertOne(filter, updateData)
if err != nil {
log.Error("CompleteGrowthTask taskrecordmod.UpsertOne", log.E(err))
return
}
return
}
func CompleteOnceTask(t *db.MongoTool, uid uint64, onceTaskType oncetaskmod.OnceTaskTypeEnum) error {
hasComplete, err := hasFinishOneceTaskByRedis(uid, onceTaskType)
if err == nil && hasComplete {
return nil
}
ot, err := oncetaskmod.GetOnceTaskValidByType(t, onceTaskType)
if err != nil {
if err.Error() == "not found" {
return nil
}
return err
}
if ot == nil {
return nil
}
hasComplete, err = hasFinishOnceTaskByMongo(uid, ot.ID)
if err != nil {
return err
}
if hasComplete {
return nil
}
var transType txnmod.TransType
switch ot.Type {
case oncetaskmod.OnceTaskTypeUserBuyVip:
transType = txnmod.OnceTaskBuyVIP
case oncetaskmod.OnceTaskTypeUserBuyCoin:
transType = txnmod.OnceTaskTypeUserBuyCoin
case oncetaskmod.OnceTaskTypeBindMobile:
transType = txnmod.OnceTaskBindMobile
default:
}
user, err := usermod.FindUserByUIDTrans(t, uid)
if err != nil {
return err
}
if user.ID.IsZero() {
return errors.New("user not found")
}
redisKey := redisconst.GetUserOnceTaskCompleteKey(uid, int64(onceTaskType))
switch ot.Type {
case oncetaskmod.OnceTaskTypeUserBuyVip: // 购买viP
if !user.IsVIP(time.Now()) {
_ = appg.Redis.Set(redisKey, 0, redisconst.GetUserOnceTaskCompleteExpired())
return nil
}
if err = taskrecordmod.CompleteOnceTask(t, uid, ot.ID); err != nil {
return err
}
if err = getPrizes(t, uid, ot.Prizes, transType); err != nil {
return err
}
_ = appg.Redis.Set(redisKey, 1, redisconst.GetUserOnceTaskCompleteExpired())
return nil
case oncetaskmod.OnceTaskTypeBindMobile: // 绑定手机
if user.Mobile == "" {
_ = appg.Redis.Set(redisKey, 0, redisconst.GetUserOnceTaskCompleteExpired())
return nil
}
if err = taskrecordmod.CompleteOnceTask(t, uid, ot.ID); err != nil {
return err
}
if err = getPrizes(t, uid, ot.Prizes, transType); err != nil {
return err
}
_ = appg.Redis.Set(redisKey, 1, redisconst.GetUserOnceTaskCompleteExpired())
return nil
case oncetaskmod.OnceTaskTypeUserBuyCoin: // 购买金币
if err = taskrecordmod.CompleteOnceTask(t, uid, ot.ID); err != nil {
return err
}
if err = getPrizes(t, uid, ot.Prizes, transType); err != nil {
return err
}
_ = appg.Redis.Set(redisKey, 1, redisconst.GetUserOnceTaskCompleteExpired())
return nil
default:
return errors.New("unknown type")
}
}
// 发放奖励
func getPrizes(t *db.MongoTool, uid uint64, prizeIDs []primitive.ObjectID, transType txnmod.TransType) error {
if len(prizeIDs) == 0 {
return nil
}
// 获取奖品列表
prizes, err := prizemod.GetPrizeListByIDs(prizeIDs)
if err != nil {
return err
}
if len(prizes) == 0 {
return nil
}
// 奖励发放
hanlders := make([]prizemod.PrizeHanlder, 0, len(prizes))
var transactionLogs []txnmod.TransactionLog
var addGoldHanlder prizemod.PrizeHanlder
for _, v := range prizes {
hanlder, err := prizemod.Run(uid, *v, transType)
if err != nil {
return err
}
switch v.Type {
case prizemod.Gold:
addGoldHanlder = hanlder
hanlders = append(hanlders, hanlder)
default:
hanlders = append(hanlders, hanlder)
transactionLogs = append(transactionLogs, hanlder.GetTransactionLog()...)
}
}
for _, v := range hanlders {
if err = v.Run(t); err != nil {
return err
}
}
if addGoldHanlder != nil {
transactionLogs = append(transactionLogs, addGoldHanlder.GetTransactionLog()...)
}
if len(transactionLogs) > 0 {
if err = txnmod.InsertManyTransactionLog(t, transactionLogs); err != nil {
return err
}
}
return nil
}
func ReceiveTask(uid uint64, in *taskmod.ReceiveTaskReq) (code stderr.Code) {
var (
transactionLogs []txnmod.TransactionLog
handlers []prizemod.PrizeHanlder
pIds []primitive.ObjectID
rId primitive.ObjectID
)
user, err := usermod.FindUserByUID(uid)
if err != nil {
return stderr.ErrParamError
}
if user.ID.IsZero() {
return stderr.UserIsNotExists
}
configID := in.TaskID
id, err := primitive.ObjectIDFromHex(configID)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取任务ID:%v;转化ObjectID异常:%v", uid, configID, err))
return stderr.ErrParamError
}
if in.Type == 1 {
// 每日任务
dailyTask, err := dailytaskmod.GetUserDailyTaskByID(nil, id)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取任务ID:%v;查询领取任务配置信息异常:%v", uid, configID, err))
return stderr.ErrDbQueryError
}
if dailyTask == nil || dailyTask.ID.IsZero() {
log.Warn(fmt.Sprintf("用户ID:%d;领取任务ID:%v;未配置领取福利/领取福利类型不正确", uid, configID))
return stderr.ErrInvalidRequest
}
// 判断今日是否领取金币
today := timeutil.BeginningOfDay(time.Now())
item, err := taskrecordmod.GetUserRecordByTime(uid, dailyTask.ID, today)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取任务ID:%v;查询用户领取任务信息异常:%v", uid, configID, err))
return stderr.ErrDbQueryError
}
// 异常判定
if item == nil || item.ID.IsZero() {
log.Warn(fmt.Sprintf("用户ID:%d;领取任务ID:%v;今日已领取", uid, configID))
return stderr.ErrInvalidRequest
}
if item.Status == taskrecordmod.Received {
return stderr.UserHasReceivedIntegral
}
for _, p := range dailyTask.Detail {
pIds = append(pIds, p.Prizes...)
}
rId = item.ID
}
if in.Type == 2 {
// 一次性任务
onceTask, err := oncetaskmod.GetTaskByID(nil, id)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取任务ID:%v;查询领取任务配置信息异常:%v", uid, configID, err))
return stderr.ErrDbQueryError
}
if onceTask == nil || onceTask.ID.IsZero() {
log.Warn(fmt.Sprintf("用户ID:%d;领取任务ID:%v;未配置领取福利/领取福利类型不正确", uid, configID))
return stderr.ErrInvalidRequest
}
// 校验是否领取
task, err := taskrecordmod.GetUserTaskRecordByUid(uid, taskrecordmod.OnceTask, id)
if err != nil {
return stderr.ErrDbQueryError
}
if task == nil || task.ID.IsZero() {
return stderr.UserHasDoTask
}
if task.Status == taskrecordmod.Received {
return stderr.UserHasReceivedIntegral
}
// 获取任务记录
pIds = onceTask.Prizes
rId = task.ID
}
if in.Type == 3 {
// 进阶任务
growthTask, err := taskmod.QueryTaskConfigByCond(bson.M{"_id": id, "status": true})
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取任务ID:%v;查询领取任务配置信息异常:%v", uid, configID, err))
return stderr.ErrDbQueryError
}
if growthTask == nil || growthTask.ID.IsZero() {
log.Warn(fmt.Sprintf("用户ID:%d;领取任务ID:%v;未配置领取福利/领取福利类型不正确", uid, configID))
return stderr.ErrInvalidRequest
}
task, err := taskrecordmod.GetUserTask(uid, id)
if err != nil {
return stderr.ErrDbQueryError
}
if task.ID.IsZero() {
return stderr.UserHasDoTask
}
if task.Status == taskrecordmod.Received {
return stderr.UserHasReceivedIntegral
}
// 超过了当前阶段
if len(growthTask.Detail) <= task.Stage {
return stderr.ErrInvalidRequest
}
// 获取任务记录
pIds = []primitive.ObjectID{growthTask.Detail[task.Stage].Prize}
rId = task.ID
}
prizes, err := prizemod.GetPrizeListByIDs(pIds)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取积分任务ID:%v;查询奖品列表异常:%v", uid, configID, err))
return stderr.ErrDbQueryError
}
if prizes == nil || len(prizes) == 0 {
log.Warn(fmt.Sprintf("用户ID:%d;领取积分任务ID:%v;奖品列表异常", uid, configID))
return stderr.ErrInvalidRequest
}
for _, v := range prizes {
handler, err := prizemod.Run(uid, *v, txnmod.ReceiveIntegral)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取积分任务ID:%v;奖品派发任务初始化异常:%v", uid, configID, err))
return stderr.ErrDbQueryError
}
handlers = append(handlers, handler)
}
if err = appg.VideoDB.Trans(func(t *db.MongoTool) error {
status := taskrecordmod.Received
if in.Type == 3 {
status = 0
}
if _, err = taskrecordmod.UpdateStatusById(t, rId, status); err != nil {
return err
}
for _, v := range handlers {
if err = v.Run(t); err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取积分任务ID:%v;奖品派发任务异常:%v", uid, configID, err))
return err
}
transactionLogs = append(transactionLogs, v.GetTransactionLog()...)
}
if len(transactionLogs) > 0 {
err = txnmod.InsertManyTransactionLog(t, transactionLogs)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取积分任务ID:%v;奖品派发资金流水日志插入异常:%v", uid, configID, err))
return err
}
}
return nil
}); err != nil {
return stderr.ErrDbTransError
}
log.Info(fmt.Sprintf("用户ID:%d;领取积分任务ID:%v;领取积分成功", uid, in.TaskID))
return stderr.Success
}
func DoTask(uid uint64, in *taskmod.DoTaskReq) (code stderr.Code) {
user, err := usermod.FindUserByUID(uid)
if err != nil {
return stderr.ErrParamError
}
if user.ID.IsZero() {
return stderr.UserIsNotExists
}
configID := in.TaskID
id, err := primitive.ObjectIDFromHex(configID)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取任务ID:%v;转化ObjectID异常:%v", uid, configID, err))
return stderr.ErrParamError
}
var taskType taskrecordmod.ConfigType
if in.Type == 1 {
// 每日任务
dailyTask, err := dailytaskmod.GetUserDailyTaskByID(nil, id)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取任务ID:%v;查询领取任务配置信息异常:%v", uid, configID, err))
return stderr.ErrDbQueryError
}
if dailyTask.ID.IsZero() {
log.Warn(fmt.Sprintf("用户ID:%d;领取任务ID:%v;未配置领取福利/领取福利类型不正确", uid, configID))
return stderr.ErrInvalidRequest
}
// 判断今日是否领取金币
today := timeutil.BeginningOfDay(time.Now())
item, err := taskrecordmod.GetUserRecordByTime(uid, dailyTask.ID, today)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取任务ID:%v;查询用户领取任务信息异常:%v", uid, configID, err))
return stderr.ErrDbQueryError
}
// 异常判定
if item != nil && !item.ID.IsZero() {
log.Warn(fmt.Sprintf("用户ID:%d;领取任务ID:%v;今日已领取", uid, configID))
return stderr.ErrInvalidRequest
}
taskType = taskrecordmod.DailyTask
}
if in.Type == 2 {
// 一次性任务
onceTask, err := oncetaskmod.GetTaskByID(nil, id)
if err != nil {
log.Error(fmt.Sprintf("用户ID:%d;领取任务ID:%v;查询领取任务配置信息异常:%v", uid, configID, err))
return stderr.ErrDbQueryError
}
if onceTask == nil || onceTask.ID.IsZero() {
log.Warn(fmt.Sprintf("用户ID:%d;领取任务ID:%v;未配置领取福利/领取福利类型不正确", uid, configID))
return stderr.ErrInvalidRequest
}
// 校验是否领取
task, err := taskrecordmod.GetUserTaskRecordByUid(uid, taskrecordmod.OnceTask, id)
if err != nil {
return stderr.ErrDbQueryError
}
if task != nil && !task.ID.IsZero() {
return stderr.UserHasDoTask
}
// 获取任务记录
taskType = taskrecordmod.OnceTask
}
if err = appg.VideoDB.Trans(func(t *db.MongoTool) error {
now := time.Now()
today := timeutil.BeginningOfDay(now)
// 更新用户记录
if err = taskrecordmod.InsertOne(taskrecordmod.Task{
TaskID: id,
Type: taskType,
TaskType: taskrecordmod.Download,
UID: uid,
Status: taskrecordmod.UnReceived,
RecordTime: today,
Count: 1,
UpdateTime: now,
CreateTime: now,
}); err != nil {
return stderr.ErrDbInsertError
}
return nil
}); err != nil {
return stderr.ErrDbTransError
}
log.Info(fmt.Sprintf("用户ID:%d;任务ID:%v;做任务成功", uid, in.TaskID))
return stderr.Success
}