task.go 6.05 KB
package task_m

import (
	"git.hilo.cn/hilo-common/domain"
	"git.hilo.cn/hilo-common/resource/mysql"
	"git.hilo.cn/hilo-common/utils"
	"gorm.io/gorm"
	"hilo-group/_const/enum/task_e"
	"hilo-group/myerr"
	"hilo-group/myerr/bizerr"
	"strconv"
	"time"
)

type TaskConfig struct {
	mysql.Entity
	*domain.Model `gorm:"-"`
	Name          mysql.Str
	Diamond       mysql.Num
	//任务类型
	Type task_e.TypeTaskConfig
	//频率类型
	RateType task_e.RateTypeTaskConfig
	//完成次数
	FinishN mysql.Num
	//排序
	I mysql.Num
	//奖励次数
	AwardN mysql.Num
	Status mysql.UserYesNo
}

type TaskUser struct {
	mysql.Entity
	*domain.Model `gorm:"-"`
	TaskConfigId  mysql.ID
	UserId        mysql.ID
	DayStr        mysql.Str
	HasFinish     mysql.YesNo
	HasAward      mysql.YesNo //整个完成奖励了
	AwardN        mysql.Num   //获取奖励次数
	FinishN       mysql.Num
}

type TaskUserDetail struct {
	mysql.Entity
	*domain.Model `gorm:"-"`
	TaskConfigId  mysql.ID
	UserId        mysql.ID
	TaskUserId    mysql.ID
	OriginId      mysql.ID
}

func addTaskUserDetail(model *domain.Model, taskConfigId mysql.ID, userId mysql.ID, taskUserId mysql.ID, originId mysql.ID) error {
	taskUserDetail := &TaskUserDetail{
		Model:        model,
		TaskConfigId: taskConfigId,
		UserId:       userId,
		TaskUserId:   taskUserId,
		OriginId:     originId,
	}
	return taskUserDetail.Persistent()
}

func GetTaskUserOrErr(model *domain.Model, userId uint64, taskConfigId uint64) (*TaskUser, TaskConfig, error) {
	//获取任务配置
	taskConfig := TaskConfig{}
	if err := model.Db.Model(&TaskConfig{}).Where(&TaskConfig{
		Status: mysql.USER,
	}).First(&taskConfig, taskConfigId).Error; err != nil {
		return nil, TaskConfig{}, myerr.WrapErr(err)
	}
	//
	paramTaskUser := TaskUser{
		TaskConfigId: taskConfig.ID,
		UserId:       userId,
	}
	if taskConfig.RateType == task_e.Daily {
		paramTaskUser.DayStr = time.Now().Format(utils.COMPACT_DATE_FORMAT)
	}
	//
	taskUser := TaskUser{}
	if err := model.Db.Model(&TaskUser{}).Where(&paramTaskUser).First(&taskUser).Error; err != nil {
		return nil, TaskConfig{}, myerr.WrapErr(err)
	}
	taskUser.Model = model
	//
	return &taskUser, taskConfig, nil
}

func getTaskUserOrInit(model *domain.Model, userId uint64, taskConfig TaskConfig) (*TaskUser, error) {
	//获取任务用户
	taskUser := TaskUser{}
	paramTaskUser := TaskUser{
		TaskConfigId: taskConfig.ID,
		UserId:       userId,
	}
	if taskConfig.RateType == task_e.Daily {
		paramTaskUser.DayStr = time.Now().Format(utils.COMPACT_DATE_FORMAT)
	}

	if err := model.Db.Model(&TaskUser{}).Where(&paramTaskUser).First(&taskUser).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return &TaskUser{
				Model:        model,
				TaskConfigId: taskConfig.ID,
				UserId:       userId,
				DayStr:       paramTaskUser.DayStr,
				HasFinish:    mysql.NO,
				HasAward:     mysql.NO,
				FinishN:      0,
			}, nil
		} else {
			return nil, myerr.WrapErr(err)
		}
	}
	taskUser.Model = model
	return &taskUser, nil
}

