lrf 2 年之前
當前提交
02a447b586
共有 54 個文件被更改,包括 1857 次插入0 次删除
  1. 29 0
      .autod.conf.js
  2. 1 0
      .eslintignore
  3. 3 0
      .eslintrc
  4. 46 0
      .github/workflows/nodejs.yml
  5. 14 0
      .gitignore
  6. 12 0
      .travis.yml
  7. 5 0
      README.md
  8. 363 0
      app.js
  9. 43 0
      app/controller/config/.match.js
  10. 39 0
      app/controller/config/.matchGroup.js
  11. 41 0
      app/controller/config/.matchProject.js
  12. 44 0
      app/controller/config/.matchSign.js
  13. 46 0
      app/controller/config/.teamApply.js
  14. 14 0
      app/controller/home.js
  15. 13 0
      app/controller/match.js
  16. 13 0
      app/controller/matchGroup.js
  17. 13 0
      app/controller/matchProject.js
  18. 13 0
      app/controller/matchSign.js
  19. 13 0
      app/controller/teamApply.js
  20. 53 0
      app/middleware/request-log.js
  21. 24 0
      app/model/base/user.js
  22. 26 0
      app/model/ground.js
  23. 30 0
      app/model/race.js
  24. 43 0
      app/model/race/match.js
  25. 32 0
      app/model/race/matchGroup.js
  26. 38 0
      app/model/race/matchProject.js
  27. 40 0
      app/model/race/matchSign.js
  28. 44 0
      app/model/race/teamApply.js
  29. 27 0
      app/public/routerRegister.js
  30. 31 0
      app/router.js
  31. 15 0
      app/service/match.js
  32. 15 0
      app/service/matchGroup.js
  33. 15 0
      app/service/matchProject.js
  34. 15 0
      app/service/matchSign.js
  35. 15 0
      app/service/race.js
  36. 15 0
      app/service/teamApply.js
  37. 83 0
      app/service/util/http-util.js
  38. 35 0
      app/service/util/install.js
  39. 18 0
      app/service/util/jwt.js
  40. 74 0
      app/service/util/rabbitMq.js
  41. 19 0
      app/z_router/match.js
  42. 19 0
      app/z_router/matchGroup.js
  43. 19 0
      app/z_router/matchProject.js
  44. 19 0
      app/z_router/matchSign.js
  45. 19 0
      app/z_router/teamApply.js
  46. 14 0
      appveyor.yml
  47. 147 0
      config/config.default.js
  48. 46 0
      config/config.prod.js
  49. 7 0
      config/config.secret.js
  50. 11 0
      config/plugin.js
  51. 18 0
      ecosystem.config.js
  52. 53 0
      package.json
  53. 10 0
      server.js
  54. 3 0
      update.sh

+ 29 - 0
.autod.conf.js

@@ -0,0 +1,29 @@
+'use strict';
+
+module.exports = {
+  write: true,
+  prefix: '^',
+  plugin: 'autod-egg',
+  test: [
+    'test',
+    'benchmark',
+  ],
+  dep: [
+    'egg',
+    'egg-scripts',
+  ],
+  devdep: [
+    'egg-ci',
+    'egg-bin',
+    'egg-mock',
+    'autod',
+    'autod-egg',
+    'eslint',
+    'eslint-config-egg',
+  ],
+  exclude: [
+    './test/fixtures',
+    './dist',
+  ],
+};
+

+ 1 - 0
.eslintignore

@@ -0,0 +1 @@
+coverage

+ 3 - 0
.eslintrc

@@ -0,0 +1,3 @@
+{
+  "extends": "eslint-config-egg"
+}

+ 46 - 0
.github/workflows/nodejs.yml

@@ -0,0 +1,46 @@
+# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
+# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
+
+name: Node.js CI
+
+on:
+  push:
+    branches:
+      - main
+      - master
+  pull_request:
+    branches:
+      - main
+      - master
+  schedule:
+    - cron: '0 2 * * *'
+
+jobs:
+  build:
+    runs-on: ${{ matrix.os }}
+
+    strategy:
+      fail-fast: false
+      matrix:
+        node-version: [10]
+        os: [ubuntu-latest, windows-latest, macos-latest]
+
+    steps:
+    - name: Checkout Git Source
+      uses: actions/checkout@v2
+
+    - name: Use Node.js ${{ matrix.node-version }}
+      uses: actions/setup-node@v1
+      with:
+        node-version: ${{ matrix.node-version }}
+
+    - name: Install Dependencies
+      run: npm i -g npminstall && npminstall
+
+    - name: Continuous Integration
+      run: npm run ci
+
+    - name: Code Coverage
+      uses: codecov/codecov-action@v1
+      with:
+        token: ${{ secrets.CODECOV_TOKEN }}

+ 14 - 0
.gitignore

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

+ 12 - 0
.travis.yml

@@ -0,0 +1,12 @@
+
+language: node_js
+node_js:
+  - '10'
+before_install:
+  - npm i npminstall -g
+install:
+  - npminstall
+script:
+  - npm run ci
+after_script:
+  - npminstall codecov && codecov

+ 5 - 0
README.md

@@ -0,0 +1,5 @@
+# server-new
+
+## 与用户有关联的全用 openid进行查询
+
+## 数据修改仍然用数据id:_id

+ 363 - 0
app.js

