261 lines
5.4 KiB
TypeScript
261 lines
5.4 KiB
TypeScript
import { dbconn } from '../../decorators/dbconn'
|
|
import { getModelForClass, modelOptions, prop } from '@typegoose/typegoose'
|
|
import { BaseModule } from '../Base'
|
|
import { Severity } from '@typegoose/typegoose/lib/internal/constants'
|
|
import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'
|
|
|
|
export class CompactPuzzleClass {
|
|
@prop()
|
|
id: string
|
|
@prop()
|
|
title: string
|
|
@prop({ type: () => [String] })
|
|
public answers: string[]
|
|
//1: 普通的文字选择题, 2: 图形, 3: 问卷式题目
|
|
@prop()
|
|
public type: number
|
|
@prop()
|
|
public category: string
|
|
@prop()
|
|
public quality: number
|
|
/**
|
|
* 题目来源
|
|
* 0: 系统题库
|
|
* 1: 自定义
|
|
* @type {number}
|
|
*/
|
|
@prop()
|
|
public source: number
|
|
|
|
public toJson() {
|
|
let answers = this.answers.slice(0)
|
|
answers.randomSort()
|
|
return {
|
|
id: this.id,
|
|
title: this.title,
|
|
answers: answers,
|
|
type: this.type,
|
|
category: this.category,
|
|
quality: this.quality,
|
|
}
|
|
}
|
|
}
|
|
|
|
@modelOptions({
|
|
options: { allowMixed: Severity.ALLOW },
|
|
})
|
|
export class PuzzleStatusClass {
|
|
@prop({ type: Number, default: new Map() })
|
|
answer: Map<string, number>
|
|
|
|
@prop({ default: 0 })
|
|
total: number
|
|
/**
|
|
* 打对数量
|
|
* @type {number}
|
|
*/
|
|
@prop({ default: 0 })
|
|
rightCount: number
|
|
/**
|
|
* 答错数量
|
|
* @type {number}
|
|
*/
|
|
@prop({ default: 0 })
|
|
errorCount: number
|
|
/**
|
|
* 当前连击数
|
|
* @type {number}
|
|
*/
|
|
@prop({ default: 0 })
|
|
comboCount: number
|
|
/**
|
|
* 最大连击数
|
|
* @type {number}
|
|
*/
|
|
@prop({ default: 0 })
|
|
maxCombo: number
|
|
/**
|
|
* 多人模式中, 该玩家在房间中的sessionId, 用于重连
|
|
* @type {string}
|
|
*/
|
|
@prop()
|
|
sessionId: string
|
|
/**
|
|
* 游戏胜利后的得分
|
|
* @type {number}
|
|
*/
|
|
@prop({ default: 0 })
|
|
score: number
|
|
|
|
@prop({ default: 0 })
|
|
star: number
|
|
|
|
@prop()
|
|
timeLeft: number
|
|
/**
|
|
* 最后一次答题时间
|
|
* @type {number}
|
|
*/
|
|
@prop()
|
|
timeLast: number
|
|
|
|
/**
|
|
* 游戏结果
|
|
* @type {number}
|
|
*/
|
|
@prop({ default: 0 })
|
|
public gameResult: number
|
|
}
|
|
// @ts-ignore
|
|
export interface PuzzleSessionClass extends Base, TimeStamps {}
|
|
|
|
@dbconn()
|
|
@modelOptions({ schemaOptions: { collection: 'puzzle_session', timestamps: true } })
|
|
export class PuzzleSessionClass extends BaseModule {
|
|
@prop({ _id: false, type: PuzzleStatusClass, default: new Map() })
|
|
public members: Map<string, PuzzleStatusClass>
|
|
|
|
@prop({ _id: false, type: CompactPuzzleClass, default: new Map() })
|
|
public questions: Map<string, CompactPuzzleClass>
|
|
|
|
@prop()
|
|
public shop: string
|
|
|
|
@prop()
|
|
public level: number
|
|
/**
|
|
* 活动或者挑战, 可将相关的id存入该字段
|
|
* @type {string}
|
|
*/
|
|
@prop()
|
|
public activityId: string
|
|
|
|
@prop()
|
|
public room: string
|
|
/**
|
|
* 类型
|
|
* 0: 单人
|
|
* 1: 多人
|
|
* 2: 测验
|
|
* @type {number}
|
|
*/
|
|
@prop({ default: 0 })
|
|
public type: number
|
|
|
|
/**
|
|
* 模式
|
|
* 0: 普通
|
|
* 1: 减低难度
|
|
* @type {number}
|
|
*/
|
|
@prop({ default: 0 })
|
|
public difficultyMode: number
|
|
|
|
/**
|
|
* 当前的问题
|
|
* @type {number}
|
|
*/
|
|
@prop({ default: 0 })
|
|
public current: number
|
|
/**
|
|
* 一共多少问题
|
|
* @type {number}
|
|
*/
|
|
@prop()
|
|
public total: number
|
|
|
|
/**
|
|
* 每一题回答时间
|
|
* @type {number}
|
|
*/
|
|
@prop()
|
|
public timeone: number
|
|
|
|
/**
|
|
* 比赛状态
|
|
* 0: 未开始答题
|
|
* 1: 答题进行中
|
|
* 9: 结束
|
|
* @type {number}
|
|
*/
|
|
@prop({ default: 0 })
|
|
public status: number
|
|
|
|
/**
|
|
* 已选择的题库分类
|
|
* @type {string[]}
|
|
*/
|
|
@prop({ type: () => [String] })
|
|
public qtypes: string[]
|
|
/**
|
|
* 开始时间
|
|
* 对于多人比赛来说, 需要一个自动开始时间
|
|
* @type {number}
|
|
*/
|
|
@prop()
|
|
public begin: number
|
|
@prop()
|
|
public expire: number
|
|
|
|
/**
|
|
* 获取正确答案次数, 只针对单人模式
|
|
* @type {number}
|
|
*/
|
|
@prop({ default: 0 })
|
|
public helpCount: number
|
|
|
|
public hasExpired(): boolean {
|
|
return this.expire < Date.now()
|
|
}
|
|
|
|
public get scheduleKey() {
|
|
// @ts-ignore
|
|
return this.room + this._id
|
|
}
|
|
|
|
public static parseQueryParam(params) {
|
|
let { exam, timeBegin, timeEnd, shop } = params
|
|
let opt: any = { type: 2 }
|
|
if (shop) {
|
|
opt.shop = shop
|
|
}
|
|
if (exam) {
|
|
opt.activityId = exam
|
|
}
|
|
if (timeBegin && !timeEnd) {
|
|
opt.createdAt = { $gte: new Date(timeBegin) }
|
|
} else if (timeBegin && timeEnd) {
|
|
opt['$and'] = [{ createdAt: { $gte: new Date(timeBegin) } }, { createdAt: { $lte: new Date(timeEnd) } }]
|
|
} else if (!timeBegin && timeEnd) {
|
|
opt.createdAt = { $lte: new Date(timeEnd) }
|
|
}
|
|
let sort = { _id: 1 }
|
|
return { opt, sort }
|
|
}
|
|
|
|
public toPartnerJson() {
|
|
const exportKeys = ['_id', 'status', 'createdAt', 'type', 'activityId']
|
|
let result: any = {}
|
|
for (let key of exportKeys) {
|
|
result[key] = this[key]
|
|
}
|
|
result.qcount = this.questions.size
|
|
let questions: any = []
|
|
const accountId = this.members.keys().next().value
|
|
const udata = this.members.get(accountId)
|
|
result.accountId = accountId
|
|
for (let [key, data] of this.questions) {
|
|
let obj = {
|
|
title: data.title,
|
|
answers: data.answers,
|
|
answer: udata.answer.has(key) ? udata.answer.get(key) : -1,
|
|
}
|
|
questions.push(obj)
|
|
}
|
|
result.questions = questions
|
|
return result
|
|
}
|
|
}
|
|
|
|
export const PuzzleSession = getModelForClass(PuzzleSessionClass, { existingConnection: PuzzleSessionClass.db })
|