zs 1 年之前
当前提交
7f08ae9cfd
共有 61 个文件被更改,包括 2941 次插入0 次删除
  1. 11 0
      .editorconfig
  2. 7 0
      .eslintrc.json
  3. 15 0
      .gitignore
  4. 3 0
      .prettierrc.js
  5. 29 0
      README.md
  6. 29 0
      README.zh-CN.md
  7. 2 0
      bootstrap.js
  8. 20 0
      ecosystem.config.js
  9. 6 0
      jest.config.js
  10. 69 0
      package.json
  11. 29 0
      src/config/config.default.ts
  12. 46 0
      src/config/config.local.ts
  13. 46 0
      src/config/config.prod.ts
  14. 7 0
      src/config/config.unittest.ts
  15. 50 0
      src/configuration.ts
  16. 139 0
      src/controller/admin.controller.ts
  17. 89 0
      src/controller/application.controller.ts
  18. 89 0
      src/controller/course.controller.ts
  19. 89 0
      src/controller/dictData.controller.ts
  20. 89 0
      src/controller/dictType.controller.ts
  21. 9 0
      src/controller/home.controller.ts
  22. 89 0
      src/controller/match.controller.ts
  23. 89 0
      src/controller/team.controller.ts
  24. 89 0
      src/controller/teamApply.controller.ts
  25. 24 0
      src/controller/token.controller.ts
  26. 139 0
      src/controller/user.controller.ts
  27. 27 0
      src/entity/admin.entity.ts
  28. 31 0
      src/entity/application.entity.ts
  29. 39 0
      src/entity/course.entity.ts
  30. 25 0
      src/entity/dictData.entity.ts
  31. 21 0
      src/entity/dictType.entity.ts
  32. 27 0
      src/entity/match.entity.ts
  33. 31 0
      src/entity/team.entity.ts
  34. 25 0
      src/entity/teamApply.entity.ts
  35. 56 0
      src/entity/user.entity.ts
  36. 13 0
      src/filter/default.filter.ts
  37. 10 0
      src/filter/notfound.filter.ts
  38. 6 0
      src/interface.ts
  39. 106 0
      src/interface/admin.interface.ts
  40. 126 0
      src/interface/application.interface.ts
  41. 152 0
      src/interface/course.interface.ts
  42. 96 0
      src/interface/dictData.interface.ts
  43. 82 0
      src/interface/dictType.interface.ts
  44. 99 0
      src/interface/match.interface.ts
  45. 120 0
      src/interface/team.interface.ts
  46. 96 0
      src/interface/teamApply.interface.ts
  47. 187 0
      src/interface/user.interface.ts
  48. 33 0
      src/middleware/checkToken.middleware.ts
  49. 27 0
      src/middleware/report.middleware.ts
  50. 30 0
      src/service/admin.service.ts
  51. 11 0
      src/service/application.service.ts
  52. 11 0
      src/service/course.service.ts
  53. 11 0
      src/service/dictData.service.ts
  54. 11 0
      src/service/dictType.service.ts
  55. 11 0
      src/service/match.service.ts
  56. 11 0
      src/service/team.service.ts
  57. 11 0
      src/service/teamApply.service.ts
  58. 30 0
      src/service/user.service.ts
  59. 20 0
      test/controller/api.test.ts
  60. 21 0
      test/controller/home.test.ts
  61. 25 0
      tsconfig.json

+ 11 - 0
.editorconfig

@@ -0,0 +1,11 @@
+# 🎨 editorconfig.org
+
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true

+ 7 - 0
.eslintrc.json

@@ -0,0 +1,7 @@
+{
+  "extends": "./node_modules/mwts/",
+  "ignorePatterns": ["node_modules", "dist", "test", "jest.config.js", "typings"],
+  "env": {
+    "jest": true
+  }
+}

+ 15 - 0
.gitignore

@@ -0,0 +1,15 @@
+logs/
+npm-debug.log
+yarn-error.log
+node_modules/
+package-lock.json
+yarn.lock
+coverage/
+dist/
+.idea/
+run/
+.DS_Store
+*.sw*
+*.un~
+.tsbuildinfo
+.tsbuildinfo.*

+ 3 - 0
.prettierrc.js

@@ -0,0 +1,3 @@
+module.exports = {
+  ...require('mwts/.prettierrc.json')
+}

+ 29 - 0
README.md

@@ -0,0 +1,29 @@
+# my_midway_project
+
+## QuickStart
+
+<!-- add docs here for user -->
+
+see [midway docs][midway] for more detail.
+
+### Development
+
+```bash
+$ npm i
+$ npm run dev
+$ open http://localhost:7001/
+```
+
+### Deploy
+
+```bash
+$ npm start
+```
+
+### npm scripts
+
+- Use `npm run lint` to check code style.
+- Use `npm test` to run unit test.
+
+
+[midway]: https://midwayjs.org

+ 29 - 0
README.zh-CN.md

@@ -0,0 +1,29 @@
+# my_midway_project
+
+## 快速入门
+
+<!-- 在此次添加使用文档 -->
+
+如需进一步了解,参见 [midway 文档][midway]。
+
+### 本地开发
+
+```bash
+$ npm i
+$ npm run dev
+$ open http://localhost:7001/
+```
+
+### 部署
+
+```bash
+$ npm start
+```
+
+### 内置指令
+
+- 使用 `npm run lint` 来做代码风格检查。
+- 使用 `npm test` 来执行单元测试。
+
+
+[midway]: https://midwayjs.org

+ 2 - 0
bootstrap.js

@@ -0,0 +1,2 @@
+const { Bootstrap } = require('@midwayjs/bootstrap');
+Bootstrap.run();

+ 20 - 0
ecosystem.config.js

@@ -0,0 +1,20 @@
+'use strict';
+// 开发服务设置
+const app = '羽毛球比赛vue3-服务';
+module.exports = {
+  apps: [
+    {
+      name: app, // 应用名称
+      script: './bootstrap.js', // 实际启动脚本
+      out: `./logs/${app}.log`,
+      error: `./logs/${app}.err`,
+      watch: [
+        // 监控变化的目录,一旦变化,自动重启
+        'dist',
+      ],
+      env: {
+        NODE_ENV: 'production', // 环境参数,当前指定为生产环境
+      },
+    },
+  ],
+};

+ 6 - 0
jest.config.js

@@ -0,0 +1,6 @@
+module.exports = {
+  preset: 'ts-jest',
+  testEnvironment: 'node',
+  testPathIgnorePatterns: ['<rootDir>/test/fixtures'],
+  coveragePathIgnorePatterns: ['<rootDir>/test/'],
+};

+ 69 - 0
package.json

@@ -0,0 +1,69 @@
+{
+  "name": "my-midway-project",
+  "version": "1.0.0",
+  "description": "",
+  "private": true,
+  "dependencies": {
+    "@midwayjs/axios": "^3.11.10",
+    "@midwayjs/bootstrap": "^3.0.0",
+    "@midwayjs/core": "^3.0.0",
+    "@midwayjs/decorator": "^3.0.0",
+    "@midwayjs/info": "^3.0.0",
+    "@midwayjs/jwt": "^3.11.10",
+    "@midwayjs/koa": "^3.0.0",
+    "@midwayjs/logger": "^2.14.0",
+    "@midwayjs/redis": "^3.11.10",
+    "@midwayjs/swagger": "^3.11.10",
+    "@midwayjs/task": "^3.6.0",
+    "@midwayjs/typegoose": "^3.11.10",
+    "@midwayjs/validate": "^3.0.0",
+    "@midwayjs/web": "^3.11.10",
+    "@typegoose/typegoose": "^11.2.0",
+    "amqp-connection-manager": "^4.1.13",
+    "amqplib": "^0.10.3",
+    "exceljs": "^4.3.0",
+    "free-midway-component": "^1.0.35",
+    "midway-schedule": "^2.15.0",
+    "moment": "^2.29.4",
+    "mongoose": "^7.2.2",
+    "swagger-ui-dist": "^4.19.0"
+  },
+  "devDependencies": {
+    "@midwayjs/cli": "^2.0.0",
+    "@midwayjs/mock": "^3.0.0",
+    "@types/amqplib": "^0.10.1",
+    "@types/jest": "^29.2.0",
+    "@types/jsonwebtoken": "^9.0.2",
+    "@types/koa": "^2.13.4",
+    "@types/lodash": "^4.14.195",
+    "@types/node": "14",
+    "cross-env": "^6.0.0",
+    "jest": "^29.2.2",
+    "mwts": "^1.0.5",
+    "ts-jest": "^29.0.3",
+    "typescript": "~4.8.0"
+  },
+  "engines": {
+    "node": ">=12.0.0"
+  },
+  "scripts": {
+    "start": "NODE_ENV=production node ./bootstrap.js",
+    "dev": "cross-env NODE_ENV=local midway-bin dev --ts",
+    "test": "midway-bin test --ts",
+    "cov": "midway-bin cov --ts",
+    "lint": "mwts check",
+    "lint:fix": "mwts fix",
+    "ci": "npm run cov",
+    "build": "midway-bin build -c"
+  },
+  "midway-bin-clean": [
+    ".vscode/.tsbuildinfo",
+    "dist"
+  ],
+  "repository": {
+    "type": "git",
+    "url": ""
+  },
+  "author": "anonymous",
+  "license": "MIT"
+}

+ 29 - 0
src/config/config.default.ts

@@ -0,0 +1,29 @@
+import { MidwayConfig } from '@midwayjs/core';
+
+const project = 'ball';
+export default {
+  // use for cookie sign key, should change to your own and keep security
+  keys: '1686030936692_986',
+  koa: {
+    port: 13005,
+  },
+  jwt: {
+    secret: 'Ziyouyanfa!@#',
+    expiresIn: '2d',
+  },
+  redis_timeout: 300, //s
+  emailConfig: project,
+  axios: {
+    clients: {},
+  },
+  export: {
+    root_path: 'D:\\temp',
+    export_path: 'D:\\temp\\export',
+    export_dir: 'export',
+    patentInfo_dir: 'patentInfo',
+    domain: 'http://broadcast.waityou24.cn',
+  },
+  rabbitmq: {
+    url: 'amqp://localhost',
+  },
+} as MidwayConfig;

+ 46 - 0
src/config/config.local.ts

@@ -0,0 +1,46 @@
+import { MidwayConfig } from '@midwayjs/core';
+const ip = '127.0.0.1';
+const project = 'ball';
+const mongodb = 'count_match_v1';
+export default {
+  // use for cookie sign key, should change to your own and keep security
+  keys: '1686030936692_986',
+  koa: {
+    globalPrefix: `/${project}/v1/api`,
+  },
+  swagger: {
+    swaggerPath: `/dev/${project}/v1/doc`,
+  },
+  mongoose: {
+    dataSource: {
+      default: {
+        uri: `mongodb://${ip}:27017/${mongodb}`,
+        options: {
+          user: 'admin',
+          pass: 'admin',
+          authSource: 'admin',
+          useNewUrlParser: true,
+        },
+        entities: ['./entity'],
+      },
+    },
+  },
+  redis: {
+    client: {
+      port: 6379, // Redis port
+      host: '127.0.0.1', // Redis host
+      password: '123456',
+      db: 4,
+    },
+  },
+  axios: {
+    clients: {},
+  },
+  export: {
+    root_path: 'D:\\temp',
+    export_path: 'D:\\temp\\export',
+    export_dir: 'export',
+    patentInfo_dir: 'patentInfo',
+    domain: 'http://broadcast.waityou24.cn',
+  },
+} as MidwayConfig;

+ 46 - 0
src/config/config.prod.ts

