修改获取题目和上报答案的接口
This commit is contained in:
parent
e21f4cd19f
commit
7399b31837
17
doc/api.md
17
doc/api.md
@ -36,6 +36,8 @@
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
|
session: "6080f330b9655b5c0467ee5a", // 当前局的id,提交答案时必须上报该字段
|
||||||
|
records: [{
|
||||||
"id": "6080f330b9655b5c0467ee5e", // 题目id
|
"id": "6080f330b9655b5c0467ee5e", // 题目id
|
||||||
"title": "“大丈夫为国捐躯,死而无憾!”这话是谁说的?", // 问题
|
"title": "“大丈夫为国捐躯,死而无憾!”这话是谁说的?", // 问题
|
||||||
"answers": [ // 可选答案
|
"answers": [ // 可选答案
|
||||||
@ -45,7 +47,9 @@
|
|||||||
"刘永福"
|
"刘永福"
|
||||||
],
|
],
|
||||||
"type": 1 // 题目类型 1: 普通的文字选择题, 2: 图形
|
"type": 1 // 题目类型 1: 普通的文字选择题, 2: 图形
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 上报题目答案
|
### 2. 上报题目答案
|
||||||
@ -63,6 +67,7 @@
|
|||||||
| 字段 | 说明 |
|
| 字段 | 说明 |
|
||||||
| -------- | -------------------------------------- |
|
| -------- | -------------------------------------- |
|
||||||
| id | 题目id |
|
| id | 题目id |
|
||||||
|
| session | 当局的id, 从关卡题目列表中获取 |
|
||||||
| level | 关卡id |
|
| level | 关卡id |
|
||||||
| answer | 回答的选项 |
|
| answer | 回答的选项 |
|
||||||
| type | 回答类型, 0: 正常, 1: 超时 |
|
| type | 回答类型, 0: 正常, 1: 超时 |
|
||||||
@ -72,6 +77,18 @@
|
|||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
result: 1 //答题结果 1: 正确, 0 : 错误
|
result: 1 //答题结果 1: 正确, 0 : 错误
|
||||||
|
"stats": { // 当局的状态
|
||||||
|
"1111": {
|
||||||
|
"answer": [ // 每一题的结果
|
||||||
|
1,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"rightCount": 1, // 答对的数量
|
||||||
|
"errorCount": 1, // 答错的数量
|
||||||
|
"comboCount": 0, // 当前连续答对的数量
|
||||||
|
"maxCombo": 1 // 当局连续答对的最大数量
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1,38 +1,41 @@
|
|||||||
import BaseController from '../../common/base.controller'
|
import BaseController from '../../common/base.controller'
|
||||||
import { role, router } from '../../decorators/router'
|
import { role, router } from '../../decorators/router'
|
||||||
import { Puzzle } from '../../models/content/Puzzle'
|
import { Puzzle } from '../../models/content/Puzzle'
|
||||||
import { PuzzleSession } from '../../models/match/PuzzleSession'
|
import {
|
||||||
|
PuzzleSession,
|
||||||
|
PuzzleStatusClass
|
||||||
|
} from '../../models/match/PuzzleSession'
|
||||||
import { ZError } from '../../common/ZError'
|
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 {
|
class PuzzleController extends BaseController {
|
||||||
@role('anon')
|
@role('anon')
|
||||||
@router('post /api/:accountid/puzzle/list')
|
@router('post /api/:accountid/puzzle/list')
|
||||||
async list(req, res) {
|
async list(req, res) {
|
||||||
let { shop, level, accountid } = req.params
|
let { shop, level, accountid } = req.params
|
||||||
let count = 10
|
let count = 10
|
||||||
let records = await Puzzle.aggregate([
|
let records = await Puzzle.randomQuestions({}, count)
|
||||||
{ $match: { status: 1, is_hide: 0, deleted: 0 } },
|
|
||||||
{ $sample: { size: count } }
|
|
||||||
]).exec()
|
|
||||||
let history = new PuzzleSession({ shop, level })
|
let history = new PuzzleSession({ shop, level })
|
||||||
history.members = [accountid]
|
history.members.set(accountid, new PuzzleStatusClass())
|
||||||
history.questions = records.map(o => o.id)
|
history.questions = records.map(o => o._id)
|
||||||
await history.save()
|
await history.save()
|
||||||
const results = records.map(o => {
|
const results = transformRecord(records)
|
||||||
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
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return {
|
return {
|
||||||
session: history.id,
|
session: history.id,
|
||||||
records: results
|
records: results
|
||||||
@ -42,10 +45,24 @@ class PuzzleController extends BaseController {
|
|||||||
@role('anon')
|
@role('anon')
|
||||||
@router('post /api/:accountid/puzzle/answer')
|
@router('post /api/:accountid/puzzle/answer')
|
||||||
async report(req, res) {
|
async report(req, res) {
|
||||||
let { id, answer, type } = req.params
|
let { id, answer, type, session, accountid } = req.params
|
||||||
if (!id) {
|
if (!id || !session) {
|
||||||
throw new ZError(11, 'param mismatch')
|
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)
|
let record = await Puzzle.findById(id)
|
||||||
if (!record) {
|
if (!record) {
|
||||||
throw new ZError(12, 'question not found')
|
throw new ZError(12, 'question not found')
|
||||||
@ -54,6 +71,18 @@ class PuzzleController extends BaseController {
|
|||||||
if (type == 1) {
|
if (type == 1) {
|
||||||
result = 0
|
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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,16 @@ class PuzzleClass extends BaseModule {
|
|||||||
public static async nextQuestion(this: ReturnModelType<typeof PuzzleClass>, id: string) {
|
public static async nextQuestion(this: ReturnModelType<typeof PuzzleClass>, id: string) {
|
||||||
return this.findOne({deleted: 0, is_hide: 0, _id: {$gt: id }}).exec()
|
return this.findOne({deleted: 0, is_hide: 0, _id: {$gt: id }}).exec()
|
||||||
}
|
}
|
||||||
|
public static async randomQuestions(this: ReturnModelType<typeof PuzzleClass>, 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 })
|
export const Puzzle = getModelForClass(PuzzleClass, { existingConnection: PuzzleClass.db })
|
||||||
|
@ -1,29 +1,60 @@
|
|||||||
import { dbconn } from '../../decorators/dbconn'
|
import { dbconn } from '../../decorators/dbconn'
|
||||||
import { getModelForClass, modelOptions, prop } from '@typegoose/typegoose'
|
import { getModelForClass, modelOptions, prop } from '@typegoose/typegoose'
|
||||||
import { BaseModule } from '../Base'
|
import { BaseModule } from '../Base'
|
||||||
|
export class PuzzleStatusClass {
|
||||||
|
|
||||||
@dbconn('second')
|
@prop({default: []})
|
||||||
@modelOptions({ schemaOptions: { collection: 'question_category' } })
|
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 {
|
class PuzzleSessionClass extends BaseModule {
|
||||||
|
|
||||||
@prop({ type: () => [String] })
|
@prop({ _id: false, type: PuzzleStatusClass, default: new Map() })
|
||||||
members: string[]
|
public members: Map<string, PuzzleStatusClass>
|
||||||
|
|
||||||
@prop({ type: () => [String] })
|
@prop({ type: () => [String] })
|
||||||
questions: string[]
|
public questions: string[]
|
||||||
|
|
||||||
@prop()
|
@prop()
|
||||||
shop: string
|
public shop: string
|
||||||
|
|
||||||
@prop()
|
@prop()
|
||||||
level: number
|
public level: number
|
||||||
|
|
||||||
@prop()
|
@prop()
|
||||||
room: string
|
public room: string
|
||||||
|
|
||||||
|
|
||||||
@prop({default: 0})
|
@prop({default: 0})
|
||||||
status: number
|
public status: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PuzzleSession = getModelForClass(PuzzleSessionClass, { existingConnection: PuzzleSessionClass.db })
|
export const PuzzleSession = getModelForClass(PuzzleSessionClass, { existingConnection: PuzzleSessionClass.db })
|
||||||
|
Loading…
x
Reference in New Issue
Block a user