增加任务repeat的支持
This commit is contained in:
parent
a41fb9aa3a
commit
145a5cb06c
@ -105,6 +105,7 @@ SiweMessage的nonce说明(具体参考例子):
|
|||||||
"title": "任务名",
|
"title": "任务名",
|
||||||
"desc": "任务描述",
|
"desc": "任务描述",
|
||||||
"type": 1, //任务类型, 1: 一次性任务, 2: 日常任务
|
"type": 1, //任务类型, 1: 一次性任务, 2: 日常任务
|
||||||
|
"repeat": 1, // 任务可重复次数
|
||||||
"pretasks": ["task id 1"], //前置任务
|
"pretasks": ["task id 1"], //前置任务
|
||||||
"score": 0, // 完成任务可获得的积分
|
"score": 0, // 完成任务可获得的积分
|
||||||
"category": "", // 任务分类
|
"category": "", // 任务分类
|
||||||
|
@ -199,6 +199,7 @@
|
|||||||
"task": "BurnNft",
|
"task": "BurnNft",
|
||||||
"type": 1,
|
"type": 1,
|
||||||
"show": true,
|
"show": true,
|
||||||
|
"repeat": 2,
|
||||||
"title": "Hero NFT",
|
"title": "Hero NFT",
|
||||||
"desc": "Click to burn and redeem Flame",
|
"desc": "Click to burn and redeem Flame",
|
||||||
"category": "CF Pal",
|
"category": "CF Pal",
|
||||||
@ -212,6 +213,7 @@
|
|||||||
"task": "BurnNft",
|
"task": "BurnNft",
|
||||||
"type": 1,
|
"type": 1,
|
||||||
"show": true,
|
"show": true,
|
||||||
|
"repeat": 2,
|
||||||
"title": "Candy Badge",
|
"title": "Candy Badge",
|
||||||
"desc": "Click to burn and redeem Flame",
|
"desc": "Click to burn and redeem Flame",
|
||||||
"category": "CF Pal",
|
"category": "CF Pal",
|
||||||
@ -224,6 +226,7 @@
|
|||||||
"task": "BurnNft",
|
"task": "BurnNft",
|
||||||
"type": 1,
|
"type": 1,
|
||||||
"show": true,
|
"show": true,
|
||||||
|
"repeat": 2,
|
||||||
"title": "Explorer Badge",
|
"title": "Explorer Badge",
|
||||||
"desc": "Click to burn and redeem Flame",
|
"desc": "Click to burn and redeem Flame",
|
||||||
"category": "CF Pal",
|
"category": "CF Pal",
|
||||||
@ -237,6 +240,7 @@
|
|||||||
"task": "BurnNft",
|
"task": "BurnNft",
|
||||||
"type": 1,
|
"type": 1,
|
||||||
"show": true,
|
"show": true,
|
||||||
|
"repeat": 2,
|
||||||
"title": "Gacha Badge",
|
"title": "Gacha Badge",
|
||||||
"desc": "Click to burn and redeem Flame",
|
"desc": "Click to burn and redeem Flame",
|
||||||
"category": "CF Pal",
|
"category": "CF Pal",
|
||||||
|
@ -96,12 +96,12 @@ export default class TasksController extends BaseController {
|
|||||||
return t.id === preTask
|
return t.id === preTask
|
||||||
});
|
});
|
||||||
if (!preTaskData || (preTaskData.status === TaskStatusEnum.NOT_START || preTaskData.status === TaskStatusEnum.RUNNING)) {
|
if (!preTaskData || (preTaskData.status === TaskStatusEnum.NOT_START || preTaskData.status === TaskStatusEnum.RUNNING)) {
|
||||||
throw new ZError(14, 'task previous not end')
|
throw new ZError(14, 'task previous not finish')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let currentTask = user.taskProgress.find((t: TaskStatus) => t.id === task);
|
let currentTask = user.taskProgress.find((t: TaskStatus) => t.id === task);
|
||||||
if (currentTask.status === TaskStatusEnum.SUCCESS || currentTask.status === TaskStatusEnum.CLAIMED) {
|
if (currentTask.status === TaskStatusEnum.PART_SUCCESS || currentTask.status === TaskStatusEnum.SUCCESS || currentTask.status === TaskStatusEnum.CLAIMED) {
|
||||||
throw new ZError(15, 'task already end')
|
throw new ZError(15, 'task already end')
|
||||||
}
|
}
|
||||||
if (currentTask.status === TaskStatusEnum.NOT_START) {
|
if (currentTask.status === TaskStatusEnum.NOT_START) {
|
||||||
@ -126,13 +126,13 @@ export default class TasksController extends BaseController {
|
|||||||
if (!currentTask) {
|
if (!currentTask) {
|
||||||
throw new ZError(11, 'task not found')
|
throw new ZError(11, 'task not found')
|
||||||
}
|
}
|
||||||
if (currentTask.status === TaskStatusEnum.SUCCESS || currentTask.status === TaskStatusEnum.CLAIMED) {
|
if (currentTask.status === TaskStatusEnum.CLAIMED) {
|
||||||
return currentTask;
|
return currentTask;
|
||||||
}
|
}
|
||||||
if (currentTask.status === TaskStatusEnum.NOT_START) {
|
if (currentTask.status === TaskStatusEnum.NOT_START) {
|
||||||
throw new ZError(11, 'task not begin');
|
throw new ZError(11, 'task not begin');
|
||||||
}
|
}
|
||||||
if (currentTask.status === TaskStatusEnum.RUNNING) {
|
if (currentTask.status === TaskStatusEnum.RUNNING || currentTask.status === TaskStatusEnum.PART_SUCCESS) {
|
||||||
let Task = require('../tasks/' + currentTask.task);
|
let Task = require('../tasks/' + currentTask.task);
|
||||||
let taskInstance = new Task.default({user, activity});
|
let taskInstance = new Task.default({user, activity});
|
||||||
await taskInstance.execute({task: currentTask});
|
await taskInstance.execute({task: currentTask});
|
||||||
@ -152,7 +152,7 @@ export default class TasksController extends BaseController {
|
|||||||
if (currentTask.status === TaskStatusEnum.CLAIMED) {
|
if (currentTask.status === TaskStatusEnum.CLAIMED) {
|
||||||
throw new ZError(12, 'task already claimed')
|
throw new ZError(12, 'task already claimed')
|
||||||
}
|
}
|
||||||
if (currentTask.status !== TaskStatusEnum.SUCCESS) {
|
if (currentTask.status !== TaskStatusEnum.SUCCESS && currentTask.status !== TaskStatusEnum.PART_SUCCESS) {
|
||||||
throw new ZError(13, 'task not end')
|
throw new ZError(13, 'task not end')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { dbconn } from 'decorators/dbconn'
|
|||||||
import findOrCreate from 'mongoose-findorcreate'
|
import findOrCreate from 'mongoose-findorcreate'
|
||||||
import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'
|
import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'
|
||||||
import { BaseModule } from './Base'
|
import { BaseModule } from './Base'
|
||||||
import exp from 'constants'
|
|
||||||
|
|
||||||
export enum TaskTypeEnum {
|
export enum TaskTypeEnum {
|
||||||
ONCE = 1,
|
ONCE = 1,
|
||||||
@ -20,6 +20,8 @@ export class TaskCfg {
|
|||||||
title: string
|
title: string
|
||||||
@prop({ enum: TaskTypeEnum, default: TaskTypeEnum.ONCE })
|
@prop({ enum: TaskTypeEnum, default: TaskTypeEnum.ONCE })
|
||||||
type: TaskTypeEnum
|
type: TaskTypeEnum
|
||||||
|
@prop({default: 1})
|
||||||
|
repeat: number
|
||||||
@prop()
|
@prop()
|
||||||
desc: string
|
desc: string
|
||||||
@prop({ type: mongoose.Schema.Types.Mixed })
|
@prop({ type: mongoose.Schema.Types.Mixed })
|
||||||
@ -76,6 +78,7 @@ class ActivityInfoClass extends BaseModule {
|
|||||||
title: task.title,
|
title: task.title,
|
||||||
desc: task.desc,
|
desc: task.desc,
|
||||||
type: task.type,
|
type: task.type,
|
||||||
|
repeat: task.repeat,
|
||||||
pretasks: task.pretasks,
|
pretasks: task.pretasks,
|
||||||
score: task.score,
|
score: task.score,
|
||||||
category: task.category,
|
category: task.category,
|
||||||
|
@ -13,6 +13,7 @@ export enum TaskStatusEnum {
|
|||||||
RUNNING = 1,
|
RUNNING = 1,
|
||||||
SUCCESS = 2,
|
SUCCESS = 2,
|
||||||
CLAIMED = 3,
|
CLAIMED = 3,
|
||||||
|
PART_SUCCESS = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
@modelOptions({ schemaOptions: { _id: false }, options: { allowMixed: Severity.ALLOW }})
|
@modelOptions({ schemaOptions: { _id: false }, options: { allowMixed: Severity.ALLOW }})
|
||||||
|
@ -10,16 +10,12 @@ import { BaseModule } from './Base'
|
|||||||
class NftBurnRecordClass extends BaseModule {
|
class NftBurnRecordClass extends BaseModule {
|
||||||
@prop({ required: true})
|
@prop({ required: true})
|
||||||
public user: string
|
public user: string
|
||||||
|
|
||||||
@prop()
|
@prop()
|
||||||
public chain: number
|
public chain: number
|
||||||
|
|
||||||
@prop({ required: true})
|
@prop({ required: true})
|
||||||
public address: string
|
public address: string
|
||||||
|
|
||||||
@prop()
|
@prop()
|
||||||
public tokenId: number
|
public tokenId: string
|
||||||
|
|
||||||
@prop()
|
@prop()
|
||||||
public activity: string
|
public activity: string
|
||||||
@prop()
|
@prop()
|
||||||
|
@ -21,31 +21,50 @@ export default class BurnNft extends ITask {
|
|||||||
const localNft = await NftBurnRecord.find({
|
const localNft = await NftBurnRecord.find({
|
||||||
user: this.params.user.id,
|
user: this.params.user.id,
|
||||||
chain,
|
chain,
|
||||||
address
|
address,
|
||||||
})
|
})
|
||||||
const localNftSet = new Set();
|
const localNftSet = new Set();
|
||||||
|
let finishAmount = 0;
|
||||||
|
let tmpNftSet = new Set();
|
||||||
for (let nft of localNft) {
|
for (let nft of localNft) {
|
||||||
localNftSet.add(nft.tokenId)
|
localNftSet.add(nft.tokenId)
|
||||||
}
|
if (nft.activity === this.params.activity.id && nft.task === task.id) {
|
||||||
let finishNft
|
finishAmount += 1
|
||||||
for (let nft of nftList) {
|
tmpNftSet.add(nft.tokenId)
|
||||||
if (!localNftSet.has(nft.tokenId)) {
|
|
||||||
finishNft = nft.tokenId
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const record = new NftBurnRecord({
|
let finishNfts = new Set();
|
||||||
user: this.params.user.id,
|
for (let nft of nftList) {
|
||||||
chain,
|
if (!localNftSet.has(nft.tokenId)) {
|
||||||
address,
|
finishNfts.add(nft.tokenId)
|
||||||
tokenId: finishNft,
|
finishAmount += 1
|
||||||
activity: this.params.activity.id,
|
if (finishAmount >= cfg.repeat) {
|
||||||
task: task.id
|
break;
|
||||||
})
|
}
|
||||||
await record.save()
|
}
|
||||||
task.status = TaskStatusEnum.SUCCESS
|
}
|
||||||
task.timeFinish = Date.now()
|
for (let finishNft of finishNfts) {
|
||||||
task.data = {tokenId: finishNft}
|
const record = new NftBurnRecord({
|
||||||
|
user: this.params.user.id,
|
||||||
|
chain,
|
||||||
|
address,
|
||||||
|
tokenId: finishNft,
|
||||||
|
activity: this.params.activity.id,
|
||||||
|
task: task.id
|
||||||
|
})
|
||||||
|
await record.save()
|
||||||
|
}
|
||||||
|
let dataToSave = task.data || {}
|
||||||
|
dataToSave.tokenId = [...tmpNftSet, ...finishNfts]
|
||||||
|
dataToSave.finishAmount = finishAmount
|
||||||
|
task.data = dataToSave
|
||||||
|
task.markModified('data')
|
||||||
|
if (finishAmount >= cfg.repeat) {
|
||||||
|
task.status = TaskStatusEnum.SUCCESS
|
||||||
|
task.timeFinish = Date.now()
|
||||||
|
} else if (finishAmount > 0) {
|
||||||
|
task.status = TaskStatusEnum.PART_SUCCESS
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await this.params.user.save()
|
await this.params.user.save()
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
@ -60,5 +79,4 @@ export default class BurnNft extends ITask {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -14,30 +14,40 @@ export abstract class ITask {
|
|||||||
}
|
}
|
||||||
abstract execute(data: any): Promise<boolean>
|
abstract execute(data: any): Promise<boolean>
|
||||||
|
|
||||||
public async claimReward(task: TaskStatus) {
|
public async claimReward(task: any) {
|
||||||
const user = this.params.user
|
const user = this.params.user
|
||||||
const [taskId, dateTag] = task.id.split(':');
|
const [taskId, dateTag] = task.id.split(':');
|
||||||
const cfg = this.params.activity.tasks.find((t: TaskCfg) => t.id === taskId)
|
const cfg = this.params.activity.tasks.find((t: TaskCfg) => t.id === taskId)
|
||||||
if (!cfg.score) {
|
if (!cfg.score) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let claimAmount = task.data.claimAmount || 0
|
||||||
let score = cfg.score
|
let score = cfg.score
|
||||||
if (user.boost > 1 && Date.now() < user.boostExpire) {
|
if (user.boost > 1 && Date.now() < user.boostExpire) {
|
||||||
score = Math.floor(score * user.boost)
|
score = Math.floor(score * user.boost)
|
||||||
}
|
}
|
||||||
await updateRankScore({
|
let finishAmount = cfg.repeat > 1 ? task.data.finishAmount || 0 : 1
|
||||||
user: user.id,
|
for (let i = claimAmount; i < Math.min(cfg.repeat, finishAmount); i++) {
|
||||||
score: score,
|
await updateRankScore({
|
||||||
activity: user.activity,
|
user: user.id,
|
||||||
scoreType: cfg.task,
|
score: score,
|
||||||
scoreParams: {
|
activity: user.activity,
|
||||||
date: dateTag,
|
scoreType: cfg.task,
|
||||||
taskId: task.id,
|
scoreParams: {
|
||||||
boost: user.boost
|
date: dateTag,
|
||||||
}
|
taskId: task.id,
|
||||||
})
|
boost: user.boost
|
||||||
task.status = TaskStatusEnum.CLAIMED
|
}
|
||||||
task.timeClaim = Date.now()
|
})
|
||||||
|
claimAmount += 1
|
||||||
|
}
|
||||||
|
task.data.claimAmount = claimAmount
|
||||||
|
task.markModified('data')
|
||||||
|
if ((cfg.repeat > 1 && claimAmount >= cfg.repeat)
|
||||||
|
|| (cfg.repeat === 1 && claimAmount >= 1)) {
|
||||||
|
task.status = TaskStatusEnum.CLAIMED
|
||||||
|
task.timeClaim = Date.now()
|
||||||
|
}
|
||||||
await user.save()
|
await user.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user