From 9b65560dd4605b018f1e38e7f86f51ff70974c56 Mon Sep 17 00:00:00 2001 From: zhl Date: Mon, 31 May 2021 15:47:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BA=97=E9=93=BA=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E9=A2=98=E5=BA=93=E7=9B=B8=E5=85=B3=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/shop_puzzle.controller.ts | 91 +++++++++++ src/models/content/Puzzle.ts | 2 +- src/models/shop/ShopCategory.ts | 59 +++++++ src/models/shop/ShopPuzzle.ts | 147 ++++++++++++++++++ 4 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 src/admin/controllers/shop_puzzle.controller.ts create mode 100644 src/models/shop/ShopCategory.ts create mode 100644 src/models/shop/ShopPuzzle.ts diff --git a/src/admin/controllers/shop_puzzle.controller.ts b/src/admin/controllers/shop_puzzle.controller.ts new file mode 100644 index 0000000..1140965 --- /dev/null +++ b/src/admin/controllers/shop_puzzle.controller.ts @@ -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) + } +} diff --git a/src/models/content/Puzzle.ts b/src/models/content/Puzzle.ts index 28da010..6436215 100644 --- a/src/models/content/Puzzle.ts +++ b/src/models/content/Puzzle.ts @@ -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 diff --git a/src/models/shop/ShopCategory.ts b/src/models/shop/ShopCategory.ts new file mode 100644 index 0000000..c8ce88c --- /dev/null +++ b/src/models/shop/ShopCategory.ts @@ -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, shop: string) { + let result: Map = 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 }) diff --git a/src/models/shop/ShopPuzzle.ts b/src/models/shop/ShopPuzzle.ts new file mode 100644 index 0000000..bbf5571 --- /dev/null +++ b/src/models/shop/ShopPuzzle.ts @@ -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, 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 })