@@ -0,0 +1,46 @@
+import { MidwayConfig } from '@midwayjs/core';
+const ip = '127.0.0.1';
+const project = 'ball';
+const mongodb = 'count_match_v1';
+export default {
+  // use for cookie sign key, should change to your own and keep security
+  keys: '1686030936692_986',
+  koa: {
+    globalPrefix: `/${project}/v1/api`,
+  },
+  swagger: {
+    swaggerPath: `/dev/${project}/v1/doc`,
+  },
+  mongoose: {
+    dataSource: {
+      default: {
+        uri: `mongodb://${ip}:27017/${mongodb}`,
+        options: {
+          user: 'admin',
+          pass: 'admin',
+          authSource: 'admin',
+          useNewUrlParser: true,
+        },
+        entities: ['./entity'],
+      },
+    },
+  },
+  redis: {
+    client: {
+      port: 6379, // Redis port
+      host: '127.0.0.1', // Redis host
+      password: '123456',
+      db: 4,
+    },
+  },
+  axios: {
+    clients: {},
+  },
+  export: {
+    root_path: '/mnt/server/service-file/upload',
+    export_path: '/mnt/server/service-file/upload',
+    export_dir: 'export',
+    patentInfo_dir: 'patentInfo',
+    domain: 'http://127.0.0.1',
+  },
+} as MidwayConfig;

+ 7 - 0
src/config/config.unittest.ts

@@ -0,0 +1,7 @@
+import { MidwayConfig } from '@midwayjs/core';
+
+export default {
+  koa: {
+    port: null,
+  },
+} as MidwayConfig;

+ 50 - 0
src/configuration.ts

@@ -0,0 +1,50 @@
+import { Configuration, App } from '@midwayjs/core';
+// import * as rabbitmq from '@midwayjs/rabbitmq';
+import * as koa from '@midwayjs/koa';
+import * as validate from '@midwayjs/validate';
+import * as info from '@midwayjs/info';
+import * as swagger from '@midwayjs/swagger';
+import * as jwt from '@midwayjs/jwt';
+import * as redis from '@midwayjs/redis';
+import * as axios from '@midwayjs/axios';
+// import { IMidwayContainer } from '@midwayjs/core';
+import { join } from 'path';
+// freemidway组件项目
+import * as FreeFrame from 'free-midway-component';
+// import { FrameworkErrorEnum, ServiceError } from 'free-midway-component';
+// 控制器执行前函数
+import { CheckTokenMiddleware } from './middleware/checkToken.middleware';
+// 请求成功,失败提示
+// const axiosResponse = response => {
+//   if (response.status === 200) return response.data;
+//   else {
+//     console.log(JSON.stringify(response));
+//     throw new ServiceError('请求失败', FrameworkErrorEnum.SERVICE_FAULT);
+//   }
+// };
+// const axiosError = error => {
+//   return Promise.reject(error);
+// };
+@Configuration({
+  imports: [
+    FreeFrame,
+    validate,
+    jwt,
+    redis,
+    axios,
+    swagger,
+    {
+      component: info,
+      enabledEnvironment: ['local'],
+    },
+  ],
+  importConfigs: [join(__dirname, './config')],
+})
+export class ContainerLifeCycle {
+  @App()
+  app: koa.Application;
+
+  async onReady() {
+    this.app.getMiddleware().insertFirst(CheckTokenMiddleware);
+  }
+}

+ 139 - 0
src/controller/admin.controller.ts

@@ -0,0 +1,139 @@
+import {
+  Body,
+  Controller,
+  Del,
+  Get,
+  Inject,
+  Param,
+  Post,
+  Query,
+  Config,
+} from '@midwayjs/decorator';
+import {
+  BaseController,
+  FrameworkErrorEnum,
+  ServiceError,
+} from 'free-midway-component';
+import { AdminService } from '../service/admin.service';
+import {
+  CDTO_admin,
+  CVO_admin,
+  FVO_admin,
+  QDTO_admin,
+  QVO_admin,
+  UDTO_admin,
+  UVAO_admin,
+  LoginDTO,
+  ResetPasswordDTO,
+  LoginVO,
+} from '../interface/admin.interface';
+import {
+  ApiOperation,
+  ApiQuery,
+  ApiResponse,
+  ApiTags,
+} from '@midwayjs/swagger';
+import { Validate } from '@midwayjs/validate';
+import { JwtService } from '@midwayjs/jwt';
+@ApiTags(['管理员'])
+@Controller('/admin')
+export class AdminController extends BaseController {
+  @Inject()
+  service: AdminService;
+
+  @Inject()
+  jwtService: JwtService;
+
+  @Config('jwt.secret')
+  jwtSecret;
+
+  @Config('jwt.expiresIn')
+  jwtExpiresIn;
+
+  @Post('/login')
+  @Validate()
+  async login(@Body() body: LoginDTO) {
+    const data = await this.service.findUserToLogin(body);
+    let vo = new LoginVO(data);
+    vo = JSON.parse(JSON.stringify(vo));
+    const token = await this.jwtService.sign(vo, this.jwtSecret, {
+      expiresIn: this.jwtExpiresIn,
+    });
+    return token;
+  }
+
+  @Post('/rp')
+  @ApiOperation({ description: '修改密码' })
+  async resetPassword(@Body() body: ResetPasswordDTO) {
+    if (!body._id)
+      throw new ServiceError('未找到用户信息', FrameworkErrorEnum.NOT_LOGIN);
+    // 查询用户
+    const user = await this.service.fetch(body._id);
+    if (!user)
+      throw new ServiceError('未找到用户', FrameworkErrorEnum.NOT_FOUND_DATA);
+    // 修改密码
+    await this.service.updateOne(body._id, { password: body.password });
+    // 返回结果
+    return 'ok';
+  }
+
+  @Post('/')
+  @Validate()
+  @ApiResponse({ type: CVO_admin })
+  async create(@Body() data: CDTO_admin) {
+    const dbData = await this.service.create(data);
+    const result = new CVO_admin(dbData);
+    return result;
+  }
+  @Get('/')
+  @ApiQuery({ name: 'query' })
+  @ApiResponse({ type: QVO_admin })
+  async query(
+    @Query() filter: QDTO_admin,
+    @Query('skip') skip: number,
+    @Query('limit') limit: number
+  ) {
+    const list = await this.service.query(filter, { skip, limit });
+    const data = [];
+    for (const i of list) {
+      const newData = new QVO_admin(i);
+      data.push(newData);
+    }
+    const total = await this.service.count(filter);
+    return { data, total };
+  }
+
+  @Get('/:id')
+  @ApiResponse({ type: FVO_admin })
+  async fetch(@Param('id') id: string) {
+    const data = await this.service.fetch(id);
+    const result = new FVO_admin(data);
+    return result;
+  }
+
+  @Post('/:id')
+  @Validate()
+  @ApiResponse({ type: UVAO_admin })
+  async update(@Param('id') id: string, @Body() body: UDTO_admin) {
+    const result = await this.service.updateOne(id, body);
+    return result;
+  }
+
+  @Del('/:id')
+  @Validate()
+  async delete(@Param('id') id: string) {
+    await this.service.delete(id);
+    return 'ok';
+  }
+  async createMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async updateMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async deleteMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+}

+ 89 - 0
src/controller/application.controller.ts

@@ -0,0 +1,89 @@
+import {
+  Body,
+  Controller,
+  Del,
+  Get,
+  Inject,
+  Param,
+  Post,
+  Query,
+} from '@midwayjs/decorator';
+import { BaseController } from 'free-midway-component';
+import { ApplicationService } from '../service/application.service';
+import {
+  CDTO_application,
+  CVO_application,
+  FVO_application,
+  QDTO_application,
+  QVO_application,
+  UDTO_application,
+  UVAO_application,
+} from '../interface/application.interface';
+import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
+import { Validate } from '@midwayjs/validate';
+@ApiTags(['比赛报名'])
+@Controller('/application')
+export class ApplicationController extends BaseController {
+  @Inject()
+  service: ApplicationService;
+
+  @Post('/')
+  @Validate()
+  @ApiResponse({ type: CVO_application })
+  async create(@Body() data: CDTO_application) {
+    const dbData = await this.service.create(data);
+    const result = new CVO_application(dbData);
+    return result;
+  }
+  @Get('/')
+  @ApiQuery({ name: 'query' })
+  @ApiResponse({ type: QVO_application })
+  async query(
+    @Query() filter: QDTO_application,
+    @Query('skip') skip: number,
+    @Query('limit') limit: number
+  ) {
+    const list = await this.service.query(filter, { skip, limit });
+    const data = [];
+    for (const i of list) {
+      const newData = new QVO_application(i);
+      data.push(newData);
+    }
+    const total = await this.service.count(filter);
+    return { data, total };
+  }
+
+  @Get('/:id')
+  @ApiResponse({ type: FVO_application })
+  async fetch(@Param('id') id: string) {
+    const data = await this.service.fetch(id);
+    const result = new FVO_application(data);
+    return result;
+  }
+
+  @Post('/:id')
+  @Validate()
+  @ApiResponse({ type: UVAO_application })
+  async update(@Param('id') id: string, @Body() body: UDTO_application) {
+    const result = await this.service.updateOne(id, body);
+    return result;
+  }
+
+  @Del('/:id')
+  @Validate()
+  async delete(@Param('id') id: string) {
+    await this.service.delete(id);
+    return 'ok';
+  }
+  async createMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async updateMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async deleteMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+}

+ 89 - 0
src/controller/course.controller.ts

@@ -0,0 +1,89 @@
+import {
+  Body,
+  Controller,
+  Del,
+  Get,
+  Inject,
+  Param,
+  Post,
+  Query,
+} from '@midwayjs/decorator';
+import { BaseController } from 'free-midway-component';
+import { CourseService } from '../service/course.service';
+import {
+  CDTO_course,
+  CVO_course,
+  FVO_course,
+  QDTO_course,
+  QVO_course,
+  UDTO_course,
+  UVAO_course,
+} from '../interface/course.interface';
+import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
+import { Validate } from '@midwayjs/validate';
+@ApiTags(['赛程'])
+@Controller('/course')
+export class CourseController extends BaseController {
+  @Inject()
+  service: CourseService;
+
+  @Post('/')
+  @Validate()
+  @ApiResponse({ type: CVO_course })
+  async create(@Body() data: CDTO_course) {
+    const dbData = await this.service.create(data);
+    const result = new CVO_course(dbData);
+    return result;
+  }
+  @Get('/')
+  @ApiQuery({ name: 'query' })
+  @ApiResponse({ type: QVO_course })
+  async query(
+    @Query() filter: QDTO_course,
+    @Query('skip') skip: number,
+    @Query('limit') limit: number
+  ) {
+    const list = await this.service.query(filter, { skip, limit });
+    const data = [];
+    for (const i of list) {
+      const newData = new QVO_course(i);
+      data.push(newData);
+    }
+    const total = await this.service.count(filter);
+    return { data, total };
+  }
+
+  @Get('/:id')
+  @ApiResponse({ type: FVO_course })
+  async fetch(@Param('id') id: string) {
+    const data = await this.service.fetch(id);
+    const result = new FVO_course(data);
+    return result;
+  }
+
+  @Post('/:id')
+  @Validate()
+  @ApiResponse({ type: UVAO_course })
+  async update(@Param('id') id: string, @Body() body: UDTO_course) {
+    const result = await this.service.updateOne(id, body);
+    return result;
+  }
+
+  @Del('/:id')
+  @Validate()
+  async delete(@Param('id') id: string) {
+    await this.service.delete(id);
+    return 'ok';
+  }
+  async createMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async updateMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async deleteMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+}

+ 89 - 0
src/controller/dictData.controller.ts