@@ -0,0 +1,363 @@
+'use strict';
+const _ = require('lodash');
+const colors = require('colors');
+class AppBootHook {
+  constructor(app) {
+    this.app = app;
+  }
+
+  async willReady() {
+    // await this.initAdmin();
+    // await this.initMenu();
+  }
+
+  async serverDidReady() {
+    // 应用已经启动完毕
+    const ctx = await this.app.createAnonymousContext();
+    ctx.service.util.install.init();
+    // await this.initAdmin(ctx);
+    // await this.initMenu(ctx);
+    // await this.initRole(ctx);
+    // 检查种子
+    // await ctx.service.install.index();
+    // await ctx.service.util.rabbitMq.mission();
+  }
+
+
+  async initRole(ctx) {
+    console.log('开始=>初始化角色'.blue);
+    const data = await ctx.model.Role.findOne();
+    if (!data) {
+      // 没有管理员,初始化一个
+      const data = {
+        default: true,
+        _tenant: 'master',
+        name: '管理员角色',
+      };
+      console.log('正在初始化角色'.blue);
+      await ctx.model.Role.create(data);
+      console.log('初始化角色=>结束'.green);
+    } else console.log('无需再次初始化角色'.yellow);
+  }
+
+  async initMenu(ctx) {
+    console.log('开始=>初始化总管理员菜单'.blue);
+    const data = await ctx.model.Menu.count();
+    if (data <= 0) {
+      console.log('正在初始化总管理员菜单'.blue);
+      console.log(colors.bgBlue.italic('菜单=>初始化 首页'));
+      // 首页初始化
+      const indexPage = {
+        name: '首页',
+        icon: 'icon-shouye',
+        order_num: 1,
+        path: '/admin/homeIndex',
+        status: '0',
+        type: '1',
+        no_delete: true,
+        _tenant: 'master',
+      };
+      await ctx.model.Menu.create(indexPage);
+      console.log(colors.bgGreen.italic('菜单=>初始化 首页'));
+
+      console.log(colors.bgBlue.italic('菜单=>初始化 系统菜单'));
+      // 系统菜单初始化
+      const sys = {
+        name: '系统设置',
+        icon: 'icon-shouye',
+        order_num: 2,
+        type: '0',
+        status: '0',
+        no_delete: true,
+        _tenant: 'master',
+      };
+      const sysData = await ctx.model.Menu.create(sys);
+      let sys_id = _.get(sysData, '_id');
+      if (sys_id) sys_id = JSON.parse(JSON.stringify(sys_id));
+      console.log(colors.bgBlue.italic('菜单=>系统菜单=>初始化 菜单管理'));
+      // 系统-菜单管理
+      const sys_menu = {
+        name: '菜单设置',
+        icon: 'icon-shouye',
+        order_num: 1,
+        parent_id: sys_id,
+        path: '/admin/menu',
+        status: '0',
+        type: '1',
+        no_delete: true,
+        _tenant: 'master',
+      };
+      await ctx.model.Menu.create(sys_menu);
+      console.log(colors.bgGreen.italic('菜单=>系统菜单=>初始化 菜单管理'));
+      console.log(colors.bgBlue.italic('菜单=>系统菜单=>初始化 角色管理'));
+      // 系统-角色
+      const sys_role = {
+        name: '角色管理',
+        icon: 'icon-shouye',
+        order_num: 2,
+        parent_id: sys_id,
+        path: '/admin/role',
+        status: '0',
+        type: '1',
+        no_delete: true,
+        _tenant: 'master',
+      };
+      const sr = await ctx.model.Menu.create(sys_role);
+      let role_id = _.get(sr, '_id');
+      if (role_id) role_id = JSON.parse(JSON.stringify(role_id));
+      const sys_role_child = {
+        status: '0',
+        icon: 'icon-shouye',
+        name: '角色信息',
+        parent_id: role_id,
+        path: '/admin/role/detail',
+        type: '2',
+        config: {
+          api: [],
+          table_btn: [],
+          btn_area: [],
+        },
+        no_delete: true,
+        _tenant: 'master',
+      };
+      await ctx.model.Menu.create(sys_role_child);
+      console.log(colors.bgGreen.italic('菜单=>系统菜单=>初始化 角色管理'));
+
+      console.log(colors.bgBlue.italic('菜单=>系统菜单=>初始化 分站管理'));
+      // 系统-分站
+      const sys_tenant = {
+        status: '0',
+        icon: 'icon-shouye',
+        no_delete: true,
+        _tenant: 'master',
+        page_type: 'list',
+        name: '分站管理',
+        parent_id: sys_id,
+        order_num: 3,
+        path: '/list/v1/tenant',
+        type: '1',
+        config: {
+          api: [
+            {
+              is_use: true,
+              module: 'tenant',
+              func: 'query',
+              opera: 'search',
+              desc: '查询列表',
+            },
+            {
+              is_use: true,
+              module: 'tenant',
+              func: 'delete',
+              opera: 'delete',
+              desc: '删除',
+            },
+          ],
+          table_btn: [
+            {
+              confirm: false,
+              label: '修改',
+              type: 'primary',
+              api: 'writeBySelf',
+              selfFunction: '(i)=>this.$router.push({name:"v1_detail",params:{service:this.service},query:{id:i._id}})',
+            },
+            {
+              confirm: false,
+              label: '删除',
+              type: 'danger',
+              api: 'delete',
+            },
+          ],
+          btn_area: [
+            {
+              label: '添加',
+              type: 'primary',
+              api: 'writeBySelf',
+              selfFunction: '(i)=>this.$router.push({name:"v1_detail",params:{service:this.service}})',
+              confirm: false,
+            },
+          ],
+        },
+      };
+      const st = await ctx.model.Menu.create(sys_tenant);
+      let tenant_id = _.get(st, '_id');
+      if (tenant_id) tenant_id = JSON.parse(JSON.stringify(tenant_id));
+      const sys_tenant_child = {
+        status: '0',
+        icon: 'icon-shouye',
+        no_delete: true,
+        _tenant: 'master',
+        page_type: 'detail',
+        name: '分站编辑',
+        parent_id: tenant_id,
+        path: '/detail/v1/tenant',
+        type: '2',
+        config: {
+          api: [
+            {
+              is_use: true,
+              module: 'tenant',
+              func: 'fetch',
+              opera: 'search',
+              desc: '查询',
+            },
+            {
+              is_use: true,
+              module: 'tenant',
+              func: 'create',
+              opera: 'create',
+              desc: '创建',
+            },
+            {
+              is_use: true,
+              module: 'tenant',
+              func: 'update',
+              opera: 'update',
+              desc: '修改',
+            },
+          ],
+          table_btn: [],
+          btn_area: [],
+        },
+      };
+      await ctx.model.Menu.create(sys_tenant_child);
+      console.log(colors.bgGreen.italic('菜单=>系统菜单=>初始化 分站管理'));
+      console.log(colors.bgBlue.italic('菜单=>系统菜单=>初始化 管理员管理'));
+      // 系统-管理员
+      const sys_admin = {
+        status: '0',
+        icon: 'icon-shouye',
+        no_delete: true,
+        _tenant: 'master',
+        name: '管理员用户',
+        parent_id: sys_id,
+        order_num: 4,
+        path: '/list/v1/admin',
+        type: '1',
+        __v: 0,
+        config: {
+          api: [
+            {
+              is_use: true,
+              module: 'admin',
+              func: 'query',
+              opera: 'search',
+              desc: '查询列表',
+            },
+            {
+              is_use: true,
+              module: 'admin',
+              func: 'create',
+              opera: 'create',
+              desc: '创建',
+            },
+            {
+              is_use: true,
+              module: 'admin',
+              func: 'update',
+              opera: 'update',
+              desc: '修改',
+            },
+            {
+              is_use: true,
+              module: 'admin',
+              func: 'delete',
+              opera: 'toDelete',
+              desc: '删除',
+            },
+            {
+              is_use: true,
+              module: 'admin',
+              func: 'fetch',
+              opera: 'toFetch',
+              desc: '单项数据查询',
+            },
+          ],
+          table_btn: [
+            {
+              confirm: false,
+              label: '修改',
+              type: 'primary',
+              api: 'writeBySelf',
+              methodZh: '',
+              display: '',
+              selfFunction: '(i)=>this.$router.push({name:"v1_detail", query:{id:i._id},params:{service:this.service}})',
+            },
+            {
+              confirm: true,
+              label: '删除',
+              type: 'danger',
+              api: 'toDelete',
+              display: '(i)=>i.is_super !== true',
+              methodZh: '确认是否删除该用户',
+            },
+            {
+              confirm: false,
+              label: '查看',
+              type: 'primary',
+              api: 'writeBySelf',
+              selfFunction: '(i)=>this.$router.push({name:"v1_info" , query:{id:i._id},params:{service:this.service}})',
+            },
+          ],
+          btn_area: [
+            {
+              label: '添加',
+              type: 'primary',
+              api: 'writeBySelf',
+              selfFunction: '(i)=>this.$router.push({name:"v1_detail",params:{service:this.service}})',
+              confirm: false,
+            },
+          ],
+        },
+        page_type: 'list',
+      };
+      const sa = await ctx.model.Menu.create(sys_admin);
+      let admin_id = _.get(sa, '_id');
+      if (admin_id) admin_id = JSON.parse(JSON.stringify(admin_id));
+      const sys_admin_child = {
+        status: '0',
+        icon: 'icon-shouye',
+        no_delete: true,
+        _tenant: 'master',
+        name: '管理员信息',
+        parent_id: admin_id,
+        path: '/detail/v1/admin',
+        type: '2',
+        config: {
+          api: [
+            {
+              is_use: true,
+              module: 'admin',
+              func: 'fetch',
+              opera: 'search',
+              desc: '单数据查询',
+            },
+            {
+              is_use: true,
+              module: 'admin',
+              func: 'create',
+              opera: 'create',
+              desc: '创建',
+            },
+            {
+              is_use: true,
+              module: 'admin',
+              func: 'update',
+              opera: 'update',
+              desc: '修改',
+            },
+          ],
+          table_btn: [],
+          btn_area: [],
+        },
+        page_type: 'detail',
+      };
+      await ctx.model.Menu.create(sys_admin_child);
+      console.log(colors.bgGreen.italic('菜单=>系统菜单=>初始化 管理员管理'));
+      console.log(colors.bgGreen.italic('菜单=>初始化 系统菜单'));
+
+      console.log('初始化总管理员菜单结束'.green);
+    } else console.log('无需初始化总管理员菜单'.yellow);
+  }
+}
+module.exports = AppBootHook;

+ 43 - 0
app/controller/config/.match.js

