├── .editorconfig
├── .gitignore
├── .prettierrc
├── .vscode
├── launch.json
└── settings.json
├── Dockerfile
├── README.md
├── build
└── BuildCover.js
├── config
├── ConfigDB.ts
├── ConfigDefault.ts
├── ConfigDev.ts
└── ConfigProd.ts
├── docker-compose.yml
├── docs
├── 1567861669077.jpg
└── 1569804144167.jpg
├── index.d.ts
├── jest.json
├── nodemon.json
├── nuxt.config.ts
├── package.json
├── src
├── client
│ ├── assets
│ │ ├── README.md
│ │ └── style
│ │ │ └── App.styl
│ ├── common
│ │ ├── CommonCart.ts
│ │ └── CommonCookie.ts
│ ├── components
│ │ ├── ComponentHeader.vue
│ │ ├── ComponentLoading.vue
│ │ ├── ComponentLogo.vue
│ │ ├── ComponentTwitter.vue
│ │ └── README.md
│ ├── core
│ │ ├── consts
│ │ │ └── ConstHttp.ts
│ │ ├── interfaces
│ │ │ ├── IView.ts
│ │ │ └── IVo.ts
│ │ ├── service
│ │ │ ├── ServiceBase.ts
│ │ │ ├── ServiceConfig.ts
│ │ │ └── ServiceTransport.ts
│ │ └── views
│ │ │ └── ViewBase.ts
│ ├── layouts
│ │ ├── LayoutDefault.vue
│ │ ├── LayoutError.vue
│ │ └── README.md
│ ├── middleware
│ │ ├── MiddlewareMobile.ts
│ │ ├── MiddlewareNotAuthenticated.ts
│ │ └── README.md
│ ├── models
│ │ ├── ModelCarts.ts
│ │ ├── ModelPost.ts
│ │ └── ModelUser.ts
│ ├── pages
│ │ ├── README.md
│ │ ├── auth
│ │ │ └── login
│ │ │ │ └── index.vue
│ │ ├── cart
│ │ │ └── index.vue
│ │ ├── error
│ │ │ ├── 400
│ │ │ │ └── index.vue
│ │ │ └── 500
│ │ │ │ └── index.vue
│ │ ├── goods
│ │ │ └── index.vue
│ │ ├── index.vue
│ │ └── list
│ │ │ └── index.vue
│ ├── plugins
│ │ ├── PluginAxios.ts
│ │ ├── PluginFlexible.js
│ │ ├── PluginVant.ts
│ │ └── README.md
│ ├── routers
│ │ └── RoutersClient.ts
│ ├── service
│ │ ├── ServiceCNode.ts
│ │ ├── ServiceLocal.ts
│ │ └── ServiceNews.ts
│ ├── static
│ │ ├── README.md
│ │ ├── about.js
│ │ ├── body.js
│ │ ├── carts.json
│ │ ├── defer.js
│ │ ├── favicon.ico
│ │ ├── friends.json
│ │ ├── goods.json
│ │ ├── head.js
│ │ ├── list.json
│ │ ├── robots.txt
│ │ └── v.png
│ └── store
│ │ ├── README.md
│ │ ├── index.ts
│ │ └── modules
│ │ ├── auth.ts
│ │ ├── carts.ts
│ │ └── root.ts
└── server
│ ├── AppController.ts
│ ├── AppModule.ts
│ ├── Main.ts
│ ├── common
│ ├── core
│ │ └── CommonEngineController.ts
│ ├── decorators
│ │ └── CommonRolesDecorator.ts
│ ├── filters
│ │ └── CommonHttpExceptionFilter.ts
│ ├── guards
│ │ └── CommonRolesGuard.ts
│ ├── interceptors
│ │ ├── CommonExceptionInterceptor.ts
│ │ ├── CommonLoggingInterceptor.ts
│ │ ├── CommonTimeoutInterceptor.ts
│ │ └── CommonTransformInterceptor.ts
│ ├── middleware
│ │ ├── CommonHttpMiddleware.ts
│ │ └── CommonLoggerMiddleware.ts
│ ├── nuxt
│ │ ├── CommonNuxtFilter.ts
│ │ └── CommonNuxtServer.ts
│ └── pipes
│ │ ├── CommonParseIntPipe.ts
│ │ └── CommonValidationPipe.ts
│ ├── modules
│ ├── cats
│ │ ├── CatsController.ts
│ │ ├── CatsModule.ts
│ │ ├── CatsService.ts
│ │ ├── dto
│ │ │ └── CatsCreateDto.ts
│ │ └── interfaces
│ │ │ └── ICats.ts
│ ├── db
│ │ ├── DBModule.ts
│ │ └── DBProviders.ts
│ ├── local
│ │ ├── LocalController.ts
│ │ ├── LocalModule.ts
│ │ ├── LocalProviders.ts
│ │ ├── LocalService.ts
│ │ ├── dto
│ │ │ ├── LocalAddCartsDto.ts
│ │ │ ├── LocalCardListItemDto.ts
│ │ │ ├── LocalCreateCatDto.ts
│ │ │ ├── LocalCreateGoodsDto.ts
│ │ │ └── LocalLoginDto.ts
│ │ ├── interfaces
│ │ │ ├── ICart.ts
│ │ │ ├── ICat.ts
│ │ │ ├── IGoods.ts
│ │ │ └── IUser.ts
│ │ └── schemas
│ │ │ ├── LocalCartSchema.ts
│ │ │ ├── LocalCatSchema.ts
│ │ │ ├── LocalGoodsSchema.ts
│ │ │ └── LocalUserSchema.ts
│ └── transport
│ │ ├── TransportController.ts
│ │ ├── TransportModule.ts
│ │ └── TransportService.ts
│ └── routers
│ └── RoutersServer.ts
├── tsconfig.json
├── tslint.json
└── webpack.config.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = tab
7 | indent_size = 4
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 | quote_type = single
11 |
12 | [*.md]
13 | max_line_length = off
14 | trim_trailing_whitespace = false
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 |
4 | # IDE
5 | /.idea
6 | /.awcache
7 |
8 | # misc
9 | npm-debug.log
10 |
11 | # tests
12 | /test
13 | /coverage
14 | /.nyc_output
15 |
16 | # dist
17 | /dist
18 | yarn.lock
19 | .nuxt
20 | .history
21 | config/config.env.ts
22 | config/env.config.ts
23 | yarn-error.log
24 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": true,
3 | "bracketSpacing": true,
4 | "jsxBracketSameLine": true,
5 | "tabWidth": 4,
6 | "useTabs": true,
7 | "singleQuote": true,
8 | "overrides": [{
9 | "files": ["*.json", ".eslintrc", ".tslintrc", ".prettierrc", ".tern-project"],
10 | "options": {
11 | "parser": "json",
12 | "tabWidth": 4
13 | }
14 | },
15 | {
16 | "files": "*.ts",
17 | "options": {
18 | "parser": "typescript"
19 | }
20 | }
21 | ]
22 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // 使用 IntelliSense 了解相关属性。
3 | // 悬停以查看现有属性的描述。
4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Nest.js Debug",
9 | "type": "node",
10 | "request": "launch",
11 | "cwd": "${workspaceFolder}",
12 | "runtimeExecutable": "npm",
13 | "runtimeArgs": ["run-script", "start:dev"],
14 | "port": 9229,
15 | "env": {
16 | "NODE_ENV": "development",
17 | "NodeLogStore": "local"
18 | },
19 | "sourceMaps": true,
20 | "protocol": "inspector",
21 | "console": "integratedTerminal",
22 | "internalConsoleOptions": "neverOpen",
23 | "autoAttachChildProcesses": true
24 | }
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.fontSize": 14,
3 | "editor.tabCompletion": "on",
4 | "editor.formatOnPaste": true,
5 | "editor.formatOnSave": true,
6 | "editor.formatOnType": true,
7 | "window.zoomLevel": 0,
8 | "terminal.integrated.fontSize": 14,
9 | "terminal.integrated.fontFamily": "Menlo, Monaco, 'Courier New', monospace",
10 | "files.exclude": {
11 | "_mock": true,
12 | "_nginx": true,
13 | ".history": true,
14 | ".idea": true,
15 | ".nuxt": true,
16 | ".vscode": true,
17 | "**/.DS_Store": true,
18 | "**/.git": true,
19 | "**/.hg": true,
20 | "**/.svn": true,
21 | "**/CVS": true,
22 | "config/config.env.ts": true,
23 | "config/env.config.ts": true,
24 | "coverage": true,
25 | "logs": true,
26 | "package-lock.json": true,
27 | "run": true,
28 | "test": true
29 | },
30 | "commentTranslate.targetLanguage": "zh-CN"
31 | }
32 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM keymetrics/pm2:latest-alpine
2 |
3 | # Create own api folder
4 | RUN mkdir -p /api
5 | WORKDIR /api
6 |
7 | # Install the dependencies
8 | ENV NPM_CONFIG_LOGLEVEL warn
9 | RUN npm i -g yarn
10 | COPY package.json .
11 | COPY yarn.lock .
12 | RUN yarn
13 |
14 | # Build the API
15 | COPY src src/
16 | COPY tsconfig.json .
17 | COPY config config/
18 | COPY build build/
19 | RUN yarn build
20 |
21 | # Expose the API port
22 | EXPOSE 8088
23 |
24 | # Run
25 | CMD [ "start" ]
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | ## Nuxt.js and Nest.js isomorphism project
4 |
5 |
Nuxt 和 Nest 集成示例工程, UI层使用 Vant框架实现
6 |
7 | ## 1.前置条件
8 |
9 | #### MongoDB
10 |
11 | > 工程中使用到了 MongoDB,需先在本地安装该服务
12 |
13 | [MongoDB 安装教程](https://docs.mongodb.com/manual/installation/)
14 |
15 | > 安装完成后使用以下命令启动:
16 |
17 | ```js
18 | mongod --config mongod配置目录/mongod.conf --dbpath 数据库存放目录
19 |
20 | 例如:
21 | mongod --config /usr/local/etc/mongod.conf --dbpath /usr/local/mongodir
22 | ```
23 |
24 |
25 |
26 | #### Charles
27 |
28 | > 对接接口时借助 Charles 抓包析工具能提升开发效率和快速定位问题,请注意 Charles 端口是否已设置为 8888(默认值)
29 |
30 | [Charles Web Debugging Proxy](https://www.charlesproxy.com/)
31 |
32 |
33 |
34 | ## 2.开发环境运行
35 |
36 | ```js
37 | npm run client:prod // local start on production mode
38 |
39 | npm run client:dev // local start on development mode
40 |
41 | visit: http://localhost:8088
42 | ```
43 |
44 | ## 3.生产环境运行
45 |
46 | ```js
47 | npm run build
48 |
49 | and
50 |
51 | cross-env NODE_ENV=production npm run start // server start on production mode
52 |
53 | cross-env NODE_ENV=development npm run start // server start on development mode
54 | ```
55 |
56 | ## 4.目录结构
57 |
58 | ```js
59 | client ---The client side source code folder, write Vue.js logical
60 | here
61 | |-------- assets
62 | |-------- components
63 | |-------- layouts
64 | |-------- middleware
65 | |-------- pages
66 | |-------- plugins
67 | |-------- static
68 | |-------- store
69 |
70 | server --- The server side(Node.js) logical here
71 | |-------- main.ts
72 | |-------- app.module.ts
73 | |-------- app.controller.ts
74 | |-------- common
75 | |--------- decorators
76 | |--------- filters
77 | |--------- guards
78 | |--------- interceptors
79 | |--------- middleware
80 | |--------- nuxt
81 | |--------- pipes
82 | |-------- routers
83 | |-------- modules
84 | |--------- modeule A..
85 | |--------- modeule B..
86 | |--------- modeule C..
87 | |--------- modeule D..
88 | ```
89 |
90 | ## 5.DataBase Proview
91 |
92 | 
93 |
94 |
95 | ## 6.Frameworks
96 |
97 | > [Vant - Mobile UI Components built on Vue](https://youzan.github.io/vant/#/zh-CN/intro)
98 |
99 | > [Nest.js - A progressive Node.js framework for building efficient, reliable and scalable server-side applications.](https://nestjs.com/)
100 |
101 | > [Nuxt.js - The Vue.js Framework](https://nuxtjs.org/)
102 |
103 | ## 7.Plugins
104 |
105 | > [Nuxt-property-decorator](https://github.com/nuxt-community/nuxt-property-decorator)
106 |
107 | > [Vue class component](https://github.com/vuejs/vue-class-component)
108 |
109 | > [Vuex class](https://github.com/ktsn/vuex-class/)
110 |
111 | > [Nuxt class component](https://github.com/nuxt-community/nuxt-class-component)
112 |
--------------------------------------------------------------------------------
/build/BuildCover.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | const arguments = process.env.NODE_ENV || 'production';
5 | let file = '';
6 | const coverPath = path.resolve(__dirname, '../config/env.config.ts');
7 |
8 | const replacestr = 'Replace ENV:: ';
9 |
10 | switch (arguments) {
11 | case 'development':
12 | file =
13 | `export default {
14 | env: 'development'
15 | };`;
16 | fs.writeFileSync(coverPath, file);
17 | console.log(replacestr, arguments);
18 | break;
19 |
20 | case 'production':
21 | file = `export default {
22 | env: 'production'
23 | };`;
24 | fs.writeFileSync(coverPath, file);
25 | console.log(replacestr, arguments);
26 | break;
27 |
28 | default:
29 | file = `export default {
30 | env: 'production'
31 | };`;
32 | fs.writeFileSync(coverPath, file);
33 | console.log(replacestr, arguments);
34 | break;
35 | }
36 |
--------------------------------------------------------------------------------
/config/ConfigDB.ts:
--------------------------------------------------------------------------------
1 | import { ConfigDefault } from './ConfigDefault';
2 |
3 | /**
4 | * DB配置
5 | *
6 | * @export
7 | * @class ConfigDB
8 | * @extends {ConfigDefault}
9 | */
10 | export class ConfigDB extends ConfigDefault {
11 | constructor() {
12 | super();
13 | }
14 |
15 | /**
16 | * 开发MOGO DB配置
17 | * @description Gets dev enviroment mongo config
18 | * @returns dev enviroment mongo config
19 | */
20 | private getDevEnviromentMongoConfig(): IMongoDBConfig {
21 | return {
22 | uri: 'localhost',
23 | port: 27017,
24 | db: 'admin',
25 | userName: 'admin',
26 | password: '123456'
27 | };
28 | }
29 |
30 | /**
31 | * 生产MOGO DB配置
32 | * @description Gets dev enviroment mongo config
33 | * @returns dev enviroment mongo config
34 | */
35 | private getProdEnviromentMongoConfig(): IMongoDBConfig {
36 | return {
37 | uri: 'localhost',
38 | port: 27017,
39 | db: 'admin',
40 | userName: 'admin',
41 | password: '123456'
42 | };
43 | }
44 |
45 | /**
46 | * 获取MONGO DB层配置
47 | * @description Gets db config
48 | * @returns db config
49 | */
50 | public getMongoDbConfig(): IMongoDBConfig {
51 | switch (this.getEnv()) {
52 | // 开发MOGO DB配置
53 | case ConfigDefault.ENV_DEV:
54 | return this.getDevEnviromentMongoConfig();
55 | // 生产MOGO DB配置
56 | case ConfigDefault.ENV_PROD:
57 | return this.getProdEnviromentMongoConfig();
58 | // 默认MOGO DB配置
59 | default:
60 | return this.getProdEnviromentMongoConfig();
61 | }
62 | }
63 | }
64 |
65 | /**
66 | * mongo db 基础配置
67 | * @description Idbconfig
68 | */
69 | export interface IMongoDBConfig {
70 | uri: string;
71 | port: number;
72 | db: string;
73 | userName: string;
74 | password: string;
75 | }
76 |
--------------------------------------------------------------------------------
/config/ConfigDefault.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 基础配置
3 | *
4 | * @export
5 | * @class ConfigDefault
6 | */
7 | export class ConfigDefault {
8 |
9 | /**
10 | * X real url of config default
11 | */
12 | public static X_REAL_URL: string = 'x-real-url';
13 |
14 | /**
15 | * X real base url of config default
16 | */
17 | public static X_REAL_BASE_URL: string = 'x-real-base-url';
18 |
19 | /**
20 | * content-type
21 | */
22 | public static CONTENT_TYPE: string = 'content-type';
23 |
24 | /**
25 | * Env dev of config default
26 | */
27 | public static ENV_DEV: string = 'development';
28 |
29 | /**
30 | * Env prod of config default
31 | */
32 | public static ENV_PROD: string = 'production';
33 |
34 | /**
35 | * 默认环境标识
36 | * @description Env of config default
37 | */
38 | private _env: string = ConfigDefault.ENV_PROD;
39 |
40 | constructor() {
41 | // hole
42 | }
43 |
44 | /**
45 | * 服务器访问路径
46 | *
47 | * @type {string}
48 | * @memberof ConfigDefault
49 | */
50 | public serverAdderess: string = '127.0.0.1';
51 |
52 | /**
53 | * 启动端口
54 | *
55 | * @type {number}
56 | * @memberof ConfigDefault
57 | */
58 | public port: number = 8088;
59 |
60 | /**
61 | * 是否输出所有日志记录
62 | */
63 | public monitorAllLogs: boolean = false;
64 |
65 | /**
66 | * 本地URL地址
67 | *
68 | * @type {string}
69 | * @memberof ConfigDefault
70 | */
71 | public localUrl: string = 'http://127.0.0.1';
72 |
73 | /**
74 | * charles抓包地址
75 | */
76 | public httpProxyUrl: string = 'http://127.0.0.1';
77 |
78 | /**
79 | * charles抓包端口
80 | */
81 | public httpProxyPort: number = 8888;
82 |
83 | /**
84 | * cnode配置
85 | *
86 | * @type {string}
87 | * @memberof ConfigDefault
88 | */
89 | public cnodeUrl: string = 'https://cnodejs.org';
90 |
91 | /**
92 | * proxy-agent地址
93 | */
94 | public getProxyAddress(): string {
95 | return `${this.httpProxyUrl}:${this.httpProxyPort}`;
96 | }
97 |
98 | /**
99 | * API统一前缀
100 | */
101 | public getGlobalPrefix(): string {
102 | return 'api';
103 | }
104 |
105 | /**
106 | * 获取当前环境标识
107 | * @description Gets env
108 | * @returns env
109 | */
110 | public getEnv(): string {
111 | return this._env;
112 | }
113 |
114 | /**
115 | * 更新环境标识
116 | * @description Updates env
117 | * @param env
118 | */
119 | public updateEnv(env: string): void {
120 | this._env = env;
121 | }
122 |
123 | /**
124 | * 鉴权白名单页面,在此列表内页面将进行登录判断
125 | */
126 | public authWhiteList(): Array {
127 | return [
128 | '/cart',
129 | '/goods',
130 | '/'
131 | ];
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/config/ConfigDev.ts:
--------------------------------------------------------------------------------
1 | import { ConfigDefault } from './ConfigDefault';
2 |
3 | /**
4 | * 开发服配置
5 | *
6 | * @export
7 | * @class ConfigDev
8 | * @extends {ConfigDefault}
9 | */
10 | export class ConfigDev extends ConfigDefault {
11 | constructor() {
12 | super();
13 | // console.log('开发服配置::: 启动');
14 | }
15 |
16 | /**
17 | * 覆盖本地URL地址
18 | *
19 | * @type {string}
20 | * @memberof ConfigDefault
21 | */
22 | public localUrl: string = 'http://localhost';
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/config/ConfigProd.ts:
--------------------------------------------------------------------------------
1 | import { ConfigDefault } from './ConfigDefault';
2 |
3 | /**
4 | * 生产服配置
5 | *
6 | * @export
7 | * @class ConfigProd
8 | * @extends {ConfigDefault}
9 | */
10 | export class ConfigProd extends ConfigDefault {
11 | constructor() {
12 | super();
13 | // console.log('生产服配置::: 启动');
14 | }
15 |
16 | /**
17 | * 覆盖本地URL地址
18 | *
19 | * @type {string}
20 | * @memberof ConfigDefault
21 | */
22 | public localUrl: string = 'http://127.0.0.1';
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | nest:
5 | build: .
6 | ports:
7 | - "3100:3100"
8 | networks:
9 | - docker-nest-typegoose-net
10 | depends_on:
11 | - mongo
12 | mongo:
13 | image: mongo:4.2
14 | ports:
15 | - "27017:27017"
16 | networks:
17 | - docker-nest-typegoose-net
18 |
19 | networks:
20 | docker-nest-typegoose-net:
21 | driver: bridge
22 |
--------------------------------------------------------------------------------
/docs/1567861669077.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1166544/nuxt.js-nest.js-isomorphism/37a442a3b09e4566580e08b8027634e153ac7ac2/docs/1567861669077.jpg
--------------------------------------------------------------------------------
/docs/1569804144167.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1166544/nuxt.js-nest.js-isomorphism/37a442a3b09e4566580e08b8027634e153ac7ac2/docs/1569804144167.jpg
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 |
3 | declare module '*.vue' {
4 | const _default: Vue;
5 | export default _default;
6 | }
7 |
--------------------------------------------------------------------------------
/jest.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": [
3 | "ts",
4 | "tsx",
5 | "js",
6 | "json"
7 | ],
8 | "transform": {
9 | "^.+\\.tsx?$": "ts-jest"
10 | },
11 | "testRegex": "/src/server/.*\\.(test|spec).(ts|tsx|js)$",
12 | "collectCoverageFrom": ["src/server/**/*.{js,jsx,tsx,ts}", "!**/node_modules/**", "!**/vendor/**"],
13 | "coverageReporters": ["json", "lcov"]
14 | }
15 |
--------------------------------------------------------------------------------
/nodemon.json:
--------------------------------------------------------------------------------
1 | {
2 | "watch": [],
3 | "exec": "node dist/main.js"
4 | }
5 |
--------------------------------------------------------------------------------
/nuxt.config.ts:
--------------------------------------------------------------------------------
1 | import { ConfigDefault } from './config/ConfigDefault';
2 | import NuxtConfiguration from '@nuxt/config';
3 | import nodeExternals from 'webpack-node-externals';
4 |
5 | const isDev: boolean = !(process.env.NODE_ENV === 'production');
6 | const configDefault: ConfigDefault = new ConfigDefault();
7 |
8 | const config: NuxtConfiguration = {
9 | mode: 'universal',
10 |
11 | env: {
12 | host: configDefault.serverAdderess,
13 | port: configDefault.port,
14 | baseUrl: process.env.BASE_URL || `http://${configDefault.serverAdderess}:${configDefault.port}`
15 | },
16 |
17 | srcDir: './src/client/',
18 | dev: isDev,
19 |
20 | /*
21 | ** 默认SEO头部信息
22 | */
23 | head: {
24 | title: 'Nuxt.js bio project',
25 | meta: [
26 | { charset: 'utf-8' },
27 | { name: 'viewport', content: 'width=device-width, initial-scale=1, user-scalable=0' },
28 | ],
29 | link: [
30 | { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
31 | ]
32 | },
33 |
34 | /** Render content */
35 | render: {
36 | ssrLog: 'collapsed'
37 | },
38 |
39 | /*
40 | ** Customize the progress-bar
41 | */
42 | loading: '~/components/ComponentLoading.vue',
43 |
44 | /*
45 | ** Global CSS
46 | */
47 | css: ['~/assets/style/App.styl'],
48 |
49 | /*
50 | ** Plugins to load before mounting the App
51 | */
52 | plugins: [
53 | {
54 | src: '~/plugins/PluginVant',
55 | ssr: true
56 | },
57 | {
58 | src: '~/plugins/PluginFlexible',
59 | ssr: false
60 | },
61 | {
62 | src: '~/plugins/PluginAxios',
63 | ssr: true
64 | }
65 | ],
66 |
67 | /*
68 | ** Nuxt.js modules
69 | */
70 | modules: [
71 | '@nuxtjs/axios' // Doc: https://axios.nuxtjs.org/usage
72 | // '@nuxtjs/proxy'
73 | ],
74 | /*
75 | ** Axios module configuration
76 | */
77 | axios: {
78 | // See https://github.com/nuxt-community/axios-module#options
79 | proxy: false,
80 | retry: { retries: 3 },
81 | credentials: true
82 | },
83 | /*
84 | ** Build configuration
85 | */
86 | build: {
87 | cache: true,
88 | postcss: {
89 | // 添加插件名称作为键,参数作为值,使用npm或yarn安装它们
90 | plugins: {
91 | 'postcss-pxtorem': {
92 | rootValue: 37.5,
93 | propList: ['*']
94 | }
95 | }
96 | },
97 | babel: {
98 | plugins: [
99 | '@babel/plugin-transform-modules-commonjs',
100 | ['@babel/plugin-proposal-decorators', { legacy: true }],
101 | ['@babel/plugin-proposal-class-properties', { loose: true }]
102 | ]
103 | },
104 | transpile: [],
105 | plugins: [],
106 | loaders: {
107 | },
108 | /*
109 | ** You can extend webpack config here
110 | */
111 | // tslint:disable-next-line:typedef
112 | extend(config, { isClient }) {
113 | if (process.server) {
114 | config.externals = [
115 | nodeExternals({
116 | whitelist: [/^vant/]
117 | })
118 | ];
119 | }
120 |
121 | if (isClient) {
122 | config.devtool = '#source-map';
123 | }
124 | }
125 | },
126 |
127 | router: {
128 | middleware: [
129 | 'MiddlewareMobile',
130 | 'MiddlewareNotAuthenticated'
131 | ]
132 | }
133 | };
134 |
135 | export default config;
136 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nuxtjs-nestjs-isomorphism",
3 | "version": "1.0.0",
4 | "description": "A project for nuxtjs and nestjs integrated.",
5 | "author": "James Liauw",
6 | "license": "MIT",
7 | "pre-commit": [
8 | "lint"
9 | ],
10 | "scripts": {
11 | "format": "prettier --write \"**/*.ts\"",
12 | "start": "npm run cover && cross-env NODE_ENV=production node dist/src/server/main.js",
13 | "start:dev": "npm run lint && cross-env NODE_ENV=development npm run cover && webpack --config webpack.config.js",
14 | "start:prod": "npm run lint && cross-env NODE_ENV=production npm run cover && webpack --config webpack.config.js",
15 | "build": "npm run lint && cross-env NODE_ENV=production npm run clean && nuxt build && tsc",
16 | "lint": "tslint -p tsconfig.json -c tslint.json",
17 | "lintfix": "tslint -p tsconfig.json --fix",
18 | "clean": "rimraf dist",
19 | "client": "npm run start:dev",
20 | "client:dev": "npm run start:dev",
21 | "client:prod": "npm run start:prod",
22 | "serve": "npm run start:dev",
23 | "prestart:prod": "npm run build",
24 | "test": "jest --config=jest.json",
25 | "cover": "node build/BuildCover.js",
26 | "test:watch": "jest --watch --config=jest.json",
27 | "test:coverage": "jest --config=jest.json --coverage --coverageDirectory=coverage"
28 | },
29 | "dependencies": {
30 | "@nestjs/common": "6.5.2",
31 | "@nestjs/core": "6.5.2",
32 | "@nestjs/microservices": "5.7.4",
33 | "@nestjs/mongoose": "6.1.2",
34 | "@nestjs/platform-express": "6.6.3",
35 | "@nestjs/testing": "6.5.2",
36 | "@nestjs/websockets": "5.7.4",
37 | "@nuxtjs/axios": "5.4.1",
38 | "@nuxtjs/proxy": "1.3.3",
39 | "@types/jasmine": "3.3.16",
40 | "@types/mocha": "5.2.7",
41 | "@types/mongoose": "5.5.16",
42 | "class-transformer": "0.2.3",
43 | "class-validator": "0.9.1",
44 | "cookieparser": "0.1.0",
45 | "cross-env": "5.2.0",
46 | "js-cookie": "2.2.1",
47 | "md5": "2.2.1",
48 | "mongoose": "5.6.11",
49 | "nuxt": "2.8.1",
50 | "pre-commit": "1.2.2",
51 | "proxy-agent": "3.1.0",
52 | "querystring": "0.2.0",
53 | "reflect-metadata": "0.1.13",
54 | "rimraf": "2.6.3",
55 | "rxjs": "6.5.2",
56 | "ts-loader": "5.3.3",
57 | "tslint-config-alloy": "0.2.1",
58 | "typescript": "3.5.3",
59 | "uuid": "3.3.3",
60 | "vant": "2.1.2",
61 | "vuex-class": "0.3.1"
62 | },
63 | "devDependencies": {
64 | "@babel/plugin-transform-modules-commonjs": "7.2.0",
65 | "@nuxt/config": "2.4.5",
66 | "@nuxt/typescript": "2.8.1",
67 | "@types/jest": "24.0.15",
68 | "@types/node": "10.14.0",
69 | "jest": "24.8.0",
70 | "nodemon": "1.18.9",
71 | "nuxt-property-decorator": "2.1.3",
72 | "postcss-pxtorem": "4.0.1",
73 | "prettier": "1.15.3",
74 | "stylus": "0.54.5",
75 | "stylus-loader": "3.0.2",
76 | "supertest": "4.0.2",
77 | "ts-jest": "24.0.2",
78 | "ts-node": "8.3.0",
79 | "tsconfig-paths": "3.7.0",
80 | "tslint": "5.13.1",
81 | "tslint-config-prettier": "1.18.0",
82 | "tslint-plugin-prettier": "2.0.1",
83 | "vuex-class-component": "1.4.3",
84 | "webpack-cli": "3.2.3",
85 | "webpack-shell-plugin": "0.5.0"
86 | },
87 | "browserslist": [
88 | "Android >= 4.0",
89 | "iOS >= 7"
90 | ]
91 | }
92 |
--------------------------------------------------------------------------------
/src/client/assets/README.md:
--------------------------------------------------------------------------------
1 | # ASSETS
2 |
3 | **This directory is not required, you can delete it if you don't want to use it.**
4 |
5 | This directory contains your un-compiled assets such as LESS, SASS, or JavaScript.
6 |
7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked).
8 |
--------------------------------------------------------------------------------
/src/client/assets/style/App.styl:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 | html, body, div, span, applet, object, iframe,
6 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
7 | a, abbr, acronym, address, big, cite, code,
8 | del, dfn, em, img, ins, kbd, q, s, samp,
9 | small, strike, strong, sub, sup, tt, var,
10 | b, u, i, center,
11 | dl, dt, dd, ol, ul, li,
12 | fieldset, form, label, legend,
13 | table, caption, tbody, tfoot, thead, tr, th, td,
14 | article, aside, canvas, details, embed,
15 | figure, figcaption, footer, header, hgroup,
16 | menu, nav, output, ruby, section, summary,
17 | time, mark, audio, video {
18 | margin: 0;
19 | padding: 0;
20 | border: 0;
21 | font-size: 100%;
22 | font: inherit;
23 | vertical-align: baseline;
24 | }
25 | /* HTML5 display-role reset for older browsers */
26 | article, aside, details, figcaption, figure,
27 | footer, header, hgroup, menu, nav, section {
28 | display: block;
29 | }
30 | body {
31 | line-height: 1;
32 | }
33 | ol, ul {
34 | list-style: none;
35 | }
36 | blockquote, q {
37 | quotes: none;
38 | }
39 | blockquote:before, blockquote:after,
40 | q:before, q:after {
41 | content: '';
42 | content: none;
43 | }
44 | table {
45 | border-collapse: collapse;
46 | border-spacing: 0;
47 | }
48 |
49 | body {
50 | font-size: 14px;
51 | background: #f6f6f6;
52 | }
--------------------------------------------------------------------------------
/src/client/common/CommonCart.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 购物车公用逻辑
3 | */
4 | class CommonCart {
5 | constructor() {
6 | // hole
7 | }
8 |
9 | /** 更新用户已添加入购物车数量 */
10 | public getUpdatedCartsList(
11 | list: Array,
12 | sourceData: Array
13 | ): Array {
14 | for (let indexList: number = 0; indexList < list.length; indexList++) {
15 | const element: any = list[indexList];
16 |
17 | for (let index: number = 0; index < sourceData.length; index++) {
18 | const item: any = sourceData[index];
19 |
20 | if (element._id === item.id) {
21 | element.num = item.num;
22 | break;
23 | }
24 | }
25 | }
26 |
27 | return list;
28 | }
29 |
30 | /** 格式价格 */
31 | public formatPrice(price: number = 1): string {
32 | return (price / 100).toFixed(2);
33 | }
34 | }
35 |
36 | export default new CommonCart();
37 |
--------------------------------------------------------------------------------
/src/client/common/CommonCookie.ts:
--------------------------------------------------------------------------------
1 | import Cookie from 'js-cookie';
2 |
3 | /**
4 | * 转换COOKIE为对象
5 | * @param cookie
6 | */
7 | export function parseCookie(cookie: string): Object {
8 | const output: Object = {};
9 | cookie.split(/\s*;\s*/).forEach((pairCopy: any): any => {
10 | let pair: any = pairCopy;
11 | pair = pair.split(/\s*=\s*/);
12 | output[pair[0]] = pair.splice(1).join('=');
13 | });
14 |
15 | return output;
16 | }
17 |
18 | /**
19 | * 服务端时生成自定义axios头部token
20 | * @param config
21 | */
22 | export function setCustomHeaderBySSR(app: any, axios: any): any {
23 |
24 | let accessToken: string = '';
25 | // 检测cookie是否存在
26 | if (app && app.context && app.context.req && app.context.req.headers) {
27 | // 抓取cookie内认证值
28 | const cookie: any = parseCookie(app.context.req.headers.cookie || '');
29 |
30 | if (cookie && cookie.auth) {
31 | let authData: any;
32 | try {
33 | authData = JSON.parse(decodeURIComponent(cookie.auth));
34 | } catch (error) {
35 | console.log(error);
36 | }
37 | accessToken = authData.accessToken;
38 | }
39 | }
40 |
41 | // 设置自定义头部token
42 | axios.setToken(accessToken);
43 |
44 | return accessToken;
45 | }
46 |
47 | /**
48 | * 客户端时生成自定义axios头部token
49 | * @param config
50 | */
51 | export function setCustomHeaderByCSR(axios: any): any {
52 |
53 | let accessToken: string = '';
54 | const cookie: any = Cookie.get('auth');
55 | // 检测cookie是否存在
56 | if (cookie) {
57 | let authData: any;
58 | try {
59 | authData = JSON.parse(decodeURIComponent(cookie));
60 | if (authData) {
61 | accessToken = authData.accessToken;
62 | }
63 | } catch (error) {
64 | console.log(error);
65 | }
66 | }
67 |
68 | // 设置自定义头部token
69 | axios.setToken(accessToken);
70 |
71 | return accessToken;
72 | }
73 |
74 | /**
75 | * 客户端更新axios头部token
76 | * @param config
77 | */
78 | export function updateCustomHeaderByCSR(accessToken: string, axios: any): any {
79 | // 设置自定义头部token
80 | axios.setToken(accessToken);
81 | }
82 |
83 | /**
84 | * 获取用户信息
85 | * @param config
86 | */
87 | export function getUser(req: any, app: any): any {
88 | // 抓取cookie
89 | let authData: any = {};
90 | if (process.server) {
91 | // ssr
92 | const cookieValue: string = req.headers.cookie;
93 | const cookie: any = parseCookie(cookieValue || '');
94 |
95 | if (cookie) {
96 | try {
97 | authData = JSON.parse(decodeURIComponent(cookie.auth));
98 | } catch (error) {
99 | console.log(error);
100 | }
101 | }
102 | } else {
103 | // csr
104 | authData = app.store.state.modules.auth.auth;
105 |
106 | if (!authData || !authData._id) {
107 | const cookie: any = Cookie.get('auth');
108 | if (cookie) {
109 | try {
110 | authData = JSON.parse(decodeURIComponent(cookie));
111 | } catch (error) {
112 | console.log(error);
113 | }
114 | }
115 | }
116 | }
117 |
118 | return authData;
119 | }
120 |
--------------------------------------------------------------------------------
/src/client/components/ComponentHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
24 |
25 |
30 |
--------------------------------------------------------------------------------
/src/client/components/ComponentLoading.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
27 |
28 |
42 |
43 |
--------------------------------------------------------------------------------
/src/client/components/ComponentLogo.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
19 |
20 |
90 |
--------------------------------------------------------------------------------
/src/client/components/ComponentTwitter.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
--------------------------------------------------------------------------------
/src/client/components/README.md:
--------------------------------------------------------------------------------
1 | # COMPONENTS
2 |
3 | **This directory is not required, you can delete it if you don't want to use it.**
4 |
5 | The components directory contains your Vue.js Components.
6 |
7 | _Nuxt.js doesn't supercharge these components._
8 |
--------------------------------------------------------------------------------
/src/client/core/consts/ConstHttp.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 网络状态常量
3 | * @description Http const
4 | */
5 | export class HttpConst {
6 | public static STATUS_200: number = 200;
7 | public static STATUS_401: number = 401;
8 | public static STATUS_403: number = 403;
9 | }
10 |
--------------------------------------------------------------------------------
/src/client/core/interfaces/IView.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 基础视图结构接口
3 | *
4 | * @export
5 | * @interface IView
6 | */
7 | export interface IView {
8 |
9 | /**
10 | * SEO页面标题
11 | *
12 | * @type {string}
13 | * @memberof IView
14 | */
15 | title: string;
16 |
17 | /**
18 | * SEO页面描述
19 | *
20 | * @type {string}
21 | * @memberof IView
22 | */
23 | description: string;
24 |
25 | /**
26 | * SEO页面关键字
27 | *
28 | * @type {string}
29 | * @memberof IView
30 | */
31 | keywords: string;
32 | }
33 |
--------------------------------------------------------------------------------
/src/client/core/interfaces/IVo.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 基础VO结构
3 | *
4 | * @export
5 | * @interface IVO
6 | */
7 | export interface IVO {
8 | /**
9 | * 更新数据
10 | *
11 | * @param {*} val
12 | * @memberof IVO
13 | */
14 | update(val: any): void;
15 | }
16 |
--------------------------------------------------------------------------------
/src/client/core/service/ServiceBase.ts:
--------------------------------------------------------------------------------
1 | import { IVO } from '~/core/interfaces/IVo';
2 | import IUser from '~/models/ModelUser';
3 | import configService from '~/core/service/ServiceConfig';
4 | import { setCustomHeaderByCSR, updateCustomHeaderByCSR } from '~/common/CommonCookie';
5 |
6 | /**
7 | * 基础配置接口
8 | *
9 | * @export
10 | * @interface IBaseOption
11 | */
12 | export interface IBaseOption {
13 | /** 基础URL */
14 | baseUrl: string;
15 |
16 | /** 是否本地调用 */
17 | isLocalHost: boolean;
18 | }
19 |
20 | /**
21 | * 基础配置类型
22 | *
23 | * @export
24 | * @class BaseOption
25 | * @implements {IBaseOption}
26 | */
27 | export class BaseOption implements IBaseOption, IVO {
28 | constructor() {
29 | // hole
30 | }
31 |
32 | /**
33 | * 调用URL地址
34 | *
35 | * @type {string}
36 | * @memberof BaseOption
37 | */
38 | public baseUrl: string;
39 |
40 | /**
41 | * 是否为本地周用
42 | *
43 | * @type {boolean}
44 | * @memberof BaseOption
45 | */
46 | public isLocalHost: boolean = false;
47 |
48 | /**
49 | * 更新数据
50 | *
51 | * @param {*} val
52 | * @memberof BaseOption
53 | */
54 | public update(val: any): void {
55 | // hole
56 | }
57 | }
58 |
59 |
60 | /**
61 | * 基础接口调用类
62 | *
63 | * @export
64 | * @class BaseService
65 | */
66 | export class BaseService {
67 | [x: string]: any;
68 | protected apiServiceInstance: any;
69 | protected options: IBaseOption;
70 |
71 | constructor(optios: IBaseOption) {
72 | this.options = optios;
73 | }
74 |
75 | protected get apiService(): any {
76 | if (!this.apiServiceInstance) {
77 | this.apiServiceInstance = configService.getAxios();
78 | }
79 |
80 | // 客户端渲染时
81 | if (process.client) {
82 | setCustomHeaderByCSR(this.apiServiceInstance);
83 | }
84 |
85 | return this.apiServiceInstance;
86 | }
87 |
88 | /**
89 | * 更新拦截信息,将token设入请求头部
90 | * @param loginData
91 | */
92 | public updateIntercept(loginData: IUser): void {
93 | updateCustomHeaderByCSR(loginData.accessToken, this.apiServiceInstance);
94 | }
95 |
96 | /**
97 | * 更新配置,加上目标URL前缀
98 | *
99 | * @protected
100 | * @memberof BaseService
101 | */
102 | protected updateConfig(url: string): string {
103 | // 本地调用
104 | if (this.options.isLocalHost) {
105 | return url;
106 | }
107 |
108 | // 非本地调用
109 | const baseUrl: string = this.options.baseUrl || '';
110 | const resultUrl: string = `${baseUrl}${url}`;
111 | // console.log(resultUrl);
112 |
113 | return resultUrl;
114 | }
115 |
116 | /**
117 | * Request请求
118 | *
119 | * @protected
120 | * @param {*} config
121 | * @returns {void}
122 | * @memberof BaseService
123 | */
124 | protected request(config: any): void {
125 | return this.apiService.request(config);
126 | }
127 |
128 | /**
129 | * 处理GET
130 | *
131 | * @param {string} url 接口地址
132 | * @returns {Promise}
133 | * @memberof BaseService
134 | */
135 | public async get(url: string, config: any = {}): Promise {
136 | return await this.apiService.get(this.updateConfig(url), config);
137 | }
138 |
139 | /**
140 | * 处理POST
141 | *
142 | * @param {string} url 接口地址
143 | * @param {*} data 请求参数
144 | * @param {*} [config={}] 配置信息
145 | * @returns {Promise}
146 | * @memberof BaseService
147 | */
148 | public async post(url: string, data: any, config: any = {}): Promise {
149 | return this.apiService.post(this.updateConfig(url), data, config);
150 | }
151 |
152 | /**
153 | * 处理DELETE
154 | *
155 | * @param {string} url 接口地址
156 | * @param {*} [config={}] 配置信息
157 | * @returns {Promise}
158 | * @memberof BaseService
159 | */
160 | public async delete(url: string, config: any = {}): Promise {
161 | return this.apiService.delete(this.updateConfig(url), config);
162 | }
163 |
164 | /**
165 | * 处理HEAD
166 | *
167 | * @param {string} url 接口地址
168 | * @param {*} [config={}] 配置信息
169 | * @returns {Promise}
170 | * @memberof BaseService
171 | */
172 | public async head(url: string, config: any = {}): Promise {
173 | return this.apiService.head(this.updateConfig(url), config);
174 | }
175 |
176 | /**
177 | * 处理PUT
178 | *
179 | * @param {string} url 接口地址
180 | * @param {*} data 请求参数
181 | * @param {*} [config={}] 配置信息
182 | * @returns {Promise}
183 | * @memberof BaseService
184 | */
185 | public async put(url: string, data: any, config: any = {}): Promise {
186 | return this.apiService.put(this.updateConfig(url), data, config);
187 | }
188 |
189 | /**
190 | * 处理PATCH
191 | *
192 | * @param {string} url 接口地址
193 | * @param {*} data 请求参数
194 | * @param {*} [config={}] 配置信息
195 | * @returns {Promise}
196 | * @memberof BaseService
197 | */
198 | public async patch(url: string, data: any, config: any = {}): Promise {
199 | return this.apiService.patch(this.updateConfig(url), data, config);
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/src/client/core/service/ServiceConfig.ts:
--------------------------------------------------------------------------------
1 | import { ConfigDefault } from '../../../../config/ConfigDefault';
2 | import { ConfigDev } from '../../../../config/ConfigDev';
3 | import { ConfigProd } from '../../../../config/ConfigProd';
4 | import ConfigEnv from '../../../../config/env.config';
5 |
6 | /**
7 | * 配置服务
8 | *
9 | * @class ConfigService
10 | */
11 | class ConfigService {
12 | private static instance: ConfigService;
13 | private axios: any;
14 |
15 | /**
16 | * 配置服务单例
17 | *
18 | * @static
19 | * @returns {ConfigService}
20 | * @memberof ConfigService
21 | */
22 | public static getInstance(): ConfigService {
23 | if (!ConfigService.instance) {
24 | ConfigService.instance = new ConfigService();
25 | }
26 |
27 | return ConfigService.instance;
28 | }
29 |
30 | /**
31 | * 配置数据
32 | *
33 | * @private
34 | * @type {ConfigDefault}
35 | * @memberof ConfigService
36 | */
37 | private config: ConfigDefault;
38 |
39 | constructor() {
40 | switch (ConfigEnv.env) {
41 | case ConfigDefault.ENV_DEV:
42 | this.config = new ConfigDev();
43 | break;
44 | case ConfigDefault.ENV_PROD:
45 | this.config = new ConfigProd();
46 | break;
47 | default:
48 | this.config = new ConfigProd();
49 | break;
50 | }
51 |
52 | // 将环境标识写入配置中
53 | this.config.updateEnv(ConfigEnv.env);
54 | }
55 |
56 | /**
57 | * 获取配置数据
58 | *
59 | * @returns {DefaultConfig}
60 | * @memberof ConfigService
61 | */
62 | public getConfig(): ConfigDefault {
63 | return this.config;
64 | }
65 |
66 | /**
67 | * 获取AXIOS实例
68 | *
69 | * @returns {*}
70 | * @memberof ConfigService
71 | */
72 | public getAxios(): any {
73 | return this.axios;
74 | }
75 |
76 | /**
77 | * 保存axios实例
78 | *
79 | * @param {*} axios
80 | * @memberof ConfigService
81 | */
82 | public saveAxios(axios: any): void {
83 | this.axios = axios;
84 | }
85 | }
86 |
87 | export default ConfigService.getInstance();
88 |
--------------------------------------------------------------------------------
/src/client/core/service/ServiceTransport.ts:
--------------------------------------------------------------------------------
1 | import { BaseService, IBaseOption } from './ServiceBase';
2 | import { ConfigDefault } from '../../../../config/ConfigDefault';
3 |
4 | /**
5 | * 重写基类,中转服务
6 | *
7 | * @export
8 | * @class TransportService
9 | * @extends {BaseService}
10 | */
11 | export class TransportService extends BaseService {
12 | constructor(optios: IBaseOption) {
13 | super(optios);
14 | }
15 |
16 | /**
17 | * 更新配置,加上目标URL前缀,如果是中转的话则指定固定地址
18 | *
19 | * @protected
20 | * @memberof BaseService
21 | */
22 | protected updateConfig(url: string): string {
23 | return '/api/transport/getTransportData';
24 | }
25 |
26 | /**
27 | * 更新配置,将URL放在HEADER头部
28 | *
29 | * @protected
30 | * @param {string} url 请求URL接口
31 | * @param {*} config 基础配置,将传入AXIOS
32 | * @returns {*}
33 | * @memberof TransportService
34 | */
35 | protected transportConfig(url: string, config: any): any {
36 | config.headers = {};
37 | config.headers[ConfigDefault.X_REAL_URL] = url;
38 | config.headers[ConfigDefault.X_REAL_BASE_URL] = this.options.baseUrl || '';
39 |
40 | return config;
41 | }
42 |
43 | /**
44 | * 处理GET
45 | *
46 | * @param {string} url 接口地址
47 | * @returns {Promise}
48 | * @memberof BaseService
49 | */
50 | public async get(url: string, config: any = {}): Promise {
51 | return await this.apiService.get(this.updateConfig(url), this.transportConfig(url, config));
52 | }
53 |
54 | /**
55 | * 处理POST
56 | *
57 | * @param {string} url 接口地址
58 | * @param {*} data 请求参数
59 | * @param {*} [config={}] 配置信息
60 | * @returns {Promise}
61 | * @memberof BaseService
62 | */
63 | public async post(url: string, data: any, config: any = {}): Promise {
64 | return this.apiService.post(this.updateConfig(url), data, this.transportConfig(url, config));
65 | }
66 |
67 | /**
68 | * 处理DELETE
69 | *
70 | * @param {string} url 接口地址
71 | * @param {*} [config={}] 配置信息
72 | * @returns {Promise}
73 | * @memberof BaseService
74 | */
75 | public async delete(url: string, config: any = {}): Promise {
76 | return this.apiService.delete(this.updateConfig(url), this.transportConfig(url, config));
77 | }
78 |
79 | /**
80 | * 处理HEAD
81 | *
82 | * @param {string} url 接口地址
83 | * @param {*} [config={}] 配置信息
84 | * @returns {Promise}
85 | * @memberof BaseService
86 | */
87 | public async head(url: string, config: any = {}): Promise {
88 | return this.apiService.head(this.updateConfig(url), this.transportConfig(url, config));
89 | }
90 |
91 | /**
92 | * 处理PUT
93 | *
94 | * @param {string} url 接口地址
95 | * @param {*} data 请求参数
96 | * @param {*} [config={}] 配置信息
97 | * @returns {Promise}
98 | * @memberof BaseService
99 | */
100 | public async put(url: string, data: any, config: any = {}): Promise {
101 | return this.apiService.put(this.updateConfig(url), data, this.transportConfig(url, config));
102 | }
103 |
104 | /**
105 | * 处理PATCH
106 | *
107 | * @param {string} url 接口地址
108 | * @param {*} data 请求参数
109 | * @param {*} [config={}] 配置信息
110 | * @returns {Promise}
111 | * @memberof BaseService
112 | */
113 | public async patch(url: string, data: any, config: any = {}): Promise {
114 | return this.apiService.patch(this.updateConfig(url), data, this.transportConfig(url, config));
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/client/core/views/ViewBase.ts:
--------------------------------------------------------------------------------
1 | import { Vue } from 'nuxt-property-decorator';
2 | import { IView } from '~/core/interfaces/IView';
3 |
4 | /**
5 | * 基础视图类
6 | *
7 | * @export
8 | * @class BaseView
9 | * @extends {Vue}
10 | * @implements {IView}
11 | */
12 | export class BaseView extends Vue implements IView {
13 |
14 | /**
15 | * SEO Title
16 | *
17 | * @type {string}
18 | * @memberof BaseView
19 | */
20 | public title: string;
21 |
22 | /**
23 | * SEO Description
24 | *
25 | * @type {string}
26 | * @memberof BaseView
27 | */
28 | public description: string;
29 |
30 | /**
31 | * SEO Keywords
32 | *
33 | * @type {string}
34 | * @memberof BaseView
35 | */
36 | public keywords: string;
37 |
38 | public constructor() {
39 | super();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/client/layouts/LayoutDefault.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
86 |
--------------------------------------------------------------------------------
/src/client/layouts/LayoutError.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Page not found
4 | An error occurred
5 | Home page
6 |
7 |
8 |
9 |
28 |
29 |
40 |
--------------------------------------------------------------------------------
/src/client/layouts/README.md:
--------------------------------------------------------------------------------
1 | # LAYOUTS
2 |
3 | **This directory is not required, you can delete it if you don't want to use it.**
4 |
5 | This directory contains your Application Layouts.
6 |
7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts).
8 |
--------------------------------------------------------------------------------
/src/client/middleware/MiddlewareMobile.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 判断是否为数移动端,同时输出标记
3 | *
4 | * @export
5 | * @param {*} ctx
6 | */
7 | export default function (ctx: any): void {
8 | const userAgent: any = ctx.req ? ctx.req.headers['user-agent'] : navigator.userAgent;
9 | ctx.isMobile = /mobile/i.test(userAgent);
10 | }
11 |
--------------------------------------------------------------------------------
/src/client/middleware/MiddlewareNotAuthenticated.ts:
--------------------------------------------------------------------------------
1 | import configService from '~/core/service/ServiceConfig';
2 | import { ConfigDefault } from '../../../config/ConfigDefault';
3 | import { parseCookie } from '~/common/CommonCookie';
4 |
5 | const config: ConfigDefault = configService.getConfig();
6 | const whiteList: Array = config.authWhiteList();
7 |
8 | /**
9 | * 检测是否在白名单中
10 | * @param url
11 | */
12 | function checkWheatherInWhiteList(url: string): boolean {
13 | let isIn: boolean = false;
14 |
15 | for (let index: number = 0; index < whiteList.length; index++) {
16 | const element: string = whiteList[index];
17 |
18 | if (element.indexOf(url) !== -1) {
19 | isIn = true;
20 | break;
21 | }
22 | }
23 |
24 | return isIn;
25 | }
26 |
27 | /**
28 | * 判断是否为未登录
29 | *
30 | * @export
31 | * @param {*} ctx
32 | */
33 | export default function ({ store, redirect, req }: any): void {
34 | if (process.server) {
35 | // 未登录跳转
36 | const originalUrl: string = req.originalUrl;
37 | const redirectUrl: string = `/auth/login?uri=${originalUrl}`;
38 | if (checkWheatherInWhiteList(originalUrl)) {
39 | // 判断COOKIE是否存在
40 | const cookie: any = parseCookie(req.headers.cookie || '');
41 | if (store && store.state && store.state.modules && cookie && cookie.auth) {
42 |
43 | if (!store.state.modules.auth || !store.state.modules.auth.auth) {
44 | let authData: Object;
45 | try {
46 | authData = JSON.parse(decodeURIComponent(cookie.auth));
47 | } catch (error) {
48 | console.log(error);
49 | }
50 | store.state.modules.auth.auth = authData;
51 | }
52 | }
53 |
54 | if (store && store.state && store.state.modules) {
55 | if (!store.state.modules.auth || !store.state.modules.auth.auth) {
56 | return redirect(redirectUrl);
57 | }
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/client/middleware/README.md:
--------------------------------------------------------------------------------
1 | # MIDDLEWARE
2 |
3 | **This directory is not required, you can delete it if you don't want to use it.**
4 |
5 | This directory contains your application middleware.
6 | Middleware let you define custom functions that can be run before rendering either a page or a group of pages.
7 |
8 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing#middleware).
9 |
--------------------------------------------------------------------------------
/src/client/models/ModelCarts.ts:
--------------------------------------------------------------------------------
1 | import { IVO } from '~/core/interfaces/IVo';
2 |
3 | /**
4 | * 基础数据结构
5 | *
6 | * @export
7 | * @interface IVO
8 | */
9 | /**
10 | * 购物车数据结构
11 | *
12 | * @export
13 | * @interface ICarts
14 | */
15 | export interface ICartsItem extends IVO {
16 | id: string;
17 | title: string;
18 | desc: string;
19 | price: number;
20 | num: number;
21 | thumb: string;
22 | thumbList: Array;
23 | userId: string;
24 | }
25 |
26 | /**
27 | * 购物车VO
28 | *
29 | * @export
30 | * @class CartsVO
31 | * @implements {ICarts}
32 | */
33 | export class CartsVO implements ICartsItem {
34 | constructor() {
35 | // hole
36 | }
37 |
38 | /** 增加 */
39 | public static INC_NUM: number = 0;
40 |
41 | /** 减少 */
42 | public static DEC_NUM: number = 1;
43 |
44 | /** 原值传入 */
45 | public static FORCE_NUM: number = 2;
46 |
47 | public id: string;
48 | public title: string;
49 | public desc: string;
50 | public price: number;
51 | public num: number;
52 | public thumb: string;
53 | public thumbList: Array = [];
54 | public userId: string;
55 |
56 | /**
57 | * 更新数据源
58 | *
59 | * @param {*} val
60 | * @memberof CartsVO
61 | */
62 | public update(val: any): void {
63 | if (val) {
64 | this.id = val.id || val._id;
65 | this.title = val.title;
66 | this.desc = val.desc;
67 | this.price = Number(val.price);
68 | this.num = Number(val.num);
69 | this.thumb = val.thumb;
70 | this.userId = val.userId;
71 |
72 | if (val.thumbList && val.thumbList.length) {
73 | for (let index: number = 0; index < val.thumbList.length; index++) {
74 | const element: any = val.thumbList[index];
75 | this.thumbList.push(element);
76 | }
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/client/models/ModelPost.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Post data structs
3 | *
4 | * @export
5 | * @interface Post
6 | */
7 | export default interface IPost {
8 | id: number;
9 | title: string;
10 | description: string;
11 | }
12 |
--------------------------------------------------------------------------------
/src/client/models/ModelUser.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 用户信息
3 | */
4 | export default interface IUser {
5 | accessToken: string;
6 | _id: string;
7 | userName: string;
8 | }
9 |
--------------------------------------------------------------------------------
/src/client/pages/README.md:
--------------------------------------------------------------------------------
1 | # PAGES
2 |
3 | This directory contains your Application Views and Routes.
4 | The framework reads all the `*.vue` files inside this directory and creates the router of your application.
5 |
6 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing).
7 |
--------------------------------------------------------------------------------
/src/client/pages/auth/login/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |

8 |
9 |
10 | 请输入用户名、密码登录
11 |
12 |
13 |
14 |
15 |
16 |
26 |
27 |
28 |
29 |
30 | 请输入用户名、密码登录
31 |
32 |
33 | 登录
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
142 |
143 |
169 |
--------------------------------------------------------------------------------
/src/client/pages/cart/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
30 |
31 | 总共
32 | {{checkedGoods.length}}
33 | 件,商品
34 |
35 |
36 |
37 |
38 |
39 |
157 |
158 |
188 |
--------------------------------------------------------------------------------
/src/client/pages/error/400/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Page not found
4 | An error occurred
5 | Home page
6 |
7 |
8 |
9 |
29 |
30 |
41 |
--------------------------------------------------------------------------------
/src/client/pages/error/500/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Server Error
4 | An error occurred
5 | Home page
6 |
7 |
8 |
9 |
29 |
30 |
41 |
--------------------------------------------------------------------------------
/src/client/pages/goods/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | {{ goods.title }}
13 | {{ formatPrice(goods.price) }}
14 |
15 |
16 | 运费: {{ goods.express }}
17 | 剩余: {{ goods.remain }}
18 |
19 |
20 |
21 |
22 |
23 |
24 | 腾源豆腐店
25 | 自营
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | 客服
37 | 购物车
38 | 加入购物车
39 | 立即购买
40 |
41 |
42 |
43 |
44 |
155 |
156 |
194 |
--------------------------------------------------------------------------------
/src/client/pages/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

7 |
8 |
9 |
10 | 待付款
11 |
12 |
13 | 待接单
14 |
15 |
16 | 待发货
17 |
18 |
19 | 已发货
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | {{ this.$vxm.carts.cartsNum }}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
132 |
133 |
177 |
--------------------------------------------------------------------------------
/src/client/pages/list/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
14 |
15 |
16 |
25 |
26 | {{item.tab.toUpperCase()}}
27 | {{ item.top ? '上升' : '下降' }}
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
123 |
124 |
154 |
--------------------------------------------------------------------------------
/src/client/plugins/PluginAxios.ts:
--------------------------------------------------------------------------------
1 | import configService from '~/core/service/ServiceConfig';
2 | import { NuxtAxiosInstance } from '@nuxtjs/axios';
3 | import { HttpConst } from '~/core/consts/ConstHttp';
4 | import Cookie from 'js-cookie';
5 | import { setCustomHeaderBySSR } from '~/common/CommonCookie';
6 |
7 | /** axios defined */
8 | export let axios: NuxtAxiosInstance = null;
9 |
10 | export const CODE_400: number = 400;
11 | export const CODE_500: number = 500;
12 |
13 | /** axios instance */
14 | export default ({ app, redirect }): any => {
15 | axios = app.$axios;
16 | axios.defaults.baseURL = '';
17 |
18 | configService.saveAxios(axios);
19 |
20 | // Adds header: `Content-Type: application/x-www-form-urlencoded` to only post requests
21 | // axios.setHeader('Content-Type', 'application/x-www-form-urlencoded', [
22 | // 'post'
23 | // ]);
24 |
25 | // Removes default Content-Type header from `post` scope
26 | // axios.setHeader('Content-Type', false, ['post']);
27 |
28 | // Overrides `Authorization` header with new value
29 | // axios.setToken('456');
30 |
31 | // Adds header: `Authorization: Bearer 123` to all requests
32 | // axios.setToken('123', 'Bearer');
33 |
34 | // Adds header: `Authorization: Bearer 123` to only post and delete requests
35 | // axios.setToken('123', 'Bearer', ['post', 'delete']);
36 |
37 | // Removes default Authorization header from `common` scope (all requests)
38 | // axios.setToken(false);
39 | // axios.setHeader('Authorization', getCustomHeader(app));
40 |
41 | // 服务端使用时设置accessToken
42 | setCustomHeaderBySSR(app, axios);
43 |
44 | // 注册状态回调
45 | axios.onRequest((config: any): any => {
46 | // 设置自定义头部,TOKEN, AUTH等
47 | // Adds header: `Authorization: test` to all requests
48 | // console.log(config.url);
49 | });
50 | axios.onResponse((response: any): any => {
51 | // console.log('onResponse..', response);
52 | switch (response.status) {
53 | case HttpConst.STATUS_401:
54 | redirect('/auth/login');
55 | break;
56 | case HttpConst.STATUS_403:
57 | if (process.client) {
58 | Cookie.set('auth', null);
59 | }
60 | redirect('/auth/login');
61 | break;
62 | }
63 | });
64 | axios.onError((error: any): any => {
65 | const code: number = Number(error.response && error.response.status);
66 | if (code === CODE_400) {
67 | redirect('/error/400');
68 | }
69 | if (code === CODE_500) {
70 | redirect('/error/500');
71 | }
72 | });
73 | axios.onRequestError((error: any): any => {
74 | console.log('onRequestError...', error);
75 | });
76 | axios.onResponseError((error: any): any => {
77 | console.log('onResponseError...', error);
78 | });
79 | };
80 |
--------------------------------------------------------------------------------
/src/client/plugins/PluginFlexible.js:
--------------------------------------------------------------------------------
1 | /** REM 自动转换 */
2 | (function flexible(window, document) {
3 | var docEl = document.documentElement
4 | var dpr = window.devicePixelRatio || 1
5 |
6 | // adjust body font size
7 | function setBodyFontSize() {
8 | if (document.body) {
9 | document.body.style.fontSize = (12 * dpr) + 'px'
10 | } else {
11 | document.addEventListener('DOMContentLoaded', setBodyFontSize)
12 | }
13 | }
14 | // setBodyFontSize();
15 |
16 | // set 1rem = viewWidth / 10
17 | function setRemUnit() {
18 | var rem = docEl.clientWidth / 10
19 | docEl.style.fontSize = rem + 'px'
20 | }
21 |
22 | setRemUnit()
23 |
24 | // reset rem unit on page resize
25 | window.addEventListener('resize', setRemUnit)
26 | window.addEventListener('pageshow', function (e) {
27 | if (e.persisted) {
28 | setRemUnit()
29 | }
30 | })
31 |
32 | // detect 0.5px supports
33 | if (dpr >= 2) {
34 | var fakeBody = document.createElement('body')
35 | var testElement = document.createElement('div')
36 | testElement.style.border = '.5px solid transparent'
37 | fakeBody.appendChild(testElement)
38 | docEl.appendChild(fakeBody)
39 | if (testElement.offsetHeight === 1) {
40 | docEl.classList.add('hairlines')
41 | }
42 | docEl.removeChild(fakeBody)
43 | }
44 | }(window, document))
45 |
--------------------------------------------------------------------------------
/src/client/plugins/PluginVant.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import {
3 | Button,
4 | Cell,
5 | CellGroup,
6 | Icon,
7 | Row,
8 | Col,
9 | Dialog,
10 | Toast,
11 | Skeleton,
12 | List,
13 | Tag,
14 | PullRefresh,
15 | NavBar,
16 | Checkbox,
17 | CheckboxGroup,
18 | Card,
19 | SubmitBar,
20 | Swipe,
21 | SwipeItem,
22 | GoodsAction,
23 | GoodsActionIcon,
24 | GoodsActionButton,
25 | Stepper,
26 | Field,
27 | Panel
28 | } from 'vant';
29 |
30 | import 'vant/lib/index.css';
31 |
32 | // 注册通用底层组件
33 | Vue.use(Button);
34 | Vue.use(Cell).use(CellGroup);
35 | Vue.use(Icon);
36 | Vue.use(Row).use(Col);
37 | Vue.use(Dialog);
38 | Vue.use(Skeleton);
39 | Vue.use(List);
40 | Vue.use(PullRefresh);
41 | Vue.use(NavBar);
42 | Vue.use(Tag);
43 | Vue.use(Col);
44 | Vue.use(Icon);
45 | Vue.use(Cell);
46 | Vue.use(CellGroup);
47 | Vue.use(Swipe);
48 | Vue.use(SwipeItem);
49 | Vue.use(GoodsAction);
50 | Vue.use(GoodsActionIcon);
51 | Vue.use(GoodsActionButton);
52 | Vue.use(Checkbox);
53 | Vue.use(CheckboxGroup);
54 | Vue.use(Card);
55 | Vue.use(SubmitBar);
56 | Vue.use(Toast);
57 | Vue.use(Stepper);
58 | Vue.use(Field);
59 | Vue.use(Panel);
60 |
--------------------------------------------------------------------------------
/src/client/plugins/README.md:
--------------------------------------------------------------------------------
1 | # PLUGINS
2 |
3 | **This directory is not required, you can delete it if you don't want to use it.**
4 |
5 | This directory contains Javascript plugins that you want to run before mounting the root Vue.js application.
6 |
7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins).
8 |
--------------------------------------------------------------------------------
/src/client/routers/RoutersClient.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 路由常量定义
3 | *
4 | * @export
5 | * @class Routers
6 | */
7 | export default class Routers {
8 |
9 | /**
10 | * 购物车页
11 | *
12 | * @static
13 | * @type {string}
14 | * @memberof Routers
15 | */
16 | public static CART_PAGE: string = 'cart';
17 |
18 | /**
19 | * 物品页
20 | *
21 | * @static
22 | * @type {string}
23 | * @memberof Routers
24 | */
25 | public static GOODS_PAGE: string = 'goods';
26 |
27 | /**
28 | * 首页
29 | *
30 | * @static
31 | * @type {string}
32 | * @memberof Routers
33 | */
34 | public static HOME_PAGE: string = '';
35 |
36 | /**
37 | * 列表页
38 | *
39 | * @static
40 | * @type {string}
41 | * @memberof Routers
42 | */
43 | public static LIST_PAGE: string = 'list';
44 |
45 | /**
46 | * 登录页
47 | *
48 | * @static
49 | * @type {string}
50 | * @memberof Routers
51 | */
52 | public static LOGIN_PAGE: string = 'auth/login';
53 | }
54 |
--------------------------------------------------------------------------------
/src/client/service/ServiceCNode.ts:
--------------------------------------------------------------------------------
1 | import { BaseOption } from '~/core/service/ServiceBase';
2 | import configService from '~/core/service/ServiceConfig';
3 | import { TransportService } from '~/core/service/ServiceTransport';
4 |
5 | /**
6 | * cn node服务(中转方式,解决跨域问题)
7 | *
8 | * @class CnNodeService
9 | * @extends {TransportService}
10 | */
11 | class CnNodeService extends TransportService {
12 | constructor() {
13 | const baseOption: BaseOption = new BaseOption();
14 | baseOption.baseUrl = configService.getConfig().cnodeUrl;
15 | super(baseOption);
16 | }
17 |
18 | /**
19 | * 获取主题列表
20 | *
21 | * @returns {Promise}
22 | * @memberof CnNodeService
23 | */
24 | public async getTopics(): Promise {
25 | return await this.get('/api/v1/topics');
26 | }
27 | }
28 |
29 | export default new CnNodeService();
30 |
--------------------------------------------------------------------------------
/src/client/service/ServiceLocal.ts:
--------------------------------------------------------------------------------
1 | import { BaseService, BaseOption } from '~/core/service/ServiceBase';
2 | import configService from '~/core/service/ServiceConfig';
3 | import { CartsVO } from '~/models/ModelCarts';
4 | /**
5 | * 本地 node服务
6 | *
7 | * @class LocalService
8 | * @extends {BaseService}
9 | */
10 | class LocalService extends BaseService {
11 | constructor() {
12 | const baseOption: BaseOption = new BaseOption();
13 | baseOption.baseUrl = configService.getConfig().localUrl;
14 | baseOption.isLocalHost = true;
15 | super(baseOption);
16 | }
17 |
18 | /**
19 | * 登录
20 | * @description login
21 | * @param userName
22 | * @param password
23 | * @returns to cart
24 | */
25 | public async login(userName: string, password: string): Promise {
26 | return await this.post('/api/local/login', {
27 | userName,
28 | password
29 | });
30 | }
31 |
32 | /**
33 | * 调用接口添加入购物车
34 | * @description Adds to cart
35 | * @param cartsVO
36 | * @param forceType 是否原值存入
37 | * @returns to cart
38 | */
39 | public async addToCart(cartsVO: CartsVO, forceType: number = 0): Promise {
40 | return await this.post('/api/local/addToCart', {
41 | id: cartsVO.id,
42 | num: cartsVO.num,
43 | forceType,
44 | userId: cartsVO.userId
45 | });
46 | }
47 |
48 | /**
49 | * 获取已选择商品数据ID列表
50 | *
51 | * @returns {Promise}
52 | * @memberof LocalService
53 | */
54 | public async getGoodsListData(userId: string): Promise {
55 | return await this.get(`/api/local/getCarts?userId=${userId}`);
56 | }
57 |
58 | /**
59 | * 获取已选择商品列表数据项
60 | *
61 | * @returns {Promise}
62 | * @memberof LocalService
63 | */
64 | public async getCartsListData(params: Array): Promise {
65 | return await this.post('/api/local/getCartsListData', { list: params });
66 | }
67 |
68 | /**
69 | * 获取商品页面单个商品数据
70 | *
71 | * @returns {Promise}
72 | * @memberof LocalService
73 | */
74 | public async getGoodsData(): Promise {
75 | return await this.get('/api/local/getGoods');
76 | }
77 |
78 | /**
79 | * 获取商品列表数据
80 | *
81 | * @returns {Promise}
82 | * @memberof LocalService
83 | */
84 | public async getListData(): Promise {
85 | return await this.get('/api/local/getList');
86 | }
87 | }
88 |
89 | export default new LocalService();
90 |
--------------------------------------------------------------------------------
/src/client/service/ServiceNews.ts:
--------------------------------------------------------------------------------
1 | import { BaseService, BaseOption } from '~/core/service/ServiceBase';
2 | import configService from '~/core/service/ServiceConfig';
3 |
4 | /**
5 | * cn node服务(非中转)
6 | *
7 | * @class NewsService
8 | * @extends {BaseService}
9 | */
10 | class NewsService extends BaseService {
11 | constructor() {
12 | const baseOption: BaseOption = new BaseOption();
13 | baseOption.baseUrl = configService.getConfig().cnodeUrl;
14 | super(baseOption);
15 | }
16 |
17 | /**
18 | * 获取主题列表
19 | *
20 | * @returns {Promise}
21 | * @memberof CnNodeService
22 | */
23 | public async getTopics(): Promise {
24 | return await this.get('/api/v1/topics');
25 | }
26 | }
27 |
28 | export default new NewsService();
29 |
--------------------------------------------------------------------------------
/src/client/static/README.md:
--------------------------------------------------------------------------------
1 | # STATIC
2 |
3 | **This directory is not required, you can delete it if you don't want to use it.**
4 |
5 | This directory contains your static files.
6 | Each file inside this directory is mapped to `/`.
7 | Thus you'd want to delete this README.md before deploying to production.
8 |
9 | Example: `/static/robots.txt` is mapped as `/robots.txt`.
10 |
11 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static).
12 |
--------------------------------------------------------------------------------
/src/client/static/about.js:
--------------------------------------------------------------------------------
1 | console.log('about.js loaded!');
2 |
--------------------------------------------------------------------------------
/src/client/static/body.js:
--------------------------------------------------------------------------------
1 | console.log('body.js loaded!');
2 |
--------------------------------------------------------------------------------
/src/client/static/carts.json:
--------------------------------------------------------------------------------
1 | {
2 | "list": [{
3 | "id": "1",
4 | "title": "进口香蕉",
5 | "desc": "约250g,2根",
6 | "price": 200,
7 | "num": "1",
8 | "thumb": "https://img.yzcdn.cn/public_files/2017/10/24/2f9a36046449dafb8608e99990b3c205.jpeg"
9 | }, {
10 | "id": "2",
11 | "title": "陕西蜜梨",
12 | "desc": "约600g",
13 | "price": 690,
14 | "num": "1",
15 | "thumb": "https://img.yzcdn.cn/public_files/2017/10/24/f6aabd6ac5521195e01e8e89ee9fc63f.jpeg"
16 | }, {
17 | "id": "3",
18 | "title": "美国伽力果",
19 | "desc": "约680g/3个",
20 | "price": 2680,
21 | "num": "1",
22 | "thumb": "https://img.yzcdn.cn/public_files/2017/10/24/320454216bbe9e25c7651e1fa51b31fd.jpeg"
23 | }]
24 | }
25 |
--------------------------------------------------------------------------------
/src/client/static/defer.js:
--------------------------------------------------------------------------------
1 | console.log('defer.js loaded!');
2 |
--------------------------------------------------------------------------------
/src/client/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1166544/nuxt.js-nest.js-isomorphism/37a442a3b09e4566580e08b8027634e153ac7ac2/src/client/static/favicon.ico
--------------------------------------------------------------------------------
/src/client/static/friends.json:
--------------------------------------------------------------------------------
1 | {
2 | "friends": [
3 | {
4 | "id": 0,
5 | "name": "Roth Murray"
6 | },
7 | {
8 | "id": 1,
9 | "name": "Colette Church"
10 | },
11 | {
12 | "id": 2,
13 | "name": "Washington Best"
14 | }
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/src/client/static/goods.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "美国伽力果(约680g/3个)",
3 | "price": 2680,
4 | "express": "免邮",
5 | "remain": 19,
6 | "desc": "约680g/3个",
7 | "num": "1",
8 | "thumb": "https://img.yzcdn.cn/public_files/2017/10/24/e5a5a02309a41f9f5def56684808d9ae.jpeg",
9 | "thumbList": ["https://img.yzcdn.cn/public_files/2017/10/24/e5a5a02309a41f9f5def56684808d9ae.jpeg", "https://img.yzcdn.cn/public_files/2017/10/24/1791ba14088f9c2be8c610d0a6cc0f93.jpeg"]
10 | }
11 |
--------------------------------------------------------------------------------
/src/client/static/head.js:
--------------------------------------------------------------------------------
1 | console.log('hesad.js loaded!');
2 |
--------------------------------------------------------------------------------
/src/client/static/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow: /cart/
3 | Disallow: /*?*
4 | Disallow: /*.sql
5 | Disallow: /*.js
6 | Disallow: /*.css
7 | Disallow: /*.asmx
8 |
--------------------------------------------------------------------------------
/src/client/static/v.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1166544/nuxt.js-nest.js-isomorphism/37a442a3b09e4566580e08b8027634e153ac7ac2/src/client/static/v.png
--------------------------------------------------------------------------------
/src/client/store/README.md:
--------------------------------------------------------------------------------
1 | # STORE
2 |
3 | **This directory is not required, you can delete it if you don't want to use it.**
4 |
5 | This directory contains your Vuex Store files.
6 | Vuex Store option is implemented in the Nuxt.js framework.
7 |
8 | Creating a file in this directory automatically activates the option in the framework.
9 |
10 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store).
11 |
--------------------------------------------------------------------------------
/src/client/store/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuex from 'vuex';
3 | import { root, RootStore } from './modules/root';
4 | import { carts, CartsStore } from './modules/carts';
5 | import { auth, AuthStore } from './modules/auth';
6 |
7 | Vue.use(Vuex);
8 |
9 | /** store */
10 | export const store: any = new Vuex.Store({
11 | modules: {
12 | root,
13 | carts,
14 | auth
15 | }
16 | });
17 |
18 | /** 注册store实例 */
19 | Vue.prototype.$vxm = {
20 | root: RootStore.CreateProxy(store, RootStore),
21 | carts: CartsStore.CreateProxy(store, CartsStore),
22 | auth: CartsStore.CreateProxy(store, AuthStore)
23 | };
24 |
25 | /** 定义接口格式用于TS语法提示 */
26 | declare module 'vue/types/vue' {
27 |
28 | /** define vue interface */
29 | // tslint:disable-next-line:interface-name
30 | interface Vue {
31 | $vxm: {
32 | root: RootStore;
33 | carts: CartsStore;
34 | auth: AuthStore;
35 | };
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/client/store/modules/auth.ts:
--------------------------------------------------------------------------------
1 | import {
2 | action,
3 | Module,
4 | mutation,
5 | VuexModule
6 | } from 'vuex-class-component';
7 | // import { axios } from '~/plugins/axios.plugins';
8 |
9 | /**
10 | * RootStore define
11 | *
12 | * @export
13 | * @class RootStore
14 | * @extends {VuexModule}
15 | */
16 | @Module({ namespacedPath: 'auth/' })
17 | export class AuthStore extends VuexModule {
18 | private authData: any = null;
19 |
20 | /**
21 | * set auth
22 | *
23 | * @param {*} authData
24 | * @memberof RootStore
25 | */
26 | @mutation
27 | public setAuth(authData: any): void {
28 | this.authData = authData;
29 | }
30 |
31 | /**
32 | * 获取auth
33 | *
34 | * @readonly
35 | * @type {*}
36 | * @memberof RootStore
37 | */
38 | public get auth(): any {
39 | return this.authData;
40 | }
41 |
42 | /**
43 | * 获取auth(异步方式)
44 | *
45 | * @returns {Promise}
46 | * @memberof RootStore
47 | */
48 | @action()
49 | public async getAuth(): Promise {
50 | // const data: any = await axios.get('/friends.json');
51 | // this.setAuth(data.data.data);
52 | // hole
53 | }
54 | }
55 |
56 | /** AuthStore */
57 | export const auth: any = AuthStore.ExtractVuexModule(AuthStore);
58 |
--------------------------------------------------------------------------------
/src/client/store/modules/carts.ts:
--------------------------------------------------------------------------------
1 | import {
2 | action,
3 | Module,
4 | mutation,
5 | VuexModule
6 | } from 'vuex-class-component';
7 | import { ICartsItem, CartsVO } from '~/models/ModelCarts';
8 | // import { axios } from '~/plugins/axios.plugins';
9 |
10 | /**
11 | * 购物车Store定义
12 | *
13 | * @export
14 | * @class CartsStore
15 | * @extends {VuexModule}
16 | */
17 | @Module({ namespacedPath: 'carts/' })
18 | export class CartsStore extends VuexModule {
19 |
20 | /**
21 | * 购物车物品总数
22 | *
23 | * @type {Array}
24 | * @memberof CartsStore
25 | */
26 | private cartsListSource: Array = [];
27 |
28 | /**
29 | * 获取购物车物品数量
30 | *
31 | * @readonly
32 | * @type {*}
33 | * @memberof CartsStore
34 | */
35 | public get cartsList(): Array {
36 | return this.cartsListSource;
37 | }
38 |
39 | /**
40 | * 获取购物车列表数据
41 | *
42 | * @readonly
43 | * @type {number}
44 | * @memberof CartsStore
45 | */
46 | public get cartsNum(): number {
47 | let totalNum: number = 0;
48 | for (let index: number = 0; index < this.cartsListSource.length; index++) {
49 | const element: CartsVO = this.cartsListSource[index];
50 | totalNum += element.num;
51 | }
52 |
53 | return totalNum;
54 | }
55 |
56 | /**
57 | * 设置购物车物品
58 | *
59 | * @param {*} friends
60 | * @memberof CartsStore
61 | */
62 | @mutation
63 | public addCarts(item: ICartsItem): void {
64 | this.cartsListSource.push(item);
65 | }
66 |
67 | /**
68 | * 更新购物车列表
69 | *
70 | * @param {Array} cartsList
71 | * @memberof CartsStore
72 | */
73 | @mutation
74 | public updateCarts(cartsList: Array): void {
75 | this.cartsListSource = cartsList;
76 | }
77 |
78 | /**
79 | * 更新购物车列表内商品数量
80 | *
81 | * @param ICartsItem item
82 | * @memberof CartsStore
83 | */
84 | @mutation
85 | public updateCartsNum(item: ICartsItem): void {
86 | for (let index: number = 0; index < this.cartsListSource.length; index++) {
87 | const element: CartsVO = this.cartsListSource[index];
88 |
89 | if (element.id === item.id) {
90 | element.num++;
91 | }
92 | }
93 | }
94 |
95 | /**
96 | * 异步获取购物车物品,例如调用接口
97 | *
98 | * @returns {Promise}
99 | * @memberof CartsStore
100 | */
101 | @action()
102 | public async getCartsListFromAsync(addedCartsList: Array): Promise {
103 | if (this.cartsNum) {
104 | return '';
105 | }
106 |
107 | let data: Array;
108 |
109 | if (addedCartsList) {
110 | // 页面渲染时已初始化
111 | if (addedCartsList && addedCartsList.length) {
112 | data = addedCartsList;
113 | }
114 | }
115 |
116 | if (data && data.length) {
117 | while (data.length) {
118 | const item: any = data.shift();
119 | const cartItem: CartsVO = new CartsVO();
120 |
121 | cartItem.update(item);
122 | this.addCarts(cartItem);
123 | }
124 | }
125 |
126 | return data;
127 | }
128 | }
129 |
130 | /** CartsStore */
131 | export const carts: any = CartsStore.ExtractVuexModule(CartsStore);
132 |
--------------------------------------------------------------------------------
/src/client/store/modules/root.ts:
--------------------------------------------------------------------------------
1 | import {
2 | action,
3 | Module,
4 | mutation,
5 | VuexModule
6 | } from 'vuex-class-component';
7 | import { axios } from '~/plugins/PluginAxios';
8 |
9 | /**
10 | * RootStore define
11 | *
12 | * @export
13 | * @class RootStore
14 | * @extends {VuexModule}
15 | */
16 | @Module({ namespacedPath: 'root/' })
17 | export class RootStore extends VuexModule {
18 | public friends: any = [];
19 |
20 | /**
21 | * set friends
22 | *
23 | * @param {*} friends
24 | * @memberof RootStore
25 | */
26 | @mutation
27 | public setFriends(friends: any): void {
28 | this.friends = friends;
29 | }
30 |
31 | /**
32 | * 获取列表 get
33 | *
34 | * @readonly
35 | * @type {*}
36 | * @memberof RootStore
37 | */
38 | public get rFriends(): any {
39 | return this.friends;
40 | }
41 |
42 | /**
43 | * 获取列表
44 | *
45 | * @returns {Promise}
46 | * @memberof RootStore
47 | */
48 | @action()
49 | public async getFriends(): Promise {
50 | console.log('root friends right?');
51 | const data: any = await axios.get('/friends.json');
52 |
53 | this.setFriends(data.data.friends);
54 | }
55 | }
56 |
57 | /** RootStore */
58 | export const root: any = RootStore.ExtractVuexModule(RootStore);
59 |
--------------------------------------------------------------------------------
/src/server/AppController.ts:
--------------------------------------------------------------------------------
1 | import { Controller, Get } from '@nestjs/common';
2 |
3 | /**
4 | * App controller
5 | *
6 | * @export
7 | * @class AppController
8 | */
9 | @Controller()
10 | export class AppController {
11 | // tslint:disable-next-line:completed-docs
12 | @Get('/test')
13 | public test(): string {
14 | return 'Server OK.';
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/server/AppModule.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { CatsModule } from './modules/cats/CatsModule';
3 | import { TransportModule } from './modules/transport/TransportModule';
4 | import { AppController } from './AppController';
5 | import { LocalModule } from './modules/local/LocalModule';
6 |
7 | /**
8 | * App Module
9 | *
10 | * @export
11 | * @class ApplicationModule
12 | */
13 | @Module({
14 | imports: [CatsModule, TransportModule, LocalModule],
15 | controllers: [AppController]
16 | })
17 | export class ApplicationModule {}
18 |
--------------------------------------------------------------------------------
/src/server/Main.ts:
--------------------------------------------------------------------------------
1 | import { ValidationPipe } from '@nestjs/common';
2 | import { NestFactory } from '@nestjs/core';
3 | // tslint:disable-next-line: no-implicit-dependencies
4 | import Consola from 'consola';
5 | import config from '../../nuxt.config';
6 | import { ApplicationModule } from './AppModule';
7 | import NuxtServer from './common/nuxt/CommonNuxtServer';
8 | import { NuxtFilter } from './common/nuxt/CommonNuxtFilter';
9 | import configService from '../client/core/service/ServiceConfig';
10 | import { ConfigDefault } from '../../config/ConfigDefault';
11 |
12 | // tslint:disable-next-line:completed-docs
13 | declare const module: any;
14 |
15 | /**
16 | * bootstrap
17 | *
18 | */
19 | // tslint:disable-next-line:typedef
20 | async function bootstrap() {
21 | const { host, port } = config.env;
22 | const serverPort: number = process.env.PORT || port;
23 |
24 | const nuxt: any = await NuxtServer.getInstance().run(
25 | config.dev ? !module.hot._main : true
26 | );
27 | const server: any = await NestFactory.create(ApplicationModule);
28 | const configer: ConfigDefault = configService.getConfig();
29 |
30 | server.useGlobalFilters(new NuxtFilter(nuxt));
31 | server.useGlobalPipes(new ValidationPipe());
32 | server.setGlobalPrefix(configer.getGlobalPrefix());
33 | await server.listen(serverPort, host, () => {
34 | Consola.ready({
35 | message: `Server listening on http://${host}:${serverPort}`,
36 | badge: true
37 | });
38 | });
39 |
40 | if (config.dev && module.hot) {
41 | module.hot.accept();
42 | module.hot.dispose(() => server.close());
43 | }
44 | }
45 |
46 | bootstrap();
47 |
--------------------------------------------------------------------------------
/src/server/common/core/CommonEngineController.ts:
--------------------------------------------------------------------------------
1 | import { HttpStatus } from '@nestjs/common';
2 |
3 | /**
4 | * CONTROLLER基类
5 | */
6 | export class EngineController {
7 | /**
8 | * 格式化列表返回数据结构
9 | * @param total 总条数
10 | * @param pageSize 每页数
11 | * @param pageNo 当前页
12 | * @param pages 总页数
13 | * @param list 集合数据
14 | * @param {number} [code=HttpStatus.OK]
15 | * @param {string} [message='操作成功']
16 | * @param {boolean} [success=true]
17 | */
18 | public encapsulationReturnList(
19 | total: number,
20 | pageSize: number,
21 | pageNo: number,
22 | pages: number,
23 | list: Array,
24 | code: number = HttpStatus.OK,
25 | message: string = '操作成功',
26 | success: boolean = true
27 | ): any {
28 | return {
29 | code,
30 | message,
31 | success,
32 | data: {
33 | total,
34 | pageSize,
35 | pageNo,
36 | pages,
37 | list
38 | }
39 | };
40 | }
41 |
42 | /**
43 | * 格式化普通对像返回结构
44 | *
45 | * @param {*} data
46 | * @param {number} [code=HttpStatus.OK]
47 | * @param {string} [message='操作成功']
48 | * @param {boolean} [success=true]
49 | * @returns
50 | * @memberof EngineController
51 | */
52 | public encapsulationReturnObject(
53 | data: any,
54 | code: number = HttpStatus.OK,
55 | message: string = '操作成功',
56 | success: boolean = true
57 | ): any {
58 | return {
59 | code,
60 | message,
61 | success,
62 | data
63 | };
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/server/common/decorators/CommonRolesDecorator.ts:
--------------------------------------------------------------------------------
1 | import { SetMetadata } from '@nestjs/common';
2 |
3 | /** Roles const */
4 | // tslint:disable-next-line: variable-name
5 | export const Roles: any = (...roles: string[]): any => SetMetadata('roles', roles);
6 |
--------------------------------------------------------------------------------
/src/server/common/filters/CommonHttpExceptionFilter.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ArgumentsHost,
3 | Catch,
4 | ExceptionFilter,
5 | HttpException
6 | } from '@nestjs/common';
7 |
8 | /**
9 | * Http exception filter
10 | *
11 | * @export
12 | * @class HttpExceptionFilter
13 | * @implements {ExceptionFilter}
14 | */
15 | @Catch(HttpException)
16 | export class HttpExceptionFilter implements ExceptionFilter {
17 |
18 | /**
19 | * Catch error
20 | *
21 | * @param {HttpException} exception
22 | * @param {ArgumentsHost} host
23 | * @memberof HttpExceptionFilter
24 | */
25 | public catch(exception: HttpException, host: ArgumentsHost): void {
26 | const ctx: any = host.switchToHttp();
27 | const response: any = ctx.getResponse();
28 | const request: any = ctx.getRequest();
29 | const statusCode: any = exception.getStatus();
30 |
31 | response.status(statusCode).json({
32 | statusCode,
33 | timestamp: new Date().toISOString(),
34 | path: request.url
35 | });
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/server/common/guards/CommonRolesGuard.ts:
--------------------------------------------------------------------------------
1 | import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
2 | import { Reflector } from '@nestjs/core';
3 |
4 | /**
5 | * RolesGurad
6 | *
7 | * @export
8 | * @class RolesGuard
9 | * @implements {CanActivate}
10 | */
11 | @Injectable()
12 | export class RolesGuard implements CanActivate {
13 | constructor(private readonly reflector: Reflector) { }
14 |
15 | /**
16 | * can active
17 | *
18 | * @param {ExecutionContext} context
19 | * @returns {boolean}
20 | * @memberof RolesGuard
21 | */
22 | public canActivate(context: ExecutionContext): boolean {
23 | const roles: any = this.reflector.get('roles', context.getHandler());
24 | if (!roles) {
25 | return true;
26 | }
27 | const request: any = context.switchToHttp().getRequest();
28 | const user: any = request.user;
29 | const hasRole: any = (): any =>
30 | user.roles.some((role) => !!roles.find((item) => item === role));
31 |
32 | return user && user.roles && hasRole();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/server/common/interceptors/CommonExceptionInterceptor.ts:
--------------------------------------------------------------------------------
1 | import {
2 | CallHandler,
3 | ExecutionContext,
4 | HttpException,
5 | HttpStatus,
6 | Injectable,
7 | NestInterceptor
8 | } from '@nestjs/common';
9 | import { Observable, throwError } from 'rxjs';
10 | import { catchError } from 'rxjs/operators';
11 |
12 | /**
13 | * ErrorsInterrecptor
14 | *
15 | * @export
16 | * @class ErrorsInterceptor
17 | * @implements {NestInterceptor}
18 | */
19 | @Injectable()
20 | export class ErrorsInterceptor implements NestInterceptor {
21 |
22 | /**
23 | * intercept
24 | *
25 | * @param {ExecutionContext} context
26 | * @param {CallHandler} next
27 | * @returns {Observable}
28 | * @memberof ErrorsInterceptor
29 | */
30 | public intercept(context: ExecutionContext, next: CallHandler): Observable {
31 | return next
32 | .handle()
33 | .pipe(
34 | catchError((err) =>
35 | throwError(new HttpException('New message', HttpStatus.BAD_GATEWAY))
36 | )
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/server/common/interceptors/CommonLoggingInterceptor.ts:
--------------------------------------------------------------------------------
1 | import {
2 | CallHandler,
3 | ExecutionContext,
4 | Injectable,
5 | NestInterceptor
6 | } from '@nestjs/common';
7 | import { Observable } from 'rxjs';
8 | import { tap } from 'rxjs/operators';
9 |
10 | /**
11 | * Logging interceptor
12 | *
13 | * @export
14 | * @class LoggingInterceptor
15 | * @implements {NestInterceptor}
16 | */
17 | @Injectable()
18 | export class LoggingInterceptor implements NestInterceptor {
19 |
20 | /**
21 | * intercept
22 | *
23 | * @param {ExecutionContext} context
24 | * @param {CallHandler} next
25 | * @returns {Observable}
26 | * @memberof LoggingInterceptor
27 | */
28 | public intercept(context: ExecutionContext, next: CallHandler): Observable {
29 | console.log('Before...');
30 |
31 | const now: any = Date.now();
32 |
33 | return next
34 | .handle()
35 | .pipe(tap(() => console.log(`After... ${Date.now() - now}ms`)));
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/server/common/interceptors/CommonTimeoutInterceptor.ts:
--------------------------------------------------------------------------------
1 | import {
2 | CallHandler,
3 | ExecutionContext,
4 | Injectable,
5 | NestInterceptor
6 | } from '@nestjs/common';
7 | import { Observable } from 'rxjs';
8 | import { timeout } from 'rxjs/operators';
9 |
10 | /**
11 | * Timeout intercept
12 | *
13 | * @export
14 | * @class TimeoutInterceptor
15 | * @implements {NestInterceptor}
16 | */
17 | @Injectable()
18 | export class TimeoutInterceptor implements NestInterceptor {
19 |
20 | /**
21 | * intercept
22 | *
23 | * @param {ExecutionContext} context
24 | * @param {CallHandler} next
25 | * @returns {Observable}
26 | * @memberof TimeoutInterceptor
27 | */
28 | public intercept(context: ExecutionContext, next: CallHandler): Observable {
29 | const timeoutNum: number = 5000;
30 |
31 | return next.handle().pipe(timeout(timeoutNum));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/server/common/interceptors/CommonTransformInterceptor.ts:
--------------------------------------------------------------------------------
1 | import {
2 | CallHandler,
3 | ExecutionContext,
4 | Injectable,
5 | NestInterceptor
6 | } from '@nestjs/common';
7 | import { Observable } from 'rxjs';
8 | import { map } from 'rxjs/operators';
9 |
10 | /**
11 | * Response
12 | *
13 | * @export
14 | * @interface Response
15 | * @template T
16 | */
17 | export interface IResponse {
18 | data: T;
19 | }
20 |
21 | /**
22 | * TransformInterreptor
23 | *
24 | * @export
25 | * @class TransformInterceptor
26 | * @implements {NestInterceptor>}
27 | * @template T
28 | */
29 | @Injectable()
30 | export class TransformInterceptor implements NestInterceptor> {
31 |
32 | /**
33 | * handle intercept
34 | *
35 | * @param {ExecutionContext} context
36 | * @param {CallHandler} next
37 | * @returns {Observable>}
38 | * @memberof TransformInterceptor
39 | */
40 | public intercept(
41 | context: ExecutionContext,
42 | next: CallHandler
43 | ): Observable> {
44 | return next.handle().pipe(
45 | map(
46 | (data: any) => ({ data })
47 | )
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/server/common/middleware/CommonHttpMiddleware.ts:
--------------------------------------------------------------------------------
1 | import Axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
2 | import { defer, Observable } from 'rxjs';
3 | import ProxyAgent from 'proxy-agent';
4 | import { ConfigDefault } from '../../../../config/ConfigDefault';
5 | import configService from '../../../client/core/service/ServiceConfig';
6 |
7 | /**
8 | *
9 | * http 请求封装基类
10 | * @export
11 | * @class BaseHttpClient
12 | */
13 | export class BaseHttpClient {
14 | /**
15 | * http代理地址
16 | */
17 | private proxyUri: string;
18 |
19 | /**
20 | * Axios 实例
21 | */
22 | private readonly instance: AxiosInstance = Axios;
23 |
24 | constructor() {
25 | // 读取配置
26 | const configer: ConfigDefault = configService.getConfig();
27 | this.proxyUri = configer.getProxyAddress();
28 |
29 | // 请求拦截
30 | this.instance.interceptors.request.use(
31 | (request: AxiosRequestConfig) => {
32 | request.headers.startInvokeTime = Date.now();
33 | // 开发模式则添加代理-charles
34 | if (process.env.NODE_ENV === ConfigDefault.ENV_DEV) {
35 | process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
36 | request.httpAgent = new ProxyAgent(this.proxyUri);
37 | request.httpsAgent = new ProxyAgent(this.proxyUri);
38 | }
39 |
40 | return request;
41 | },
42 | (error: any) => {
43 | // hole 采集上传错误日志 error.response || {}
44 | }
45 | );
46 |
47 | // 响应拦截
48 | this.instance.interceptors.response.use(
49 | (response: AxiosResponse) => {
50 | // hole 采信响应日志 response
51 |
52 | return response;
53 | },
54 | (error) => {
55 | // hole 采集响应错误日志 console.log('error.......', error);
56 | // const copyHeaders: any = { ...(error.config.headers || {}) };
57 | // `Error: ${error.syscall} ${error.errno} ${error.hostname} ${error.port}`
58 | throw error;
59 | }
60 | );
61 | }
62 |
63 | /**
64 | * request 请求
65 | * @template T
66 | * @param {AxiosRequestConfig} config
67 | * @returns {Observable>}
68 | * @memberof BaseHttpClient
69 | */
70 | public request(
71 | config: AxiosRequestConfig
72 | ): Observable> {
73 | return defer(() => this.instance.request(config));
74 | }
75 |
76 | /**
77 | * get 请求
78 | * @template T
79 | * @param {string} url
80 | * @param {AxiosRequestConfig} [config]
81 | * @returns {Observable>}
82 | * @memberof BaseHttpClient
83 | */
84 | public get(
85 | url: string,
86 | config?: AxiosRequestConfig
87 | ): Observable> {
88 | return defer(() => this.instance.get(url, config));
89 | }
90 |
91 | /**
92 | *
93 | * delete
94 | * @template T
95 | * @param {string} url
96 | * @param {AxiosRequestConfig} [config]
97 | * @returns {Observable>}
98 | * @memberof BaseHttpClient
99 | */
100 | public delete(
101 | url: string,
102 | config?: AxiosRequestConfig
103 | ): Observable> {
104 | return defer(() => this.instance.delete(url, config));
105 | }
106 |
107 | /**
108 | *
109 | * head
110 | * @template T
111 | * @param {string} url
112 | * @param {AxiosRequestConfig} [config]
113 | * @returns {Observable>}
114 | * @memberof BaseHttpClient
115 | */
116 | public head(
117 | url: string,
118 | config?: AxiosRequestConfig
119 | ): Observable> {
120 | return defer(() => this.instance.head(url, config));
121 | }
122 |
123 | /**
124 | *
125 | * post
126 | * @template T
127 | * @param {string} url
128 | * @param {*} [data]
129 | * @param {AxiosRequestConfig} [config]
130 | * @returns {Observable>}
131 | * @memberof BaseHttpClient
132 | */
133 | public post(
134 | url: string,
135 | data?: any,
136 | config?: AxiosRequestConfig
137 | ): Observable> {
138 | return defer(() => this.instance.post(url, data, config));
139 | }
140 |
141 | /**
142 | *
143 | * put
144 | * @template T
145 | * @param {string} url
146 | * @param {*} [data]
147 | * @param {AxiosRequestConfig} [config]
148 | * @returns {Observable>}
149 | * @memberof BaseHttpClient
150 | */
151 | public put(
152 | url: string,
153 | data?: any,
154 | config?: AxiosRequestConfig
155 | ): Observable> {
156 | return defer(() => this.instance.put(url, data, config));
157 | }
158 |
159 | /**
160 | *
161 | * patch
162 | * @template T
163 | * @param {string} url
164 | * @param {*} [data]
165 | * @param {AxiosRequestConfig} [config]
166 | * @returns {Observable>}
167 | * @memberof BaseHttpClient
168 | */
169 | public patch(
170 | url: string,
171 | data?: any,
172 | config?: AxiosRequestConfig
173 | ): Observable> {
174 | return defer(() => this.instance.patch(url, data, config));
175 | }
176 |
177 | /**
178 | *
179 | * AxiosInstance
180 | * @readonly
181 | * @type {AxiosInstance}
182 | * @memberof BaseHttpClient
183 | */
184 | public get axiosRef(): AxiosInstance {
185 | return this.instance;
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/src/server/common/middleware/CommonLoggerMiddleware.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, NestMiddleware } from '@nestjs/common';
2 |
3 | /**
4 | * LoggerMiddleware
5 | *
6 | * @export
7 | * @class LoggerMiddleware
8 | * @implements {NestMiddleware}
9 | */
10 | @Injectable()
11 | export class LoggerMiddleware implements NestMiddleware {
12 |
13 | /**
14 | * use middleware
15 | *
16 | * @param {*} req
17 | * @param {*} res
18 | * @param {() => void} next
19 | * @memberof LoggerMiddleware
20 | */
21 | public use(req: any, res: any, next: () => void): void {
22 | console.log('Request...');
23 | next();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/server/common/nuxt/CommonNuxtFilter.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ArgumentsHost,
3 | Catch,
4 | ExceptionFilter,
5 | HttpException,
6 | HttpStatus
7 | } from '@nestjs/common';
8 | import { Nuxt } from 'nuxt';
9 |
10 | /**
11 | * NUXT过滤器
12 | *
13 | * @export
14 | * @class NuxtFilter
15 | * @implements {ExceptionFilter}
16 | */
17 | @Catch()
18 | export class NuxtFilter implements ExceptionFilter {
19 | private readonly nuxt: Nuxt;
20 |
21 | constructor(nuxt: Nuxt) {
22 | this.nuxt = nuxt;
23 | }
24 |
25 | /**
26 | * catch
27 | *
28 | * @param {HttpException} exception
29 | * @param {ArgumentsHost} host
30 | * @memberof NuxtFilter
31 | */
32 | public async catch(exception: HttpException, host: ArgumentsHost): Promise {
33 |
34 | try {
35 | if (exception && !exception.hasOwnProperty('getStatus')) {
36 | const response: any = exception.getResponse();
37 |
38 | if (response.message.indexOf('Cannot GET /') === -1) {
39 | console.log(exception);
40 | }
41 | }
42 |
43 | const ctx: any = host.switchToHttp();
44 | const res: any = ctx.getResponse();
45 | const req: any = ctx.getRequest();
46 | const status: any = exception ? exception.getStatus() : HttpStatus.OK;
47 |
48 | if (status === HttpStatus.NOT_FOUND) {
49 | // console.log('Render========', HttpStatus.NOT_FOUND);
50 | if (!res.headersSent) {
51 | await this.nuxt.render(req, res);
52 | }
53 | } else {
54 | // console.log('Render========', status);
55 | res.status(status).json({
56 | statusCode: status,
57 | timestamp: new Date().toISOString(),
58 | path: req.url
59 | });
60 | }
61 | } catch (error) {
62 | console.log(error);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/server/common/nuxt/CommonNuxtServer.ts:
--------------------------------------------------------------------------------
1 | import { Builder } from '@nuxt/builder';
2 | import { Nuxt } from '@nuxt/core';
3 | import { BundleBuilder } from '@nuxt/webpack';
4 | import config from '../../../../nuxt.config';
5 |
6 | /**
7 | * NUXT服务
8 | *
9 | * @export
10 | * @class NuxtServer
11 | */
12 | // tslint:disable-next-line: no-default-export
13 | export default class NuxtServer {
14 | private static instance: NuxtServer;
15 | public nuxt: Nuxt;
16 |
17 | /**
18 | * RUN
19 | *
20 | * @param {boolean} [shouldBuild=true]
21 | * @returns {Nuxt}
22 | * @memberof NuxtServer
23 | */
24 | public async run(shouldBuild: boolean = true): Nuxt {
25 | const nuxt: any = new Nuxt(config);
26 |
27 | // Build only in dev mode
28 | if (config.dev && shouldBuild) {
29 | const builder: any = new Builder(nuxt, BundleBuilder);
30 | const res: any = await builder.build();
31 |
32 | this.nuxt = res.nuxt;
33 |
34 | return res.nuxt;
35 | }
36 |
37 | if (this.nuxt) {
38 | return this.nuxt;
39 | }
40 |
41 | return nuxt;
42 | }
43 |
44 | /**
45 | * 单例模式
46 | *
47 | * @static
48 | * @returns {NuxtServer}
49 | * @memberof NuxtServer
50 | */
51 | public static getInstance(): NuxtServer {
52 | if (this.instance) {
53 | return this.instance;
54 | } else {
55 | this.instance = new NuxtServer();
56 |
57 | return this.instance;
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/server/common/pipes/CommonParseIntPipe.ts:
--------------------------------------------------------------------------------
1 | import { BadRequestException } from '@nestjs/common';
2 | import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
3 |
4 | /**
5 | * Parse init pipe
6 | *
7 | * @export
8 | * @class ParseIntPipe
9 | * @implements {PipeTransform}
10 | */
11 | @Injectable()
12 | export class ParseIntPipe implements PipeTransform {
13 |
14 | /**
15 | * transform
16 | *
17 | * @param {string} value
18 | * @param {ArgumentMetadata} metadata
19 | * @returns
20 | * @memberof ParseIntPipe
21 | */
22 | public async transform(value: string, metadata: ArgumentMetadata): Promise {
23 | const val: any = parseInt(value, 10);
24 | if (isNaN(val)) {
25 | throw new BadRequestException('Validation failed');
26 | }
27 |
28 | return val;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/server/common/pipes/CommonValidationPipe.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ArgumentMetadata,
3 | BadRequestException,
4 | Injectable,
5 | PipeTransform,
6 | Type
7 | } from '@nestjs/common';
8 | import { plainToClass } from 'class-transformer';
9 | import { validate } from 'class-validator';
10 |
11 | /**
12 | * ValidationPipe
13 | *
14 | * @export
15 | * @class ValidationPipe
16 | * @implements {PipeTransform}
17 | */
18 | @Injectable()
19 | export class ValidationPipe implements PipeTransform {
20 |
21 | /**
22 | * transform
23 | *
24 | * @param {*} value
25 | * @param {ArgumentMetadata} metadata
26 | * @returns
27 | * @memberof ValidationPipe
28 | */
29 | public async transform(value: any, metadata: ArgumentMetadata): Promise {
30 | const { metatype } = metadata;
31 | if (!metatype || !this.toValidate(metatype)) {
32 | return value;
33 | }
34 | const object: any = plainToClass(metatype, value);
35 | const errors: any = await validate(object);
36 | if (errors.length > 0) {
37 | throw new BadRequestException('Validation failed');
38 | }
39 |
40 | return value;
41 | }
42 |
43 | /**
44 | * toValidate
45 | *
46 | * @private
47 | * @param {Type} metatype
48 | * @returns {boolean}
49 | * @memberof ValidationPipe
50 | */
51 | private toValidate(metatype: Type): boolean {
52 | const types: any = [String, Boolean, Number, Array, Object];
53 |
54 | return !types.find(
55 | (type: any) => {
56 | return metatype === type;
57 | }
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/server/modules/cats/CatsController.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Body,
3 | Controller,
4 | Get,
5 | Param,
6 | Post,
7 | UseGuards,
8 | UseInterceptors
9 | } from '@nestjs/common';
10 | import { Roles } from '../../common/decorators/CommonRolesDecorator';
11 | import { RolesGuard } from '../../common/guards/CommonRolesGuard';
12 | import { LoggingInterceptor } from '../../common/interceptors/CommonLoggingInterceptor';
13 | import { TransformInterceptor } from '../../common/interceptors/CommonTransformInterceptor';
14 | import { ParseIntPipe } from '../../common/pipes/CommonParseIntPipe';
15 | import { Routers } from '../../routers/RoutersServer';
16 | import { CatsService } from './CatsService';
17 | import { CreateCatDto } from './dto/CatsCreateDto';
18 | import { ICat } from './interfaces/ICats';
19 |
20 | /**
21 | * Cats controller
22 | *
23 | * @export
24 | * @class CatsController
25 | */
26 | @Controller(Routers.CATS_MODULE_ROUTER)
27 | @UseGuards(RolesGuard)
28 | @UseInterceptors(LoggingInterceptor, TransformInterceptor)
29 | export class CatsController {
30 | constructor(private readonly catsService: CatsService) { }
31 |
32 | /**
33 | * create
34 | *
35 | * @param {CreateCatDto} createCatDto
36 | * @memberof CatsController
37 | */
38 | @Post()
39 | @Roles('admin')
40 | public async create(@Body() createCatDto: CreateCatDto): Promise {
41 | this.catsService.create(createCatDto);
42 | }
43 |
44 | /**
45 | * Find all
46 | *
47 | * @returns {Promise}
48 | * @memberof CatsController
49 | */
50 | @Get()
51 | public async findAll(): Promise {
52 | return this.catsService.findAll();
53 | }
54 |
55 | /**
56 | * Find one
57 | *
58 | * @param {*} id
59 | * @memberof CatsController
60 | */
61 | @Get(':id')
62 | public findOne(
63 | @Param('id', new ParseIntPipe())
64 | id: any
65 | ): any {
66 | // logic
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/server/modules/cats/CatsModule.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { CatsController } from './CatsController';
3 | import { CatsService } from './CatsService';
4 |
5 | /**
6 | * Cats Module
7 | *
8 | * @export
9 | * @class CatsModule
10 | */
11 | @Module({
12 | controllers: [CatsController],
13 | providers: [CatsService]
14 | })
15 | export class CatsModule { }
16 |
--------------------------------------------------------------------------------
/src/server/modules/cats/CatsService.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 | import { ICat } from './interfaces/ICats';
3 |
4 | /**
5 | * Cats service
6 | *
7 | * @export
8 | * @class CatsService
9 | */
10 | @Injectable()
11 | export class CatsService {
12 | private readonly cats: ICat[] = [];
13 |
14 | /**
15 | * create
16 | *
17 | * @param {ICat} cat
18 | * @returns {*}
19 | * @memberof CatsService
20 | */
21 | public create(cat: ICat): any {
22 | this.cats.push(cat);
23 | }
24 |
25 | /**
26 | * Find all
27 | *
28 | * @returns {ICat[]}
29 | * @memberof CatsService
30 | */
31 | public findAll(): ICat[] {
32 | return this.cats;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/server/modules/cats/dto/CatsCreateDto.ts:
--------------------------------------------------------------------------------
1 | import { IsInt, IsString } from 'class-validator';
2 |
3 | /**
4 | * Create4 cat dto
5 | *
6 | * @export
7 | * @class CreateCatDto
8 | */
9 | export class CreateCatDto {
10 | /**
11 | * name field
12 | *
13 | * @type {string}
14 | * @memberof CreateCatDto
15 | */
16 | @IsString()
17 | public readonly name: string;
18 |
19 | /**
20 | * age field
21 | *
22 | * @type {number}
23 | * @memberof CreateCatDto
24 | */
25 | @IsInt()
26 | public readonly age: number;
27 |
28 | /**
29 | * bread
30 | *
31 | * @type {string}
32 | * @memberof CreateCatDto
33 | */
34 | @IsString()
35 | public readonly breed: string;
36 | }
37 |
--------------------------------------------------------------------------------
/src/server/modules/cats/interfaces/ICats.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Interface cat
3 | *
4 | * @export
5 | * @interface ICat
6 | */
7 | export interface ICat {
8 | /**
9 | * name field
10 | *
11 | * @type {string}
12 | * @memberof ICat
13 | */
14 | readonly name: string;
15 |
16 | /**
17 | * age field
18 | *
19 | * @type {number}
20 | * @memberof ICat
21 | */
22 | readonly age: number;
23 |
24 | /**
25 | * breed field
26 | *
27 | * @type {string}
28 | * @memberof ICat
29 | */
30 | readonly breed: string;
31 | }
32 |
--------------------------------------------------------------------------------
/src/server/modules/db/DBModule.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { databaseProviders } from './DBProviders';
3 |
4 | /**
5 | * database module
6 | * @description Module
7 | */
8 | @Module({
9 | providers: [...databaseProviders],
10 | exports: [...databaseProviders]
11 | })
12 | export class DataBaseModule {
13 | // hole
14 | }
15 |
--------------------------------------------------------------------------------
/src/server/modules/db/DBProviders.ts:
--------------------------------------------------------------------------------
1 | import mongoose from 'mongoose';
2 | import configService from '../../../client/core/service/ServiceConfig';
3 | import { ConfigDefault } from '../../../../config/ConfigDefault';
4 | import { ConfigDB, IMongoDBConfig } from '../../../../config/ConfigDB';
5 |
6 | /**
7 | * data base providers
8 | */
9 | export const databaseProviders: Array = [
10 | {
11 | provide: 'DATABASE_CONNECTION',
12 | useFactory: async (): Promise => {
13 | // 获取默认配置
14 | const configer: ConfigDefault = configService.getConfig();
15 | const configDB: ConfigDB = new ConfigDB();
16 |
17 | // 更新当前环境配置
18 | configDB.updateEnv(configer.getEnv());
19 |
20 | // 组装连接字符串
21 | const config: Object = {
22 | autoIndex: false,
23 | useNewUrlParser: true
24 | };
25 | const configData: IMongoDBConfig = configDB.getMongoDbConfig();
26 | const configStr: string = `mongodb://${configData.userName}:${configData.password}@${configData.uri}:${configData.port}/${configData.db}`;
27 | const connectResult: any = await mongoose.connect(configStr, config);
28 |
29 | return connectResult;
30 | }
31 | }
32 | ];
33 |
--------------------------------------------------------------------------------
/src/server/modules/local/LocalController.ts:
--------------------------------------------------------------------------------
1 | import { Controller, Req, Get, Res, HttpStatus, Post, Body, Query } from '@nestjs/common';
2 | import { LocalService } from './LocalService';
3 | import { Routers } from '../../routers/RoutersServer';
4 | import { CreateCatDto } from './dto/LocalCreateCatDto';
5 | import { ICat } from './interfaces/ICat';
6 | import { CreateGoodsDto } from './dto/LocalCreateGoodsDto';
7 | import { EngineController } from '../../common/core/CommonEngineController';
8 | import { AddCartsDto } from './dto/LocalAddCartsDto';
9 | import { CardListItemDto } from './dto/LocalCardListItemDto';
10 | import { LoginDto } from './dto/LocalLoginDto';
11 |
12 | /**
13 | * 中转服务CONTROLLER处理器
14 | *
15 | * @export
16 | * @class LocalController
17 | * @extends {}
18 | */
19 | @Controller(Routers.LOCAL_MODULE_ROUTER)
20 | export class LocalController extends EngineController {
21 | constructor(
22 | private readonly localService: LocalService
23 | ) {
24 | super();
25 | }
26 |
27 | /**
28 | * create cat
29 | * @description Posts local controller
30 | * @param createCatDto
31 | */
32 | @Post('login')
33 | public async login(@Res() res: any, @Body() loginDto: LoginDto): Promise {
34 | const returnData: Array = await this.localService.login(loginDto);
35 |
36 | if (returnData.length) {
37 | res.status(HttpStatus.OK).json(
38 | this.encapsulationReturnObject(returnData[0])
39 | );
40 | } else {
41 | res.status(HttpStatus.FORBIDDEN).json(
42 | this.encapsulationReturnObject({}, HttpStatus.FORBIDDEN, '用户名或密码不正确')
43 | );
44 | }
45 | }
46 |
47 | /**
48 | * create cat
49 | * @description Posts local controller
50 | * @param createCatDto
51 | */
52 | @Post('createCat')
53 | public async create(@Body() createCatDto: CreateCatDto): Promise {
54 | return await this.localService.create(createCatDto);
55 | }
56 |
57 | /**
58 | * find all
59 | * @description Gets local controller
60 | * @returns all
61 | */
62 | @Get('findAll')
63 | public async findAll(): Promise {
64 | return this.localService.findAll();
65 | }
66 |
67 | /**
68 | * 获取新闻列表
69 | *
70 | * @param {*} request
71 | * @returns
72 | * @memberof TransportController
73 | */
74 | @Get('getList')
75 | public async getList(@Res() res: any, @Req() request: any): Promise {
76 | const returnData: any = await this.localService.getList();
77 |
78 | res.status(HttpStatus.OK).json(returnData.data);
79 | }
80 |
81 | /**
82 | * 获取购物车信息
83 | * @param request
84 | * @returns carts
85 | */
86 | @Get('getCarts')
87 | public async getCarts(@Res() res: any, @Req() request: any, @Query() cartsParams: any): Promise {
88 | const returnData: any = await this.localService.getCarts(cartsParams.userId);
89 |
90 | res.status(HttpStatus.OK).json(returnData);
91 | }
92 |
93 | /**
94 | * 获取商品信息
95 | * @param request
96 | * @returns goods
97 | */
98 | @Get('getGoods')
99 | public async getGoods(@Res() res: any, @Req() request: any, @Query() query: any): Promise {
100 | const id: string = query.id || '5d74f3dc40407532cd556949';
101 | const returnData: any = await this.localService.getGoods(id);
102 |
103 | res.status(HttpStatus.OK).json(
104 | this.encapsulationReturnObject(returnData)
105 | );
106 | }
107 |
108 | /**
109 | * create goods
110 | * @description Posts local controller
111 | * @param createGoodsDto
112 | */
113 | @Post('createGoods')
114 | public async createGoods(@Body() createGoodsDto: CreateGoodsDto): Promise {
115 | await this.localService.createGoods(createGoodsDto);
116 | }
117 |
118 | /**
119 | * 添加商品入购物车
120 | * @description Posts local controller
121 | * @param addToCartsDto
122 | */
123 | @Post('addToCart')
124 | public async addToCart(@Res() res: any, @Body() addToCartsDto: AddCartsDto): Promise {
125 | const returnData: any = await this.localService.addToCart(addToCartsDto);
126 |
127 | res.status(HttpStatus.OK).json(
128 | this.encapsulationReturnObject(returnData)
129 | );
130 | }
131 |
132 | /**
133 | * 依据ID获取已添加入购物车的列表数据项
134 | * @description Posts local controller
135 | * @param addToCartsDto
136 | */
137 | @Post('getCartsListData')
138 | public async getCartsListData(@Res() res: any, @Body() cartListItem: CardListItemDto): Promise {
139 | const returnData: any = await this.localService.getCartsListData(cartListItem);
140 |
141 | res.status(HttpStatus.OK).json(
142 | this.encapsulationReturnObject(returnData)
143 | );
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/src/server/modules/local/LocalModule.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { LocalController } from './LocalController';
3 | import { LocalService } from './LocalService';
4 | import { DataBaseModule } from '../db/DBModule';
5 | import { localProviders } from './LocalProviders';
6 |
7 | /**
8 | * 本地服务模块
9 | */
10 | @Module({
11 | imports: [DataBaseModule],
12 | controllers: [LocalController],
13 | providers: [LocalService, ...localProviders]
14 | })
15 | export class LocalModule {
16 | constructor() {
17 | // hole
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/server/modules/local/LocalProviders.ts:
--------------------------------------------------------------------------------
1 | import { Connection } from 'mongoose';
2 | import { CatSchema } from './schemas/LocalCatSchema';
3 | import { GoodsSchema } from './schemas/LocalGoodsSchema';
4 | import { CartsSchema } from './schemas/LocalCartSchema';
5 | import { UserSchema } from './schemas/LocalUserSchema';
6 |
7 | /**
8 | * model常量
9 | * @description Model
10 | */
11 | export class MODEL {
12 | public static CAT_MODEL: string = 'CAT_MODEL';
13 | public static GOODS_MODEL: string = 'GOODS_MODEL';
14 | public static CARTS_MODEL: string = 'CARTS_MODEL';
15 | public static USER_MODEL: string = 'USER_MODEL';
16 | }
17 |
18 | /**
19 | * MODEL定义
20 | */
21 | export const localProviders: Array = [
22 | {
23 | provide: MODEL.CAT_MODEL,
24 | useFactory: (connection: Connection): any => connection.model('Cat', CatSchema),
25 | inject: ['DATABASE_CONNECTION']
26 | },
27 | {
28 | provide: MODEL.USER_MODEL,
29 | useFactory: (connection: Connection): any => connection.model('User', UserSchema),
30 | inject: ['DATABASE_CONNECTION']
31 | },
32 | {
33 | provide: MODEL.GOODS_MODEL,
34 | useFactory: (connection: Connection): any => connection.model('Goods', GoodsSchema),
35 | inject: ['DATABASE_CONNECTION']
36 | },
37 | {
38 | provide: MODEL.CARTS_MODEL,
39 | useFactory: (connection: Connection): any => connection.model('Carts', CartsSchema),
40 | inject: ['DATABASE_CONNECTION']
41 | }
42 | ];
43 |
--------------------------------------------------------------------------------
/src/server/modules/local/LocalService.ts:
--------------------------------------------------------------------------------
1 | import { BaseHttpClient } from '../../common/middleware/CommonHttpMiddleware';
2 | import { Model } from 'mongoose';
3 | import { Injectable, Inject } from '@nestjs/common';
4 | import { ICat } from './interfaces/ICat';
5 | import { CreateCatDto } from './dto/LocalCreateCatDto';
6 | import { CreateGoodsDto } from './dto/LocalCreateGoodsDto';
7 | import { IGoods } from './interfaces/IGoods';
8 | import { MODEL } from './LocalProviders';
9 | import { AddCartsDto } from './dto/LocalAddCartsDto';
10 | import { ICart } from './interfaces/ICart';
11 | import { CardListItemDto } from './dto/LocalCardListItemDto';
12 | import { LoginDto } from './dto/LocalLoginDto';
13 | import uuidV1 from 'uuid/v1';
14 | import uuidV3 from 'uuid/v3';
15 | import { IUser } from './interfaces/IUser';
16 |
17 | /**
18 | * 本地服务
19 | *
20 | * @export
21 | * @class LocalService
22 | */
23 | @Injectable()
24 | export class LocalService extends BaseHttpClient {
25 | constructor(
26 | @Inject(MODEL.CAT_MODEL) private readonly catModel: Model,
27 | @Inject(MODEL.GOODS_MODEL) private readonly goodsModel: Model,
28 | @Inject(MODEL.CARTS_MODEL) private readonly cartsModel: Model,
29 | @Inject(MODEL.USER_MODEL) private readonly userModel: Model
30 | ) {
31 | super();
32 | }
33 |
34 | /**
35 | * 添加入购物车
36 | * @description Creates local service
37 | * @param addToCartsDto
38 | * @returns create
39 | */
40 | public async addToCart(addToCartsDto: AddCartsDto): Promise {
41 | const findResult: Array = await this.cartsModel.find({ id: addToCartsDto.id }).exec();
42 | let processResult: any;
43 | if (findResult && findResult.length === 0) {
44 | // 插入新的
45 | const addToCarts: any = new this.cartsModel(addToCartsDto);
46 | processResult = await addToCarts.save();
47 | } else {
48 |
49 | // 更新数量
50 | // 0.增加 1.减少 2.原值存入
51 | let numValue: number;
52 | switch (addToCartsDto.forceType) {
53 | case AddCartsDto.INC_NUM:
54 | // 增加
55 | numValue = Number(findResult[0].num) + 1;
56 | break;
57 | case AddCartsDto.DEC_NUM:
58 | // 减少
59 | numValue = Number(findResult[0].num) - 1;
60 | break;
61 | case AddCartsDto.FORCE_NUM:
62 | // 原值存入
63 | numValue = addToCartsDto.num;
64 | break;
65 | default:
66 | // 增加
67 | numValue = Number(findResult[0].num) + 1;
68 | break;
69 | }
70 | // 执行更新
71 | processResult = this.cartsModel.updateOne({ id: addToCartsDto.id, userId: addToCartsDto.userId }, { num: numValue });
72 | }
73 |
74 | return processResult;
75 | }
76 |
77 | /**
78 | * login
79 | * @description Creates local service
80 | * @param loginDto
81 | * @returns create
82 | */
83 | public async login(loginDto: LoginDto): Promise> {
84 | const returnValue: Array = await this.userModel.find({ userName: loginDto.userName }).exec();
85 | const userList: Array = [];
86 |
87 | if (returnValue.length > 0) {
88 | while (returnValue.length) {
89 | const item: IUser = returnValue.shift();
90 | let accessToken: string = uuidV3(item.userName, uuidV1());
91 |
92 | accessToken = accessToken.replace(/-/ig, '');
93 | userList.push({
94 | userName: item.userName,
95 | _id: item._id,
96 | accessToken
97 | });
98 |
99 | // TODO: 存储token到redis或全局对象用于校验
100 | }
101 | }
102 |
103 | return userList;
104 | }
105 |
106 | /**
107 | * create goods
108 | * @description Creates local service
109 | * @param createGoodsDto
110 | * @returns create
111 | */
112 | public async createGoods(createGoodsDto: CreateGoodsDto): Promise {
113 | const createdGoods: any = new this.goodsModel(createGoodsDto);
114 |
115 | return await createdGoods.save();
116 | }
117 |
118 | /**
119 | * create cat
120 | * @description Creates local service
121 | * @param createCatDto
122 | * @returns create
123 | */
124 | public async create(createCatDto: CreateCatDto): Promise {
125 | const createdCat: any = new this.catModel(createCatDto);
126 |
127 | return await createdCat.save();
128 | }
129 |
130 | /**
131 | * finds all
132 | * @description Finds all
133 | * @returns all
134 | */
135 | public async findAll(): Promise {
136 | return await this.catModel.find().exec();
137 | }
138 |
139 | /**
140 | * 获取已选择商品列表数据
141 | *
142 | * @returns {Promise}
143 | * @memberof LocalService
144 | */
145 | public async getCarts(userId: string): Promise {
146 | const returnData: any = await this.cartsModel.find({ userId }).exec();
147 |
148 | return returnData;
149 | }
150 |
151 | /**
152 | * 获取商品页面单个商品数据
153 | *
154 | * @returns {Promise}
155 | * @memberof LocalService
156 | */
157 | public async getGoods(id: string): Promise {
158 | const result: any = await this.goodsModel.findById(id).exec();
159 |
160 | return result;
161 | }
162 |
163 | /**
164 | * 依据ID获取已添加入购物车的列表数据项
165 | *
166 | * @returns {Promise}
167 | * @memberof LocalService
168 | */
169 | public async getCartsListData(cartListItem: CardListItemDto): Promise {
170 | const ids: Array = [];
171 | while (cartListItem.list.length) {
172 | const cartItem: AddCartsDto = cartListItem.list.shift();
173 | ids.push(cartItem.id);
174 | }
175 |
176 | const result: IGoods[] = await this.goodsModel.find().where('_id').in(ids).exec();
177 |
178 | return result;
179 | }
180 |
181 | /**
182 | * 获取商品列表数据
183 | *
184 | * @returns {Promise}
185 | * @memberof LocalService
186 | */
187 | public async getList(): Promise {
188 | return await this.get('/list.json').toPromise();
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/src/server/modules/local/dto/LocalAddCartsDto.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 添加入购物车DTO
3 | * @description Add carts dto
4 | */
5 | export class AddCartsDto {
6 |
7 | /** 增加 */
8 | public static INC_NUM: number = 0;
9 |
10 | /** 减少 */
11 | public static DEC_NUM: number = 1;
12 |
13 | /** 原值传入 */
14 | public static FORCE_NUM: number = 2;
15 |
16 | public readonly id: string;
17 | public readonly num: number;
18 | public readonly forceType: number;
19 | public readonly userId: string;
20 | }
21 |
--------------------------------------------------------------------------------
/src/server/modules/local/dto/LocalCardListItemDto.ts:
--------------------------------------------------------------------------------
1 | import { AddCartsDto } from './LocalAddCartsDto';
2 |
3 | /**
4 | * 购物车列表ID DTO
5 | * @description Add carts dto
6 | */
7 | export class CardListItemDto {
8 | public readonly list: Array;
9 | }
10 |
--------------------------------------------------------------------------------
/src/server/modules/local/dto/LocalCreateCatDto.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * create cat dto
3 | * @description Create cat dto
4 | */
5 | export class CreateCatDto {
6 | public readonly name: string;
7 | public readonly age: number;
8 | public readonly bread: string;
9 | }
10 |
--------------------------------------------------------------------------------
/src/server/modules/local/dto/LocalCreateGoodsDto.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 产品DTO
3 | * @description Create goods dto
4 | */
5 | export class CreateGoodsDto {
6 | public readonly title: string;
7 | public readonly price: number;
8 | public readonly express: string;
9 | public readonly remain: number;
10 | public readonly num: string;
11 | public readonly thumb: string;
12 | public readonly thumbList: Array;
13 | }
14 |
--------------------------------------------------------------------------------
/src/server/modules/local/dto/LocalLoginDto.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * login dto
3 | */
4 | export class LoginDto {
5 | public readonly userName: string;
6 | public readonly password: string;
7 | }
8 |
--------------------------------------------------------------------------------
/src/server/modules/local/interfaces/ICart.ts:
--------------------------------------------------------------------------------
1 | import { Document } from 'mongoose';
2 |
3 | /**
4 | * ICart
5 | * @description ICart
6 | */
7 | export interface ICart extends Document {
8 | id: string;
9 | num: number;
10 | userId: string;
11 | }
12 |
--------------------------------------------------------------------------------
/src/server/modules/local/interfaces/ICat.ts:
--------------------------------------------------------------------------------
1 | import { Document } from 'mongoose';
2 |
3 | /**
4 | * cat
5 | * @description Cat
6 | */
7 | export interface ICat extends Document {
8 | readonly name: string,
9 | readonly age: number,
10 | readonly bread: string
11 | }
12 |
--------------------------------------------------------------------------------
/src/server/modules/local/interfaces/IGoods.ts:
--------------------------------------------------------------------------------
1 | import { Document } from 'mongoose';
2 |
3 | /**
4 | * 产品数据结构
5 | * @description Igoods
6 | */
7 | export interface IGoods extends Document {
8 | readonly title: string;
9 | readonly price: number;
10 | readonly express: string;
11 | readonly remain: number;
12 | readonly num: string;
13 | readonly thumb: string;
14 | readonly thumbList: Array;
15 | }
16 |
--------------------------------------------------------------------------------
/src/server/modules/local/interfaces/IUser.ts:
--------------------------------------------------------------------------------
1 | import { Document } from 'mongoose';
2 |
3 | /**
4 | * 用户信息
5 | */
6 | export interface IUser extends Document {
7 | _id: string;
8 | userName: string;
9 | }
10 |
--------------------------------------------------------------------------------
/src/server/modules/local/schemas/LocalCartSchema.ts:
--------------------------------------------------------------------------------
1 | import * as mongoose from 'mongoose';
2 |
3 | /**
4 | * carts schema
5 | */
6 | export const CartsSchema: any = new mongoose.Schema({
7 | id: { type: String, unique: true, required: true },
8 | num: Number,
9 | userId: { type: String, unique: true, required: true }
10 | },
11 | { collection: 'isomorphism.carts' }
12 | );
13 |
--------------------------------------------------------------------------------
/src/server/modules/local/schemas/LocalCatSchema.ts:
--------------------------------------------------------------------------------
1 | import * as mongoose from 'mongoose';
2 |
3 | /**
4 | * cat schema
5 | */
6 | export const CatSchema: any = new mongoose.Schema({
7 | name: String,
8 | age: Number,
9 | bread: String
10 | }, { collection: 'isomorphism.cats' });
11 |
--------------------------------------------------------------------------------
/src/server/modules/local/schemas/LocalGoodsSchema.ts:
--------------------------------------------------------------------------------
1 | import * as mongoose from 'mongoose';
2 |
3 | /**
4 | * Goods Schema
5 | */
6 | export const GoodsSchema: any = new mongoose.Schema({
7 | title: String,
8 | price: Number,
9 | express: String,
10 | remain: Number,
11 | num: String,
12 | thumb: String,
13 | thumbList: Array
14 | }, { collection: 'isomorphism.goods' });
15 |
--------------------------------------------------------------------------------
/src/server/modules/local/schemas/LocalUserSchema.ts:
--------------------------------------------------------------------------------
1 | import * as mongoose from 'mongoose';
2 |
3 | /**
4 | * user schema
5 | */
6 | export const UserSchema: any = new mongoose.Schema({
7 | userName: { type: String, unique: true, required: true },
8 | password: { type: String, unique: true, required: true }
9 | },
10 | { collection: 'isomorphism.user' }
11 | );
12 |
--------------------------------------------------------------------------------
/src/server/modules/transport/TransportController.ts:
--------------------------------------------------------------------------------
1 | import { All, Controller, HttpCode, Req, HttpStatus } from '@nestjs/common';
2 | import { TransportService } from './TransportService';
3 | import { Routers } from '../../routers/RoutersServer';
4 |
5 | /**
6 | * 中转服务CONTROLLER处理器
7 | *
8 | * @export
9 | * @class TransportController
10 | * @extends {EngineController}
11 | */
12 | @Controller(Routers.TRANSPORT_MODULE_ROUTER)
13 | export class TransportController {
14 | constructor(
15 | private readonly transportService: TransportService
16 | ) {
17 | // hole
18 | }
19 |
20 | /**
21 | * 中转服务接收
22 | *
23 | * @param {*} request
24 | * @returns
25 | * @memberof TransportController
26 | */
27 | @HttpCode(HttpStatus.OK)
28 | @All('getTransportData')
29 | public async getTransportData(@Req() request: any): Promise {
30 |
31 | let result: any = await this.transportService.getTransportData(request);
32 |
33 | if (result === undefined) {
34 | result = {
35 | code: HttpStatus.INTERNAL_SERVER_ERROR,
36 | message: 'Internal server error'
37 | };
38 |
39 | return result;
40 | } else {
41 | return result.data;
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/server/modules/transport/TransportModule.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { TransportController } from './TransportController';
3 | import { TransportService } from './TransportService';
4 |
5 | /**
6 | * 中转模块
7 | */
8 | @Module({
9 | imports: [],
10 | controllers: [TransportController],
11 | providers: [TransportService]
12 | })
13 | export class TransportModule {
14 | constructor() {
15 | // hole
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/server/modules/transport/TransportService.ts:
--------------------------------------------------------------------------------
1 | import { AxiosRequestConfig } from 'axios';
2 | import { stringify } from 'querystring';
3 | import { BaseHttpClient } from '../../common/middleware/CommonHttpMiddleware';
4 | import { ConfigDefault } from '../../../../config/ConfigDefault';
5 |
6 | /**
7 | * 中转接口服务
8 | *
9 | * @export
10 | * @class TransportService
11 | */
12 | export class TransportService extends BaseHttpClient {
13 | constructor() {
14 | super();
15 | }
16 |
17 | /**
18 | * 中转
19 | */
20 | public async getTransportData(request: any): Promise {
21 |
22 | const url: string = request.headers[ConfigDefault.X_REAL_URL];
23 | const baseURL: string = request.headers[ConfigDefault.X_REAL_BASE_URL];
24 | const contentType: string = request.headers[ConfigDefault.CONTENT_TYPE];
25 |
26 | let headers: any = {};
27 | let requestObj: AxiosRequestConfig = {
28 | data: request.body,
29 | params: request.query || request.params,
30 | baseURL,
31 | url,
32 | method: request.method
33 | };
34 |
35 | if (
36 | contentType &&
37 | contentType === 'application/x-www-form-urlencoded'
38 | ) {
39 | headers[ConfigDefault.CONTENT_TYPE] = contentType;
40 | requestObj.data = stringify(requestObj.data);
41 | }
42 | requestObj.headers = headers;
43 |
44 | return await this.request(requestObj).toPromise();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/server/routers/RoutersServer.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Router list
3 | *
4 | * @export
5 | * @class Routers
6 | */
7 | export class Routers {
8 |
9 | /**
10 | * cats router /api/cats/....visit
11 | */
12 | public static CATS_MODULE_ROUTER: string = 'cats';
13 |
14 | /**
15 | * transport router /api/transport/....visit
16 | */
17 | public static TRANSPORT_MODULE_ROUTER: string = 'transport';
18 |
19 | /**
20 | * local router /api/local/....visit
21 | */
22 | public static LOCAL_MODULE_ROUTER: string = 'local';
23 | }
24 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "declaration": false,
5 | "removeComments": true,
6 | "noLib": false,
7 | "allowSyntheticDefaultImports": true,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "allowJs": true,
11 | "target": "es6",
12 | "resolveJsonModule": true,
13 | "sourceMap": true,
14 | "outDir": "./dist",
15 | "esModuleInterop": true,
16 | "moduleResolution": "node",
17 | "baseUrl": "./",
18 | "noImplicitAny": false,
19 | "paths": {
20 | "~/*": ["src/client/*"]
21 | },
22 | "types": ["@types/node", "@nuxt/vue-app", "vuex-class-component/dist"]
23 | },
24 | "include": ["src/server/**/*", "src/client/**/*"],
25 | "exclude": ["node_modules"]
26 | }
27 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "error",
3 | "extends": [
4 | "tslint-config-alloy"
5 | ],
6 | "linterOptions": {
7 | "exclude": [
8 | "e2e/*",
9 | "src/server/*-spec.ts",
10 | "e2e/*-spec.ts",
11 | "src/server/nuxt/index.ts",
12 | "nuxt.config.ts",
13 | "config/env.config.ts"
14 | ]
15 | },
16 | "jsRules": {
17 | "no-unused-expression": true
18 | },
19 | "rules": {
20 | "ordered-imports": false,
21 | "no-implicit-dependencies": false,
22 | "no-inferrable-types": false,
23 | "typedef": [true, "variable-declaration", "property-declaration", "arrow-call-signature", "call-signature", "parameter", "member-variable-declaration", "array-destructuring"],
24 | // 禁止给类的构造函数的参数添加修饰符
25 | "no-parameter-properties": false,
26 | // 禁止使用 debugger
27 | "no-debugger": true,
28 | // 禁止行尾有空格
29 | "no-trailing-whitespace": true,
30 | // 禁止无用的表达式
31 | "no-unused-expression": true,
32 | // 定义过的变量必须使用
33 | "no-unused-variable": true,
34 | // 变量必须先定义后使用
35 | "no-use-before-declare": true,
36 | // 禁止使用 var
37 | "no-var-keyword": true,
38 | // 必须使用 === 或 !==,禁止使用 == 或 !=,与 null 比较时除外
39 | "triple-equals": true,
40 | // 指定类成员的排序规则
41 | "member-ordering": false,
42 | // 强制方法注释
43 | "completed-docs": [true, "enums", "functions", "methods", "classes", "interfaces", "namespaces", "types"],
44 | // 方法RETURN 前必须有空行
45 | "newline-before-return": true,
46 | // 禁止将 this 赋值给其他变量,除非是解构赋值
47 | "no-this-assignment": [
48 | false,
49 | {
50 | "allowed-names": [
51 | "^self$",
52 | "^that$"
53 | ],
54 | "allow-destructuring": true
55 | }
56 | ],
57 | // 必须使用箭头函数,除非是单独的函数声明或是命名函数
58 | "only-arrow-functions": [
59 | true,
60 | "allow-declarations",
61 | "allow-named-functions"
62 | ],
63 | // 禁止出现空代码块,允许 catch 是空代码块
64 | "no-empty": [
65 | true,
66 | "allow-empty-catch"
67 | ],
68 | // 禁止无用的类型断言
69 | "no-unnecessary-type-assertion": true,
70 | // 使用 return; 而不是 return undefined;
71 | "return-undefined": true,
72 | // 禁止对 array 使用 for in 循环
73 | "no-for-in-array": true,
74 | "comment-format": [
75 | true,
76 | "check-space"
77 | ],
78 | // 单行注释格式化规则
79 | // 定义函数时如果用到了覆写,则必须将覆写的函数写到一起
80 | "adjacent-overload-signatures": true,
81 | // 禁止对函数的参数重新赋值
82 | "no-parameter-reassignment": true,
83 | // if 后面必须有 {,除非是单行 if
84 | "curly": [
85 | true,
86 | "ignore-same-line"
87 | ],
88 | // for in 内部必须有 hasOwnProperty
89 | "forin": true,
90 | // 禁止在分支条件判断中有赋值操作
91 | "no-conditional-assignment": true,
92 | // 禁止使用 new 来生成 String, Number 或 Boolean
93 | "no-construct": true,
94 | // 禁止 super 在一个构造函数中出现两次
95 | "no-duplicate-super": true,
96 | // 禁止在 switch 语句中出现重复测试表达式的 case
97 | "no-duplicate-switch-case": true,
98 | // 禁止出现重复的变量定义或函数参数名
99 | "no-duplicate-variable": [
100 | true,
101 | "check-parameters"
102 | ],
103 | // 禁止使用 eval
104 | "no-eval": true,
105 | // 禁止对对象字面量进行类型断言(断言成 any 是允许的)
106 | "no-object-literal-type-assertion": false,
107 | // 禁止没必要的 return await
108 | "no-return-await": false,
109 | // 禁止在数组中出现连续的逗号,如 let foo = [,,]
110 | "no-sparse-arrays": true,
111 | // 禁止 throw 字符串,必须 throw 一个 Error 对象
112 | "no-string-throw": true,
113 | // switch 的 case 必须 return 或 break
114 | "no-switch-case-fall-through": true,
115 | // 使用实例的方法时,必须 bind 到实例上
116 | "no-unbound-method": [
117 | true,
118 | "ignore-static"
119 | ],
120 | // 使用 { ...foo, bar: 1 } 代替 Object.assign({}, foo, { bar: 1 })
121 | // 前者的类型检查更完善
122 | "prefer-object-spread": true,
123 | // parseInt 必须传入第二个参数
124 | "radix": true,
125 | // 必须使用 isNaN(foo) 而不是 foo === NaN
126 | "use-isnan": true,
127 | //
128 | //
129 | // 可维护性
130 | // 这些规则可以增加代码的可维护性
131 | //
132 | // 禁止函数的循环复杂度超过 20,https://en.wikipedia.org/wiki/Cyclomatic_complexity
133 | "cyclomatic-complexity": [
134 | true,
135 | 20
136 | ],
137 | // 禁止使用废弃(被标识了 @deprecated)的 API
138 | "deprecation": true,
139 | // 一个缩进必须用四个空格替代
140 | "indent": [
141 | true,
142 | "tabs",
143 | 2
144 | ],
145 | // 禁止出现重复的 import
146 | "no-duplicate-imports": false,
147 | // 禁止一个文件中出现多个相同的 namespace
148 | "no-mergeable-namespace": true,
149 | // 文件类型必须时 utf-8
150 | "encoding": true,
151 | // import 语句中,关键字之间的间距必须是一个空格
152 | "import-spacing": true,
153 | // 接口可以 implement extend 和 merge
154 | "interface-over-type-literal": true,
155 | // new 后面只必须有一个空格
156 | "new-parens": true,
157 | // 类型断言必须使用 as Type,禁止使用
158 | // 容易被理解为 jsx
159 | "no-angle-bracket-type-assertion": false,
160 | // 禁止连续超过三行空行
161 | "no-consecutive-blank-lines": [
162 | true,
163 | 3
164 | ],
165 | // 禁止使用特殊空白符(比如全角空格)
166 | "no-irregular-whitespace": true,
167 | // 禁止使用 JSDoc,因为 TypeScirpt 已经包含了大部分功能
168 | "no-redundant-jsdoc": false,
169 | // 禁止使用三斜杠引入类型定义文件
170 | "no-reference-import": true,
171 | // 禁止变量定义时赋值为 undefined
172 | "no-unnecessary-initializer": true,
173 | // 小数必须以 0. 开头,禁止以 . 开头,并且不能以 0 结尾
174 | "number-literal-format": true,
175 | // 必须使用 a = {b} 而不是 a = {b: b}
176 | "object-literal-shorthand": true,
177 | // 变量申明必须每行一个,for 循环的初始条件中除外
178 | "one-variable-per-declaration": [
179 | true,
180 | "ignore-for-loop"
181 | ],
182 | // if 后的 { 禁止换行
183 | "one-line": true,
184 | // 必须使用单引号,jsx 中必须使用双引号
185 | "quotemark": [
186 | true,
187 | "single",
188 | "jsx-double",
189 | "avoid-template",
190 | "avoid-escape"
191 | ],
192 | // 行尾必须有分号
193 | "semicolon": [
194 | true,
195 | "always",
196 | "ignore-interfaces"
197 | ],
198 | // 函数名前必须有空格
199 | "space-before-function-paren": [
200 | true,
201 | "asyncArrow"
202 | ],
203 | // 括号内首尾禁止有空格
204 | "space-within-parens": [
205 | true,
206 | 0
207 | ],
208 | // 禁止 finally 内出现 return, continue, break, throw 等
209 | // finally 会比 catch 先执行
210 | "no-unsafe-finally": true,
211 | // 设置成员对象的访问权限(public,private,protect)
212 | "member-access": true,
213 | // 不允许空接口
214 | "no-empty-interface": true,
215 | // 如果for循环中没有使用索引,建议是使用for-of
216 | "prefer-for-of": false,
217 | // 不允许没有Promise的情况下使用await
218 | "await-promise": true,
219 | // 不允许使用arguments.callee
220 | "no-arg": true,
221 | // 不允许使用特殊运算符 &, &=, |, |=, ^, ^=, <<, <<=, >>, >>=, >>>, >>>=, ~
222 | // "no-bitwise":true,
223 | // 不允许使用console对象
224 | // "no-console":true,
225 | // 只允许在模板字符串中使用${
226 | "no-invalid-template-strings": true,
227 | // 不允许在class之外使用this
228 | "no-invalid-this": true,
229 | // 不允许使用null,使用undefined代替null,指代空指针对象
230 | "no-null-keyword": false,
231 | // 不允许自动类型转换,如果已设置不允许使用关键字var该设置无效
232 | "restrict-plus-operands": true,
233 |
234 | // 换行符格式 CR/LF可以通用使用在windows和osx
235 | "linebreak-style": [false, "CR/LF"],
236 | // 每个文件中可定义类的个数
237 | "max-classes-per-file": [true, 6],
238 | // 定义每个文件代码行数
239 | "max-file-line-count": [true, 500],
240 | // 定义每行代码数
241 | "max-line-length": [true, 500],
242 | // 禁止使用export default关键字,因为当export对象名称发生变化时,需要修改import中的对象名。https://github.com/palantir/tslint/issues/1182#issue-151780453
243 | "no-default-export": false,
244 |
245 | // 定义对齐风格
246 | "align": [true, "parameters", "statements", "members", "elements"],
247 | // 建议使用T[]方式声明一个数组对象
248 | "array-type": [false, "array"],
249 | // 类名以大驼峰格式命名
250 | "class-name": true,
251 | // interface必须以I开头
252 | "interface-name": [true, "always-prefix"],
253 | // 注释基于jsdoc风格
254 | "jsdoc-format": false,
255 | // 定义变量命名规则
256 | "variable-name": [false, "check-format",
257 | "allow-leading-underscore",
258 | "allow-trailing-underscore",
259 | "ban-keywords"
260 | ]
261 | },
262 | "rulesDirectory": []
263 | }
264 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 | const nodeExternals = require('webpack-node-externals');
4 | const WebpackShellPlugin = require('webpack-shell-plugin');
5 |
6 | module.exports = {
7 | entry: ['webpack/hot/poll?1000', './src/server/Main.ts'],
8 | watch: true,
9 | target: 'node',
10 | externals: [
11 | nodeExternals({
12 | whitelist: ['webpack/hot/poll?1000'],
13 | }),
14 | ],
15 | module: {
16 | rules: [{
17 | test: /\.tsx?$/,
18 | use: 'ts-loader',
19 | exclude: /node_modules/,
20 | }, ],
21 | },
22 | mode: 'development',
23 | resolve: {
24 | extensions: ['.tsx', '.ts', '.js'],
25 | },
26 | plugins: [
27 | new webpack.HotModuleReplacementPlugin(),
28 | new WebpackShellPlugin({
29 | onBuildEnd: ['node dist/main.js']
30 | }),
31 | ],
32 | output: {
33 | path: `${__dirname}/dist`,
34 | publicPath: '/',
35 | },
36 | };
37 |
--------------------------------------------------------------------------------