增加挑战结算的定时任务
This commit is contained in:
parent
5a90fb3e1c
commit
cf07e39ffe
@ -44,6 +44,7 @@
|
||||
"mongoose-findorcreate": "^3.0.0",
|
||||
"nanoid": "^3.1.23",
|
||||
"node-html-to-image": "^3.1.0",
|
||||
"node-schedule": "^2.0.0",
|
||||
"qrcode": "^1.4.4",
|
||||
"querystring": "^0.2.1",
|
||||
"queue": "^6.0.2",
|
||||
@ -62,6 +63,7 @@
|
||||
"@types/dotenv": "^8.2.0",
|
||||
"@types/mongoose": "5.10.3",
|
||||
"@types/node": "^14.14.20",
|
||||
"@types/node-schedule": "^1.3.2",
|
||||
"@types/redis": "^2.8.28",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
|
@ -9,6 +9,7 @@ import { AdminRole } from 'models/admin/AdminRole'
|
||||
import { Shop } from './models/shop/Shop'
|
||||
import { MongoTool } from './services/MongoTool'
|
||||
import { GameItem } from './models/content/GameItem'
|
||||
import ExamSchedule from './schedule/exam.schedule'
|
||||
|
||||
const rbacPlugin = require('plugins/zrbac')
|
||||
const zAuthPlugin = require('plugins/zauth')
|
||||
@ -148,6 +149,11 @@ export class AdminServer {
|
||||
new MongoTool().init('gameitem', id)
|
||||
}
|
||||
|
||||
private initSchedules() {
|
||||
new ExamSchedule().scheduleAll()
|
||||
// new ExamSchedule().parseAllRecord()
|
||||
}
|
||||
|
||||
public async start() {
|
||||
let self = this
|
||||
return new Promise(async (resolve, reject) => {
|
||||
@ -158,6 +164,7 @@ export class AdminServer {
|
||||
self.registerRouter()
|
||||
self.setErrHandler()
|
||||
self.setFormatSend()
|
||||
self.initSchedules()
|
||||
this.server.listen({ port: config.admin.port }, (err: any, address: any) => {
|
||||
if (err) {
|
||||
logger.log(err)
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { dbconn } from '../../decorators/dbconn'
|
||||
import { getModelForClass, index, modelOptions, prop } from '@typegoose/typegoose'
|
||||
import { getModelForClass, index, modelOptions, prop, ReturnModelType } from '@typegoose/typegoose'
|
||||
import { BaseModule } from '../Base'
|
||||
import { noJson } from '../../decorators/nojson'
|
||||
import { Severity } from '@typegoose/typegoose/lib/internal/constants'
|
||||
import { Base } from '@typegoose/typegoose/lib/defaultClasses'
|
||||
import { CompactPuzzleClass } from '../match/PuzzleSession'
|
||||
import { AdminClass } from '../admin/Admin'
|
||||
|
||||
export class ShopPuzzleClass extends Base {
|
||||
@prop()
|
||||
@ -70,7 +71,7 @@ export class ExamRewardClass extends Base {
|
||||
|
||||
/**
|
||||
* 奖励类型
|
||||
* @type {number} 0: 单局, 1: 累积
|
||||
* @type {number} 0: 单局, 1: 累积 2: 累计排名
|
||||
*/
|
||||
@prop({ default: 0 })
|
||||
public type: number
|
||||
@ -192,6 +193,19 @@ export class ShopExamClass extends BaseModule {
|
||||
@prop({ type: [ShopPuzzleClass] })
|
||||
public questions: ShopPuzzleClass[]
|
||||
|
||||
/**
|
||||
* 挑战状态
|
||||
* @type {number} 0: 默认状态, 9: 奖励已发放
|
||||
*/
|
||||
@prop({ default: 0 })
|
||||
public status: number
|
||||
|
||||
/**
|
||||
* 返回所有已完结但未结算的挑战记录
|
||||
*/
|
||||
public static allUnSettleRecords(this: ReturnModelType<typeof ShopExamClass>) {
|
||||
return this.find({ endTime: { $gte: Date.now() }, status: { $ne: 9 } })
|
||||
}
|
||||
public static parseQueryParam(params) {
|
||||
let { key, timeBegin, timeEnd, active, shop, source } = params
|
||||
let opt: any = { deleted: false }
|
||||
@ -239,6 +253,25 @@ export class ShopExamClass extends BaseModule {
|
||||
return results
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据排名获取赛季奖励
|
||||
* @param {number} rank
|
||||
*/
|
||||
public getRewardByRank(rank: number) {
|
||||
if (!this.rewardInfo || this.rewardInfo.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
let results = []
|
||||
for (let reward of this.rewardInfo) {
|
||||
if (rank <= reward.rank && reward.type === 2) {
|
||||
results.push({ id: reward._id + '', coupon: reward.coupon, count: reward.count })
|
||||
break
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
public toPartnerJson() {
|
||||
const exportKeys = [
|
||||
'_id',
|
||||
|
@ -73,6 +73,18 @@ export class UserMailClass extends BaseModule {
|
||||
return record
|
||||
}
|
||||
|
||||
public static async addOneMail({ accountId, shop, items, title, content, senderShop }) {
|
||||
let record = new UserMail({})
|
||||
record.title = title
|
||||
record.content = content
|
||||
record.sender = shop
|
||||
record.accountId = accountId
|
||||
record.items = items
|
||||
record.senderShop = senderShop
|
||||
record.expire = Date.now() + 3600 * 24 * 15 * 1000
|
||||
await record.save()
|
||||
}
|
||||
|
||||
public static async updateExpire(accountId: string) {
|
||||
await UserMail.updateMany(
|
||||
{ accountId, deleted: false, expire: { $lt: Date.now() } },
|
||||
|
70
src/schedule/exam.schedule.ts
Normal file
70
src/schedule/exam.schedule.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import * as schedule from 'node-schedule'
|
||||
import { singleton } from '../decorators/singleton'
|
||||
import { ShopExam } from '../models/shop/ShopExam'
|
||||
import { getRankCount, getRankList } from '../services/Rank'
|
||||
import { rankKey } from '../services/GameLogic'
|
||||
import { UserMail } from '../models/user/UserMail'
|
||||
import { Coupon } from '../models/shop/Coupon'
|
||||
import { Shop } from '../models/shop/Shop'
|
||||
|
||||
@singleton
|
||||
export default class ExamSchedule {
|
||||
async parseOneExam(data: any) {
|
||||
const shop = data.shop
|
||||
let shopName = ''
|
||||
const shopData = await Shop.fetchByID(shop)
|
||||
if (shopData) {
|
||||
shopName = shopData.showName
|
||||
}
|
||||
const level = data.id + '_total'
|
||||
const mode = 2
|
||||
const skip = 0
|
||||
const key = rankKey(shop, level, mode)
|
||||
const limit = (await getRankCount(key)) as number
|
||||
let datas: any = await getRankList(skip, limit, key)
|
||||
const accountIDS = []
|
||||
for (let i = 0, l = datas.length; i < l; i += 2) {
|
||||
accountIDS.push(datas[i])
|
||||
}
|
||||
data.rewardInfo.sort((a, b) => a.rank - b.rank)
|
||||
for (let i = 0, l = accountIDS.length; i < l; i++) {
|
||||
let rewards = data.getRewardByRank(i + 1)
|
||||
let items = []
|
||||
for (let r of rewards) {
|
||||
let name = '抽奖券'
|
||||
if (r.type === 0) {
|
||||
let cdata = await Coupon.findById(r.coupon)
|
||||
if (cdata) {
|
||||
name = cdata.name
|
||||
}
|
||||
}
|
||||
items.push({
|
||||
itemId: r.coupon,
|
||||
name,
|
||||
count: r.count,
|
||||
})
|
||||
}
|
||||
const title = `${data.name} 第${i + 1}名奖励`
|
||||
const content = `您在 ${shopName} 的 ${data.name}活动中获得第${i + 1}名, 获得如下奖励`
|
||||
await UserMail.addOneMail({
|
||||
accountId: accountIDS[i],
|
||||
shop,
|
||||
items,
|
||||
title,
|
||||
content,
|
||||
senderShop: shopName,
|
||||
})
|
||||
}
|
||||
}
|
||||
async parseAllRecord() {
|
||||
let records = await ShopExam.allUnSettleRecords()
|
||||
for (let record of records) {
|
||||
await this.parseOneExam(record)
|
||||
}
|
||||
}
|
||||
scheduleAll() {
|
||||
const job = schedule.scheduleJob('1 0 0 * * *', async () => {
|
||||
await this.parseAllRecord()
|
||||
})
|
||||
}
|
||||
}
|
59
yarn.lock
59
yarn.lock
@ -194,6 +194,13 @@
|
||||
"@types/mongodb" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node-schedule@^1.3.2":
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node-schedule/-/node-schedule-1.3.2.tgz#cc7e32c6795cbadc8de03d0e1f86311727375423"
|
||||
integrity sha512-Y0CqdAr+lCpArT8CJJjJq4U2v8Bb5e7ru2nV/NhDdaptCMCRdOL3Y7tAhen39HluQMaIKWvPbDuiFBUQpg7Srw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*", "@types/node@^14.14.20":
|
||||
version "14.14.41"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.41.tgz#d0b939d94c1d7bd53d04824af45f1139b8c45615"
|
||||
@ -773,6 +780,14 @@ create-require@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||
|
||||
cron-parser@^3.1.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-3.5.0.tgz#b1a9da9514c0310aa7ef99c2f3f1d0f8c235257c"
|
||||
integrity sha512-wyVZtbRs6qDfFd8ap457w3XVntdvqcwBGxBoTvJQH9KGVKL/fB+h2k3C8AqiVxvUQKN1Ps/Ns46CNViOpVDhfQ==
|
||||
dependencies:
|
||||
is-nan "^1.3.2"
|
||||
luxon "^1.26.0"
|
||||
|
||||
cross-spawn@^7.0.2:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||
@ -870,6 +885,13 @@ default-user-agent@^1.0.0:
|
||||
dependencies:
|
||||
os-name "~1.0.3"
|
||||
|
||||
define-properties@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
|
||||
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
|
||||
dependencies:
|
||||
object-keys "^1.0.12"
|
||||
|
||||
degenerator@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-2.2.0.tgz#49e98c11fa0293c5b26edfbb52f15729afcdb254"
|
||||
@ -1845,6 +1867,14 @@ is-json@^2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff"
|
||||
integrity sha1-a+Fm0USCihMdaGiRuYPfYsOUkf8=
|
||||
|
||||
is-nan@^1.3.2:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d"
|
||||
integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==
|
||||
dependencies:
|
||||
call-bind "^1.0.0"
|
||||
define-properties "^1.1.3"
|
||||
|
||||
is-number@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||
@ -2092,6 +2122,11 @@ loglevel@^1.6.7, loglevel@^1.7.0:
|
||||
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197"
|
||||
integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==
|
||||
|
||||
long-timeout@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/long-timeout/-/long-timeout-0.1.1.tgz#9721d788b47e0bcb5a24c2e2bee1a0da55dab514"
|
||||
integrity sha1-lyHXiLR+C8taJMLivuGg2lXatRQ=
|
||||
|
||||
lru-cache@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
||||
@ -2106,6 +2141,11 @@ lru-cache@^6.0.0:
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
luxon@^1.26.0:
|
||||
version "1.27.0"
|
||||
resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.27.0.tgz#ae10c69113d85dab8f15f5e8390d0cbeddf4f00f"
|
||||
integrity sha512-VKsFsPggTA0DvnxtJdiExAucKdAnwbCCNlMM5ENvHlxubqWd0xhZcdb4XgZ7QFNhaRhilXCFxHuoObP5BNA4PA==
|
||||
|
||||
make-error@^1.1.1:
|
||||
version "1.3.6"
|
||||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||
@ -2308,6 +2348,15 @@ node-html-to-image@^3.1.0:
|
||||
puppeteer "3.0.0"
|
||||
puppeteer-cluster "^0.21.0"
|
||||
|
||||
node-schedule@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-schedule/-/node-schedule-2.0.0.tgz#73ab4957d056c63708409cc1fab676e0e149c191"
|
||||
integrity sha512-cHc9KEcfiuXxYDU+HjsBVo2FkWL1jRAUoczFoMIzRBpOA4p/NRHuuLs85AWOLgKsHtSPjN8csvwIxc2SqMv+CQ==
|
||||
dependencies:
|
||||
cron-parser "^3.1.0"
|
||||
long-timeout "0.1.1"
|
||||
sorted-array-functions "^1.3.0"
|
||||
|
||||
nth-check@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125"
|
||||
@ -2330,6 +2379,11 @@ object-inspect@^1.9.0:
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.2.tgz#b6385a3e2b7cae0b5eafcf90cddf85d128767f30"
|
||||
integrity sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA==
|
||||
|
||||
object-keys@^1.0.12:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
|
||||
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
|
||||
|
||||
once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
@ -3011,6 +3065,11 @@ sonic-boom@^1.0.2:
|
||||
atomic-sleep "^1.0.0"
|
||||
flatstr "^1.0.12"
|
||||
|
||||
sorted-array-functions@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz#8605695563294dffb2c9796d602bd8459f7a0dd5"
|
||||
integrity sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==
|
||||
|
||||
source-map-support@^0.5.17:
|
||||
version "0.5.19"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
|
||||
|
Loading…
x
Reference in New Issue
Block a user