@@ -0,0 +1,43 @@
+module.exports = {
+  create: {
+    requestBody: ['!logo', '!name', '!start_time', '!end_time', '!address', '!sign_time', 'money_remark', 'money_mode', '!contact', 'explain', 'regular', '!status'],
+  },
+  destroy: {
+    params: ['!id'],
+    service: 'delete',
+  },
+  update: {
+    params: ['!id'],
+    requestBody: ['logo', 'name', 'start_time', 'end_time', 'address', 'sign_time', 'money_remark', 'money_mode', 'contact', 'explain', 'regular', 'status'],
+  },
+  show: {
+    parameters: {
+      params: ['!id'],
+    },
+    service: 'fetch',
+  },
+  index: {
+    parameters: {
+      query: {
+        'meta.createdAt@start': 'meta.createdAt@start',
+        'meta.createdAt@end': 'meta.createdAt@end',
+        name: 'name',
+        start_time: 'start_time',
+        end_time: 'end_time',
+        sign_time: 'sign_time',
+        contact: 'contact',
+        status: 'status',
+      },
+      // options: {
+      //   "meta.state": 0 // 默认条件
+      // },
+    },
+    service: 'query',
+    options: {
+      query: ['skip', 'limit'],
+      sort: ['meta.createdAt'],
+      desc: true,
+      count: true,
+    },
+  },
+};

+ 39 - 0
app/controller/config/.matchGroup.js

@@ -0,0 +1,39 @@
+module.exports = {
+  create: {
+    requestBody: ['!match_id', '!name', 'age', 'explain'],
+  },
+  destroy: {
+    params: ['!id'],
+    service: 'delete',
+  },
+  update: {
+    params: ['!id'],
+    requestBody: ['match_id', 'name', 'age', 'explain'],
+  },
+  show: {
+    parameters: {
+      params: ['!id'],
+    },
+    service: 'fetch',
+  },
+  index: {
+    parameters: {
+      query: {
+        'meta.createdAt@start': 'meta.createdAt@start',
+        'meta.createdAt@end': 'meta.createdAt@end',
+        match_id: 'match_id',
+        name: 'name',
+      },
+      // options: {
+      //   "meta.state": 0 // 默认条件
+      // },
+    },
+    service: 'query',
+    options: {
+      query: ['skip', 'limit'],
+      sort: ['meta.createdAt'],
+      desc: true,
+      count: true,
+    },
+  },
+};

+ 41 - 0
app/controller/config/.matchProject.js

@@ -0,0 +1,41 @@
+module.exports = {
+  create: {
+    requestBody: ['!match_id', '!group_id', '!type', '!name', 'age', 'gender', 'num', 'explain'],
+  },
+  destroy: {
+    params: ['!id'],
+    service: 'delete',
+  },
+  update: {
+    params: ['!id'],
+    requestBody: ['match_id', 'group_id', 'type', 'name', 'age', 'gender', 'num', 'explain'],
+  },
+  show: {
+    parameters: {
+      params: ['!id'],
+    },
+    service: 'fetch',
+  },
+  index: {
+    parameters: {
+      query: {
+        'meta.createdAt@start': 'meta.createdAt@start',
+        'meta.createdAt@end': 'meta.createdAt@end',
+        match_id: 'match_id',
+        group_id: 'group_id',
+        type: 'type',
+        name: 'name',
+      },
+      // options: {
+      //   "meta.state": 0 // 默认条件
+      // },
+    },
+    service: 'query',
+    options: {
+      query: ['skip', 'limit'],
+      sort: ['meta.createdAt'],
+      desc: true,
+      count: true,
+    },
+  },
+};

+ 44 - 0
app/controller/config/.matchSign.js

@@ -0,0 +1,44 @@
+module.exports = {
+  create: {
+    requestBody: ['!match_id', '!group_id', '!project_id', '!user_id', 'is_share', 'pay_id', 'pay_status'],
+  },
+  destroy: {
+    params: ['!id'],
+    service: 'delete',
+  },
+  update: {
+    params: ['!id'],
+    requestBody: ['match_id', 'group_id', 'project_id', 'user_id', 'is_share', 'pay_id', 'pay_status'],
+  },
+  show: {
+    parameters: {
+      params: ['!id'],
+    },
+    service: 'fetch',
+  },
+  index: {
+    parameters: {
+      query: {
+        'meta.createdAt@start': 'meta.createdAt@start',
+        'meta.createdAt@end': 'meta.createdAt@end',
+        match_id: 'match_id',
+        group_id: 'group_id',
+        project_id: 'project_id',
+        user_id: 'user_id',
+        is_share: 'is_share',
+        pay_id: 'pay_id',
+        pay_status: 'pay_status',
+      },
+      // options: {
+      //   "meta.state": 0 // 默认条件
+      // },
+    },
+    service: 'query',
+    options: {
+      query: ['skip', 'limit'],
+      sort: ['meta.createdAt'],
+      desc: true,
+      count: true,
+    },
+  },
+};

+ 46 - 0
app/controller/config/.teamApply.js

@@ -0,0 +1,46 @@
+module.exports = {
+  create: {
+    requestBody: ['!match_id', '!group_id', '!project_id', '!one_member_id', '!one_member_name', '!two_member_id', '!two_member_name', '!apply_time', 'status'],
+  },
+  destroy: {
+    params: ['!id'],
+    service: 'delete',
+  },
+  update: {
+    params: ['!id'],
+    requestBody: ['match_id', 'group_id', 'project_id', 'one_member_id', 'one_member_name', 'two_member_id', 'two_member_name', 'apply_time', 'status'],
+  },
+  show: {
+    parameters: {
+      params: ['!id'],
+    },
+    service: 'fetch',
+  },
+  index: {
+    parameters: {
+      query: {
+        'meta.createdAt@start': 'meta.createdAt@start',
+        'meta.createdAt@end': 'meta.createdAt@end',
+        match_id: 'match_id',
+        group_id: 'group_id',
+        project_id: 'project_id',
+        one_member_id: 'one_member_id',
+        one_member_name: 'one_member_name',
+        two_member_id: 'two_member_id',
+        two_member_name: 'two_member_name',
+        apply_time: 'apply_time',
+        status: 'status',
+      },
+      // options: {
+      //   "meta.state": 0 // 默认条件
+      // },
+    },
+    service: 'query',
+    options: {
+      query: ['skip', 'limit'],
+      sort: ['meta.createdAt'],
+      desc: true,
+      count: true,
+    },
+  },
+};

+ 14 - 0
app/controller/home.js

@@ -0,0 +1,14 @@
+'use strict';
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose-free/lib/controller');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const { ObjectId } = require('mongoose').Types;
+
+// 项目测试及管理员登陆
+class HomeController extends Controller {
+  async index() {
+    const { ctx } = this;
+    ctx.body = 'hello';
+  }
+}
+module.exports = CrudController(HomeController, {});

+ 13 - 0
app/controller/match.js

@@ -0,0 +1,13 @@
+'use strict';
+const meta = require('./config/.match.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose-free/lib/controller');
+
+//
+class MatchController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.match;
+  }
+}
+module.exports = CrudController(MatchController, meta);

+ 13 - 0
app/controller/matchGroup.js

@@ -0,0 +1,13 @@
+'use strict';
+const meta = require('./config/.matchGroup.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose-free/lib/controller');
+
+// 
+class MatchGroupController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.matchGroup;
+  }
+}
+module.exports = CrudController(MatchGroupController, meta);

+ 13 - 0
app/controller/matchProject.js

@@ -0,0 +1,13 @@
+'use strict';
+const meta = require('./config/.matchProject.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose-free/lib/controller');
+
+// 
+class MatchProjectController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.matchProject;
+  }
+}
+module.exports = CrudController(MatchProjectController, meta);

+ 13 - 0
app/controller/matchSign.js

@@ -0,0 +1,13 @@
+'use strict';
+const meta = require('./config/.matchSign.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose-free/lib/controller');
+
+//
+class MatchSignController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.matchSign;
+  }
+}
+module.exports = CrudController(MatchSignController, meta);