@@ -0,0 +1,89 @@
+import {
+  Body,
+  Controller,
+  Del,
+  Get,
+  Inject,
+  Param,
+  Post,
+  Query,
+} from '@midwayjs/decorator';
+import { BaseController } from 'free-midway-component';
+import { DictDataService } from '../service/dictData.service';
+import {
+  CDTO_dictData,
+  CVO_dictData,
+  FVO_dictData,
+  QDTO_dictData,
+  QVO_dictData,
+  UDTO_dictData,
+  UVAO_dictData,
+} from '../interface/dictData.interface';
+import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
+import { Validate } from '@midwayjs/validate';
+@ApiTags(['字典数据'])
+@Controller('/dictData')
+export class DictDataController extends BaseController {
+  @Inject()
+  service: DictDataService;
+
+  @Post('/')
+  @Validate()
+  @ApiResponse({ type: CVO_dictData })
+  async create(@Body() data: CDTO_dictData) {
+    const dbData = await this.service.create(data);
+    const result = new CVO_dictData(dbData);
+    return result;
+  }
+  @Get('/')
+  @ApiQuery({ name: 'query' })
+  @ApiResponse({ type: QVO_dictData })
+  async query(
+    @Query() filter: QDTO_dictData,
+    @Query('skip') skip: number,
+    @Query('limit') limit: number
+  ) {
+    const list = await this.service.query(filter, { skip, limit });
+    const data = [];
+    for (const i of list) {
+      const newData = new QVO_dictData(i);
+      data.push(newData);
+    }
+    const total = await this.service.count(filter);
+    return { data, total };
+  }
+
+  @Get('/:id')
+  @ApiResponse({ type: FVO_dictData })
+  async fetch(@Param('id') id: string) {
+    const data = await this.service.fetch(id);
+    const result = new FVO_dictData(data);
+    return result;
+  }
+
+  @Post('/:id')
+  @Validate()
+  @ApiResponse({ type: UVAO_dictData })
+  async update(@Param('id') id: string, @Body() body: UDTO_dictData) {
+    const result = await this.service.updateOne(id, body);
+    return result;
+  }
+
+  @Del('/:id')
+  @Validate()
+  async delete(@Param('id') id: string) {
+    await this.service.delete(id);
+    return 'ok';
+  }
+  async createMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async updateMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async deleteMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+}

+ 89 - 0
src/controller/dictType.controller.ts

@@ -0,0 +1,89 @@
+import {
+  Body,
+  Controller,
+  Del,
+  Get,
+  Inject,
+  Param,
+  Post,
+  Query,
+} from '@midwayjs/decorator';
+import { BaseController } from 'free-midway-component';
+import { DictTypeService } from '../service/dictType.service';
+import {
+  CDTO_dictType,
+  CVO_dictType,
+  FVO_dictType,
+  QDTO_dictType,
+  QVO_dictType,
+  UDTO_dictType,
+  UVAO_dictType,
+} from '../interface/dictType.interface';
+import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
+import { Validate } from '@midwayjs/validate';
+@ApiTags(['字典类型'])
+@Controller('/dictType')
+export class DictTypeController extends BaseController {
+  @Inject()
+  service: DictTypeService;
+
+  @Post('/')
+  @Validate()
+  @ApiResponse({ type: CVO_dictType })
+  async create(@Body() data: CDTO_dictType) {
+    const dbData = await this.service.create(data);
+    const result = new CVO_dictType(dbData);
+    return result;
+  }
+  @Get('/')
+  @ApiQuery({ name: 'query' })
+  @ApiResponse({ type: QVO_dictType })
+  async query(
+    @Query() filter: QDTO_dictType,
+    @Query('skip') skip: number,
+    @Query('limit') limit: number
+  ) {
+    const list = await this.service.query(filter, { skip, limit });
+    const data = [];
+    for (const i of list) {
+      const newData = new QVO_dictType(i);
+      data.push(newData);
+    }
+    const total = await this.service.count(filter);
+    return { data, total };
+  }
+
+  @Get('/:id')
+  @ApiResponse({ type: FVO_dictType })
+  async fetch(@Param('id') id: string) {
+    const data = await this.service.fetch(id);
+    const result = new FVO_dictType(data);
+    return result;
+  }
+
+  @Post('/:id')
+  @Validate()
+  @ApiResponse({ type: UVAO_dictType })
+  async update(@Param('id') id: string, @Body() body: UDTO_dictType) {
+    const result = await this.service.updateOne(id, body);
+    return result;
+  }
+
+  @Del('/:id')
+  @Validate()
+  async delete(@Param('id') id: string) {
+    await this.service.delete(id);
+    return 'ok';
+  }
+  async createMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async updateMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async deleteMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+}

+ 9 - 0
src/controller/home.controller.ts

@@ -0,0 +1,9 @@
+import { Controller, Get } from '@midwayjs/core';
+
+@Controller('/')
+export class HomeController {
+  @Get('/')
+  async home(): Promise<string> {
+    return 'Hello Midwayjs!';
+  }
+}

+ 89 - 0
src/controller/match.controller.ts

@@ -0,0 +1,89 @@
+import {
+  Body,
+  Controller,
+  Del,
+  Get,
+  Inject,
+  Param,
+  Post,
+  Query,
+} from '@midwayjs/decorator';
+import { BaseController } from 'free-midway-component';
+import { MatchService } from '../service/match.service';
+import {
+  CDTO_match,
+  CVO_match,
+  FVO_match,
+  QDTO_match,
+  QVO_match,
+  UDTO_match,
+  UVAO_match,
+} from '../interface/match.interface';
+import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
+import { Validate } from '@midwayjs/validate';
+@ApiTags(['比赛表'])
+@Controller('/match')
+export class MatchController extends BaseController {
+  @Inject()
+  service: MatchService;
+
+  @Post('/')
+  @Validate()
+  @ApiResponse({ type: CVO_match })
+  async create(@Body() data: CDTO_match) {
+    const dbData = await this.service.create(data);
+    const result = new CVO_match(dbData);
+    return result;
+  }
+  @Get('/')
+  @ApiQuery({ name: 'query' })
+  @ApiResponse({ type: QVO_match })
+  async query(
+    @Query() filter: QDTO_match,
+    @Query('skip') skip: number,
+    @Query('limit') limit: number
+  ) {
+    const list = await this.service.query(filter, { skip, limit });
+    const data = [];
+    for (const i of list) {
+      const newData = new QVO_match(i);
+      data.push(newData);
+    }
+    const total = await this.service.count(filter);
+    return { data, total };
+  }
+
+  @Get('/:id')
+  @ApiResponse({ type: FVO_match })
+  async fetch(@Param('id') id: string) {
+    const data = await this.service.fetch(id);
+    const result = new FVO_match(data);
+    return result;
+  }
+
+  @Post('/:id')
+  @Validate()
+  @ApiResponse({ type: UVAO_match })
+  async update(@Param('id') id: string, @Body() body: UDTO_match) {
+    const result = await this.service.updateOne(id, body);
+    return result;
+  }
+
+  @Del('/:id')
+  @Validate()
+  async delete(@Param('id') id: string) {
+    await this.service.delete(id);
+    return 'ok';
+  }
+  async createMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async updateMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async deleteMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+}

+ 89 - 0
src/controller/team.controller.ts

@@ -0,0 +1,89 @@
+import {
+  Body,
+  Controller,
+  Del,
+  Get,
+  Inject,
+  Param,
+  Post,
+  Query,
+} from '@midwayjs/decorator';
+import { BaseController } from 'free-midway-component';
+import { TeamService } from '../service/team.service';
+import {
+  CDTO_team,
+  CVO_team,
+  FVO_team,
+  QDTO_team,
+  QVO_team,
+  UDTO_team,
+  UVAO_team,
+} from '../interface/team.interface';
+import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
+import { Validate } from '@midwayjs/validate';
+@ApiTags(['团队'])
+@Controller('/team')
+export class TeamController extends BaseController {
+  @Inject()
+  service: TeamService;
+
+  @Post('/')
+  @Validate()
+  @ApiResponse({ type: CVO_team })
+  async create(@Body() data: CDTO_team) {
+    const dbData = await this.service.create(data);
+    const result = new CVO_team(dbData);
+    return result;
+  }
+  @Get('/')
+  @ApiQuery({ name: 'query' })
+  @ApiResponse({ type: QVO_team })
+  async query(
+    @Query() filter: QDTO_team,
+    @Query('skip') skip: number,
+    @Query('limit') limit: number
+  ) {
+    const list = await this.service.query(filter, { skip, limit });
+    const data = [];
+    for (const i of list) {
+      const newData = new QVO_team(i);
+      data.push(newData);
+    }
+    const total = await this.service.count(filter);
+    return { data, total };
+  }
+
+  @Get('/:id')
+  @ApiResponse({ type: FVO_team })
+  async fetch(@Param('id') id: string) {
+    const data = await this.service.fetch(id);
+    const result = new FVO_team(data);
+    return result;
+  }
+
+  @Post('/:id')
+  @Validate()
+  @ApiResponse({ type: UVAO_team })
+  async update(@Param('id') id: string, @Body() body: UDTO_team) {
+    const result = await this.service.updateOne(id, body);
+    return result;
+  }
+
+  @Del('/:id')
+  @Validate()
+  async delete(@Param('id') id: string) {
+    await this.service.delete(id);
+    return 'ok';
+  }
+  async createMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async updateMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async deleteMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+}

+ 89 - 0
src/controller/teamApply.controller.ts

@@ -0,0 +1,89 @@
+import {
+  Body,
+  Controller,
+  Del,
+  Get,
+  Inject,
+  Param,
+  Post,
+  Query,
+} from '@midwayjs/decorator';
+import { BaseController } from 'free-midway-component';
+import { TeamApplyService } from '../service/teamApply.service';
+import {
+  CDTO_teamApply,
+  CVO_teamApply,
+  FVO_teamApply,
+  QDTO_teamApply,
+  QVO_teamApply,
+  UDTO_teamApply,
+  UVAO_teamApply,
+} from '../interface/teamApply.interface';
+import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
+import { Validate } from '@midwayjs/validate';
+@ApiTags(['团队申请'])
+@Controller('/teamApply')
+export class TeamApplyController extends BaseController {
+  @Inject()
+  service: TeamApplyService;
+
+  @Post('/')
+  @Validate()
+  @ApiResponse({ type: CVO_teamApply })
+  async create(@Body() data: CDTO_teamApply) {
+    const dbData = await this.service.create(data);
+    const result = new CVO_teamApply(dbData);
+    return result;
+  }
+  @Get('/')
+  @ApiQuery({ name: 'query' })
+  @ApiResponse({ type: QVO_teamApply })
+  async query(
+    @Query() filter: QDTO_teamApply,
+    @Query('skip') skip: number,
+    @Query('limit') limit: number
+  ) {
+    const list = await this.service.query(filter, { skip, limit });
+    const data = [];
+    for (const i of list) {
+      const newData = new QVO_teamApply(i);
+      data.push(newData);
+    }
+    const total = await this.service.count(filter);
+    return { data, total };
+  }
+
+  @Get('/:id')
+  @ApiResponse({ type: FVO_teamApply })
+  async fetch(@Param('id') id: string) {
+    const data = await this.service.fetch(id);
+    const result = new FVO_teamApply(data);
+    return result;
+  }
+
+  @Post('/:id')
+  @Validate()
+  @ApiResponse({ type: UVAO_teamApply })
+  async update(@Param('id') id: string, @Body() body: UDTO_teamApply) {
+    const result = await this.service.updateOne(id, body);
+    return result;
+  }
+
+  @Del('/:id')
+  @Validate()
+  async delete(@Param('id') id: string) {
+    await this.service.delete(id);
+    return 'ok';
+  }
+  async createMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async updateMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async deleteMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+}

