增加店铺自定义题库相关接口
This commit is contained in:
parent
a6c3b1c081
commit
9b65560dd4
91
src/admin/controllers/shop_puzzle.controller.ts
Normal file
91
src/admin/controllers/shop_puzzle.controller.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import BaseController from '../../common/base.controller'
|
||||
import { permission, router } from '../../decorators/router'
|
||||
import { ShopPuzzle } from '../../models/shop/ShopPuzzle'
|
||||
import { ZError } from '../../common/ZError'
|
||||
|
||||
export default class ShopPuzzleController extends BaseController {
|
||||
@permission('shoppuzzle:read')
|
||||
@router('post /api/:shop/puzzles')
|
||||
async list(req, res) {
|
||||
let { start, limit, page, shop } = req.params
|
||||
limit = +limit || 10
|
||||
start = +start || (+page - 1) * limit || 0
|
||||
let { opt, sort } = ShopPuzzle.parseQueryParam(req.params)
|
||||
let puzzles = await ShopPuzzle.find(opt).sort(sort).skip(start).limit(limit)
|
||||
let count = await ShopPuzzle.countDocuments(opt)
|
||||
let records = []
|
||||
for (let record of puzzles) {
|
||||
let data = record.toJson()
|
||||
records.push(data)
|
||||
}
|
||||
return {
|
||||
total: count,
|
||||
start,
|
||||
limit,
|
||||
records,
|
||||
}
|
||||
}
|
||||
|
||||
@permission('shoppuzzle:read')
|
||||
@router('get /api/:shop/puzzle/:id')
|
||||
async detail(req, res) {
|
||||
let { id } = req.params
|
||||
const record = await ShopPuzzle.findById(id)
|
||||
if (!record) {
|
||||
throw new ZError(11, 'record not found')
|
||||
}
|
||||
return record.toJson()
|
||||
}
|
||||
|
||||
@permission('shoppuzzle:edit')
|
||||
@router('post /api/:shop/puzzle/save')
|
||||
async save(req: any) {
|
||||
let { _id, withNext, shop } = req.params
|
||||
let user = req.user
|
||||
let record
|
||||
if (!_id) {
|
||||
record = new ShopPuzzle(req.params)
|
||||
record.createdBy = user.id
|
||||
} else {
|
||||
record = await ShopPuzzle.findById(_id)
|
||||
record.updateFromReq(req.params)
|
||||
}
|
||||
await record.save()
|
||||
if (withNext) {
|
||||
let nextRecord = await ShopPuzzle.nextQuestion(record.id, shop)
|
||||
return nextRecord.toJson()
|
||||
}
|
||||
return record.toJson()
|
||||
}
|
||||
@permission('shoppuzzle:delete')
|
||||
@router('post /api/:shop/puzzle/:id/delete')
|
||||
async delete(req: any) {
|
||||
let { id } = req.params
|
||||
if (!id) {
|
||||
throw new ZError(11, 'params mismatch')
|
||||
}
|
||||
await ShopPuzzle.findByIdAndUpdate(id, {
|
||||
$set: {
|
||||
deleted: 1,
|
||||
deleteTime: new Date(),
|
||||
},
|
||||
})
|
||||
return {}
|
||||
}
|
||||
@permission('shoppuzzle:read')
|
||||
@router('post /api/:shop/nextpuzzle')
|
||||
async next(req: any) {
|
||||
let { id, shop } = req.params
|
||||
if (!id) {
|
||||
throw new ZError(11, 'params mismatch')
|
||||
}
|
||||
let nextRecord = await ShopPuzzle.nextQuestion(id, shop)
|
||||
return nextRecord.toJson()
|
||||
}
|
||||
|
||||
@router('get /api/:shop/categorys')
|
||||
async categoryList(req, res) {
|
||||
const { shop } = req.params
|
||||
return await ShopPuzzle.allTags(shop)
|
||||
}
|
||||
}
|
@ -71,7 +71,7 @@ export class PuzzleClass extends BaseModule {
|
||||
opt.sub_tag = sub_tag
|
||||
}
|
||||
if (groups) {
|
||||
Object.assign(opt, { groups })
|
||||
Object.assign(opt, { groups: { $in: groups } })
|
||||
}
|
||||
if (quality != undefined) {
|
||||
opt.quality = quality
|
||||
|
59
src/models/shop/ShopCategory.ts
Normal file
59
src/models/shop/ShopCategory.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { dbconn } from '../../decorators/dbconn'
|
||||
import { getModelForClass, index, modelOptions, prop, ReturnModelType } from '@typegoose/typegoose'
|
||||
import { BaseModule } from '../Base'
|
||||
import { noJson } from '../../decorators/nojson'
|
||||
|
||||
/**
|
||||
* 店铺的分类
|
||||
*/
|
||||
|
||||
class SubType {
|
||||
@prop()
|
||||
public _id: string
|
||||
|
||||
@prop()
|
||||
public name: string
|
||||
}
|
||||
|
||||
@dbconn('second')
|
||||
@index({ shop: 1 }, { unique: false })
|
||||
@modelOptions({ schemaOptions: { collection: 'question_category' } })
|
||||
class ShopCategoryClass extends BaseModule {
|
||||
@prop()
|
||||
public _id: string
|
||||
|
||||
@prop()
|
||||
public shop: string
|
||||
|
||||
@prop()
|
||||
public name: string
|
||||
|
||||
@prop({ type: () => [SubType] })
|
||||
public children: SubType[]
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
* @type {boolean}
|
||||
*/
|
||||
@noJson()
|
||||
@prop({ default: false })
|
||||
public deleted: boolean
|
||||
|
||||
@noJson()
|
||||
@prop()
|
||||
public deleteTime: Date
|
||||
|
||||
public static async allCateMap(this: ReturnModelType<typeof ShopCategoryClass>, shop: string) {
|
||||
let result: Map<string, string> = new Map()
|
||||
let records = await this.find({ shop, deleted: false }).exec()
|
||||
for (let record of records) {
|
||||
result.set(record._id, record.name)
|
||||
for (let sub of record.children) {
|
||||
result.set(sub._id, sub.name)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
export const ShopCategory = getModelForClass(ShopCategoryClass, { existingConnection: ShopCategoryClass.db })
|
147
src/models/shop/ShopPuzzle.ts
Normal file
147
src/models/shop/ShopPuzzle.ts
Normal file
@ -0,0 +1,147 @@
|
||||
import { dbconn } from '../../decorators/dbconn'
|
||||
import { getModelForClass, index, modelOptions, prop, ReturnModelType } from '@typegoose/typegoose'
|
||||
import { BaseModule } from '../Base'
|
||||
import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'
|
||||
import { checkJson, noJson } from '../../decorators/nojson'
|
||||
import { PuzzleClass } from '../content/Puzzle'
|
||||
|
||||
const jsonExcludeKeys = ['updatedAt', '__v']
|
||||
|
||||
/**
|
||||
* 店铺自定义题库, 单独拿出来放, 避免污染系统题库
|
||||
*/
|
||||
// @ts-ignore
|
||||
export interface ShopPuzzleClass extends Base, TimeStamps {}
|
||||
|
||||
@dbconn()
|
||||
@index({ shop: 1 }, { unique: false })
|
||||
@index({ groups: 1 }, { unique: false })
|
||||
@index({ shop: 1, tag: 1, sub_tag: 1 }, { unique: false })
|
||||
@modelOptions({ schemaOptions: { collection: 'shop_puzzle', timestamps: true } })
|
||||
export class ShopPuzzleClass extends BaseModule {
|
||||
@prop()
|
||||
public shop: string
|
||||
@prop()
|
||||
public question: string
|
||||
@prop()
|
||||
public a1: string
|
||||
@prop()
|
||||
public a2: string
|
||||
@prop()
|
||||
public a3: string
|
||||
@prop()
|
||||
public a4: string
|
||||
/**
|
||||
* 难度
|
||||
* @type {number}
|
||||
*/
|
||||
@prop({ default: 1 })
|
||||
public quality: number
|
||||
|
||||
/**
|
||||
* 大分类
|
||||
* @type {string}
|
||||
*/
|
||||
@prop()
|
||||
public tag: string
|
||||
/**
|
||||
* 子分类
|
||||
* @type {string}
|
||||
*/
|
||||
@prop()
|
||||
public sub_tag: string
|
||||
|
||||
/**
|
||||
* 这个是tag
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
@prop({ type: () => [String] })
|
||||
public groups: string[]
|
||||
/**
|
||||
* 是否删除
|
||||
* @type {boolean}
|
||||
*/
|
||||
@noJson()
|
||||
@prop({ default: 0 })
|
||||
public deleted: number
|
||||
|
||||
@noJson()
|
||||
@prop()
|
||||
public deleteTime: Date
|
||||
|
||||
@noJson()
|
||||
@prop({ default: 0 })
|
||||
public is_hide: number
|
||||
|
||||
public static parseQueryParam(params) {
|
||||
let { key, timeBegin, timeEnd, tag, sub_tag, groups, dp, quality, sort, length, shop } = params
|
||||
let opt: any = { deleted: 0, is_hide: 0 }
|
||||
if (key) {
|
||||
opt.question = { $regex: key, $options: 'i' }
|
||||
}
|
||||
if (tag) {
|
||||
opt.tag = tag
|
||||
}
|
||||
if (sub_tag) {
|
||||
opt.sub_tag = sub_tag
|
||||
}
|
||||
if (groups) {
|
||||
Object.assign(opt, { groups: { $in: groups } })
|
||||
}
|
||||
if (quality != undefined) {
|
||||
opt.quality = quality
|
||||
}
|
||||
if (dp != undefined) {
|
||||
if (dp == 'none') {
|
||||
opt.dp = { $exists: false }
|
||||
} else {
|
||||
opt.dp = dp
|
||||
}
|
||||
}
|
||||
if (shop) {
|
||||
opt.shop = shop
|
||||
}
|
||||
if (timeBegin && !timeEnd) {
|
||||
opt.createdAt = { $gte: timeBegin }
|
||||
} else if (timeBegin && timeEnd) {
|
||||
opt['$and'] = [{ createdAt: { $gte: timeBegin } }, { createdAt: { $lte: timeEnd } }]
|
||||
} else if (!timeBegin && timeEnd) {
|
||||
opt.createdAt = { $lte: timeEnd }
|
||||
}
|
||||
if (length) {
|
||||
opt.length = { $gte: length }
|
||||
}
|
||||
let sortObj = { _id: 1 }
|
||||
if (sort) {
|
||||
sortObj = sort
|
||||
}
|
||||
|
||||
return { opt, sort: sortObj }
|
||||
}
|
||||
|
||||
public toJson() {
|
||||
let result: any = {}
|
||||
// @ts-ignore
|
||||
for (let key in this._doc) {
|
||||
if (checkJson(this, key + '') && jsonExcludeKeys.indexOf(key) == -1) {
|
||||
if (key === 'createdAt') {
|
||||
result.createtime = this['createdAt']
|
||||
} else {
|
||||
result[key] = this[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public static async nextQuestion(this: ReturnModelType<typeof ShopPuzzleClass>, id: string, shop: string) {
|
||||
return this.findOne({ deleted: 0, shop, is_hide: 0, _id: { $gt: id } }).exec()
|
||||
}
|
||||
|
||||
public static async allTags(shop: string) {
|
||||
return ShopPuzzle.distinct('groups', { shop, deleted: 0 })
|
||||
}
|
||||
}
|
||||
|
||||
export const ShopPuzzle = getModelForClass(ShopPuzzleClass, { existingConnection: ShopPuzzleClass.db })
|
Loading…
x
Reference in New Issue
Block a user