+ 13 - 0
app/controller/teamApply.js

@@ -0,0 +1,13 @@
+'use strict';
+const meta = require('./config/.teamApply.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose-free/lib/controller');
+
+// 
+class TeamApplyController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.teamApply;
+  }
+}
+module.exports = CrudController(TeamApplyController, meta);

+ 53 - 0
app/middleware/request-log.js

@@ -0,0 +1,53 @@
+'use strict';
+module.exports = ({ toMongoDB = false }) =>
+  async function requestLog(ctx, next) {
+    await next();
+    try {
+      const request = ctx.request;
+      // 请求路由
+      const url = request.url;
+      // 请求方法
+      const method = request.method;
+      // get 请求不发日志
+      if (method === 'GET') return;
+      // 请求的分站标识
+      const tenant = ctx.tenant || 'master';
+      // 请求的用户
+      const user = ctx.user;
+      // 当前模块
+      const module = ctx.app.config.module;
+      // 所有的请求路由
+      const routers = ctx.router.stack;
+      // 匹配路由及http请求方法
+      const route = routers.find(route => {
+        const reg = new RegExp(route.regexp);
+        // 正则验证
+        const regResult = reg.test(url);
+        // http方法验证
+        const methodResult = route.methods.includes(method);
+        if (regResult && methodResult) return true;
+        return false;
+      });
+      if (!route) return;
+      // 不往数据库里写,就回去
+      if (!toMongoDB) return;
+      // 组织数据,给MQ,让日志服务去写
+      const { id: user_id, account, name } = user;
+      const logData = { user_id, account, name, _tenant: tenant, opera: route.name, path: url, module };
+      // 先用mq发送,不行再用http发
+      if (ctx.mq) {
+        ctx.service.util.rabbitMq.sendToMqQueue(logData, 'logs');
+      } else {
+        // http请求
+        const httpPrefix = ctx.app.config.httpPrefix;
+        if (httpPrefix && httpPrefix.logs) {
+          const uri = `${httpPrefix.logs}/logs`;
+          ctx.service.util.httpUtil.cpost(uri, logData);
+        }
+      }
+    } catch (error) {
+      // 没啥可输出,别中断就行
+    }
+
+
+  };

+ 24 - 0
app/model/base/user.js