+ 24 - 0
src/controller/token.controller.ts

@@ -0,0 +1,24 @@
+import { Controller, Get, Inject } from '@midwayjs/decorator';
+import { Context } from '@midwayjs/koa';
+import { ApiResponse, ApiTags } from '@midwayjs/swagger';
+const assert = require('assert');
+import { JwtService } from '@midwayjs/jwt';
+import get = require('lodash/get');
+@ApiTags(['解析token'])
+@Controller('/token')
+export class TokenController {
+  @Inject()
+  jwtService: JwtService;
+
+  @Inject()
+  ctx: Context;
+
+  @Get('/tokenView')
+  @ApiResponse({})
+  async tokenView() {
+    const token = get(this.ctx, 'request.header.token');
+    assert(token, '缺少token信息');
+    const result: any = await this.jwtService.decode(token);
+    return result;
+  }
+}

+ 139 - 0
src/controller/user.controller.ts

@@ -0,0 +1,139 @@
+import {
+  Body,
+  Controller,
+  Del,
+  Get,
+  Inject,
+  Param,
+  Post,
+  Query,
+  Config,
+} from '@midwayjs/decorator';
+import {
+  BaseController,
+  FrameworkErrorEnum,
+  ServiceError,
+} from 'free-midway-component';
+import { UserService } from '../service/user.service';
+import {
+  CDTO_user,
+  CVO_user,
+  FVO_user,
+  QDTO_user,
+  QVO_user,
+  UDTO_user,
+  UVAO_user,
+  LoginDTO,
+  ResetPasswordDTO,
+  LoginVO,
+} from '../interface/user.interface';
+import {
+  ApiOperation,
+  ApiQuery,
+  ApiResponse,
+  ApiTags,
+} from '@midwayjs/swagger';
+import { Validate } from '@midwayjs/validate';
+import { JwtService } from '@midwayjs/jwt';
+@ApiTags(['用户'])
+@Controller('/user')
+export class UserController extends BaseController {
+  @Inject()
+  service: UserService;
+
+  @Inject()
+  jwtService: JwtService;
+
+  @Config('jwt.secret')
+  jwtSecret;
+
+  @Config('jwt.expiresIn')
+  jwtExpiresIn;
+
+  @Post('/login')
+  @Validate()
+  async login(@Body() body: LoginDTO) {
+    const data = await this.service.findUserToLogin(body);
+    let vo = new LoginVO(data);
+    vo = JSON.parse(JSON.stringify(vo));
+    const token = await this.jwtService.sign(vo, this.jwtSecret, {
+      expiresIn: this.jwtExpiresIn,
+    });
+    return token;
+  }
+
+  @Post('/rp')
+  @ApiOperation({ description: '修改密码' })
+  async resetPassword(@Body() body: ResetPasswordDTO) {
+    if (!body._id)
+      throw new ServiceError('未找到用户信息', FrameworkErrorEnum.NOT_LOGIN);
+    // 查询用户
+    const user = await this.service.fetch(body._id);
+    if (!user)
+      throw new ServiceError('未找到用户', FrameworkErrorEnum.NOT_FOUND_DATA);
+    // 修改密码
+    await this.service.updateOne(body._id, { password: body.password });
+    // 返回结果
+    return 'ok';
+  }
+
+  @Post('/')
+  @Validate()
+  @ApiResponse({ type: CVO_user })
+  async create(@Body() data: CDTO_user) {
+    const dbData = await this.service.create(data);
+    const result = new CVO_user(dbData);
+    return result;
+  }
+  @Get('/')
+  @ApiQuery({ name: 'query' })
+  @ApiResponse({ type: QVO_user })
+  async query(
+    @Query() filter: QDTO_user,
+    @Query('skip') skip: number,
+    @Query('limit') limit: number
+  ) {
+    const list = await this.service.query(filter, { skip, limit });
+    const data = [];
+    for (const i of list) {
+      const newData = new QVO_user(i);
+      data.push(newData);
+    }
+    const total = await this.service.count(filter);
+    return { data, total };
+  }
+
+  @Get('/:id')
+  @ApiResponse({ type: FVO_user })
+  async fetch(@Param('id') id: string) {
+    const data = await this.service.fetch(id);
+    const result = new FVO_user(data);
+    return result;
+  }
+
+  @Post('/:id')
+  @Validate()
+  @ApiResponse({ type: UVAO_user })
+  async update(@Param('id') id: string, @Body() body: UDTO_user) {
+    const result = await this.service.updateOne(id, body);
+    return result;
+  }
+
+  @Del('/:id')
+  @Validate()
+  async delete(@Param('id') id: string) {
+    await this.service.delete(id);
+    return 'ok';
+  }
+  async createMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async updateMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async deleteMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+}

+ 27 - 0
src/entity/admin.entity.ts

@@ -0,0 +1,27 @@
+import { modelOptions, prop } from '@typegoose/typegoose';
+import { BaseModel } from 'free-midway-component';
+import isString = require('lodash/isString');
+@modelOptions({
+  schemaOptions: { collection: 'admin' },
+})
+export class Admin extends BaseModel {
+  @prop({ required: false, index: true, zh: '账号' })
+  account: string;
+  @prop({
+    required: false,
+    index: false,
+    zh: '密码',
+    select: false,
+    set: (val: string | object) => {
+      if (isString(val)) {
+        return { secret: val };
+      }
+      return val;
+    },
+  })
+  password: {
+    secret: string;
+  };
+  @prop({ required: false, index: true, zh: '名称' })
+  name: string;
+}

+ 31 - 0
src/entity/application.entity.ts

@@ -0,0 +1,31 @@
+import { modelOptions, prop } from '@typegoose/typegoose';
+import { BaseModel } from 'free-midway-component';
+@modelOptions({
+  schemaOptions: { collection: 'application' },
+})
+export class Application extends BaseModel {
+  @prop({ required: false, index: true, zh: '报名的比赛id' })
+  match_id: string;
+  @prop({ required: false, index: true, zh: '报名比赛名称' })
+  match_name: string;
+  @prop({ required: false, index: true, zh: '团队id' })
+  team_id: string;
+  @prop({ required: false, index: true, zh: '团队名称' })
+  team_name: string;
+  @prop({ required: false, index: true, zh: '参赛人数' })
+  num: string;
+  @prop({ required: false, index: true, zh: '比赛成员id' })
+  user_id: Array<any>;
+  @prop({ required: false, index: false, zh: '报名时间' })
+  apply_time: string;
+  @prop({ required: false, index: true, zh: '分数' })
+  score: string;
+  @prop({
+    required: false,
+    index: true,
+    zh: '状态',
+    remark: '字典表:status',
+    default: '0',
+  })
+  status: string;
+}

+ 39 - 0
src/entity/course.entity.ts

@@ -0,0 +1,39 @@
+import { modelOptions, prop } from '@typegoose/typegoose';
+import { BaseModel } from 'free-midway-component';
+@modelOptions({
+  schemaOptions: { collection: 'course' },
+})
+export class Course extends BaseModel {
+  @prop({ required: false, index: true, zh: '比赛id' })
+  match_id: string;
+  @prop({ required: false, index: false, zh: '比赛名称' })
+  match_name: string;
+  @prop({ required: false, index: true, zh: '红方团队id' })
+  red_team_id: string;
+  @prop({ required: false, index: true, zh: '红方团队名称' })
+  red_team_name: string;
+  @prop({ required: false, index: true, zh: '红方' })
+  red_person: Array<any>;
+  @prop({ required: false, index: true, zh: '红方分数' })
+  red_score: string;
+  @prop({ required: false, index: true, zh: '蓝方团队id' })
+  blue_team_id: string;
+  @prop({ required: false, index: true, zh: '蓝方团队名称' })
+  blue_team_name: string;
+  @prop({ required: false, index: true, zh: '蓝方' })
+  blue_person: Array<any>;
+  @prop({ required: false, index: true, zh: '蓝方分数' })
+  blue_score: string;
+  @prop({ required: false, index: false, zh: '比赛时间' })
+  match_time: string;
+  @prop({ required: false, index: false, zh: '胜者' })
+  winner: string;
+  @prop({
+    required: false,
+    index: true,
+    zh: '状态',
+    remark: '字典表:match_status',
+    default: '0',
+  })
+  status: string;
+}

+ 25 - 0
src/entity/dictData.entity.ts

@@ -0,0 +1,25 @@
+import { modelOptions, prop } from '@typegoose/typegoose';
+import { BaseModel } from 'free-midway-component';
+@modelOptions({
+  schemaOptions: { collection: 'dictData' },
+})
+export class DictData extends BaseModel {
+  @prop({ required: false, index: true, zh: '类型' })
+  type: string;
+  @prop({ required: false, index: true, zh: '标签' })
+  label: string;
+  @prop({ required: false, index: true, zh: '键值' })
+  value: string;
+  @prop({ required: false, index: true, zh: '排序' })
+  sort: number;
+  @prop({
+    required: false,
+    index: true,
+    zh: '是否使用',
+    remark: '字典表:is_use',
+    default: '0',
+  })
+  is_use: string;
+  @prop({ required: false, index: false, zh: '字数据' })
+  children: Array<any>;
+}

+ 21 - 0
src/entity/dictType.entity.ts

@@ -0,0 +1,21 @@
+import { modelOptions, prop } from '@typegoose/typegoose';
+import { BaseModel } from 'free-midway-component';
+@modelOptions({
+  schemaOptions: { collection: 'dictType' },
+})
+export class DictType extends BaseModel {
+  @prop({ required: false, index: true, zh: '名称' })
+  title: string;
+  @prop({ required: false, index: true, zh: '类型' })
+  type: string;
+  @prop({ required: false, index: false, zh: '备注' })
+  remark: string;
+  @prop({
+    required: false,
+    index: true,
+    zh: '是否使用',
+    remark: '字典表:is_use',
+    default: '0',
+  })
+  is_use: string;
+}

+ 27 - 0
src/entity/match.entity.ts

@@ -0,0 +1,27 @@
+import { modelOptions, prop } from '@typegoose/typegoose';
+import { BaseModel } from 'free-midway-component';
+@modelOptions({
+  schemaOptions: { collection: 'match' },
+})
+export class Match extends BaseModel {
+  @prop({ required: false, index: true, zh: '比赛名称' })
+  name: string;
+  @prop({ required: false, index: true, zh: '开始时间' })
+  start_time: string;
+  @prop({ required: false, index: true, zh: '结束时间' })
+  end_time: string;
+  @prop({ required: false, index: false, zh: '比赛地点' })
+  address: string;
+  @prop({
+    required: false,
+    index: true,
+    zh: '状态',
+    remark: '字典表:match_status',
+    default: '0',
+  })
+  status: string;
+  @prop({ required: false, index: false, zh: '报名截止时间' })
+  sign_deadline: string;
+  @prop({ required: false, index: false, zh: '比赛信息' })
+  information: string;
+}

+ 31 - 0
src/entity/team.entity.ts

@@ -0,0 +1,31 @@
+import { modelOptions, prop } from '@typegoose/typegoose';
+import { BaseModel } from 'free-midway-component';
+@modelOptions({
+  schemaOptions: { collection: 'team' },
+})
+export class Team extends BaseModel {
+  @prop({ required: false, index: true, zh: '所属管理员' })
+  administrator: string;
+  @prop({ required: false, index: true, zh: '团队名称' })
+  name: string;
+  @prop({ required: false, index: true, zh: '成立时间' })
+  create_time: string;
+  @prop({ required: false, index: false, zh: '单位地址' })
+  address: string;
+  @prop({ required: false, index: true, zh: '手机号' })
+  phone: string;
+  @prop({ required: false, index: false, zh: '团队logo' })
+  logo: string;
+  @prop({ required: false, index: true, zh: '团队人数' })
+  number: string;
+  @prop({ required: false, index: false, zh: '团队成员' })
+  member: Array<any>;
+  @prop({
+    required: false,
+    index: true,
+    zh: '状态',
+    remark: '字典表:status',
+    default: '0',
+  })
+  status: string;
+}

