增加活动和挑战奖励的发放

This commit is contained in:
zhl 2021-05-20 20:18:57 +08:00
parent de3d850c62
commit bf6028c934
7 changed files with 164 additions and 13 deletions

View File

@ -97,7 +97,14 @@
"timeLeft": 1, // 当局剩余时间
"gameResult": 0 // 当局的游戏结果, 单人的话和上一层gameResult相同
}
}
},
"rewards": [{
coupon: '优惠券的id',
name: '优惠券名',
count: 1, //数量
couponUrl: '优惠券详情图的url',
ids: ['获取记录的短id']
}]
}
```
### 3. 开始匹配

View File

@ -13,7 +13,8 @@ import {
transformRecord,
updateExamRank
} from '../../services/GameLogic'
import { validShopId } from '../../models/shop/Shop'
import { Shop, validShopId } from '../../models/shop/Shop'
import { UserReward } from '../../models/UserReward'
class ExamController extends BaseController {
@role('anon')
@ -34,6 +35,11 @@ class ExamController extends BaseController {
}
let params = {}
let results: any[] = []
let shopData = await Shop.fetchByID(shop)
if (!shopData) {
throw new ZError(13, 'shop not found')
}
shop = shopData.id
let history = new PuzzleSession({ shop, level: 0})
if (record.source === 0) {
if (record.qtypes && record.qtypes.length > 0) {
@ -141,8 +147,23 @@ class ExamController extends BaseController {
rspData.rankList = rankList
rspData.userRank = userRank
rspData.rankTotal = rankTotal
let examData = await ShopExam.findById(history.activityId)
let rewardList = []
if (!examData && examData.rewardInfo && examData.rewardInfo.length > 0) {
let rewards = examData.getReward(statMap.score)
for (let reward of rewards) {
let geted = await UserReward.examRewardGeted(history, accountid, reward.id)
if (geted) {
continue
}
const data = await UserReward.addOneRecord(history, accountid, reward.id, reward.coupon, reward.count)
rewardList.push(data)
}
}
rspData.rewords = rewardList
}
rspData.gameResult = gameResult
rspData.rewords = {}
return rspData
}
}

View File

@ -28,6 +28,7 @@ import {
updateSingleRank
} from '../../services/GameLogic'
import { Shop, validShopId } from '../../models/shop/Shop'
import { ShopActivity } from '../../models/shop/ShopActivity'
class PuzzleController extends BaseController {
@ -57,7 +58,7 @@ class PuzzleController extends BaseController {
}
const cfg = fetchLevelCfg(level)
let params = {}
let typeArr = await fetchSinglePuzzleType({shopId: shop, levelCfg: cfg})
let { shopId, typeArr } = await fetchSinglePuzzleType({shopId: shop, levelCfg: cfg})
if (typeArr?.length > 0) {
params = {$or: [{tag: {$in: typeArr}}, {sub_tag: {$in: typeArr}}]}
}
@ -65,7 +66,7 @@ class PuzzleController extends BaseController {
let record2 = await Puzzle.randomQuestions(Object.assign(params, {quality: 2}), 5)
let record3 = await Puzzle.randomQuestions(Object.assign(params, {quality: 3}), 5)
const records = (record1.concat(record2)).concat(record3)
let history = new PuzzleSession({ shop, level })
let history = new PuzzleSession({ shop: shopId, level })
history.members.set(accountid, new PuzzleStatusClass())
for (let record of records) {
history.questions.set(record.id, record.a1)
@ -203,7 +204,7 @@ class PuzzleController extends BaseController {
@role('anon')
@router('post /api/:accountid/puzzle/match')
async joinMultipleGame(req, res) {
const { shop, aid, accountid, debug_begin_sec, debug_qcount } = req.params
let { shop, aid, accountid, debug_begin_sec, debug_qcount } = req.params
let data: any = { shop, maxTime: 3600, accountid }
let beginSecond = (debug_begin_sec ? +debug_begin_sec : 20)
beginSecond = (Math.max(2, beginSecond)) * 1000
@ -213,12 +214,19 @@ class PuzzleController extends BaseController {
* , ,
* TODO::
*/
let activityId = '1111111'
let roomId = ''
let sessionId = ''
let sessionMatch = ''
let beginTime = 0
if (!aid) {
throw new ZError(12, 'params no match')
}
let activity = await ShopActivity.findById(aid)
let shopData = await Shop.fetchByID(shop)
shop = shopData.id
if (!activity) {
throw new ZError(13, 'activity not found')
}
let result = new RoomState().isLock(shop)
try {
await retry<Promise<string>>(async () => {
@ -226,7 +234,7 @@ class PuzzleController extends BaseController {
throw new RoomLockErr('')
}
new RoomState().lock(shop)
let history = await PuzzleSession.findOne({ shop, status: {$in: [0, 1]}, type: 1 })
let history = await PuzzleSession.findOne({ shop, status: {$in: [0, 1]}, type: 1, activityId: aid })
if (history) {
// if (history && !history.hasExpired()) {
beginTime = history.begin
@ -261,6 +269,7 @@ class PuzzleController extends BaseController {
roomId = rsp.data?.room?.roomId
sessionId = rsp.data?.sessionId
history = new PuzzleSession({shop, status: 0, type: 1})
history.activityId = aid
let memberData = new PuzzleStatusClass()
memberData.sessionId = sessionId
history.members.set(accountid, memberData)

View File

@ -10,6 +10,7 @@ import { customAlphabet, } from 'nanoid'
import { Shop } from './shop/Shop'
import { Coupon } from './shop/Coupon'
import { getCouponUrl } from '../services/File'
import { PuzzleSessionClass } from './match/PuzzleSession'
const nanoid = customAlphabet('2345678abcdefghjkmnpqrstwxy', 10)
@ -60,6 +61,9 @@ class UserRewardClass extends BaseModule {
@prop()
public coupon: string
@prop()
public rewardId: string
/**
*
* 0: 未使用
@ -102,6 +106,50 @@ class UserRewardClass extends BaseModule {
}
}
public compactInfo() {
return {
id: this.sid,
couponUrl: getCouponUrl(this.sid, this.coupon),
}
}
public static async addOneRecord(history: PuzzleSessionClass, accountId: string, rewardId: string, coupon: string, count: number, ) {
let ids: string[] = []
let cdata = await Coupon.findById(coupon)
for (let i = 0; i < count; i++) {
let record = new UserReward({
accountId,
shop: history.shop,
sessionId: history._id,
status: 0,
rewardId
})
if (history.type === 1) {
record.activityId = history.activityId
}
await record.save()
ids.push(record.sid)
}
return {
coupon,
name: cdata.name,
count,
couponUrl: getCouponUrl(history.shop, coupon),
ids
}
}
/**
*
* @param {PuzzleSessionClass} history
* @param {string} accountId
* @param rewardId
* @return {Promise<boolean>}
*/
public static async examRewardGeted(history: PuzzleSessionClass, accountId: string, rewardId: string) {
let records = await UserReward.find({accountId, examId: history.activityId, rewardId, shop: history.shop}, {_id: 1}).limit(1)
return records.length > 0
}
}
export const UserReward = getModelForClass(UserRewardClass, {existingConnection: UserRewardClass.db})

View File

@ -9,8 +9,9 @@ import { noJson } from '../../decorators/nojson'
import { Severity } from '@typegoose/typegoose/lib/internal/constants'
import moment from 'moment'
import { GameEnv } from '../../config/GameEnv'
import { Base } from '@typegoose/typegoose/lib/defaultClasses'
export class ActivityRewardClass {
export class ActivityRewardClass extends Base{
@prop()
public id: number
@prop()
@ -172,6 +173,24 @@ export class ShopActivityClass extends BaseModule {
result.next = getNextTime(record, result.current)
return result
}
/**
*
* @param {number} rank
* @return {null | {count: number, id: string}}
*/
public getReward(rank: number) {
if (!this.rewardInfo || this.rewardInfo.length === 0) {
return null
}
this.rewardInfo.sort((a, b) => a.rank - b.rank)
for (let reward of this.rewardInfo) {
if (rank < reward.rank || (reward.rankEnd && rank < reward.rankEnd)) {
return {id: reward._id + '', coupon:reward.coupon, count: reward.count}
}
}
return null
}
}
export const ShopActivity = getModelForClass(ShopActivityClass, { existingConnection: ShopActivityClass.db })

View File

@ -8,6 +8,7 @@ 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 { UserReward } from '../UserReward'
export class ShopPuzzleClass extends Base{
@prop()
@ -22,7 +23,7 @@ export class ShopPuzzleClass extends Base{
public a4: string
}
export class ExamRewardClass {
export class ExamRewardClass extends Base{
@prop()
public id: number
@prop()
@ -179,6 +180,19 @@ export class ShopExamClass extends BaseModule {
}
})
}
public getReward(score: number) {
if (!this.rewardInfo || this.rewardInfo.length === 0) {
return []
}
this.rewardInfo.sort((a, b) => a.rank - b.rank)
let results = []
for (let reward of this.rewardInfo) {
if (score >= reward.rank) {
results.push({id: reward._id + '', coupon:reward.coupon, count: reward.count})
}
}
return results
}
}
export const ShopExam = getModelForClass(ShopExamClass, { existingConnection: ShopExamClass.db })

View File

@ -1,6 +1,6 @@
import {
beginGame,
endGame,
endGame, sendMsg,
sendQuestion,
updateRound,
updateScore
@ -16,6 +16,7 @@ import { mission_vo } from '../config/parsers/mission_vo'
import { ShopActivity } from '../models/shop/ShopActivity'
import { getAccountRank, getRankCount, getRankList, updateRank } from './Rank'
import { PuzzleRank } from '../models/match/PuzzleRank'
import { UserReward } from '../models/UserReward'
export function transformRecord(records: any[]) {
@ -64,7 +65,12 @@ export function checkSubFinish(history: any, qid: string) {
*/
export async function startGame(roomId: string, sessionId: string) {
let history = await PuzzleSession.findById(sessionId)
let records = await Puzzle.randomQuestions({status: 1, is_hide: 0, deleted: 0, dp: 1}, history.total)
let typeArr = await fetchPvpPuzzleType({shopId: history.shop, aid: history.activityId})
let params = {}
if (typeArr?.length > 0) {
params = {$or: [{tag: {$in: typeArr}}, {sub_tag: {$in: typeArr}}]}
}
let records = await Puzzle.randomQuestions(params, history.total)
await beginGame(roomId, {})
for (let record of records) {
history.questions.set(record.id, record.a1)
@ -85,6 +91,8 @@ export async function sendOneQuestion(history: any) {
history.status = 9
await history.save()
await endGame(roomId, {closeTime: BaseConst.ROOM_AUTO_CLOSE_TIME})
//TODO:: 发送奖励
await sendReward(history)
return
}
const questions:string[] = Array.from(history.questions.keys())
@ -114,6 +122,31 @@ export async function sendOneQuestion(history: any) {
}, history.scheduleKey)
}
/**
*
* @param history
* @return {Promise<void>}
*/
export async function sendReward(history: any) {
let activity = await ShopActivity.findById(history.activity)
if (activity.rewardInfo.length === 0) {
return
}
let members = []
for (let [ key, val ] of history.members) {
members.push({accountId: key, score: val.score, sessionId: val.sessionId})
}
members.sort((a, b) => a.score - b.score)
for (let i = 0, len = members.length; i < len; i++) {
const adata = activity.getReward(i)
if (!adata) {
continue
}
const data = await UserReward.addOneRecord(history, members[i].accountId, adata.id, adata.coupon, adata.count)
await sendMsg(history.room, members[i].sessionId, 'rewords', data)
}
}
export function calcExamScore(time: number, combo: number) {
const cfg = new GameEnv()
return cfg.pvpBaseScore + time / 100 * cfg.pvpTimeRate + combo * cfg.pvpComboRate
@ -281,7 +314,7 @@ export async function fetchSinglePuzzleType({shopId, levelCfg} : {shopId: string
if (typeArr.length === 0 && levelCfg?.keyID) {
typeArr = levelCfg.keyID.split(':')
}
return typeArr
return {shopId: shop.id, typeArr}
}
/**