@@ -0,0 +1,24 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+
+// 微信用户表
+const user = {
+  openid: { type: String, required: true, zh: 'openid ' }, //
+  name: { type: String, required: false, zh: '用户名' }, //
+  gender: { type: String, required: false, zh: '性别' }, //
+  phone: { type: String, required: false, zh: '手机号' }, //
+  icon: { type: Array, required: false, zh: '头像' }, //
+  type: { type: String, required: false, default: '0', zh: '用户类别' }, // -1:超级管理员;0:普通用户;1-学院管理员;2-教练;3-学员;10-游客
+};
+const schema = new Schema(user, { toJSON: { virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.index({ openid: 1 });
+schema.index({ name: 1 });
+
+schema.plugin(metaPlugin);
+module.exports = app => {
+  const conn = app.mongooseDB.get('base');
+  return conn.model('User', schema, 'user');
+};

+ 26 - 0
app/model/ground.js

@@ -0,0 +1,26 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+const { ObjectId } = require('mongoose').Types;
+const source = 'race';
+// 表
+const ground = {
+  name: { type: String, zh: '场地名' },
+  remark: { type: String },
+};
+const schema = new Schema(ground, { toJSON: { virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.plugin(metaPlugin);
+module.exports = app => {
+  const is_multiple = app.mongooseDB.clients;
+  let model;
+  if (is_multiple) {
+    const conn = app.mongooseDB.get(source);
+    model = conn.model('Ground', schema, 'ground');
+  } else {
+    const { mongoose } = app;
+    model = mongoose.model('Ground', schema, 'ground');
+  }
+  return model;
+};

+ 30 - 0
app/model/race.js

@@ -0,0 +1,30 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+const { ObjectId } = require('mongoose').Types;
+const source = 'race';
+// 表
+const race = {
+  title: { type: String, zh: '比赛名称' },
+  user: { type: String, zh: '用户', ref: 'base.User', getProp: [ 'name' ] },
+  ground: { type: String, zh: '场地', ref: 'Ground', getProp: [ 'name' ] },
+  player: { type: String, zh: '选手', refPath: 'player_from', getProp: [ 'name' ] },
+  player_from: { type: String, zh: '选手数据来源' },
+  remark: { type: String },
+};
+const schema = new Schema(race, { toJSON: { virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.plugin(metaPlugin);
+module.exports = app => {
+  const is_multiple = app.mongooseDB.clients;
+  let model;
+  if (is_multiple) {
+    const conn = app.mongooseDB.get(source);
+    model = conn.model('Race', schema, 'race');
+  } else {
+    const { mongoose } = app;
+    model = mongoose.model('Race', schema, 'race');
+  }
+  return model;
+};

+ 43 - 0
app/model/race/match.js

@@ -0,0 +1,43 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+// 比赛信息
+const match = {
+  logo: { type: Array, required: true, zh: '比赛logo' }, // 比赛logo
+  name: { type: String, required: true, zh: '比赛名称' }, // 比赛名称
+  start_time: { type: String, required: true, zh: '比赛开始时间' }, // 比赛开始时间
+  end_time: { type: String, required: true, zh: '比赛结束时间' }, // 比赛结束时间
+  address: { type: String, required: true, zh: '比赛地点' }, // 比赛地点
+  sign_time: { type: String, required: true, zh: '报名截止时间' }, // 报名截止时间
+  money_remark: { type: String, required: false, zh: '报名费用说明' }, // 报名费用说明
+  money_mode: { type: String, required: false, zh: '付款方式' }, // 付款方式
+  contact: { type: String, required: true, zh: '联系方式' }, // 联系方式
+  explain: { type: String, required: false, zh: '报名说明' }, // 报名说明
+  regular: { type: String, required: false, zh: '赛事规程' }, // 赛事规程
+  status: { type: String, required: true, default: '0', zh: '比赛状态', ref: 'dict', getProp: [ 'label' ] }, // 字典表中的标签
+};
+const schema = new Schema(match, { toJSON: { getters: true, virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.index({ name: 1 });
+schema.index({ start_time: 1 });
+schema.index({ end_time: 1 });
+schema.index({ sign_time: 1 });
+schema.index({ contact: 1 });
+schema.index({ status: 1 });
+
+schema.plugin(metaPlugin);
+
+const source = 'race';
+module.exports = app => {
+  const is_multiple = app.mongooseDB.clients;
+  let model;
+  if (is_multiple) {
+    const conn = app.mongooseDB.get(source);
+    model = conn.model('Match', schema, 'match');
+  } else {
+    const { mongoose } = app;
+    model = mongoose.model('Match', schema, 'match');
+  }
+  return model;
+};

+ 32 - 0
app/model/race/matchGroup.js

@@ -0,0 +1,32 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+const source = 'race';
+
+// 赛事组别
+const match_group = {
+  match_id: { type: String, required: true, zh: '赛事id', ref: 'match', getProp: [ 'name' ] }, // 比赛信息中的比赛名称
+  name: { type: String, required: true, zh: '名称' }, //
+  age: { type: String, required: false, zh: '年龄限制' }, //
+  explain: { type: String, required: false, zh: '说明' }, //
+};
+const schema = new Schema(match_group, { toJSON: { getters: true, virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.index({ match_id: 1 });
+schema.index({ name: 1 });
+
+schema.plugin(metaPlugin);
+
+module.exports = app => {
+  const is_multiple = app.mongooseDB.clients;
+  let model;
+  if (is_multiple) {
+    const conn = app.mongooseDB.get(source);
+    model = conn.model('MatchGroup', schema, 'matchGroup');
+  } else {
+    const { mongoose } = app;
+    model = mongoose.model('MatchGroup', schema, 'matchGroup');
+  }
+  return model;
+};

+ 38 - 0
app/model/race/matchProject.js

@@ -0,0 +1,38 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+
+// 组别项目
+const match_project = {
+  match_id: { type: String, required: true, zh: '赛事id', ref: 'match', getProp: [ 'name' ] }, // 比赛信息中的比赛名称
+  group_id: { type: String, required: true, zh: '赛事分组id', ref: 'match_group', getProp: [ 'name' ] }, // 赛事分组中的组名称
+  type: { type: String, required: true, zh: '项目类别', ref: 'dict', getProp: [ 'label' ] }, // 字典表中的标签
+  name: { type: String, required: true, zh: '名称' }, //
+  age: { type: String, required: false, zh: '年龄限制' }, //
+  gender: { type: String, required: false, zh: '性别限制', ref: 'dict', getProp: [ 'label' ] }, // 字典表中的标签
+  num: { type: Number, required: false, zh: '人数限制' }, //
+  explain: { type: String, required: false, zh: '说明' }, //
+};
+const schema = new Schema(match_project, { toJSON: { getters: true, virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.index({ match_id: 1 });
+schema.index({ group_id: 1 });
+schema.index({ type: 1 });
+schema.index({ name: 1 });
+
+schema.plugin(metaPlugin);
+
+const source = 'race';
+module.exports = app => {
+  const is_multiple = app.mongooseDB.clients;
+  let model;
+  if (is_multiple) {
+    const conn = app.mongooseDB.get(source);
+    model = conn.model('MatchProject', schema, 'matchProject');
+  } else {
+    const { mongoose } = app;
+    model = mongoose.model('MatchProject', schema, 'matchProject');
+  }
+  return model;
+};

+ 40 - 0
app/model/race/matchSign.js

@@ -0,0 +1,40 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+
+// 赛事报名
+const match_sign = {
+  match_id: { type: String, required: true, zh: '赛事id', ref: 'match', getProp: [ 'name' ] }, // 比赛信息中的名称
+  group_id: { type: String, required: true, zh: '组别id', ref: 'match_group', getProp: [ 'name' ] }, // 赛事组别中的名称
+  project_id: { type: String, required: true, zh: '项目id', ref: 'match_project', getProp: [ 'name' ] }, // 组别项目中的名称
+  user_id: { type: String, required: true, zh: '用户id' }, //
+  is_share: { type: Boolean, required: false, zh: '是否转发' }, //
+  pay_id: { type: String, required: false, zh: '账单id' }, //
+  pay_status: { type: String, required: false, zh: '账单状态' }, //
+};
+const schema = new Schema(match_sign, { toJSON: { getters: true, virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.index({ match_id: 1 });
+schema.index({ group_id: 1 });
+schema.index({ project_id: 1 });
+schema.index({ user_id: 1 });
+schema.index({ is_share: 1 });
+schema.index({ pay_id: 1 });
+schema.index({ pay_status: 1 });
+
+schema.plugin(metaPlugin);
+
+const source = 'race';
+module.exports = app => {
+  const is_multiple = app.mongooseDB.clients;
+  let model;
+  if (is_multiple) {
+    const conn = app.mongooseDB.get(source);
+    model = conn.model('MatchSign', schema, 'matchSign');
+  } else {
+    const { mongoose } = app;
+    model = mongoose.model('MatchSign', schema, 'matchSign');
+  }
+  return model;
+};

+ 44 - 0
app/model/race/teamApply.js

@@ -0,0 +1,44 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+
+// 组队申请
+const team_apply = {
+  match_id: { type: String, required: true, zh: '赛事id', ref: 'match', getProp: [ 'name' ] }, // 比赛信息表中的名称
+  group_id: { type: String, required: true, zh: '组别id', ref: 'match_group', getProp: [ 'name' ] }, // 赛事组别中的名称
+  project_id: { type: String, required: true, zh: '项目id', ref: 'match_project', getProp: [ 'name' ] }, // 组别项目中的名称
+  one_member_id: { type: String, required: true, zh: '成员一id' }, //
+  one_member_name: { type: String, required: true, zh: '成员一姓名' }, //
+  two_member_id: { type: String, required: true, zh: '成员二id' }, //
+  two_member_name: { type: String, required: true, zh: '成员二姓名' }, //
+  apply_time: { type: String, required: true, zh: '申请时间' }, //
+  status: { type: String, required: false, default: '0', zh: '状态', ref: 'dict', getProp: [ 'label' ] }, // 字典表中公共审核状态-code:examine_status
+};
+const schema = new Schema(team_apply, { toJSON: { getters: true, virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.index({ match_id: 1 });
+schema.index({ group_id: 1 });
+schema.index({ project_id: 1 });
+schema.index({ one_member_id: 1 });
+schema.index({ one_member_name: 1 });
+schema.index({ two_member_id: 1 });
+schema.index({ two_member_name: 1 });
+schema.index({ apply_time: 1 });
+schema.index({ status: 1 });
+
+schema.plugin(metaPlugin);
+
+const source = 'race';
+module.exports = app => {
+  const is_multiple = app.mongooseDB.clients;
+  let model;
+  if (is_multiple) {
+    const conn = app.mongooseDB.get(source);
+    model = conn.model('TeamApply', schema, 'teamApply');
+  } else {
+    const { mongoose } = app;
+    model = mongoose.model('TeamApply', schema, 'teamApply');
+  }
+  return model;
+};

+ 27 - 0
app/public/routerRegister.js

@@ -0,0 +1,27 @@
+'use strict';
+/**
+ * 注册路由
+ * @param {App} app 全局变量
+ * @param {Array} routes 路由数组
+ * @param {String} keyZh 路由主题
+ * @param {String} rkey 路由主位置的标识
+ * @param {String} ckey 路由对应的controller的标识
+ */
+const _ = require('lodash');
+module.exports = (app, routes, keyZh, rkey, ckey) => {
+  const { router, config } = app;
+  const mwares = app.middleware;
+  if (process.env.NODE_ENV === 'development') console.log(`${keyZh}:  ${rkey}`);
+  for (const route of routes) {
+    const { method, path, controller: ctl, zh } = route;
+    let { middleware = [] } = route;
+    if (!method || !path || !ctl) continue;
+    // 拼全路径
+    const allPath = `${config.routePrefix}/${path}`;
+    if (process.env.NODE_ENV === 'development') console.log(`     ${zh}: ${allPath}`);
+    // 处理中间件
+    if (middleware.length > 0) middleware = middleware.map(i => _.get(mwares, i)({ enable: true, model: ckey || rkey }));
+    // 注册路由
+    router[method](zh, allPath, ...middleware, ctl);
+  }
+};

+ 31 - 0
app/router.js

@@ -0,0 +1,31 @@
+'use strict';
+
+/**
+ * @param {Egg.Application} app - egg application
+ */
+
+const os = require('os');
+function getIPAdress() {
+  const interfaces = os.networkInterfaces();
+  for (const devName in interfaces) {
+    const iface = interfaces[devName];
+    for (let i = 0; i < iface.length; i++) {
+      const alias = iface[i];
+      if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
+        return alias.address;
+      }
+    }
+  }
+}
+module.exports = app => {
+  const { router, controller } = app;
+  const { routePrefix, cluster } = app.config;
+  const ipAddress = getIPAdress();
+  console.log(`前缀:http://${ipAddress}:${cluster.listen.port}${routePrefix}`);
+  router.get('/', controller.home.index);
+  require('./z_router/match')(app); // 比赛信息
+  require('./z_router/matchGroup')(app); // 比赛组别
+  require('./z_router/matchProject')(app); // 组别项目
+  require('./z_router/teamApply')(app); // 组队申请
+  require('./z_router/matchSign')(app); // 赛事报名
+};

+ 15 - 0
app/service/match.js

@@ -0,0 +1,15 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+
+// 
+class MatchService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'match');
+    this.model = this.ctx.model.Race.Match;
+  }
+}
+
+module.exports = MatchService;

+ 15 - 0
app/service/matchGroup.js

@@ -0,0 +1,15 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+
+// 
+class MatchGroupService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'matchgroup');
+    this.model = this.ctx.model.Race.MatchGroup;
+  }
+}
+
+module.exports = MatchGroupService;

+ 15 - 0
app/service/matchProject.js

@@ -0,0 +1,15 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+
+// 
+class MatchProjectService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'matchproject');
+    this.model = this.ctx.model.Race.MatchProject;
+  }
+}
+
+module.exports = MatchProjectService;

+ 15 - 0
app/service/matchSign.js

@@ -0,0 +1,15 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+
+// 
+class MatchSignService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'matchsign');
+    this.model = this.ctx.model.Race.MatchSign;
+  }
+}
+
+module.exports = MatchSignService;

+ 15 - 0
app/service/race.js

@@ -0,0 +1,15 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+
+//
+class RaceService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'race');
+    this.model = this.ctx.model.Race;
+  }
+}
+
+module.exports = RaceService;

+ 15 - 0
app/service/teamApply.js

@@ -0,0 +1,15 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+
+// 
+class TeamApplyService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'teamapply');
+    this.model = this.ctx.model.Race.TeamApply;
+  }
+}
+
+module.exports = TeamApplyService;

+ 83 - 0
app/service/util/http-util.js

@@ -0,0 +1,83 @@
+'use strict';
+const { AxiosService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const { isNullOrUndefined } = require('naf-core').Util;
+const _ = require('lodash');
+
+//
+class HttpUtilService extends AxiosService {
+  constructor(ctx) {
+    super(ctx, {}, {});
+  }
+
+  // 替换uri中的参数变量
+  merge(uri, query = {}) {
+    const keys = Object.keys(query);
+    const arr = [];
+    for (const k of keys) {
+      arr.push(`${k}=${query[k]}`);
+    }
+    if (arr.length > 0) {
+      uri = `${uri}?${arr.join('&')}`;
+    }
+    return uri;
+  }
+
+  /**
+   * curl-get请求
+   * @param {String} uri 接口地址
+   * @param {Object} query 地址栏参数
+   * @param {Object} options 额外参数
+   */
+  async cget(uri, query, options) {
+    return this.toRequest(uri, null, query, options);
+  }
+
+  /**
+   * curl-post请求
+   * @param {String} uri 接口地址
+   * @param {Object} data post的body
+   * @param {Object} query 地址栏参数
+   * @param {Object} options 额外参数
+   */
+  async cpost(uri, data = {}, query, options) {
+    return this.toRequest(uri, data, query, options);
+  }
+
+  async toRequest(uri, data, query, options) {
+    query = _.pickBy(query, val => val !== '' && val !== 'undefined' && val !== 'null');
+    if (!uri) console.error('uri不能为空');
+    if (_.isObject(query) && _.isObject(options)) {
+      const params = query.params ? query.params : query;
+      options = { ...options, params };
+    } else if (_.isObject(query) && !query.params) {
+      options = { params: query };
+    } else if (_.isObject(query) && query.params) {
+      options = query;
+    }
+    const headers = { 'content-type': 'application/json' };
+    console.log(uri);
+    const url = this.merge(`${uri}`, options.params);
+    let res = await this.ctx.curl(url, {
+      method: isNullOrUndefined(data) ? 'get' : 'post',
+      url,
+      data,
+      dataType: 'json',
+      headers,
+      ...options,
+    });
+    if (res.status === 200) {
+      res = res.data || {};
+      const { errcode, errmsg, details } = res;
+      if (errcode) {
+        console.warn(`[${uri}] fail: ${errcode}-${errmsg} ${details}`);
+        return { errcode, errmsg };
+      }
+      return res.data;
+    }
+    const { status } = res;
+    console.warn(`[${uri}] fail: ${status}-${res.data.message} `);
+  }
+}
+
+module.exports = HttpUtilService;

+ 35 - 0
app/service/util/install.js

@@ -0,0 +1,35 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+
+// 初始化
+class InstallService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'install');
+    this.model = this.ctx.model.Install;
+  }
+  async init() {
+    // this.initAdmin();
+  }
+
+  async initAdmin() {
+    console.log('开始=>初始化总管理员'.blue);
+    const data = await this.ctx.model.Admin.findOne();
+    if (!data) {
+      // 没有管理员,初始化一个
+      const data = {
+        account: 'admin',
+        is_super: true,
+        password: { secret: '111111' },
+        _tenant: 'master',
+      };
+      console.log('正在初始化总管理员'.blue);
+      await this.ctx.model.Admin.create(data);
+      console.log('初始化总管理员=>结束'.green);
+    } else console.log('无需再次初始化总管理员'.yellow);
+  }
+}
+
+module.exports = InstallService;

+ 18 - 0
app/service/util/jwt.js

@@ -0,0 +1,18 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const jwt = require('jsonwebtoken');
+
+// jsonWebToken处理
+class JwtService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'jwt');
+  }
+
+  encrypt(data) {
+    const { secret } = this.config.jwt;
+    const token = jwt.sign(data, secret);
+    return token;
+  }
+}
+
+module.exports = JwtService;