+ 25 - 0
src/entity/teamApply.entity.ts

@@ -0,0 +1,25 @@
+import { modelOptions, prop } from '@typegoose/typegoose';
+import { BaseModel } from 'free-midway-component';
+@modelOptions({
+  schemaOptions: { collection: 'teamApply' },
+})
+export class TeamApply extends BaseModel {
+  @prop({ required: false, index: true, zh: '团队id' })
+  team_id: string;
+  @prop({ required: false, index: true, zh: '团队名称' })
+  team_name: string;
+  @prop({ required: false, index: true, zh: '申请人id' })
+  apply_id: string;
+  @prop({ required: false, index: true, zh: '申请人名称' })
+  apply_name: string;
+  @prop({ required: false, index: false, zh: '申请时间' })
+  apply_time: string;
+  @prop({
+    required: false,
+    index: true,
+    zh: '状态',
+    remark: '字典表:status',
+    default: '0',
+  })
+  status: string;
+}

+ 56 - 0
src/entity/user.entity.ts

@@ -0,0 +1,56 @@
+import { modelOptions, prop } from '@typegoose/typegoose';
+import { BaseModel } from 'free-midway-component';
+import isString = require('lodash/isString');
+@modelOptions({
+  schemaOptions: { collection: 'user' },
+})
+export class User extends BaseModel {
+  @prop({ required: false, index: true, zh: 'openid' })
+  openid: string;
+  @prop({
+    required: false,
+    index: true,
+    zh: '类别',
+    remark: '字典表:type用户类别:0:比赛人员,1:团队管理人员用户',
+  })
+  type: string;
+  @prop({ required: false, index: true, zh: '名称' })
+  name: string;
+  @prop({ required: false, index: true, zh: '账号' })
+  account: string;
+  @prop({
+    required: false,
+    index: false,
+    zh: '密码',
+    select: false,
+    set: (val: string | object) => {
+      if (isString(val)) {
+        return { secret: val };
+      }
+      return val;
+    },
+  })
+  password: {
+    secret: string;
+  };
+  @prop({ required: false, index: true, zh: '手机号' })
+  phone: string;
+  @prop({ required: false, index: false, zh: '邮箱' })
+  email: string;
+  @prop({ required: false, index: false, zh: '性别', remark: '字典表:gender' })
+  gender: string;
+  @prop({ required: false, index: false, zh: '头像' })
+  icon: Array<any>;
+  @prop({ required: false, index: true, zh: '年龄' })
+  age: string;
+  @prop({
+    required: false,
+    index: true,
+    zh: '状态',
+    remark: '字典表:status',
+    default: '0',
+  })
+  status: string;
+  @prop({ required: false, index: false, zh: '工作单位' })
+  work: string;
+}

+ 13 - 0
src/filter/default.filter.ts

@@ -0,0 +1,13 @@
+import { Catch } from '@midwayjs/core';
+import { Context } from '@midwayjs/koa';
+
+@Catch()
+export class DefaultErrorFilter {
+  async catch(err: Error, ctx: Context) {
+    // 所有的未分类错误会到这里
+    return {
+      success: false,
+      message: err.message,
+    };
+  }
+}

+ 10 - 0
src/filter/notfound.filter.ts

@@ -0,0 +1,10 @@
+import { Catch, httpError, MidwayHttpError } from '@midwayjs/core';
+import { Context } from '@midwayjs/koa';
+
+@Catch(httpError.NotFoundError)
+export class NotFoundFilter {
+  async catch(err: MidwayHttpError, ctx: Context) {
+    // 404 错误会到这里
+    ctx.redirect('/404.html');
+  }
+}

+ 6 - 0
src/interface.ts

@@ -0,0 +1,6 @@
+/**
+ * @description User-Service parameters
+ */
+export interface IUserOptions {
+  uid: number;
+}

+ 106 - 0
src/interface/admin.interface.ts

