diff --git a/doc/api.md b/doc/api.md index 6c0efba..7f2c8e2 100644 --- a/doc/api.md +++ b/doc/api.md @@ -36,6 +36,8 @@ ```js { + session: "6080f330b9655b5c0467ee5a", // 当前局的id,提交答案时必须上报该字段 + records: [{ "id": "6080f330b9655b5c0467ee5e", // 题目id "title": "“大丈夫为国捐躯,死而无憾!”这话是谁说的?", // 问题 "answers": [ // 可选答案 @@ -45,7 +47,9 @@ "刘永福" ], "type": 1 // 题目类型 1: 普通的文字选择题, 2: 图形 +}] } + ``` ### 2. 上报题目答案 @@ -63,6 +67,7 @@ | 字段 | 说明 | | -------- | -------------------------------------- | | id | 题目id | +| session | 当局的id, 从关卡题目列表中获取 | | level | 关卡id | | answer | 回答的选项 | | type | 回答类型, 0: 正常, 1: 超时 | @@ -72,6 +77,18 @@ ```js { result: 1 //答题结果 1: 正确, 0 : 错误 + "stats": { // 当局的状态 + "1111": { + "answer": [ // 每一题的结果 + 1, + 0 + ], + "rightCount": 1, // 答对的数量 + "errorCount": 1, // 答错的数量 + "comboCount": 0, // 当前连续答对的数量 + "maxCombo": 1 // 当局连续答对的最大数量 + } + } } ``` diff --git a/src/api/controllers/puzzle.controller.ts b/src/api/controllers/puzzle.controller.ts index 3789b1e..aeb1163 100644 --- a/src/api/controllers/puzzle.controller.ts +++ b/src/api/controllers/puzzle.controller.ts @@ -1,38 +1,41 @@ import BaseController from '../../common/base.controller' import { role, router } from '../../decorators/router' import { Puzzle } from '../../models/content/Puzzle' -import { PuzzleSession } from '../../models/match/PuzzleSession' +import { + PuzzleSession, + PuzzleStatusClass +} from '../../models/match/PuzzleSession' import { ZError } from '../../common/ZError' +const transformRecord = function (records: any[]) { + return records.map(o => { + let answers = [] + for (let i = 1; i <= 4; i++) { + if (o[`a${ i }`]) { + answers.push(o[`a${ i }`]) + } + } + answers.randomSort() + return { + id: o._id, + title: o.question, + answers, + type: 1 + } + }) +} class PuzzleController extends BaseController { @role('anon') @router('post /api/:accountid/puzzle/list') async list(req, res) { let { shop, level, accountid } = req.params let count = 10 - let records = await Puzzle.aggregate([ - { $match: { status: 1, is_hide: 0, deleted: 0 } }, - { $sample: { size: count } } - ]).exec() + let records = await Puzzle.randomQuestions({}, count) let history = new PuzzleSession({ shop, level }) - history.members = [accountid] - history.questions = records.map(o => o.id) + history.members.set(accountid, new PuzzleStatusClass()) + history.questions = records.map(o => o._id) await history.save() - const results = records.map(o => { - let answers = [] - for (let i = 1; i <= 4; i++) { - if (o[`a${ i }`]) { - answers.push(o[`a${ i }`]) - } - } - answers.randomSort() - return { - id: o._id, - title: o.question, - answers, - type: 1 - } - }) + const results = transformRecord(records) return { session: history.id, records: results @@ -42,10 +45,24 @@ class PuzzleController extends BaseController { @role('anon') @router('post /api/:accountid/puzzle/answer') async report(req, res) { - let { id, answer, type } = req.params - if (!id) { + let { id, answer, type, session, accountid } = req.params + if (!id || !session) { throw new ZError(11, 'param mismatch') } + let history = await PuzzleSession.findById(session) + if (!history) { + throw new ZError(13, 'not found match info') + } + if (!history.members.has(accountid)) { + throw new ZError(14, 'not in current match') + } + if (!history.questions.find(o => o == id)) { + throw new ZError(16, 'current question not in current match') + } + let statMap = history.members.get(accountid) + if (statMap.questions.find(o => o == id)) { + throw new ZError(15, 'current question already answered') + } let record = await Puzzle.findById(id) if (!record) { throw new ZError(12, 'question not found') @@ -54,6 +71,18 @@ class PuzzleController extends BaseController { if (type == 1) { result = 0 } - return { result } + statMap.answer.push(result) + statMap.questions.push(id) + if (result == 1) { + statMap.rightCount ++ + statMap.comboCount ++ + statMap.maxCombo = Math.max(statMap.maxCombo, statMap.comboCount) + } else { + statMap.errorCount ++ + statMap.comboCount = 0 + } + history.markModified('members') + await history.save() + return { result, stats: history.members } } } diff --git a/src/models/content/Puzzle.ts b/src/models/content/Puzzle.ts index 14eb80e..0d56a1e 100644 --- a/src/models/content/Puzzle.ts +++ b/src/models/content/Puzzle.ts @@ -82,6 +82,16 @@ class PuzzleClass extends BaseModule { public static async nextQuestion(this: ReturnModelType, id: string) { return this.findOne({deleted: 0, is_hide: 0, _id: {$gt: id }}).exec() } + public static async randomQuestions(this: ReturnModelType, options: any, count: number) { + let filters = {status: 1, is_hide: 0, deleted: 0} + Object.assign(options) + return Puzzle.aggregate([ + { $match: filters }, + { $sample: { size: count } } + ]).exec() + + } + } export const Puzzle = getModelForClass(PuzzleClass, { existingConnection: PuzzleClass.db }) diff --git a/src/models/match/PuzzleSession.ts b/src/models/match/PuzzleSession.ts index e5ae700..b4ca3c5 100644 --- a/src/models/match/PuzzleSession.ts +++ b/src/models/match/PuzzleSession.ts @@ -1,29 +1,60 @@ import { dbconn } from '../../decorators/dbconn' import { getModelForClass, modelOptions, prop } from '@typegoose/typegoose' import { BaseModule } from '../Base' +export class PuzzleStatusClass { -@dbconn('second') -@modelOptions({ schemaOptions: { collection: 'question_category' } }) + @prop({default: []}) + answer: number[] + + @prop({ type: () => [String], default: [] }) + questions: string[] + /** + * 打对数量 + * @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 +} +@dbconn() +@modelOptions({ schemaOptions: { collection: 'puzzle_session' } }) class PuzzleSessionClass extends BaseModule { - @prop({ type: () => [String] }) - members: string[] + @prop({ _id: false, type: PuzzleStatusClass, default: new Map() }) + public members: Map @prop({ type: () => [String] }) - questions: string[] + public questions: string[] @prop() - shop: string + public shop: string @prop() - level: number + public level: number @prop() - room: string + public room: string @prop({default: 0}) - status: number + public status: number } export const PuzzleSession = getModelForClass(PuzzleSessionClass, { existingConnection: PuzzleSessionClass.db })