+ 74 - 0
app/service/util/rabbitMq.js

@@ -0,0 +1,74 @@
+'use strict';
+
+const Service = require('egg').Service;
+const _ = require('lodash');
+
+class RabbitmqService extends Service {
+  // mission队列处理
+  async mission() {
+    const { mq } = this.ctx;
+    const { queue } = this.ctx.app.config;
+    if (mq && queue) {
+      const ch = await mq.conn.createChannel();
+      // const queue = 'freeAdmin/server-user';
+      try {
+        // 创建队列:在没有队列的情况,直接获取会导致程序无法启动
+        await ch.assertQueue(queue, { durable: false });
+        await ch.consume(queue, msg => this.dealMission(msg), { noAck: true });
+      } catch (error) {
+        this.ctx.logger.error('未找到订阅的队列');
+      }
+    } else {
+      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
+    }
+  }
+  // 执行任务
+  async dealMission(bdata) {
+    //   if (!bdata) this.ctx.logger.error('mission队列中信息不存在');
+    //   let data = bdata.content.toString();
+    //   try {
+    //     data = JSON.parse(data);
+    //   } catch (error) {
+    //     this.ctx.logger.error('数据不是object');
+    //   }
+    //   const { service, method, project, ...others } = data;
+    //   const arr = service.split('.');
+    //   let s = this.ctx.service;
+    //   for (const key of arr) {
+    //     s = s[key];
+    //   }
+    //   s[method](others);
+  }
+
+  /**
+   * 发送队列消息
+   * @param {Any} data 消息队列数据
+   * @param {String} queueKey 消息队列可以
+   */
+  async sendToMqQueue(data, queueKey) {
+    const { mq } = this.ctx;
+    const { sendQueue } = this.ctx.app.config;
+    let queue;
+    // 获取队列名称
+    if (_.isObject(sendQueue)) {
+      queue = sendQueue[queueKey];
+    }
+    if (mq && queue) {
+      if (!_.isString(data)) data = JSON.stringify(data);
+      const ch = await mq.conn.createChannel();
+      try {
+        // 创建队列:在没有队列的情况,直接获取会导致程序无法启动
+        // await ch.assertQueue(queue, { durable: false });
+        await ch.sendToQueue(queue, Buffer.from(data));
+        await ch.close();
+      } catch (error) {
+        console.error(error);
+        this.ctx.logger.error('mq消息发送失败');
+      }
+    } else {
+      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
+    }
+  }
+}
+
+module.exports = RabbitmqService;

+ 19 - 0
app/z_router/match.js