// 次数加1
func (taskUser *TaskUser) addFinishN(taskConfig TaskConfig) bool {
	//没有使用sql悲观锁,update set where,第一:观察业务,都是用户自动触发,有时间性 第二:验证业务这样写,被投诉的概率,以证明此场景业务。
	if taskUser.HasFinish == mysql.YES {
		return false
	} else {
		taskUser.FinishN = taskUser.FinishN + 1
		if taskUser.FinishN >= taskConfig.FinishN {
			taskUser.HasFinish = mysql.YES
		}
		return true
	}
}

// 次数覆盖
func (taskUser *TaskUser) beFinishN(taskConfig TaskConfig, finishN uint32) bool {
	//没有使用sql悲观锁,update set where,第一:观察业务,都是用户自动触发,有时间性 第二:验证业务这样写,被投诉的概率,以证明此场景业务。
	if taskUser.HasFinish == mysql.YES {
		return false
	} else {
		taskUser.FinishN = finishN
		if taskUser.FinishN >= taskConfig.FinishN {
			taskUser.HasFinish = mysql.YES
		}
		return true
	}
}

func (taskUser *TaskUser) Award(taskConfig TaskConfig) error {
	if taskUser.HasAward == mysql.YES {
		return bizerr.TaskHasAward
	}
	taskUser.AwardN = taskUser.AwardN + 1
	if taskUser.AwardN >= taskConfig.AwardN {
		taskUser.HasAward = mysql.YES
	}
	taskUser.SetCheckUpdateCondition("has_award = " + strconv.Itoa(int(mysql.NO)))
	return nil
}

func AddTaskUser(model *domain.Model, t task_e.TypeTaskConfig, userId uint64, orginId uint64) (mysql.ID, error) {
	//获取任务配置
	taskConfig := TaskConfig{}
	if err := model.Db.Model(&TaskConfig{}).Where(&TaskConfig{
		Type:   t,
		Status: mysql.USER,
	}).First(&taskConfig).Error; err != nil {
		return 0, myerr.WrapErr(err)
	}
	//
	taskUser, err := getTaskUserOrInit(model, userId, taskConfig)
	if err != nil {
		return 0, err
	}
	if taskUser.addFinishN(taskConfig) {
		if err := taskUser.Persistent(); err != nil {
			return 0, myerr.WrapErr(err)
		}
		return taskConfig.ID, addTaskUserDetail(taskUser.Model, taskConfig.ID, userId, taskUser.ID, orginId)
	}
	return taskConfig.ID, nil
}

// return true:已经完成 false:未完成
func isTaskUserFinish(model *domain.Model, t task_e.TypeTaskConfig, userId uint64) (bool, error) {
	//获取任务配置
	taskConfig := TaskConfig{}
	if err := model.Db.Model(&TaskConfig{}).Where(&TaskConfig{
		Type:   t,
		Status: mysql.USER,
	}).First(&taskConfig).Error; err != nil {
		return false, myerr.WrapErr(err)
	}
	//
	taskUser, err := getTaskUserOrInit(model, userId, taskConfig)
	if err != nil {
		return false, err
	}
	return taskUser.HasFinish == mysql.YES, nil
}

func addTaskUserFinishN(model *domain.Model, t task_e.TypeTaskConfig, userId uint64, finishN uint32) error {
	//获取任务配置
	taskConfig := TaskConfig{}
	if err := model.Db.Model(&TaskConfig{}).Where(&TaskConfig{
		Type:   t,
		Status: mysql.USER,
	}).First(&taskConfig).Error; err != nil {
		return myerr.WrapErr(err)
	}
	//
	taskUser, err := getTaskUserOrInit(model, userId, taskConfig)
	if err != nil {
		return err
	}
	if taskUser.beFinishN(taskConfig, finishN) {
		if err := taskUser.Persistent(); err != nil {
			return myerr.WrapErr(err)
		}
		return addTaskUserDetail(taskUser.Model, taskConfig.ID, userId, taskUser.ID, 0)
	}
	return nil
}