@@ -0,0 +1,106 @@
+import { Rule, RuleType } from '@midwayjs/validate';
+import { ApiProperty } from '@midwayjs/swagger';
+import { SearchBase } from 'free-midway-component';
+import get = require('lodash/get');
+const dealVO = (cla, data) => {
+  for (const key in cla) {
+    const val = get(data, key);
+    if (val || val === 0) cla[key] = val;
+  }
+};
+export class FVO_admin {
+  constructor(data: object) {
+    dealVO(this, data);
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: '账号' })
+  'account': string = undefined;
+  @ApiProperty({ description: '密码' })
+  'password': string = undefined;
+  @ApiProperty({ description: '名称' })
+  'name': string = undefined;
+}
+
+export class QDTO_admin extends SearchBase {
+  constructor() {
+    const like_prop = [];
+    const props = ['account', 'name'];
+    const mapping = [];
+    super({ like_prop, props, mapping });
+  }
+  @ApiProperty({ description: '账号' })
+  'account': string = undefined;
+  @ApiProperty({ description: '名称' })
+  'name': string = undefined;
+}
+
+export class QVO_admin extends FVO_admin {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class CDTO_admin {
+  @ApiProperty({ description: '账号' })
+  @Rule(RuleType['string']().empty(''))
+  'account': string = undefined;
+  @ApiProperty({ description: '密码' })
+  @Rule(RuleType['string']().empty(''))
+  'password': string = undefined;
+  @ApiProperty({ description: '名称' })
+  @Rule(RuleType['string']().empty(''))
+  'name': string = undefined;
+}
+
+export class CVO_admin extends FVO_admin {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class UDTO_admin extends CDTO_admin {
+  @ApiProperty({ description: '数据id' })
+  @Rule(RuleType['string']().empty(''))
+  _id: string = undefined;
+}
+
+export class UVAO_admin extends FVO_admin {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+export class LoginVO {
+  constructor(data: object) {
+    for (const key of Object.keys(this)) {
+      this[key] = get(data, key);
+    }
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: '名称' })
+  'name': string = undefined;
+  @ApiProperty({ description: '账号' })
+  'account': string = undefined;
+}
+
+export class LoginDTO {
+  @ApiProperty({ description: '账号', example: 'test' })
+  @Rule(RuleType['string']().empty(''))
+  'account': string = undefined;
+  @ApiProperty({ description: '密码', example: '111111' })
+  @Rule(RuleType['string']().empty(''))
+  'password': string = undefined;
+}
+
+export class ResetPasswordDTO {
+  @ApiProperty({ description: '用户id', example: '' })
+  @Rule(RuleType['string']().required())
+  '_id': string = undefined;
+  @ApiProperty({ description: '密码', example: '123456' })
+  @Rule(RuleType['string']().required())
+  'password': string = undefined;
+}

+ 126 - 0
src/interface/application.interface.ts

@@ -0,0 +1,126 @@
+import { Rule, RuleType } from '@midwayjs/validate';
+import { ApiProperty } from '@midwayjs/swagger';
+import { SearchBase } from 'free-midway-component';
+import get = require('lodash/get');
+const dealVO = (cla, data) => {
+  for (const key in cla) {
+    const val = get(data, key);
+    if (val || val === 0) cla[key] = val;
+  }
+};
+export class FVO_application {
+  constructor(data: object) {
+    dealVO(this, data);
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: '报名的比赛id' })
+  'match_id': string = undefined;
+  @ApiProperty({ description: '报名比赛名称' })
+  'match_name': string = undefined;
+  @ApiProperty({ description: '团队id' })
+  'team_id': string = undefined;
+  @ApiProperty({ description: '团队名称' })
+  'team_name': string = undefined;
+  @ApiProperty({ description: '参赛人数' })
+  'num': string = undefined;
+  @ApiProperty({ description: '比赛成员id' })
+  'user_id': Array<any> = undefined;
+  @ApiProperty({ description: '报名时间' })
+  'apply_time': string = undefined;
+  @ApiProperty({ description: '分数' })
+  'score': string = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+}
+
+export class QDTO_application extends SearchBase {
+  constructor() {
+    const like_prop = [];
+    const props = [
+      'match_id',
+      'match_name',
+      'team_id',
+      'team_name',
+      'num',
+      'user_id',
+      'score',
+      'status',
+    ];
+    const mapping = [];
+    super({ like_prop, props, mapping });
+  }
+  @ApiProperty({ description: '报名的比赛id' })
+  'match_id': string = undefined;
+  @ApiProperty({ description: '报名比赛名称' })
+  'match_name': string = undefined;
+  @ApiProperty({ description: '团队id' })
+  'team_id': string = undefined;
+  @ApiProperty({ description: '团队名称' })
+  'team_name': string = undefined;
+  @ApiProperty({ description: '参赛人数' })
+  'num': string = undefined;
+  @ApiProperty({ description: '比赛成员id' })
+  'user_id': Array<any> = undefined;
+  @ApiProperty({ description: '分数' })
+  'score': string = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+}
+
+export class QVO_application extends FVO_application {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class CDTO_application {
+  @ApiProperty({ description: '报名的比赛id' })
+  @Rule(RuleType['string']().empty(''))
+  'match_id': string = undefined;
+  @ApiProperty({ description: '报名比赛名称' })
+  @Rule(RuleType['string']().empty(''))
+  'match_name': string = undefined;
+  @ApiProperty({ description: '团队id' })
+  @Rule(RuleType['string']().empty(''))
+  'team_id': string = undefined;
+  @ApiProperty({ description: '团队名称' })
+  @Rule(RuleType['string']().empty(''))
+  'team_name': string = undefined;
+  @ApiProperty({ description: '参赛人数' })
+  @Rule(RuleType['string']().empty(''))
+  'num': string = undefined;
+  @ApiProperty({ description: '比赛成员id' })
+  @Rule(RuleType['array']().empty(''))
+  'user_id': Array<any> = undefined;
+  @ApiProperty({ description: '报名时间' })
+  @Rule(RuleType['string']().empty(''))
+  'apply_time': string = undefined;
+  @ApiProperty({ description: '分数' })
+  @Rule(RuleType['string']().empty(''))
+  'score': string = undefined;
+  @ApiProperty({ description: '状态' })
+  @Rule(RuleType['string']().empty(''))
+  'status': string = undefined;
+}
+
+export class CVO_application extends FVO_application {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class UDTO_application extends CDTO_application {
+  @ApiProperty({ description: '数据id' })
+  @Rule(RuleType['string']().empty(''))
+  _id: string = undefined;
+}
+
+export class UVAO_application extends FVO_application {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}

+ 152 - 0
src/interface/course.interface.ts

@@ -0,0 +1,152 @@
+import { Rule, RuleType } from '@midwayjs/validate';
+import { ApiProperty } from '@midwayjs/swagger';
+import { SearchBase } from 'free-midway-component';
+import get = require('lodash/get');
+const dealVO = (cla, data) => {
+  for (const key in cla) {
+    const val = get(data, key);
+    if (val || val === 0) cla[key] = val;
+  }
+};
+export class FVO_course {
+  constructor(data: object) {
+    dealVO(this, data);
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: '比赛id' })
+  'match_id': string = undefined;
+  @ApiProperty({ description: '比赛名称' })
+  'match_name': string = undefined;
+  @ApiProperty({ description: '红方团队id' })
+  'red_team_id': string = undefined;
+  @ApiProperty({ description: '红方团队名称' })
+  'red_team_name': string = undefined;
+  @ApiProperty({ description: '红方' })
+  'red_person': Array<any> = undefined;
+  @ApiProperty({ description: '红方分数' })
+  'red_score': string = undefined;
+  @ApiProperty({ description: '蓝方团队id' })
+  'blue_team_id': string = undefined;
+  @ApiProperty({ description: '蓝方团队名称' })
+  'blue_team_name': string = undefined;
+  @ApiProperty({ description: '蓝方' })
+  'blue_person': Array<any> = undefined;
+  @ApiProperty({ description: '蓝方分数' })
+  'blue_score': string = undefined;
+  @ApiProperty({ description: '比赛时间' })
+  'match_time': string = undefined;
+  @ApiProperty({ description: '胜者' })
+  'winner': string = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+}
+
+export class QDTO_course extends SearchBase {
+  constructor() {
+    const like_prop = [];
+    const props = [
+      'match_id',
+      'red_team_id',
+      'red_team_name',
+      'red_person',
+      'red_score',
+      'blue_team_id',
+      'blue_team_name',
+      'blue_person',
+      'blue_score',
+      'status',
+    ];
+    const mapping = [];
+    super({ like_prop, props, mapping });
+  }
+  @ApiProperty({ description: '比赛id' })
+  'match_id': string = undefined;
+  @ApiProperty({ description: '红方团队id' })
+  'red_team_id': string = undefined;
+  @ApiProperty({ description: '红方团队名称' })
+  'red_team_name': string = undefined;
+  @ApiProperty({ description: '红方' })
+  'red_person': Array<any> = undefined;
+  @ApiProperty({ description: '红方分数' })
+  'red_score': string = undefined;
+  @ApiProperty({ description: '蓝方团队id' })
+  'blue_team_id': string = undefined;
+  @ApiProperty({ description: '蓝方团队名称' })
+  'blue_team_name': string = undefined;
+  @ApiProperty({ description: '蓝方' })
+  'blue_person': Array<any> = undefined;
+  @ApiProperty({ description: '蓝方分数' })
+  'blue_score': string = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+}
+
+export class QVO_course extends FVO_course {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class CDTO_course {
+  @ApiProperty({ description: '比赛id' })
+  @Rule(RuleType['string']().empty(''))
+  'match_id': string = undefined;
+  @ApiProperty({ description: '比赛名称' })
+  @Rule(RuleType['string']().empty(''))
+  'match_name': string = undefined;
+  @ApiProperty({ description: '红方团队id' })
+  @Rule(RuleType['string']().empty(''))
+  'red_team_id': string = undefined;
+  @ApiProperty({ description: '红方团队名称' })
+  @Rule(RuleType['string']().empty(''))
+  'red_team_name': string = undefined;
+  @ApiProperty({ description: '红方' })
+  @Rule(RuleType['array']().empty(''))
+  'red_person': Array<any> = undefined;
+  @ApiProperty({ description: '红方分数' })
+  @Rule(RuleType['string']().empty(''))
+  'red_score': string = undefined;
+  @ApiProperty({ description: '蓝方团队id' })
+  @Rule(RuleType['string']().empty(''))
+  'blue_team_id': string = undefined;
+  @ApiProperty({ description: '蓝方团队名称' })
+  @Rule(RuleType['string']().empty(''))
+  'blue_team_name': string = undefined;
+  @ApiProperty({ description: '蓝方' })
+  @Rule(RuleType['array']().empty(''))
+  'blue_person': Array<any> = undefined;
+  @ApiProperty({ description: '蓝方分数' })
+  @Rule(RuleType['string']().empty(''))
+  'blue_score': string = undefined;
+  @ApiProperty({ description: '比赛时间' })
+  @Rule(RuleType['string']().empty(''))
+  'match_time': string = undefined;
+  @ApiProperty({ description: '胜者' })
+  @Rule(RuleType['string']().empty(''))
+  'winner': string = undefined;
+  @ApiProperty({ description: '状态' })
+  @Rule(RuleType['string']().empty(''))
+  'status': string = undefined;
+}
+
+export class CVO_course extends FVO_course {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class UDTO_course extends CDTO_course {
+  @ApiProperty({ description: '数据id' })
+  @Rule(RuleType['string']().empty(''))
+  _id: string = undefined;
+}
+
+export class UVAO_course extends FVO_course {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}

+ 96 - 0
src/interface/dictData.interface.ts

@@ -0,0 +1,96 @@
+import { Rule, RuleType } from '@midwayjs/validate';
+import { ApiProperty } from '@midwayjs/swagger';
+import { SearchBase } from 'free-midway-component';
+import get = require('lodash/get');
+const dealVO = (cla, data) => {
+  for (const key in cla) {
+    const val = get(data, key);
+    if (val || val === 0) cla[key] = val;
+  }
+};
+export class FVO_dictData {
+  constructor(data: object) {
+    dealVO(this, data);
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: '类型' })
+  'type': string = undefined;
+  @ApiProperty({ description: '标签' })
+  'label': string = undefined;
+  @ApiProperty({ description: '键值' })
+  'value': string = undefined;
+  @ApiProperty({ description: '排序' })
+  'sort': number = undefined;
+  @ApiProperty({ description: '是否使用' })
+  'is_use': string = undefined;
+  @ApiProperty({ description: '字数据' })
+  'children': Array<any> = undefined;
+}
+
+export class QDTO_dictData extends SearchBase {
+  constructor() {
+    const like_prop = [];
+    const props = ['type', 'label', 'value', 'sort', 'is_use'];
+    const mapping = [];
+    super({ like_prop, props, mapping });
+  }
+  @ApiProperty({ description: '类型' })
+  'type': string = undefined;
+  @ApiProperty({ description: '标签' })
+  'label': string = undefined;
+  @ApiProperty({ description: '键值' })
+  'value': string = undefined;
+  @ApiProperty({ description: '排序' })
+  'sort': number = undefined;
+  @ApiProperty({ description: '是否使用' })
+  'is_use': string = undefined;
+}
+
+export class QVO_dictData extends FVO_dictData {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class CDTO_dictData {
+  @ApiProperty({ description: '类型' })
+  @Rule(RuleType['string']().empty(''))
+  'type': string = undefined;
+  @ApiProperty({ description: '标签' })
+  @Rule(RuleType['string']().empty(''))
+  'label': string = undefined;
+  @ApiProperty({ description: '键值' })
+  @Rule(RuleType['string']().empty(''))
+  'value': string = undefined;
+  @ApiProperty({ description: '排序' })
+  @Rule(RuleType['number']().empty(''))
+  'sort': number = undefined;
+  @ApiProperty({ description: '是否使用' })
+  @Rule(RuleType['string']().empty(''))
+  'is_use': string = undefined;
+  @ApiProperty({ description: '字数据' })
+  @Rule(RuleType['array']().empty(''))
+  'children': Array<any> = undefined;
+}
+
+export class CVO_dictData extends FVO_dictData {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class UDTO_dictData extends CDTO_dictData {
+  @ApiProperty({ description: '数据id' })
+  @Rule(RuleType['string']().empty(''))
+  _id: string = undefined;
+}
+
+export class UVAO_dictData extends FVO_dictData {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}

+ 82 - 0
src/interface/dictType.interface.ts

@@ -0,0 +1,82 @@
+import { Rule, RuleType } from '@midwayjs/validate';
+import { ApiProperty } from '@midwayjs/swagger';
+import { SearchBase } from 'free-midway-component';
+import get = require('lodash/get');
+const dealVO = (cla, data) => {
+  for (const key in cla) {
+    const val = get(data, key);
+    if (val || val === 0) cla[key] = val;
+  }
+};
+export class FVO_dictType {
+  constructor(data: object) {
+    dealVO(this, data);
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: '名称' })
+  'title': string = undefined;
+  @ApiProperty({ description: '类型' })
+  'type': string = undefined;
+  @ApiProperty({ description: '备注' })
+  'remark': string = undefined;
+  @ApiProperty({ description: '是否使用' })
+  'is_use': string = undefined;
+}
+
+export class QDTO_dictType extends SearchBase {
+  constructor() {
+    const like_prop = [];
+    const props = ['title', 'type', 'is_use'];
+    const mapping = [];
+    super({ like_prop, props, mapping });
+  }
+  @ApiProperty({ description: '名称' })
+  'title': string = undefined;
+  @ApiProperty({ description: '类型' })
+  'type': string = undefined;
+  @ApiProperty({ description: '是否使用' })
+  'is_use': string = undefined;
+}
+
+export class QVO_dictType extends FVO_dictType {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class CDTO_dictType {
+  @ApiProperty({ description: '名称' })
+  @Rule(RuleType['string']().empty(''))
+  'title': string = undefined;
+  @ApiProperty({ description: '类型' })
+  @Rule(RuleType['string']().empty(''))
+  'type': string = undefined;
+  @ApiProperty({ description: '备注' })
+  @Rule(RuleType['string']().empty(''))
+  'remark': string = undefined;
+  @ApiProperty({ description: '是否使用' })
+  @Rule(RuleType['string']().empty(''))
+  'is_use': string = undefined;
+}
+
+export class CVO_dictType extends FVO_dictType {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class UDTO_dictType extends CDTO_dictType {
+  @ApiProperty({ description: '数据id' })
+  @Rule(RuleType['string']().empty(''))
+  _id: string = undefined;
+}
+
+export class UVAO_dictType extends FVO_dictType {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}

+ 99 - 0
src/interface/match.interface.ts

@@ -0,0 +1,99 @@
+import { Rule, RuleType } from '@midwayjs/validate';
+import { ApiProperty } from '@midwayjs/swagger';
+import { SearchBase } from 'free-midway-component';
+import get = require('lodash/get');
+const dealVO = (cla, data) => {
+  for (const key in cla) {
+    const val = get(data, key);
+    if (val || val === 0) cla[key] = val;
+  }
+};
+export class FVO_match {
+  constructor(data: object) {
+    dealVO(this, data);
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: '比赛名称' })
+  'name': string = undefined;
+  @ApiProperty({ description: '开始时间' })
+  'start_time': string = undefined;
+  @ApiProperty({ description: '结束时间' })
+  'end_time': string = undefined;
+  @ApiProperty({ description: '比赛地点' })
+  'address': string = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+  @ApiProperty({ description: '报名截止时间' })
+  'sign_deadline': string = undefined;
+  @ApiProperty({ description: '比赛信息' })
+  'information': string = undefined;
+}
+
+export class QDTO_match extends SearchBase {
+  constructor() {
+    const like_prop = [];
+    const props = ['name', 'start_time', 'end_time', 'status'];
+    const mapping = [];
+    super({ like_prop, props, mapping });
+  }
+  @ApiProperty({ description: '比赛名称' })
+  'name': string = undefined;
+  @ApiProperty({ description: '开始时间' })
+  'start_time': string = undefined;
+  @ApiProperty({ description: '结束时间' })
+  'end_time': string = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+}
+
+export class QVO_match extends FVO_match {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class CDTO_match {
+  @ApiProperty({ description: '比赛名称' })
+  @Rule(RuleType['string']().empty(''))
+  'name': string = undefined;
+  @ApiProperty({ description: '开始时间' })
+  @Rule(RuleType['string']().empty(''))
+  'start_time': string = undefined;
+  @ApiProperty({ description: '结束时间' })
+  @Rule(RuleType['string']().empty(''))
+  'end_time': string = undefined;
+  @ApiProperty({ description: '比赛地点' })
+  @Rule(RuleType['string']().empty(''))
+  'address': string = undefined;
+  @ApiProperty({ description: '状态' })
+  @Rule(RuleType['string']().empty(''))
+  'status': string = undefined;
+  @ApiProperty({ description: '报名截止时间' })
+  @Rule(RuleType['string']().empty(''))
+  'sign_deadline': string = undefined;
+  @ApiProperty({ description: '比赛信息' })
+  @Rule(RuleType['string']().empty(''))
+  'information': string = undefined;
+}
+
+export class CVO_match extends FVO_match {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class UDTO_match extends CDTO_match {
+  @ApiProperty({ description: '数据id' })
+  @Rule(RuleType['string']().empty(''))
+  _id: string = undefined;
+}
+
+export class UVAO_match extends FVO_match {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}

+ 120 - 0
src/interface/team.interface.ts

@@ -0,0 +1,120 @@
+import { Rule, RuleType } from '@midwayjs/validate';
+import { ApiProperty } from '@midwayjs/swagger';
+import { SearchBase } from 'free-midway-component';
+import get = require('lodash/get');
+const dealVO = (cla, data) => {
+  for (const key in cla) {
+    const val = get(data, key);
+    if (val || val === 0) cla[key] = val;
+  }
+};
+export class FVO_team {
+  constructor(data: object) {
+    dealVO(this, data);
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: '所属管理员' })
+  'administrator': string = undefined;
+  @ApiProperty({ description: '团队名称' })
+  'name': string = undefined;
+  @ApiProperty({ description: '成立时间' })
+  'create_time': string = undefined;
+  @ApiProperty({ description: '单位地址' })
+  'address': string = undefined;
+  @ApiProperty({ description: '手机号' })
+  'phone': string = undefined;
+  @ApiProperty({ description: '团队logo' })
+  'logo': string = undefined;
+  @ApiProperty({ description: '团队人数' })
+  'number': string = undefined;
+  @ApiProperty({ description: '团队成员' })
+  'member': Array<any> = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+}
+
+export class QDTO_team extends SearchBase {
+  constructor() {
+    const like_prop = [];
+    const props = [
+      'administrator',
+      'name',
+      'create_time',
+      'phone',
+      'number',
+      'status',
+    ];
+    const mapping = [];
+    super({ like_prop, props, mapping });
+  }
+  @ApiProperty({ description: '所属管理员' })
+  'administrator': string = undefined;
+  @ApiProperty({ description: '团队名称' })
+  'name': string = undefined;
+  @ApiProperty({ description: '成立时间' })
+  'create_time': string = undefined;
+  @ApiProperty({ description: '手机号' })
+  'phone': string = undefined;
+  @ApiProperty({ description: '团队人数' })
+  'number': string = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+}
+
+export class QVO_team extends FVO_team {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class CDTO_team {
+  @ApiProperty({ description: '所属管理员' })
+  @Rule(RuleType['string']().empty(''))
+  'administrator': string = undefined;
+  @ApiProperty({ description: '团队名称' })
+  @Rule(RuleType['string']().empty(''))
+  'name': string = undefined;
+  @ApiProperty({ description: '成立时间' })
+  @Rule(RuleType['string']().empty(''))
+  'create_time': string = undefined;
+  @ApiProperty({ description: '单位地址' })
+  @Rule(RuleType['string']().empty(''))
+  'address': string = undefined;
+  @ApiProperty({ description: '手机号' })
+  @Rule(RuleType['string']().empty(''))
+  'phone': string = undefined;
+  @ApiProperty({ description: '团队logo' })
+  @Rule(RuleType['string']().empty(''))
+  'logo': string = undefined;
+  @ApiProperty({ description: '团队人数' })
+  @Rule(RuleType['string']().empty(''))
+  'number': string = undefined;
+  @ApiProperty({ description: '团队成员' })
+  @Rule(RuleType['array']().empty(''))
+  'member': Array<any> = undefined;
+  @ApiProperty({ description: '状态' })
+  @Rule(RuleType['string']().empty(''))
+  'status': string = undefined;
+}
+
+export class CVO_team extends FVO_team {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class UDTO_team extends CDTO_team {
+  @ApiProperty({ description: '数据id' })
+  @Rule(RuleType['string']().empty(''))
+  _id: string = undefined;
+}
+
+export class UVAO_team extends FVO_team {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}

+ 96 - 0
src/interface/teamApply.interface.ts

@@ -0,0 +1,96 @@
+import { Rule, RuleType } from '@midwayjs/validate';
+import { ApiProperty } from '@midwayjs/swagger';
+import { SearchBase } from 'free-midway-component';
+import get = require('lodash/get');
+const dealVO = (cla, data) => {
+  for (const key in cla) {
+    const val = get(data, key);
+    if (val || val === 0) cla[key] = val;
+  }
+};
+export class FVO_teamApply {
+  constructor(data: object) {
+    dealVO(this, data);
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: '团队id' })
+  'team_id': string = undefined;
+  @ApiProperty({ description: '团队名称' })
+  'team_name': string = undefined;
+  @ApiProperty({ description: '申请人id' })
+  'apply_id': string = undefined;
+  @ApiProperty({ description: '申请人名称' })
+  'apply_name': string = undefined;
+  @ApiProperty({ description: '申请时间' })
+  'apply_time': string = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+}
+
+export class QDTO_teamApply extends SearchBase {
+  constructor() {
+    const like_prop = [];
+    const props = ['team_id', 'team_name', 'apply_id', 'apply_name', 'status'];
+    const mapping = [];
+    super({ like_prop, props, mapping });
+  }
+  @ApiProperty({ description: '团队id' })
+  'team_id': string = undefined;
+  @ApiProperty({ description: '团队名称' })
+  'team_name': string = undefined;
+  @ApiProperty({ description: '申请人id' })
+  'apply_id': string = undefined;
+  @ApiProperty({ description: '申请人名称' })
+  'apply_name': string = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+}
+
+export class QVO_teamApply extends FVO_teamApply {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class CDTO_teamApply {
+  @ApiProperty({ description: '团队id' })
+  @Rule(RuleType['string']().empty(''))
+  'team_id': string = undefined;
+  @ApiProperty({ description: '团队名称' })
+  @Rule(RuleType['string']().empty(''))
+  'team_name': string = undefined;
+  @ApiProperty({ description: '申请人id' })
+  @Rule(RuleType['string']().empty(''))
+  'apply_id': string = undefined;
+  @ApiProperty({ description: '申请人名称' })
+  @Rule(RuleType['string']().empty(''))
+  'apply_name': string = undefined;
+  @ApiProperty({ description: '申请时间' })
+  @Rule(RuleType['string']().empty(''))
+  'apply_time': string = undefined;
+  @ApiProperty({ description: '状态' })
+  @Rule(RuleType['string']().empty(''))
+  'status': string = undefined;
+}
+
+export class CVO_teamApply extends FVO_teamApply {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class UDTO_teamApply extends CDTO_teamApply {
+  @ApiProperty({ description: '数据id' })
+  @Rule(RuleType['string']().empty(''))
+  _id: string = undefined;
+}
+
+export class UVAO_teamApply extends FVO_teamApply {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}

+ 187 - 0
src/interface/user.interface.ts

@@ -0,0 +1,187 @@
+import { Rule, RuleType } from '@midwayjs/validate';
+import { ApiProperty } from '@midwayjs/swagger';
+import { SearchBase } from 'free-midway-component';
+import get = require('lodash/get');
+const dealVO = (cla, data) => {
+  for (const key in cla) {
+    const val = get(data, key);
+    if (val || val === 0) cla[key] = val;
+  }
+};
+export class FVO_user {
+  constructor(data: object) {
+    dealVO(this, data);
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: 'openid' })
+  'openid': string = undefined;
+  @ApiProperty({ description: '类别' })
+  'type': string = undefined;
+  @ApiProperty({ description: '名称' })
+  'name': string = undefined;
+  @ApiProperty({ description: '账号' })
+  'account': string = undefined;
+  @ApiProperty({ description: '密码' })
+  'password': string = undefined;
+  @ApiProperty({ description: '手机号' })
+  'phone': string = undefined;
+  @ApiProperty({ description: '邮箱' })
+  'email': string = undefined;
+  @ApiProperty({ description: '性别' })
+  'gender': string = undefined;
+  @ApiProperty({ description: '头像' })
+  'icon': Array<any> = undefined;
+  @ApiProperty({ description: '年龄' })
+  'age': string = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+  @ApiProperty({ description: '工作单位' })
+  'work': string = undefined;
+}
+
+export class QDTO_user extends SearchBase {
+  constructor() {
+    const like_prop = [];
+    const props = [
+      'openid',
+      'type',
+      'name',
+      'account',
+      'phone',
+      'age',
+      'status',
+    ];
+    const mapping = [];
+    super({ like_prop, props, mapping });
+  }
+  @ApiProperty({ description: 'openid' })
+  'openid': string = undefined;
+  @ApiProperty({ description: '类别' })
+  'type': string = undefined;
+  @ApiProperty({ description: '名称' })
+  'name': string = undefined;
+  @ApiProperty({ description: '账号' })
+  'account': string = undefined;
+  @ApiProperty({ description: '手机号' })
+  'phone': string = undefined;
+  @ApiProperty({ description: '年龄' })
+  'age': string = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+}
+
+export class QVO_user extends FVO_user {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class CDTO_user {
+  @ApiProperty({ description: 'openid' })
+  @Rule(RuleType['string']().empty(''))
+  'openid': string = undefined;
+  @ApiProperty({ description: '类别' })
+  @Rule(RuleType['string']().empty(''))
+  'type': string = undefined;
+  @ApiProperty({ description: '名称' })
+  @Rule(RuleType['string']().empty(''))
+  'name': string = undefined;
+  @ApiProperty({ description: '账号' })
+  @Rule(RuleType['string']().empty(''))
+  'account': string = undefined;
+  @ApiProperty({ description: '密码' })
+  @Rule(RuleType['string']().empty(''))
+  'password': string = undefined;
+  @ApiProperty({ description: '手机号' })
+  @Rule(RuleType['string']().empty(''))
+  'phone': string = undefined;
+  @ApiProperty({ description: '邮箱' })
+  @Rule(RuleType['string']().empty(''))
+  'email': string = undefined;
+  @ApiProperty({ description: '性别' })
+  @Rule(RuleType['string']().empty(''))
+  'gender': string = undefined;
+  @ApiProperty({ description: '头像' })
+  @Rule(RuleType['array']().empty(''))
+  'icon': Array<any> = undefined;
+  @ApiProperty({ description: '年龄' })
+  @Rule(RuleType['string']().empty(''))
+  'age': string = undefined;
+  @ApiProperty({ description: '状态' })
+  @Rule(RuleType['string']().empty(''))
+  'status': string = undefined;
+  @ApiProperty({ description: '工作单位' })
+  @Rule(RuleType['string']().empty(''))
+  'work': string = undefined;
+}
+
+export class CVO_user extends FVO_user {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class UDTO_user extends CDTO_user {
+  @ApiProperty({ description: '数据id' })
+  @Rule(RuleType['string']().empty(''))
+  _id: string = undefined;
+}
+
+export class UVAO_user extends FVO_user {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+export class LoginVO {
+  constructor(data: object) {
+    for (const key of Object.keys(this)) {
+      this[key] = get(data, key);
+    }
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: 'openid' })
+  'openid': string = undefined;
+  @ApiProperty({ description: '类别' })
+  'type': string = undefined;
+  @ApiProperty({ description: '名称' })
+  'name': string = undefined;
+  @ApiProperty({ description: '账号' })
+  'account': string = undefined;
+  @ApiProperty({ description: '手机号' })
+  'phone': string = undefined;
+  @ApiProperty({ description: '邮箱' })
+  'email': string = undefined;
+  @ApiProperty({ description: '性别' })
+  'gender': string = undefined;
+  @ApiProperty({ description: '头像' })
+  'icon': Array<any> = undefined;
+  @ApiProperty({ description: '年龄' })
+  'age': string = undefined;
+  @ApiProperty({ description: '状态' })
+  'status': string = undefined;
+  @ApiProperty({ description: '工作单位' })
+  'work': string = undefined;
+}
+
+export class LoginDTO {
+  @ApiProperty({ description: '账号', example: 'test' })
+  @Rule(RuleType['string']().empty(''))
+  'account': string = undefined;
+  @ApiProperty({ description: '密码', example: '111111' })
+  @Rule(RuleType['string']().empty(''))
+  'password': string = undefined;
+}
+
+export class ResetPasswordDTO {
+  @ApiProperty({ description: '用户id', example: '' })
+  @Rule(RuleType['string']().required())
+  '_id': string = undefined;
+  @ApiProperty({ description: '密码', example: '123456' })
+  @Rule(RuleType['string']().required())
+  'password': string = undefined;
+}

+ 33 - 0
src/middleware/checkToken.middleware.ts

@@ -0,0 +1,33 @@
+import { IMiddleware } from '@midwayjs/core';
+import { Middleware, Inject } from '@midwayjs/decorator';
+import { NextFunction, Context } from '@midwayjs/koa';
+import get = require('lodash/get');
+import { JwtService } from '@midwayjs/jwt';
+
+@Middleware()
+export class CheckTokenMiddleware
+  implements IMiddleware<Context, NextFunction>
+{
+  @Inject()
+  jwtService: JwtService;
+  resolve() {
+    return async (ctx: Context, next: NextFunction) => {
+      const token: any = get(ctx.request, 'header.token');
+      if (token) {
+        const data = this.jwtService.decodeSync(token);
+        if (data) ctx.user = data;
+      }
+      // 添加管理员身份
+      const adminToken: any = get(ctx.request, 'header.admin-token');
+      if (adminToken) {
+        const data = this.jwtService.decodeSync(adminToken);
+        if (data) ctx.admin = data;
+      }
+      await next();
+    };
+  }
+
+  static getName(): string {
+    return 'checkToken';
+  }
+}

+ 27 - 0
src/middleware/report.middleware.ts

@@ -0,0 +1,27 @@
+import { Middleware, IMiddleware } from '@midwayjs/core';
+import { NextFunction, Context } from '@midwayjs/koa';
+
+@Middleware()
+export class ReportMiddleware implements IMiddleware<Context, NextFunction> {
+  resolve() {
+    return async (ctx: Context, next: NextFunction) => {
+      // 控制器前执行的逻辑
+      const startTime = Date.now();
+      // 执行下一个 Web 中间件,最后执行到控制器
+      // 这里可以拿到下一个中间件或者控制器的返回值
+      const result = await next();
+      // 控制器之后执行的逻辑
+      ctx.logger.info(
+        `Report in "src/middleware/report.middleware.ts", rt = ${
+          Date.now() - startTime
+        }ms`
+      );
+      // 返回给上一个中间件的结果
+      return result;
+    };
+  }
+
+  static getName(): string {
+    return 'report';
+  }
+}

+ 30 - 0
src/service/admin.service.ts

@@ -0,0 +1,30 @@
+import { Provide } from '@midwayjs/decorator';
+import { InjectEntityModel } from '@midwayjs/typegoose';
+import { ReturnModelType } from '@typegoose/typegoose';
+import {
+  BaseService,
+  FrameworkErrorEnum,
+  ServiceError,
+} from 'free-midway-component';
+import { Admin } from '../entity/admin.entity';
+import isEqual = require('lodash/isEqual');
+import { LoginDTO } from '../interface/admin.interface';
+type modelType = ReturnModelType<typeof Admin>;
+@Provide()
+export class AdminService extends BaseService<modelType> {
+  @InjectEntityModel(Admin)
+  model: modelType;
+
+  async findUserToLogin(data: LoginDTO): Promise<object> {
+    const { account, password } = data;
+    const user = await this.model.findOne({ account }, '+password').lean();
+    if (!user)
+      throw new ServiceError(
+        '未找到管理员信息',
+        FrameworkErrorEnum.NOT_FOUND_DATA
+      );
+    if (!isEqual(user.password.secret, password))
+      throw new ServiceError('密码错误', FrameworkErrorEnum.SERVICE_FAULT);
+    return user;
+  }
+}

+ 11 - 0
src/service/application.service.ts

@@ -0,0 +1,11 @@
+import { Provide } from '@midwayjs/decorator';
+import { InjectEntityModel } from '@midwayjs/typegoose';
+import { ReturnModelType } from '@typegoose/typegoose';
+import { BaseService } from 'free-midway-component';
+import { Application } from '../entity/application.entity';
+type modelType = ReturnModelType<typeof Application>;
+@Provide()
+export class ApplicationService extends BaseService<modelType> {
+  @InjectEntityModel(Application)
+  model: modelType;
+}

+ 11 - 0
src/service/course.service.ts

@@ -0,0 +1,11 @@
+import { Provide } from '@midwayjs/decorator';
+import { InjectEntityModel } from '@midwayjs/typegoose';
+import { ReturnModelType } from '@typegoose/typegoose';
+import { BaseService } from 'free-midway-component';
+import { Course } from '../entity/course.entity';
+type modelType = ReturnModelType<typeof Course>;
+@Provide()
+export class CourseService extends BaseService<modelType> {
+  @InjectEntityModel(Course)
+  model: modelType;
+}

+ 11 - 0
src/service/dictData.service.ts

@@ -0,0 +1,11 @@
+import { Provide } from '@midwayjs/decorator';
+import { InjectEntityModel } from '@midwayjs/typegoose';
+import { ReturnModelType } from '@typegoose/typegoose';
+import { BaseService } from 'free-midway-component';
+import { DictData } from '../entity/dictData.entity';
+type modelType = ReturnModelType<typeof DictData>;
+@Provide()
+export class DictDataService extends BaseService<modelType> {
+  @InjectEntityModel(DictData)
+  model: modelType;
+}

+ 11 - 0
src/service/dictType.service.ts

@@ -0,0 +1,11 @@
+import { Provide } from '@midwayjs/decorator';
+import { InjectEntityModel } from '@midwayjs/typegoose';
+import { ReturnModelType } from '@typegoose/typegoose';
+import { BaseService } from 'free-midway-component';
+import { DictType } from '../entity/dictType.entity';
+type modelType = ReturnModelType<typeof DictType>;
+@Provide()
+export class DictTypeService extends BaseService<modelType> {
+  @InjectEntityModel(DictType)
+  model: modelType;
+}

+ 11 - 0
src/service/match.service.ts

@@ -0,0 +1,11 @@
+import { Provide } from '@midwayjs/decorator';
+import { InjectEntityModel } from '@midwayjs/typegoose';
+import { ReturnModelType } from '@typegoose/typegoose';
+import { BaseService } from 'free-midway-component';
+import { Match } from '../entity/match.entity';
+type modelType = ReturnModelType<typeof Match>;
+@Provide()
+export class MatchService extends BaseService<modelType> {
+  @InjectEntityModel(Match)
+  model: modelType;
+}

+ 11 - 0
src/service/team.service.ts

@@ -0,0 +1,11 @@
+import { Provide } from '@midwayjs/decorator';
+import { InjectEntityModel } from '@midwayjs/typegoose';
+import { ReturnModelType } from '@typegoose/typegoose';
+import { BaseService } from 'free-midway-component';
+import { Team } from '../entity/team.entity';
+type modelType = ReturnModelType<typeof Team>;
+@Provide()
+export class TeamService extends BaseService<modelType> {
+  @InjectEntityModel(Team)
+  model: modelType;
+}

+ 11 - 0
src/service/teamApply.service.ts

@@ -0,0 +1,11 @@
+import { Provide } from '@midwayjs/decorator';
+import { InjectEntityModel } from '@midwayjs/typegoose';
+import { ReturnModelType } from '@typegoose/typegoose';
+import { BaseService } from 'free-midway-component';
+import { TeamApply } from '../entity/teamApply.entity';
+type modelType = ReturnModelType<typeof TeamApply>;
+@Provide()
+export class TeamApplyService extends BaseService<modelType> {
+  @InjectEntityModel(TeamApply)
+  model: modelType;
+}

+ 30 - 0
src/service/user.service.ts

@@ -0,0 +1,30 @@
+import { Provide } from '@midwayjs/decorator';
+import { InjectEntityModel } from '@midwayjs/typegoose';
+import { ReturnModelType } from '@typegoose/typegoose';
+import {
+  BaseService,
+  FrameworkErrorEnum,
+  ServiceError,
+} from 'free-midway-component';
+import isEqual = require('lodash/isEqual');
+import { User } from '../entity/user.entity';
+import { LoginDTO } from '../interface/user.interface';
+type modelType = ReturnModelType<typeof User>;
+@Provide()
+export class UserService extends BaseService<modelType> {
+  @InjectEntityModel(User)
+  model: modelType;
+
+  async findUserToLogin(data: LoginDTO): Promise<object> {
+    const { account, password } = data;
+    const user = await this.model.findOne({ account }, '+password').lean();
+    if (!user)
+      throw new ServiceError(
+        '未找到用户信息',
+        FrameworkErrorEnum.NOT_FOUND_DATA
+      );
+    if (!isEqual(user.password.secret, password))
+      throw new ServiceError('密码错误', FrameworkErrorEnum.SERVICE_FAULT);
+    return user;
+  }
+}

+ 20 - 0
test/controller/api.test.ts

@@ -0,0 +1,20 @@
+import { createApp, close, createHttpRequest } from '@midwayjs/mock';
+import { Framework } from '@midwayjs/koa';
+
+describe('test/controller/home.test.ts', () => {
+
+  it('should POST /api/get_user', async () => {
+    // create app
+    const app = await createApp<Framework>();
+
+    // make request
+    const result = await createHttpRequest(app).get('/api/get_user').query({ uid: 123 });
+
+    // use expect by jest
+    expect(result.status).toBe(200);
+    expect(result.body.message).toBe('OK');
+
+    // close app
+    await close(app);
+  });
+});

+ 21 - 0
test/controller/home.test.ts

@@ -0,0 +1,21 @@
+import { createApp, close, createHttpRequest } from '@midwayjs/mock';
+import { Framework } from '@midwayjs/koa';
+
+describe('test/controller/home.test.ts', () => {
+
+  it('should GET /', async () => {
+    // create app
+    const app = await createApp<Framework>();
+
+    // make request
+    const result = await createHttpRequest(app).get('/');
+
+    // use expect by jest
+    expect(result.status).toBe(200);
+    expect(result.text).toBe('Hello Midwayjs!');
+
+    // close app
+    await close(app);
+  });
+
+});

+ 25 - 0
tsconfig.json

@@ -0,0 +1,25 @@
+{
+  "compileOnSave": true,
+  "compilerOptions": {
+    "target": "es2018",
+    "module": "commonjs",
+    "moduleResolution": "node",
+    "experimentalDecorators": true,
+    "emitDecoratorMetadata": true,
+    "inlineSourceMap":true,
+    "noImplicitThis": true,
+    "noUnusedLocals": true,
+    "stripInternal": true,
+    "skipLibCheck": true,
+    "pretty": true,
+    "declaration": true,
+    "forceConsistentCasingInFileNames": true,
+    "typeRoots": [ "./typings", "./node_modules/@types"],
+    "outDir": "dist"
+  },
+  "exclude": [
+    "dist",
+    "node_modules",
+    "test"
+  ]
+}