@@ -0,0 +1,19 @@
+'use strict';
+// 路由配置
+const path = require('path');
+const regPath = path.resolve('app', 'public', 'routerRegister');
+const routerRegister = require(regPath);
+const rkey = 'match';
+const ckey = 'match';
+const keyZh = '比赛信息';
+const routes = [
+  { method: 'get', path: `${rkey}`, controller: `${ckey}.index`, name: `${ckey}Query`, zh: `${keyZh}列表查询` },
+  { method: 'get', path: `${rkey}/:id`, controller: `${ckey}.show`, name: `${ckey}Show`, zh: `${keyZh}查询` },
+  { method: 'post', path: `${rkey}`, controller: `${ckey}.create`, middleware: [ 'password' ], name: `${ckey}Create`, zh: `创建${keyZh}` },
+  { method: 'post', path: `${rkey}/:id`, controller: `${ckey}.update`, name: `${ckey}Update`, zh: `修改${keyZh}` },
+  { method: 'delete', path: `${rkey}/:id`, controller: `${ckey}.destroy`, name: `${ckey}Delete`, zh: `删除${keyZh}` },
+];
+
+module.exports = app => {
+  routerRegister(app, routes, keyZh, rkey, ckey);
+};

+ 19 - 0
app/z_router/matchGroup.js

@@ -0,0 +1,19 @@
+'use strict';
+// 路由配置
+const path = require('path');
+const regPath = path.resolve('app', 'public', 'routerRegister');
+const routerRegister = require(regPath);
+const rkey = 'matchGroup';
+const ckey = 'matchGroup';
+const keyZh = '比赛组别';
+const routes = [
+  { method: 'get', path: `${rkey}`, controller: `${ckey}.index`, name: `${ckey}Query`, zh: `${keyZh}列表查询` },
+  { method: 'get', path: `${rkey}/:id`, controller: `${ckey}.show`, name: `${ckey}Show`, zh: `${keyZh}查询` },
+  { method: 'post', path: `${rkey}`, controller: `${ckey}.create`, middleware: [ 'password' ], name: `${ckey}Create`, zh: `创建${keyZh}` },
+  { method: 'post', path: `${rkey}/:id`, controller: `${ckey}.update`, name: `${ckey}Update`, zh: `修改${keyZh}` },
+  { method: 'delete', path: `${rkey}/:id`, controller: `${ckey}.destroy`, name: `${ckey}Delete`, zh: `删除${keyZh}` },
+];
+
+module.exports = app => {
+  routerRegister(app, routes, keyZh, rkey, ckey);
+};

+ 19 - 0
app/z_router/matchProject.js

@@ -0,0 +1,19 @@
+'use strict';
+// 路由配置
+const path = require('path');
+const regPath = path.resolve('app', 'public', 'routerRegister');
+const routerRegister = require(regPath);
+const rkey = 'matchProject';
+const ckey = 'matchProject';
+const keyZh = '组别项目';
+const routes = [
+  { method: 'get', path: `${rkey}`, controller: `${ckey}.index`, name: `${ckey}Query`, zh: `${keyZh}列表查询` },
+  { method: 'get', path: `${rkey}/:id`, controller: `${ckey}.show`, name: `${ckey}Show`, zh: `${keyZh}查询` },
+  { method: 'post', path: `${rkey}`, controller: `${ckey}.create`, middleware: [ 'password' ], name: `${ckey}Create`, zh: `创建${keyZh}` },
+  { method: 'post', path: `${rkey}/:id`, controller: `${ckey}.update`, name: `${ckey}Update`, zh: `修改${keyZh}` },
+  { method: 'delete', path: `${rkey}/:id`, controller: `${ckey}.destroy`, name: `${ckey}Delete`, zh: `删除${keyZh}` },
+];
+
+module.exports = app => {
+  routerRegister(app, routes, keyZh, rkey, ckey);
+};

+ 19 - 0
app/z_router/matchSign.js

@@ -0,0 +1,19 @@
+'use strict';
+// 路由配置
+const path = require('path');
+const regPath = path.resolve('app', 'public', 'routerRegister');
+const routerRegister = require(regPath);
+const rkey = 'matchSign';
+const ckey = 'matchSign';
+const keyZh = '赛事报名';
+const routes = [
+  { method: 'get', path: `${rkey}`, controller: `${ckey}.index`, name: `${ckey}Query`, zh: `${keyZh}列表查询` },
+  { method: 'get', path: `${rkey}/:id`, controller: `${ckey}.show`, name: `${ckey}Show`, zh: `${keyZh}查询` },
+  { method: 'post', path: `${rkey}`, controller: `${ckey}.create`, middleware: [ 'password' ], name: `${ckey}Create`, zh: `创建${keyZh}` },
+  { method: 'post', path: `${rkey}/:id`, controller: `${ckey}.update`, name: `${ckey}Update`, zh: `修改${keyZh}` },
+  { method: 'delete', path: `${rkey}/:id`, controller: `${ckey}.destroy`, name: `${ckey}Delete`, zh: `删除${keyZh}` },
+];
+
+module.exports = app => {
+  routerRegister(app, routes, keyZh, rkey, ckey);
+};

+ 19 - 0
app/z_router/teamApply.js

@@ -0,0 +1,19 @@
+'use strict';
+// 路由配置
+const path = require('path');
+const regPath = path.resolve('app', 'public', 'routerRegister');
+const routerRegister = require(regPath);
+const rkey = 'teamApply';
+const ckey = 'teamApply';
+const keyZh = '组队申请';
+const routes = [
+  { method: 'get', path: `${rkey}`, controller: `${ckey}.index`, name: `${ckey}Query`, zh: `${keyZh}列表查询` },
+  { method: 'get', path: `${rkey}/:id`, controller: `${ckey}.show`, name: `${ckey}Show`, zh: `${keyZh}查询` },
+  { method: 'post', path: `${rkey}`, controller: `${ckey}.create`, middleware: [ 'password' ], name: `${ckey}Create`, zh: `创建${keyZh}` },
+  { method: 'post', path: `${rkey}/:id`, controller: `${ckey}.update`, name: `${ckey}Update`, zh: `修改${keyZh}` },
+  { method: 'delete', path: `${rkey}/:id`, controller: `${ckey}.destroy`, name: `${ckey}Delete`, zh: `删除${keyZh}` },
+];
+
+module.exports = app => {
+  routerRegister(app, routes, keyZh, rkey, ckey);
+};

+ 14 - 0
appveyor.yml

@@ -0,0 +1,14 @@
+environment:
+  matrix:
+    - nodejs_version: '10'
+
+install:
+  - ps: Install-Product node $env:nodejs_version
+  - npm i npminstall && node_modules\.bin\npminstall
+
+test_script:
+  - node --version
+  - npm --version
+  - npm run test
+
+build: off

+ 147 - 0
config/config.default.js

@@ -0,0 +1,147 @@
+/* eslint valid-jsdoc: "off" */
+
+'use strict';
+
+/**
+ * @param {Egg.EggAppInfo} appInfo app info
+ */
+const { jwt } = require('./config.secret');
+module.exports = appInfo => {
+  /**
+   * built-in config
+   * @type {Egg.EggAppConfig}
+   **/
+  const config = (exports = {});
+
+  // use for cookie sign key, should change to your own and keep security
+  config.keys = appInfo.name + '_1640765284662_2781';
+
+  // add your middleware config here
+  config.middleware = [ 'requestLog' ];
+
+  // add your user config here
+  const userConfig = {
+    // myAppName: 'egg',
+  };
+  // 日志
+  config.logger = {
+    level: 'DEBUG',
+    allowDebugAtProd: true,
+  };
+  // mq设置
+  // config.amqp = {
+  //   client: {
+  //     hostname: '127.0.0.1',
+  //     username: 'freeAdmin',
+  //     password: '1qaz2wsx',
+  //     vhost: 'freeAdmin',
+  //   },
+  //   app: true,
+  //   agent: true,
+  // };
+  // 接收队列名称
+  // config.queue = 'freeAdmin/server-haocai-new';
+  // 发送队列名称
+  // config.sendQueue = {
+  //   logs: 'freeAdmin/server-logs',
+  // };
+  // http请求前缀
+  config.httpPrefix = {
+    // wechat: 'http://127.0.0.1:14001/wechat/api',
+    wechat: 'https://broadcast.waityou24.cn/wechat/api',
+  };
+  // 微信小程序消息模板
+  config.msgTemplate = {
+    exit: {
+      template_id: 'XC1Is016sqt09_3PsyySYKFtwdrLUqggdn5qIvOiSNI',
+      data: [
+        { key: 'thing1', value: { value: '活动名称' } },
+        { key: 'thing2', value: { value: '项目名称' } },
+        { key: 'time3', value: { value: '申请时间' } },
+        { key: 'amount4', value: { value: '退款金额' } },
+      ],
+    },
+    enroll: {
+      template_id: 'HClmobxtn7b4qunUBF5a5y68cwak8d7VSwqGY0vAx1U',
+      data: [
+        { key: 'thing1', value: { value: '比赛名称' } },
+        { key: 'thing4', value: { value: '赛事类型' } },
+        { key: 'thing5', value: { value: '参赛者姓名' } },
+        { key: 'thing8', value: { value: '报名审核结果' } },
+        { key: 'time2', value: { value: '报名时间' } },
+      ],
+    },
+    remind: {
+      template_id: 'cq3JPX9RMFdEGjH9dBn6n5P5CFCJJ9Q8LIljZlJgBlM',
+      data: [
+        { key: 'thing1', value: { value: '比赛名称' } },
+        { key: 'thing2', value: { value: '比赛时间' } },
+        { key: 'thing4', value: { value: '赛制' } },
+        { key: 'thing7', value: { value: '比赛地点' } },
+        { key: 'thing8', value: { value: '参赛选手' } },
+      ],
+    },
+  };
+
+  // redis设置
+  // config.redis = {
+  //   client: {
+  //     port: 6379, // Redis port
+  //     host: '127.0.0.1', // Redis host
+  //     password: '123456',
+  //     db: 0,
+  //   },
+  // };
+  // 进程设置
+  config.cluster = {
+    listen: {
+      port: 15001,
+    },
+  };
+
+  // jwt设置
+  config.jwt = {
+    ...jwt,
+    expiresIn: '1d',
+    issuer: 'new_court',
+  };
+
+  // 数据库设置
+  config.dbName = 'court_race_v2';
+  config.baseDbName = 'court_v2';
+  config.mongoose = {
+    clients: {
+      base: {
+        url: `mongodb://127.0.0.1:27017/${config.baseDbName}`, // 120.48.146.1 127.0.0.1
+        options: {
+          user: 'admin',
+          pass: 'admin',
+          authSource: 'admin',
+          useNewUrlParser: true,
+          useCreateIndex: true,
+        },
+      },
+      race: {
+        url: `mongodb://127.0.0.1:27017/${config.dbName}`, // 120.48.146.1 127.0.0.1
+        options: {
+          user: 'admin',
+          pass: 'admin',
+          authSource: 'admin',
+          useNewUrlParser: true,
+          useCreateIndex: true,
+        },
+      },
+    },
+  };
+  // 路由设置
+  config.routePrefix = '/newCourt/race/v2/api';
+
+  // 中间件
+  config.requestLog = {
+    toMongoDB: true,
+  };
+  return {
+    ...config,
+    ...userConfig,
+  };
+};

+ 46 - 0
config/config.prod.js

@@ -0,0 +1,46 @@
+'use strict';
+
+module.exports = () => {
+  const config = (exports = {});
+
+  config.logger = {
+    level: 'INFO',
+    consoleLevel: 'INFO',
+  };
+  // http请求前缀
+  config.httpPrefix = {
+    wechat: 'http://localhost:14001/wechat/api',
+  };
+  // config.dbName = 'new-platform';
+  // config.mongoose = {
+  //   url: `mongodb://localhost:27017/${config.dbName}`,
+  //   options: {
+  //     user: 'admin',
+  //     pass: 'admin',
+  //     authSource: 'admin',
+  //     useNewUrlParser: true,
+  //     useCreateIndex: true,
+  //   },
+  // };
+  // // redis config
+  // config.redis = {
+  //   client: {
+  //     port: 6379, // Redis port
+  //     host: '127.0.0.1', // Redis host
+  //     password: 123456,
+  //     db: 0,
+  //   },
+  // };
+
+  // config.export = {
+  //   root_path: 'D:\\free\\workspace\\server\\service-file\\upload',
+  //   export_path: 'D:\\free\\workspace\\server\\service-file\\upload\\export',
+  //   export_dir: 'export',
+  //   patentInfo_dir: 'patentInfo',
+  //   domain: 'http://127.0.0.1',
+  // };
+  // config.import = {
+  //   root_path: 'D:\\free\\workspace\\server\\service-file\\upload',
+  // };
+  return config;
+};

+ 7 - 0
config/config.secret.js

@@ -0,0 +1,7 @@
+'use strict';
+
+module.exports = {
+  jwt: {
+    secret: 'Ziyouyanfa!@#',
+  },
+};

+ 11 - 0
config/plugin.js

@@ -0,0 +1,11 @@
+'use strict';
+// rabbitMq
+// exports.amqp = {
+//   enable: true,
+//   package: 'egg-naf-amqp',
+// };
+// // redis
+// exports.redis = {
+//   enable: true,
+//   package: 'egg-redis',
+// };

+ 18 - 0
ecosystem.config.js

@@ -0,0 +1,18 @@
+'use strict';
+
+// const app = 'server-group-business';
+const app = '赛场-服务-v2';
+module.exports = {
+  apps: [{
+    name: app, // 应用名称
+    script: './server.js', // 实际启动脚本
+    out: `./logs/${app}.log`,
+    error: `./logs/${app}.err`,
+    watch: [ // 监控变化的目录,一旦变化,自动重启
+      'app', 'config',
+    ],
+    env: {
+      NODE_ENV: 'production', // 环境参数,当前指定为生产环境
+    },
+  }],
+};

+ 53 - 0
package.json

@@ -0,0 +1,53 @@
+{
+  "name": "server-court-v2",
+  "version": "1.0.0",
+  "description": "新赛场v2",
+  "private": true,
+  "egg": {
+    "framework": "naf-framework-mongoose-free"
+  },
+  "dependencies": {
+    "colors": "^1.4.0",
+    "egg": "^2.15.1",
+    "egg-naf-amqp": "0.0.13",
+    "egg-redis": "^2.4.0",
+    "egg-scripts": "^2.11.0",
+    "lodash": "^4.17.21",
+    "moment": "^2.29.1",
+    "naf-framework-mongoose-free": "^0.0.34"
+  },
+  "devDependencies": {
+    "autod": "^3.0.1",
+    "autod-egg": "^1.1.0",
+    "egg-bin": "^4.11.0",
+    "egg-ci": "^1.11.0",
+    "egg-mock": "^3.21.0",
+    "eslint": "^5.13.0",
+    "eslint-config-egg": "^7.1.0",
+    "jsonwebtoken": "^8.5.1"
+  },
+  "engines": {
+    "node": ">=10.0.0"
+  },
+  "scripts": {
+    "start": "egg-scripts start --daemon --title=egg-server-server-user",
+    "stop": "egg-scripts stop --title=egg-server-server-user",
+    "dev": "egg-bin dev",
+    "debug": "egg-bin debug",
+    "test": "npm run lint -- --fix && npm run test-local",
+    "test-local": "egg-bin test",
+    "cov": "egg-bin cov",
+    "lint": "eslint .",
+    "ci": "npm run lint && npm run cov",
+    "autod": "autod"
+  },
+  "ci": {
+    "version": "10"
+  },
+  "repository": {
+    "type": "git",
+    "url": ""
+  },
+  "author": "lrf",
+  "license": "MIT"
+}

+ 10 - 0
server.js

@@ -0,0 +1,10 @@
+
+// eslint-disable-next-line strict
+const egg = require('egg');
+// const l = process.argv[2] || require('os').cpus().length;
+const l = 1;
+const workers = Number(l);
+egg.startCluster({
+  workers,
+  baseDir: __dirname,
+});

+ 3 - 0
update.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+git pull && pm2 restart $1