├── .eslintignore ├── app ├── extend │ ├── note.rec │ ├── RESTfulHTTPStatus.rec │ └── helper.js ├── controller │ ├── home.js │ ├── testCrypto.js │ ├── testCURL.js │ ├── testJWT.js │ ├── testRedis.js │ ├── testMysql.js │ ├── testMongo.js │ ├── testMock.js │ └── testUpload.js ├── view │ └── index │ │ └── index.html ├── schedule │ ├── allTask.js │ └── timeTask.js ├── model │ └── testMongo.js ├── middleware │ ├── error_handler.js │ └── token_handler.js ├── service │ ├── token.js │ ├── role.js │ ├── mycurl.js │ ├── mysql.js │ └── mongo.js └── router.js ├── .gitattributes ├── apidoc.json ├── assets └── 20190103 │ └── 5c2dc13bbcbc8966198fa660.jpg ├── .babelrc ├── config ├── config.stage.js ├── config.local.js ├── config.unittest.js ├── plugin.js ├── config.prod.js └── config.default.js ├── .gitignore ├── .travis.yml ├── appveyor.yml ├── .autod.conf.js ├── .eslintrc ├── app.js ├── LICENSE ├── test └── home.test.js ├── .vscode ├── launch.json └── settings.json ├── package.json └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | test -------------------------------------------------------------------------------- /app/extend/note.rec: -------------------------------------------------------------------------------- 1 | ctx.state.user jwt验证通过,可以获取到之前加密的data,如获取到该token对应的user -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /apidoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "接口文档-链链前端", 3 | "version": "1.1.0", 4 | "description": "gaochao", 5 | "title": "接口文档-链链前端", 6 | "url" : "" 7 | } -------------------------------------------------------------------------------- /assets/20190103/5c2dc13bbcbc8966198fa660.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcdreams/eggjs-go-examples/HEAD/assets/20190103/5c2dc13bbcbc8966198fa660.jpg -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react", 4 | "es2015", 5 | "stage-0", 6 | "env" 7 | ], 8 | "plugins": ["transform-decorators-legacy" ,"transform-runtime"] 9 | } 10 | -------------------------------------------------------------------------------- /config/config.stage.js: -------------------------------------------------------------------------------- 1 | module.exports = appInfo => { 2 | const config = exports = {} 3 | 4 | 5 | config.swaggerdoc = { 6 | enable: false, 7 | } 8 | 9 | return config 10 | } 11 | 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | yarn-error.log 4 | node_modules/ 5 | package-lock.json 6 | yarn.lock 7 | coverage/ 8 | .idea/ 9 | run/ 10 | __MACOSX/ 11 | .DS_Store 12 | *.sw* 13 | *.un~ 14 | #.vscode/ 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '8' 5 | install: 6 | - npm i npminstall && npminstall 7 | script: 8 | - npm run ci 9 | after_script: 10 | - npminstall codecov && codecov 11 | -------------------------------------------------------------------------------- /config/config.local.js: -------------------------------------------------------------------------------- 1 | module.exports = appInfo => { 2 | 3 | const config = exports = {} 4 | 5 | config.cluster = { 6 | listen: { 7 | port: 7001, 8 | hostname: '127.0.0.1', 9 | } 10 | } 11 | 12 | return config 13 | } 14 | -------------------------------------------------------------------------------- /config/config.unittest.js: -------------------------------------------------------------------------------- 1 | module.exports = appInfo => { 2 | 3 | const config = exports = {} 4 | config.cluster = { 5 | listen: { 6 | port: 7001, 7 | hostname: '0.0.0.0', 8 | } 9 | } 10 | 11 | return config 12 | } 13 | 14 | 15 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: '8' 4 | 5 | install: 6 | - ps: Install-Product node $env:nodejs_version 7 | - npm i npminstall && node_modules\.bin\npminstall 8 | 9 | test_script: 10 | - node --version 11 | - npm --version 12 | - npm run test 13 | 14 | build: off 15 | -------------------------------------------------------------------------------- /app/controller/home.js: -------------------------------------------------------------------------------- 1 | const Controller = require('egg').Controller 2 | 3 | class HomeController extends Controller { 4 | async index() { 5 | const title = { 6 | name: 'Egg-go', 7 | content: '链链前端 node API基础库,基于Egg.js,用于快速集成开发BFF端。
created by gaochao.' 8 | } 9 | await this.ctx.render('index/index',{ 10 | title: title 11 | }) 12 | } 13 | } 14 | 15 | module.exports = HomeController 16 | -------------------------------------------------------------------------------- /app/view/index/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%-title.name%> 8 | 9 | 10 | 11 |

<%-title.name%>

12 | 13 |

<%-title.content%>

14 | 15 | -------------------------------------------------------------------------------- /.autod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | write: true, 5 | prefix: '^', 6 | plugin: 'autod-egg', 7 | test: [ 8 | 'test', 9 | 'benchmark', 10 | ], 11 | dep: [ 12 | 'egg', 13 | 'egg-scripts', 14 | ], 15 | devdep: [ 16 | 'egg-ci', 17 | 'egg-bin', 18 | 'egg-mock', 19 | 'autod', 20 | 'autod-egg', 21 | 'eslint', 22 | 'eslint-config-egg', 23 | 'webstorm-disable-index', 24 | ], 25 | exclude: [ 26 | './test/fixtures', 27 | './dist', 28 | ], 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true 5 | }, 6 | "extends": "eslint:recommended", 7 | "parserOptions": { 8 | "sourceType": "module", 9 | "ecmaVersion": 8 10 | }, 11 | "rules": { 12 | "indent": [ 13 | "error", 14 | 2 15 | ], 16 | "linebreak-style": [ 17 | 0, 18 | "error", 19 | "windows" 20 | ], 21 | "quotes": [ 22 | "error", 23 | "single" 24 | ], 25 | "semi": [ 26 | "error", 27 | "never" 28 | ], 29 | "no-console": "off", 30 | "no-self-assign": "off", 31 | "no-unused-vars": "off" 32 | } 33 | } -------------------------------------------------------------------------------- /app/controller/testCrypto.js: -------------------------------------------------------------------------------- 1 | const Controller = require('egg').Controller 2 | const Jwt = require('jsonwebtoken') 3 | class TestRedisController extends Controller { 4 | constructor(ctx) { 5 | super(ctx) 6 | } 7 | 8 | async get() { 9 | const {ctx, app} = this 10 | const str = 'I am handsome man!' 11 | const res = { 12 | string: str, 13 | md5: ctx.helper.tomd5(str), 14 | des3: ctx.helper.todes(str, ctx), 15 | des3ToString: ctx.helper.dedes(ctx.helper.todes(str, ctx), ctx) 16 | } 17 | ctx.helper.success({ctx, res}) 18 | } 19 | 20 | } 21 | 22 | module.exports = TestRedisController 23 | -------------------------------------------------------------------------------- /app/schedule/allTask.js: -------------------------------------------------------------------------------- 1 | const Subscription = require('egg').Subscription 2 | const moment = require('moment') 3 | class AllTask extends Subscription { 4 | constructor(ctx){ 5 | super(ctx) 6 | } 7 | static get schedule() { 8 | return { 9 | interval: '15s', 10 | type: 'all', //all egg的所有worker都会执行此任务 worker只有一个worker执行 11 | disable: true, 12 | env: ['prod'] 13 | } 14 | } 15 | 16 | async subscribe() { 17 | const time = moment().format('MMMM Do YYYY, h:mm:ss a') 18 | this.ctx.app.cache = time 19 | console.log('所有worker执行定时任务:' + time) 20 | } 21 | } 22 | 23 | module.exports = AllTask -------------------------------------------------------------------------------- /app/schedule/timeTask.js: -------------------------------------------------------------------------------- 1 | const Subscription = require('egg').Subscription 2 | const moment = require('moment') 3 | class MyTask extends Subscription { 4 | constructor(ctx){ 5 | super(ctx) 6 | } 7 | static get schedule() { 8 | return { 9 | interval: '15s', 10 | type: 'worker', //all egg的所有worker都会执行此任务 worker只有一个worker执行 11 | immediate: true, 12 | env: ['local'] 13 | } 14 | } 15 | 16 | async subscribe() { 17 | const time = moment().format('MMMM Do YYYY, h:mm:ss a') 18 | this.ctx.app.cache = time 19 | console.log('单个workerworker执行定时任务:' + time) 20 | } 21 | } 22 | 23 | module.exports = MyTask -------------------------------------------------------------------------------- /config/plugin.js: -------------------------------------------------------------------------------- 1 | exports.validate = { 2 | enable: true, 3 | package: 'egg-validate', 4 | } 5 | 6 | exports.bcrypt = { 7 | enable: true, 8 | package: 'egg-bcrypt' 9 | } 10 | 11 | exports.mongoose = { 12 | enable: false, 13 | package: 'egg-mongoose', 14 | } 15 | 16 | exports.jwt = { 17 | enable: true, 18 | package: 'egg-jwt', 19 | } 20 | 21 | exports.cors = { 22 | enable: true, 23 | package: 'egg-cors', 24 | } 25 | 26 | exports.mysql = { 27 | enable: false, 28 | package: 'egg-mysql', 29 | } 30 | 31 | exports.redis = { 32 | enable: false, 33 | package: 'egg-redis', 34 | } 35 | 36 | exports.ejs = { 37 | enable: true, 38 | package: 'egg-view-ejs', 39 | } -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | class AppBootHook { 2 | constructor(app) { 3 | this.app = app 4 | } 5 | //以下为egg的生命周期 6 | configWillLoad() { 7 | // 此时 config 文件已经被读取并合并,但是还并未生效 8 | // 这是应用层修改配置的最后时机 9 | // 注意:此函数只支持同步调用 10 | } 11 | 12 | async didLoad() { 13 | // 所有的配置已经加载完毕 14 | // 可以用来加载应用自定义的文件,启动自定义的服务 15 | } 16 | 17 | async willReady() { 18 | // 所有的插件都已启动完毕,但是应用整体还未 ready 19 | // 可以做一些数据初始化等操作,这些操作成功才会启动应用 20 | } 21 | 22 | async didReady() { 23 | // 应用已经启动完毕 24 | } 25 | 26 | async beforeStart(){ 27 | await this.app.runSchedule('timeTask') 28 | } 29 | 30 | async serverDidReady() { 31 | 32 | } 33 | } 34 | module.exports = AppBootHook 35 | -------------------------------------------------------------------------------- /app/controller/testCURL.js: -------------------------------------------------------------------------------- 1 | const Controller = require('egg').Controller 2 | class TestCURLController extends Controller { 3 | constructor(ctx) { 4 | super(ctx) 5 | } 6 | 7 | async get() { 8 | const {ctx, service} = this 9 | const res = await service.mycurl.curlall(ctx.app.config.llpath.curlUrl + 'api/?version=v1', 'GET' , {}) 10 | ctx.helper.success({ctx, res}) 11 | } 12 | 13 | async post() { 14 | const {ctx, service} = this 15 | const payload = ctx.request.body || {} 16 | const res = await service.mycurl.curlall(ctx.app.config.llpath.curlUrl + 'api/?version=v1', 'POST' , payload) 17 | ctx.helper.success({ctx, res}) 18 | } 19 | } 20 | 21 | module.exports = TestCURLController 22 | -------------------------------------------------------------------------------- /app/controller/testJWT.js: -------------------------------------------------------------------------------- 1 | const Controller = require('egg').Controller 2 | const Jwt = require('jsonwebtoken') 3 | class TestJWTController extends Controller { 4 | constructor(ctx) { 5 | super(ctx) 6 | } 7 | 8 | async login() { 9 | const {ctx, app, service} = this 10 | const payload = ctx.request.body || {} 11 | const res = await service.token.login(payload) 12 | this.ctx.cookies.set('mttoken', res.token, { 13 | httpOnly: true, 14 | signed: true, 15 | path: '/' 16 | }) 17 | ctx.helper.success({ctx, res}) 18 | } 19 | 20 | async get() { 21 | const {ctx, app} = this 22 | ctx.helper.success({ctx}) 23 | } 24 | 25 | } 26 | 27 | module.exports = TestJWTController 28 | -------------------------------------------------------------------------------- /config/config.prod.js: -------------------------------------------------------------------------------- 1 | module.exports = appInfo => { 2 | 3 | const config = exports = {} 4 | 5 | config.llpath = { 6 | pcurl: 'http://127.0.0.1/lianapi-v1/assets', 7 | wapurl: 'http://127.0.0.1/lianapi-v1/assets', 8 | images: 'assets', 9 | upload: 'assets/', 10 | curlUrl: 'http://p2p-inner-jxq-test.ljjr.com/p2p-inner/', 11 | curlTimeOut: 3000, 12 | mykey: '123456789' 13 | } 14 | 15 | config.mongoose = { 16 | url: 'mongodb://mongouser:mongopassword@127.0.0.1:27017/gcprod', 17 | options: { 18 | useMongoClient: true, 19 | autoReconnect: true, 20 | reconnectTries: Number.MAX_VALUE, 21 | bufferMaxEntries: 0, 22 | }, 23 | } 24 | 25 | config.swaggerdoc = { 26 | enable: false, 27 | } 28 | 29 | return config 30 | } 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/model/testMongo.js: -------------------------------------------------------------------------------- 1 | module.exports = app => { 2 | const mongoose = app.mongoose 3 | const TestMongoSchema = new mongoose.Schema({ 4 | name: { type: String, unique: true, required: true }, 5 | realName: { type: String, unique: true, required: true }, 6 | onceLimit: { type: Number, required: true, default: 1 }, 7 | dayLimit: { type: Number, required: true, default: 1 }, 8 | ifShow: { type: Boolean, default: true }, 9 | flag: { type: Boolean, default: true }, 10 | bankType: { type: String, unique: true, required: true }, 11 | ifQuick: { type: Boolean, default: true }, 12 | desc:{type: String,default: ''}, 13 | image:{type: String,default: ''}, 14 | bankId:{type: Number , default: 0}, 15 | createdAt: { type: Date, default: Date.now } 16 | }) 17 | return mongoose.model('Testmongo', TestMongoSchema) 18 | } -------------------------------------------------------------------------------- /app/middleware/error_handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = (option, app) => { 4 | return async function (ctx, next) { 5 | try { 6 | await next() 7 | } catch (err) { 8 | // 所有的异常都在 app 上触发一个 error 事件,框架会记录一条错误日志 9 | app.emit('error', err, this) 10 | const status = err.status || 500 11 | // 生产环境时 500 错误的详细错误内容不返回给客户端,因为可能包含敏感信息 12 | const error = status === 500 && app.config.env === 'prod' ? 13 | 'Internal Server Error' : 14 | err.message 15 | // 从 error 对象上读出各个属性,设置到响应中 16 | ctx.body = { 17 | code: status, // 服务端自身的处理逻辑错误(包含框架错误500 及 自定义业务逻辑错误533开始 ) 客户端请求参数导致的错误(4xx开始),设置不同的状态码 18 | error: err.message 19 | } 20 | if (status === 422) { 21 | ctx.body.detail = err.errors 22 | } 23 | ctx.status = 200 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/controller/testRedis.js: -------------------------------------------------------------------------------- 1 | const Controller = require('egg').Controller 2 | const Jwt = require('jsonwebtoken') 3 | class TestRedisController extends Controller { 4 | constructor(ctx) { 5 | super(ctx) 6 | } 7 | 8 | async set() { 9 | const {ctx, app} = this 10 | const {name} = ctx.params 11 | let token = Jwt.sign({ 12 | user_id: 1, 13 | user_name:'gaochao' 14 | }, app.config.jwtSet.key, { 15 | expiresIn: app.config.jwtSet.tokenTime 16 | }) 17 | const res = await app.redis.set('token', token, function(){ 18 | app.redis.expire('token', 40) //TTL 19 | }) 20 | if(res !== 'OK') { 21 | ctx.throw(500, 'not save') 22 | } 23 | ctx.helper.success({ctx}) 24 | } 25 | 26 | async get() { 27 | const {ctx, app} = this 28 | const res = await app.redis.get('token') 29 | ctx.helper.success({ctx, res}) 30 | } 31 | 32 | } 33 | 34 | module.exports = TestRedisController 35 | -------------------------------------------------------------------------------- /app/extend/RESTfulHTTPStatus.rec: -------------------------------------------------------------------------------- 1 | 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 2 | 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 3 | 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 4 | 204 NO CONTENT - [DELETE]:用户删除数据成功。 5 | 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 6 | 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 7 | 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。 8 | 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 9 | 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。 10 | 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。 11 | 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 12 | 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功 13 | 14 | /** 15 | * 在接口处理发生错误的时候,如果是客户端请求参数导致的错误,我们会返回 4xx 状态码, 16 | * 如果是服务端自身的处理逻辑错误,我们会返回 5xx 状态码。 17 | * 所有的异常对象都是对这个异常状态的描述,其中 error 字段是错误的描述,detail 字段(可选)是导致错误的详细原因。 18 | */ 19 | 20 | eg----: 21 | 533 INTERNAL SERVER ERROR - [*]:keystore 不存在 22 | 534 INTERNAL SERVER ERROR - [*]:keystore 已过期 -------------------------------------------------------------------------------- /app/service/token.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Service = require('egg').Service 4 | const Jwt = require('jsonwebtoken') 5 | class TokenService extends Service { 6 | async login(payload) { 7 | const { ctx, service ,app } = this 8 | const user = {id:1, userName:'gao', password: '111111'} 9 | if(!user){ 10 | return {'status':'error','type':'account','currentAuthority':'guest'} 11 | } 12 | let verifyPsw = true 13 | if(!verifyPsw) { 14 | return {'status':'error','type':'account','currentAuthority':'guest','tips':'password'} 15 | }else{ 16 | let token = Jwt.sign({ 17 | user_id: user.id, 18 | user_name: user.userName 19 | }, app.config.jwtSet.key, { 20 | expiresIn: app.config.jwtSet.tokenTime 21 | }) 22 | return { 23 | user: user, 24 | status: 'ok', 25 | type: 'account', 26 | currentAuthority: 'admin', 27 | token: token 28 | } 29 | } 30 | } 31 | } 32 | 33 | module.exports = TokenService 34 | -------------------------------------------------------------------------------- /app/service/role.js: -------------------------------------------------------------------------------- 1 | const Service = require('egg').Service 2 | 3 | class RoleService extends Service { 4 | 5 | async index(params) { 6 | const { pageNo = 1, pageSize = 99, } = params 7 | const res = await this.ctx.model.User.find() 8 | .skip((pageNo - 1) * pageSize) 9 | .limit(pageSize) 10 | .exec() 11 | const { formatTime } = this.ctx.helper 12 | let data = res.map((item) => { 13 | let obj = Object.assign({}, item._doc) 14 | obj.createDate = formatTime(item.createDate) 15 | return obj 16 | }) 17 | return { 18 | count: res.length, 19 | list: data 20 | } 21 | } 22 | 23 | async create(params) { 24 | return this.ctx.model.User.create(params) 25 | } 26 | 27 | async update(params) { 28 | const id = params.id 29 | delete params.id 30 | return this.ctx.model.User.findByIdAndUpdate(id, params) 31 | } 32 | 33 | async removes(params) { 34 | return this.ctx.model.User.remove({ _id: { $in: params } }) 35 | } 36 | } 37 | 38 | module.exports = RoleService 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 高超 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /test/home.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert') 2 | const mock = require('egg-mock') 3 | //https://github.com/visionmedia/supertest#getting-started 4 | describe('some test', () => { 5 | let app 6 | let token = 0 7 | before(() => { 8 | app = mock.app() 9 | return app.ready() 10 | }) 11 | 12 | it('访问/应返回200', async () => { 13 | const result = await app.httpRequest() 14 | .get('/') 15 | .expect(200) 16 | return await app.httpRequest() 17 | .get('/') 18 | .expect(200) 19 | }) 20 | 21 | it('访问/api/testJWT/login应返回200', async () => { 22 | return await app.httpRequest() 23 | .post('/api/testJWT/login') 24 | .type('form') 25 | .send({ 26 | password: '1111111', 27 | }) 28 | .expect(200) 29 | .then(response => { 30 | token = response.body.data.token 31 | assert.strictEqual(response.body.code, 0) 32 | }) 33 | }) 34 | 35 | it('访问/api/testJWT/get应返回200', async () => { 36 | return await app.httpRequest() 37 | .get('/api/testJWT/get') 38 | .set('x-csrf-token' , `token ${token}`) 39 | .expect(200) 40 | .then(response => { 41 | assert.strictEqual(response.body.code, 0) 42 | }) 43 | }) 44 | 45 | }) -------------------------------------------------------------------------------- /app/service/mycurl.js: -------------------------------------------------------------------------------- 1 | const Service = require('egg').Service 2 | const moment = require('moment') 3 | class MycurlService extends Service{ 4 | 5 | async get(url){ 6 | const res = await this.ctx.curl(url, { 7 | dataType: 'json', 8 | timeout: 3000, 9 | }) 10 | return res 11 | } 12 | 13 | async curlall(url,method,req,encrypt = false){ 14 | const {ctx} = this 15 | let payload = req 16 | if(encrypt){ 17 | payload = ctx.helper.todes(req,ctx) 18 | } 19 | const data = await this.ctx.curl(url,{ 20 | method: method, 21 | headers: '', 22 | gzip: false, 23 | data: payload, 24 | timeout: ctx.app.config.llpath.curlTimeOut, 25 | }) 26 | let res = ctx.helper.bufferToJSON(data.data) 27 | if(encrypt){ 28 | res = JSON.parse(ctx.helper.dedes(res,ctx)) 29 | } 30 | const thislogger = { 31 | url:ctx.request.url, 32 | method:method, 33 | request:req, 34 | response:res, 35 | date:moment().format('YYYY-MM-DD HH:mm:ss'), 36 | useragent:ctx.request.header['user-agent'] 37 | } 38 | ctx.getLogger('curlLogger').info('lianlian-API',JSON.stringify(thislogger)) 39 | return res 40 | } 41 | } 42 | 43 | module.exports = MycurlService 44 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Egg Debug", 11 | "runtimeExecutable": "npm", 12 | "runtimeArgs": [ 13 | "run", 14 | "debug" 15 | ], 16 | "console": "integratedTerminal", 17 | "restart": true, 18 | "protocol": "auto", 19 | "port": 9999 20 | }, 21 | { 22 | "type": "node", 23 | "request": "launch", 24 | "name": "Egg Debug with brk", 25 | "runtimeExecutable": "npm", 26 | "runtimeArgs": [ 27 | "run", 28 | "debug", 29 | "--", 30 | "--inspect-brk" 31 | ], 32 | "protocol": "inspector", 33 | "port": 9229 34 | }, 35 | { 36 | "type": "node", 37 | "request": "launch", 38 | "name": "Egg Test", 39 | "runtimeExecutable": "npm", 40 | "runtimeArgs": [ 41 | "run", 42 | "test-local", 43 | "--", 44 | "--inspect-brk" 45 | ], 46 | "protocol": "auto", 47 | "port": 9229 48 | }, 49 | { 50 | "type": "node", 51 | "request": "attach", 52 | "name": "Egg Attach to remote", 53 | "localRoot": "${workspaceRoot}", 54 | "remoteRoot": "/usr/src/app", 55 | "address": "localhost", 56 | "protocol": "auto", 57 | "port": 9999 58 | } 59 | ] 60 | } -------------------------------------------------------------------------------- /app/controller/testMysql.js: -------------------------------------------------------------------------------- 1 | const Controller = require('egg').Controller 2 | 3 | class TestMysqlController extends Controller { 4 | constructor(ctx) { 5 | super(ctx) 6 | this.createRule = { 7 | name: { type: 'string', required: true, allowEmpty: false }, 8 | tel: { type: 'string', required: true, allowEmpty: false }, 9 | } 10 | this.operRule = { 11 | id: { type: 'string', required: true, allowEmpty: false }, 12 | } 13 | } 14 | 15 | async add() { 16 | const { ctx, service } = this 17 | ctx.validate(this.createRule) 18 | const payload = ctx.request.body || {} 19 | const res = await service.mysql.create(payload) 20 | ctx.helper.success({ctx}) 21 | } 22 | 23 | async update() { 24 | const { ctx, service } = this 25 | ctx.validate(this.operRule) 26 | const payload = ctx.request.body 27 | const res = await service.mysql.update(Number(payload.id), payload) 28 | ctx.helper.success({ctx}) 29 | } 30 | 31 | async remove() { 32 | const { ctx, service } = this 33 | ctx.validate(this.operRule) 34 | const payload = ctx.request.body 35 | const res = await service.mysql.remove(Number(payload.id)) 36 | ctx.helper.success({ctx}) 37 | } 38 | 39 | async findOne() { 40 | const { ctx, service } = this 41 | const { id } = ctx.params 42 | const res = await service.mysql.find(Number(id)) 43 | ctx.helper.success({ctx, res}) 44 | } 45 | 46 | async list() { 47 | const { ctx, service } = this 48 | let res = await service.mysql.list() 49 | ctx.helper.success({ctx, res}) 50 | } 51 | 52 | async pagelist() { 53 | const { ctx, service } = this 54 | let res = await service.mysql.pagelist(ctx.params) 55 | ctx.helper.success({ctx, res}) 56 | } 57 | 58 | } 59 | 60 | module.exports = TestMysqlController 61 | -------------------------------------------------------------------------------- /app/service/mysql.js: -------------------------------------------------------------------------------- 1 | const Service = require('egg').Service 2 | 3 | class MysqlService extends Service { 4 | 5 | async create(payload) { 6 | payload.addtime = this.app.mysql.literals.now 7 | const result = await this.app.mysql.insert('test',payload) 8 | return result 9 | } 10 | 11 | 12 | async remove(id) { 13 | const { ctx, service } = this 14 | const role = await this.find(id) 15 | if (!role) { 16 | ctx.throw(404, 'not found') 17 | } 18 | return this.app.mysql.delete('test', {id}) 19 | } 20 | 21 | 22 | async update(id, payload) { 23 | const { ctx, service } = this 24 | const role = await this.find(id) 25 | if (!role) { 26 | ctx.throw(404, 'not found') 27 | } 28 | const options = {id} 29 | const result = await this.app.mysql.update('test', payload, options) 30 | } 31 | 32 | async list() { 33 | let res = [] 34 | let count = 0 35 | const results = await this.app.mysql.select('test', { 36 | columns: ['id','name', 'tel', 'addtime'], 37 | orders: [['id','desc']], 38 | limit: 10, 39 | offset: 0, 40 | }) 41 | return { count: count, list: results } 42 | } 43 | 44 | 45 | async pagelist(payload) { 46 | const { currentPage, pageSize } = payload 47 | let res = [] 48 | let count = 0 49 | let skip = ((Number(currentPage)) - 1) * Number(pageSize || 10) 50 | res = await this.app.mysql.select('test',{ 51 | orders: [['id','desc']], 52 | limit: Number(pageSize), 53 | offset: Number(currentPage - 1) * Number(pageSize) 54 | }) 55 | count = await this.app.mysql.count('test') 56 | return { count: count, list: res, pageSize: Number(pageSize), currentPage: Number(currentPage) } 57 | } 58 | 59 | 60 | async find(id) { 61 | return this.app.mysql.get('test', { id }) 62 | } 63 | 64 | } 65 | 66 | module.exports = MysqlService -------------------------------------------------------------------------------- /app/middleware/token_handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = (options) => { // 若放到线上中间要加入redis做中转验证 4 | const Jwt = require('jsonwebtoken') 5 | return async function (ctx, next) { 6 | const config = options.config 7 | const delUrl = options.urlMatch 8 | if(ctx.request.url.indexOf(delUrl) !== -1 && ctx.request.url.indexOf('login') === -1 && ctx.request.url.indexOf('logout') === -1 ){ 9 | if (ctx.request.header['x-csrf-token']) { 10 | const user = ctx.helper.getToken(ctx.request.header['x-csrf-token']) 11 | let token = ctx.request.header['x-csrf-token'].split(' ')[1] 12 | let decoded 13 | try { 14 | decoded = Jwt.verify(token, config.key) 15 | } catch (error) { 16 | if (error.name === 'TokenExpiredError') { 17 | token = Jwt.sign({ 18 | user_id: user.user_id, 19 | user_name: user.user_name 20 | }, config.key, { 21 | expiresIn: config.tokenTime 22 | }) 23 | ctx.cookies.set('token', token, { 24 | maxAge: config.cookiesTime, 25 | httpOnly: true, 26 | overwrite: true, 27 | signed: true 28 | }) 29 | } else { 30 | ctx.status = 200 31 | ctx.body = { 32 | code:401, 33 | message: '信息失效,请登录' 34 | } 35 | return 36 | } 37 | } 38 | ctx.cookies.set('token', token, { 39 | maxAge: config.cookiesTime, 40 | httpOnly: true, 41 | overwrite: true, 42 | signed: true 43 | }) 44 | await next() 45 | } else { 46 | ctx.status = 200 47 | ctx.body = { 48 | code:401, 49 | message: '请登录' 50 | } 51 | return 52 | } 53 | }else{ 54 | await next() 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "egg_go", 3 | "version": "1.0.0", 4 | "description": "Node.js RESTful API & DB demo Server for lianlian.based on egg.js!", 5 | "private": true, 6 | "dependencies": { 7 | "await-stream-ready": "^1.0.1", 8 | "egg": "^2.0.0", 9 | "egg-bcrypt": "^1.0.0", 10 | "egg-cors": "^2.0.0", 11 | "egg-jwt": "^2.2.0", 12 | "egg-mongoose": "^2.1.1", 13 | "egg-mysql": "^3.0.0", 14 | "egg-redis": "^2.3.1", 15 | "egg-scripts": "^2.1.0", 16 | "egg-validate": "^1.0.0", 17 | "egg-view-assets": "^1.3.0", 18 | "egg-view-ejs": "^2.0.0", 19 | "image-downloader": "^3.3.0", 20 | "jsonwebtoken": "^8.3.0", 21 | "moment": "^2.20.1", 22 | "stream-to-array": "^2.3.0", 23 | "stream-wormhole": "^1.0.3" 24 | }, 25 | "devDependencies": { 26 | "autod": "^3.0.1", 27 | "autod-egg": "^1.0.0", 28 | "egg-bin": "^4.3.5", 29 | "egg-ci": "^1.8.0", 30 | "egg-mock": "^3.13.0", 31 | "eslint": "^4.11.0", 32 | "eslint-config-egg": "^5.1.0", 33 | "mocha": "^6.1.3", 34 | "mockjs": "^1.0.1-beta3", 35 | "webstorm-disable-index": "^1.2.0" 36 | }, 37 | "engines": { 38 | "node": ">=8.9.0" 39 | }, 40 | "scripts": { 41 | "start": "egg-scripts start --env=prod", 42 | "uat": "egg-scripts start --env=unittest", 43 | "local": "egg-scripts start --env=local", 44 | "stage": "egg-scripts start --env=stage", 45 | "document": "apidoc -i app/controller/ -o apidoc/", 46 | "stop": "egg-scripts stop", 47 | "dev": "egg-bin dev", 48 | "debug": "egg-bin debug", 49 | "test": "npm run lint -- --fix && npm run test-local", 50 | "test-local": "egg-bin test", 51 | "cov": "egg-bin cov", 52 | "lint": "eslint .", 53 | "ci": "npm run lint && npm run cov", 54 | "autod": "autod" 55 | }, 56 | "ci": { 57 | "version": "8" 58 | }, 59 | "repository": { 60 | "type": "git", 61 | "url": "" 62 | }, 63 | "author": "chao.gao@bkjk.com", 64 | "license": "MIT" 65 | } 66 | -------------------------------------------------------------------------------- /app/controller/testMongo.js: -------------------------------------------------------------------------------- 1 | const Controller = require('egg').Controller 2 | 3 | class TestMongoController extends Controller { 4 | constructor(ctx) { 5 | super(ctx) 6 | this.createRule = { 7 | name: { type: 'string', required: true, allowEmpty: false }, 8 | onceLimit: { type: 'string', required: true, allowEmpty: false }, 9 | dayLimit: { type: 'string', required: true, allowEmpty: false }, 10 | realName: { type: 'string', required: true, allowEmpty: false }, 11 | bankType: { type: 'string', required: true, allowEmpty: false }, 12 | } 13 | this.operRule = { 14 | id: { type: 'string', required: true, allowEmpty: false }, 15 | } 16 | } 17 | 18 | async add() { 19 | const { ctx, service } = this 20 | ctx.validate(this.createRule) 21 | const payload = ctx.request.body || {} 22 | const res = await service.mongo.create(payload) 23 | ctx.helper.success({ctx, res}) 24 | } 25 | 26 | async update() { 27 | const { ctx, service } = this 28 | ctx.validate(this.operRule) 29 | const payload = ctx.request.body 30 | const res = await service.mongo.update(payload.id, payload) 31 | ctx.helper.success({ctx}) 32 | } 33 | 34 | async remove() { 35 | const { ctx, service } = this 36 | ctx.validate(this.operRule) 37 | const {id} = ctx.request.body 38 | const res = await service.mongo.remove(id) 39 | ctx.helper.success({ctx}) 40 | } 41 | 42 | async findOne() { 43 | const { ctx, service } = this 44 | const { id } = ctx.params 45 | const res = await service.mongo.find(id) 46 | ctx.helper.success({ctx, res}) 47 | } 48 | 49 | async list() { 50 | const { ctx, service } = this 51 | let res = await service.mongo.list() 52 | ctx.helper.success({ctx, res}) 53 | } 54 | 55 | async pagelist() { 56 | const { ctx, service } = this 57 | let res = await service.mongo.pagelist(ctx.params) 58 | ctx.helper.success({ctx, res}) 59 | } 60 | 61 | } 62 | 63 | module.exports = TestMongoController 64 | -------------------------------------------------------------------------------- /app/router.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = app => { 3 | const { router, controller } = app 4 | //输出页面 && ejs模板输出 5 | router.get('/', controller.home.index) 6 | //生成Mock数据 7 | router.get('/api/testMock', controller.testMock.index) 8 | //操作mongoDB 9 | router.post('/api/testMongo/add', controller.testMongo.add) //插入记录 10 | router.get('/api/testMongo/list', controller.testMongo.list) //读取记录 11 | router.put('/api/testMongo/update', controller.testMongo.update) //更新记录 12 | router.delete('/api/testMongo/remove', controller.testMongo.remove) //删除记录 13 | router.get('/api/testMongo/find/:id', controller.testMongo.findOne) //获取某条记录 14 | router.get('/api/testMongo/pagelist/:currentPage/:pageSize', controller.testMongo.pagelist) //获取分页记录 15 | //操作mysql 16 | router.post('/api/testMysql/add', controller.testMysql.add) //插入记录 17 | router.get('/api/testMysql/list', controller.testMysql.list) //读取记录 18 | router.put('/api/testMysql/update', controller.testMysql.update) //更新记录 19 | router.delete('/api/testMysql/remove', controller.testMysql.remove) //删除记录 20 | router.get('/api/testMysql/find/:id', controller.testMysql.findOne) //获取某条记录 21 | router.get('/api/testMysql/pagelist/:currentPage/:pageSize', controller.testMysql.pagelist) //获取分页记录 22 | //操作redis 23 | router.get('/api/testRedis/set', controller.testRedis.set) //生成token 设置redis 24 | router.get('/api/testRedis/get', controller.testRedis.get) //获取redis 25 | //token验证 26 | router.post('/api/testJWT/login', controller.testJWT.login) 27 | router.get('/api/testJWT/get', controller.testJWT.get) //中间件token_handler 校验请求头x-csrf-token中携带的token 28 | //curl & 日志 logger 29 | router.get('/api/testCURL/get', controller.testCURL.get) 30 | router.post('/api/testCURL/post', controller.testCURL.post) 31 | //MD5 & DES3 32 | router.get('/api/testCrypto/get', controller.testCrypto.get) 33 | //antd/antd M 上传接口 34 | router.post('/api/inner/upload', controller.testUpload.create) //上传单个文件 35 | router.post('/api/inner/upload', controller.testUpload.multiple) //上传多个文件 36 | //Web Socket 37 | } 38 | -------------------------------------------------------------------------------- /app/service/mongo.js: -------------------------------------------------------------------------------- 1 | const Service = require('egg').Service 2 | 3 | class MongoService extends Service { 4 | 5 | async create(payload) { 6 | return this.ctx.model.TestMongo.create(payload) 7 | } 8 | 9 | 10 | async remove(id) { 11 | const { ctx, service } = this 12 | const role = await this.find(id) 13 | if (!role) { 14 | ctx.throw(404, 'not found') 15 | } 16 | return ctx.model.TestMongo.findByIdAndRemove(id) 17 | } 18 | 19 | 20 | async update(id, payload) { 21 | console.log(id) 22 | const { ctx, service } = this 23 | const role = await this.find(id) 24 | if (!role) { 25 | ctx.throw(404, 'not found') 26 | } 27 | return ctx.model.TestMongo.findByIdAndUpdate(id, payload) 28 | } 29 | 30 | async list() { 31 | let res = [] 32 | let count = 0 33 | res = await this.ctx.model.TestMongo.find({ifShow: true}).sort({ _id: 1 }).exec() 34 | count = res.length 35 | let data = res.map((e,i) => { 36 | const jsonObject = Object.assign({}, e._doc) 37 | jsonObject.key = i 38 | jsonObject.createdAt = this.ctx.helper.formatTime(e.createdAt) 39 | return jsonObject 40 | }) 41 | return { count: count, list: data } 42 | } 43 | 44 | 45 | async pagelist(payload) { 46 | const { currentPage, pageSize, search } = payload 47 | let res = [] 48 | let count = 0 49 | let skip = ((Number(currentPage)) - 1) * Number(pageSize || 10) 50 | if(search) { 51 | res = await this.ctx.model.TestMongo.find({name: { $regex: search } }).skip(skip).limit(Number(pageSize)).sort({ _id: 1 }).exec() 52 | count = res.length 53 | } else { 54 | res = await this.ctx.model.TestMongo.find({}).skip(skip).limit(Number(pageSize)).sort({ _id: 1 }).exec() 55 | count = await this.ctx.model.TestMongo.count({}).exec() 56 | } 57 | let data = res.map((e,i) => { 58 | const jsonObject = Object.assign({}, e._doc) 59 | jsonObject.key = i 60 | jsonObject.createdAt = this.ctx.helper.formatTime(e.createdAt) 61 | return jsonObject 62 | }) 63 | 64 | return { count: count, list: data, pageSize: Number(pageSize), currentPage: Number(currentPage) } 65 | } 66 | 67 | 68 | async removes(values) { 69 | return this.ctx.model.TestMongo.remove({ _id: { $in: values } }) 70 | } 71 | 72 | 73 | async find(id) { 74 | return this.ctx.model.TestMongo.findById(id) 75 | } 76 | 77 | } 78 | 79 | module.exports = MongoService -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eggjs-go-examples 2 | 3 | node API实例基础库,基于Egg.js,用于快速集成开发前后端分离的服务端。 4 | 涵盖mysql、redis、mongodb、Mock数据服务&生成文档、服务器渲染(ejs)、curl、定时任务、RESTful接口开发、文件上传、单元测试、token验证、数据加密、日志定制等 5 | 6 | 7 | 8 | ### QuickStart 9 | 10 | ```bash 11 | $ mkdir myegg & cd myegg 12 | $ npm i 13 | $ npm install apidoc -g 14 | $ npm run local 15 | $ open http://localhost:7001/ 16 | ``` 17 | 18 | ### Development 19 | 20 | ```bash 21 | $ npm run local //启动local环境 22 | $ npm run uat //启动uat测试环境 23 | $ npm run prod //启动生产环境 24 | $ npm run stage //启动stage环境 25 | $ npm stop //停止服务 26 | $ npm run document //生产API文档 27 | $ npm run test //单元测试 mocha 28 | ``` 29 | ### 链接数据库 (mysql, mongoDB, redis) 30 | ```bash 31 | 参见 ./app/router.js 32 | 其中包含操作实例,包含mysql, mongoDB增删改查及分页请求;redis设置读取 33 | 启动步骤: 34 | 1、./config/plugin.js 将对应插件的enable设置为true 35 | 2、./config/config.defaule.js 配置连接信息 36 | ``` 37 | mongoDB API参见 [mongoosejs] 38 | 39 | mysql API参见 [egg-mysql] API较少不能满足可使用 app.mysql.query(sql, values); 40 | 41 | ### 生产mock数据及生产API文档 42 | ```bash 43 | 参见 ./app/router.js 44 | 参见 ./app/controller/testMock.js 其中包含Mockjs、apidocs实例 45 | npm run document //生成文档 生成apidoc文件夹 46 | ``` 47 | mockjs 规则参见 [mockjs] 48 | 49 | apidoc 规则参见 [apidoc] 50 | 51 | ### token生成及验证 52 | ```bash 53 | 参见 ./app/router.js 54 | 参见 ./app/controller/testJWT.js 55 | 实例包含:登录获取token,通过中间件token_handler.js 验证 56 | PS:中间件启用模式为通过自定义URL识别 见config文件 57 | 中间件相关文档可见eggjs官方文档 58 | ``` 59 | ### curl 60 | ```bash 61 | 参见 ./app/router.js 62 | 参见 ./app/controller/testCURL.js 63 | 参见 ./app/service/mycurl.js 64 | 实例包含:明文请求&DES3加密请求,DES3密钥可在config中设置 65 | ``` 66 | 67 | ### 日志 68 | ```bash 69 | 参见 ./app/service/mycurl.js 70 | eggjs启动后自动生成日志,日志位置./logs 71 | PS: 自定义日志,开启方式见./config/config.defaule.js ,在curl实例中包含自定义日志的生成方式 72 | ``` 73 | 74 | ### 数据加密 75 | ```bash 76 | 参见 ./app/extend/helper.js 77 | 实例包含:md5 + DES3加密解密 78 | ``` 79 | ### 静态文件管理 80 | ```bash 81 | 参见./config/config.defaule.js中config.static 82 | ``` 83 | 84 | ### 图片上传 85 | ```bash 86 | 参见 ./app/controller/testUpload.js 87 | 实例包含:单个文件及多个文件上传 适用UI为antd & antd-m 88 | ``` 89 | ### 定时任务 90 | ```bash 91 | 参见 ./app/schedule/.. 92 | 实例包含:启动单一worker定时任务及所有worker定时任务,定时任务启动时机可根据业务或在./app.js中根据生命周期启动 93 | ``` 94 | ### 单元测试 95 | ```bash 96 | 参见 ./app/test/.. 97 | 实例包含:eslint检测及token验证的单元测试 ,单元测试使用mocha 98 | npm run test //运行单元测试 首先会检测eslint 99 | ``` 100 | 101 | ### restful 102 | ```bash 103 | 参见 ./app/router.js 104 | ``` 105 | ### 服务器渲染(ejs) 106 | ```bash 107 | 参见 ./app/controller/home.js 108 | 实例包含:通过ejs模板渲染页面 109 | ``` 110 | ### websocket 111 | ```bash 112 | 下版本待续 113 | ``` 114 | 115 | [egg]: https://eggjs.org 116 | [mockjs]: http://mockjs.com/examples.html 117 | [apidoc]: http://apidocjs.com/ 118 | [mongoosejs]:https://mongoosejs.com/docs/api.html 119 | [egg-mysql]:https://www.npmjs.com/package/egg-mysql 120 | -------------------------------------------------------------------------------- /config/config.default.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | // {app_root}/config/config.default.js 3 | 4 | module.exports = appInfo => { 5 | 6 | const config = exports = {} 7 | config.keys = appInfo.name + '_1513779989145_1984' 8 | config.llpath = { 9 | pcurl: 'http://127.0.0.1/lianapi-v1/assets', //PC端图片地址 10 | wapurl: 'http://127.0.0.1/lianapi-v1/assets',//移动端图片地址 11 | images: 'assets', //静态文件文件夹 12 | upload: 'assets/',//图片上传文件夹 13 | curlUrl: 'https://www.tianqiapi.com/', //curl地址 14 | curlTimeOut: 3000, //curl超时时间 15 | mykey: 'eb3bCk3NSqiRxv2R7vTyOhgoiownIXav' //DES3密钥 32位 16 | } 17 | 18 | config.static = { 19 | prefix:'/' + config.llpath.images + '/', 20 | dir: path.join(appInfo.baseDir, config.llpath.images), 21 | dynamic: true, 22 | preload: false, 23 | maxAge: 31536000, 24 | buffer: false 25 | } 26 | 27 | config.cluster = { 28 | listen: { 29 | port: 7001, 30 | hostname: '0.0.0.0', 31 | } 32 | } 33 | 34 | config.logger = { 35 | dir: path.join(appInfo.baseDir, 'logs'), 36 | } 37 | 38 | config.cors = { 39 | origin: '*', 40 | allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS', 41 | credentials: true, 42 | } 43 | 44 | config.security = { 45 | csrf: { 46 | enable: false, 47 | ignoreJSON: false 48 | }, 49 | domainWhiteList: [ '*' ], 50 | } 51 | 52 | config.multipart = { 53 | fileExtensions: [ '.apk', '.pptx', '.docx', '.csv', '.doc', '.ppt', '.pdf', '.pages', '.wav', '.mov' ], // 增加对 .apk 扩展名的支持 54 | } 55 | 56 | config.bcrypt = { 57 | saltRounds: 10 // default 10 58 | } 59 | 60 | config.mongoose = { 61 | url: 'mongodb://admin:gaochao@127.0.0.1:27017/LianApi', 62 | options: { 63 | useMongoClient: true, 64 | autoReconnect: true, 65 | reconnectTries: Number.MAX_VALUE, 66 | bufferMaxEntries: 0, 67 | }, 68 | } 69 | 70 | config.jwt = { 71 | secret: 'Great4-M', 72 | enable: true, 73 | match: '/jwt', 74 | } 75 | 76 | config.jwtSet = { 77 | key: 'gaochao09240924', 78 | tokenTime: '15s', 79 | cookiesTime: 60*1000*60 80 | } 81 | 82 | config.middleware = [ 'tokenHandler' , 'errorHandler' ] 83 | 84 | config.tokenHandler = { 85 | config: config.jwtSet, 86 | urlMatch: '/api/testJWT', 87 | } 88 | 89 | config.customLogger = { 90 | curlLogger: { 91 | file: path.join(appInfo.baseDir, 'logs/lianlian-curl.log') 92 | } 93 | } 94 | 95 | config.mysql = { 96 | client: { 97 | host: '127.0.0.1', 98 | port: '3306', 99 | user: 'root', 100 | password: '123456', 101 | database: 'test', 102 | debug: false 103 | }, 104 | app: true, 105 | agent: false, 106 | } 107 | 108 | config.redis = { 109 | client: { 110 | port: 6380, 111 | host: '127.0.0.1', 112 | password: '', 113 | db: 10 114 | }, 115 | } 116 | 117 | config.view = { 118 | root: path.join(appInfo.baseDir, 'app/view'), 119 | mapping: {'.html': 'ejs'} 120 | } 121 | return config 122 | } 123 | -------------------------------------------------------------------------------- /app/controller/testMock.js: -------------------------------------------------------------------------------- 1 | const Controller = require('egg').Controller 2 | const Mock = require('mockjs') 3 | //定义公共文档信息可公用 4 | 5 | /** 6 | * @apiDefine MyError 7 | * @apiError MyError 找不到相关数据 8 | * @apiErrorExample MyError-Response: 9 | * HTTP/1.1 404 Not Found 10 | * { 11 | * "error": { 12 | * "code": 404, 13 | * "msg": "", 14 | * "path" "" 15 | * } 16 | * } 17 | * 18 | */ 19 | 20 | /** 21 | * @apiDefine MyAuth 22 | * @apiError MyAuth token无效 23 | * @apiErrorExample MyAuth-Response: 24 | * HTTP/1.1 401 Not Auth 25 | * { 26 | * "error": { 27 | * "code": 401, 28 | * "msg": "", 29 | * "path" "" 30 | * } 31 | * } 32 | */ 33 | 34 | /** 35 | * @apiDefine MyHeader 36 | * @apiHeader {String} Authorization 用户授权token 37 | * @apiHeader {String} myid 编码 38 | * @apiHeaderExample {json} Header-Example: 39 | * { 40 | * "Authorization": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOjM2NzgsImF1ZGllbmNlIjoid2ViIiwib3BlbkFJZCI6MTM2NywiY3JlYXRlZCI6MTUzMzg3OTM2ODA0Nywicm9sZXMiOiJVU0VSIiwiZXhwIjoxNTM0NDg0MTY4fQ.Gl5L-NpuwhjuPXFuhPax8ak5c64skjDTCBC64N_QdKQ2VT-zZeceuzXB9TqaYJuhkwNYEhrV3pUx1zhMWG7Org", 41 | * "myid": "cnE=" 42 | * } 43 | */ 44 | 45 | //定义某个API文档信息 46 | /** 47 | * @apiVersion 1.1.0 48 | * @apiName getList 49 | * @apiGroup Test 50 | * @api {get} /api/testMock 获取信息 51 | * @apiUse MyHeader 52 | * @apiParam {Number} id 编号 53 | * 54 | * @apiSuccess {Number} totalCompensation 总款 55 | * @apiSuccess {Number} amountToBeRepaid 代偿款 56 | * @apiSuccess {String} recentPaymentDate 代偿时间(yyyy-MM-dd HH:mm:ss) 57 | * @apiSuccess {Object[]} orderList 列表 58 | * @apiSuccess {Number} profiles.orderId ID. 59 | * @apiSuccess {Number} profiles.orderAmount 金额. 60 | * 61 | * @apiSuccessExample {json} Success-Response: 62 | * HTTP/1.1 200 OK 63 | * { 64 | * "totalCompensation": 3268.58, 65 | * "amountToBeRepaid": 2367.15, 66 | * "recentPaymentDate": "1973-07-29 08:53:08", 67 | * "orderList":[ 68 | * { 69 | * "orderId" : 1 70 | * "orderAmount" : 1.00 71 | * } 72 | * ] 73 | * } 74 | * 75 | * @apiUse MyError 76 | * @apiUse MyAuth 77 | */ 78 | class TestMockController extends Controller { 79 | constructor(ctx) { 80 | super(ctx) 81 | } 82 | async index() { 83 | const { ctx } = this 84 | const res = Mock.mock({ 85 | 'totalCompensation|1-10000.2':1, 86 | 'amountToBeRepaid|1-10000.2':1, 87 | 'recentPaymentDate':Mock.Random.datetime('yyyy-MM-dd HH:mm:ss'), 88 | 'orderList|10': [{ 89 | 'orderId':'@word(10)', 90 | 'protocalId':'@word(10)', 91 | 'type|0-1':1, 92 | 'orderAmount|1-10000.2': 1, 93 | 'orderCreateTime': Mock.Random.datetime('yyyy-MM-dd HH:mm:ss'), 94 | 'orderAmountToBeRepaid|1-10000.2':1, 95 | 'dueDate':Mock.Random.datetime('yyyy-MM-dd HH:mm:ss'), 96 | 'state|0-2':1 97 | }] 98 | }) 99 | ctx.helper.success({ctx , res }) 100 | } 101 | } 102 | 103 | module.exports = TestMockController 104 | -------------------------------------------------------------------------------- /app/extend/helper.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment') 2 | const fs = require('fs') 3 | const path = require('path') 4 | const crypto = require('crypto') 5 | const assert = require('assert') 6 | // 格式化时间 7 | exports.formatTime = time => moment(time).format('YYYY-MM-DD HH:mm:ss') 8 | 9 | exports.getToken = token =>{ 10 | const _token = token.split(' ')[1] 11 | let _res = -1 12 | if(_token !== 'login'){ 13 | const _id = new Buffer(_token.split('.')[1], 'base64') 14 | _res = JSON.parse(_id.toString()) 15 | } 16 | return _res 17 | } 18 | 19 | // 处理成功响应 20 | exports.getAgent = (ctx) => { 21 | const deviceAgent = ctx.request.header['user-agent'].toLowerCase() 22 | const isiOS = deviceAgent.indexOf('mac os x') > -1 || deviceAgent.indexOf('ios') > -1 || deviceAgent.indexOf('iphone') > -1 //ios终端 23 | const isAndroid = deviceAgent.indexOf('android') > -1 || deviceAgent.indexOf('linux') > -1 || deviceAgent.indexOf('Android') > -1 || deviceAgent.indexOf('Linux') > -1 24 | if (isAndroid) { 25 | return 'Android' 26 | } else if(isiOS) { 27 | return 'IOS' 28 | }else{ 29 | return 'PC' 30 | } 31 | } 32 | 33 | exports.success = ({ ctx , res = null, code = 0 , msg = '请求成功' , status = 200 })=> { 34 | ctx.body = { 35 | code: code, 36 | data: res, 37 | msg 38 | } 39 | ctx.status = status 40 | } 41 | 42 | exports.list = ({ ctx, res = null, current , pageSize })=> { 43 | ctx.body = { 44 | list: res.list, 45 | pagination:{ 46 | current: current, 47 | pageSize: pageSize, 48 | total:res.count 49 | }, 50 | code:0 51 | } 52 | ctx.status = 200 53 | } 54 | 55 | exports.uploadmk = (self) => { 56 | const dateMk = moment().format('YYYYMMDD') 57 | const target = path.join(self.config.baseDir, self.config.llpath.upload + dateMk) 58 | const _dir = fs.existsSync(target) 59 | if(!_dir){ 60 | fs.mkdirSync(target, 777) 61 | } 62 | return dateMk 63 | } 64 | 65 | exports.tomd5 = (str) =>{ 66 | const md5 = crypto.createHash('md5') 67 | return md5.update(str).digest('hex') 68 | } 69 | 70 | exports.bufferToJSON = (str) => { 71 | if (str && typeof str === 'object' && Buffer.isBuffer(str)){ 72 | return JSON.parse(str.toString('utf-8')) 73 | } 74 | return str 75 | } 76 | 77 | exports.todes = (data,ctx) =>{ 78 | const param={ 79 | alg: 'des-ede3', 80 | autoPad: true, 81 | key: ctx.app.config.llpath.mykey, 82 | plaintext: JSON.stringify(data), 83 | iv: null 84 | } 85 | //console.log("请求数据加密前:" + param.plaintext); 86 | const key = new Buffer(param.key, 'base64') 87 | const iv = new Buffer(param.iv ? param.iv : 0) 88 | let cipher = crypto.createCipheriv(param.alg, key, iv) 89 | cipher.setAutoPadding( param.autoPad) 90 | let ciph = cipher.update(param.plaintext, 'utf8', 'base64') 91 | ciph += cipher.final('base64') 92 | //console.log("请求数据加密后:" + ciph); 93 | return ciph 94 | } 95 | 96 | exports.dedes = (data,ctx) =>{ 97 | const param={ 98 | alg: 'des-ede3', 99 | autoPad: true, 100 | key: ctx.app.config.llpath.mykey, 101 | plaintext: data.toString('utf-8'), 102 | iv: null 103 | } 104 | //console.log("返回数据解密前:" + param.plaintext); 105 | const key = new Buffer(param.key, 'base64') 106 | const iv = new Buffer(param.iv ? param.iv : 0) 107 | const decipher = crypto.createDecipheriv(param.alg, key, iv) 108 | decipher.setAutoPadding(true) 109 | let txt = decipher.update(param.plaintext, 'base64', 'utf8') 110 | txt += decipher.final('utf8') 111 | //console.log("返回数据解密后:" + txt); 112 | return txt 113 | } 114 | -------------------------------------------------------------------------------- /app/controller/testUpload.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const Controller = require('egg').Controller 4 | const awaitWriteStream = require('await-stream-ready').write 5 | const sendToWormhole = require('stream-wormhole') 6 | const download = require('image-downloader') 7 | 8 | class testUploadController extends Controller { 9 | constructor (ctx){ 10 | super(ctx) 11 | } 12 | 13 | async create() { 14 | const { ctx, service } = this 15 | const stream = await ctx.getFileStream() 16 | const mkdir = await ctx.helper.uploadmk(this) 17 | const filename = path.basename(stream.filename) 18 | const extname = path.extname(stream.filename).toLowerCase() 19 | const attachment = new this.ctx.model.Attachment 20 | attachment.extname = extname 21 | attachment.filename = filename 22 | attachment.url = `/${mkdir}/${attachment._id.toString()}${extname}` 23 | const target = path.join(this.config.baseDir, this.config.llpath.upload + mkdir, `${attachment._id.toString()}${attachment.extname}`) 24 | const writeStream = fs.createWriteStream(target) 25 | try { 26 | await awaitWriteStream(stream.pipe(writeStream)) 27 | } catch (err) { 28 | await sendToWormhole(stream) 29 | throw err 30 | } 31 | // 调用 Service 进行业务处理 32 | const res = {} 33 | ctx.helper.success({ctx, res}) 34 | } 35 | 36 | // 通过URL添加单个图片: 如果网络地址不合法,EGG会返回500错误 37 | async url() { 38 | const { ctx, service } = this 39 | const attachment = new this.ctx.model.Attachment 40 | const { url } = ctx.request.body 41 | const filename = path.basename(url) 42 | const extname = path.extname(url).toLowerCase() 43 | const options = { 44 | url: url, 45 | dest: path.join(this.config.baseDir, this.config.llpath.upload , `${attachment._id.toString()}${extname}`) 46 | } 47 | let res 48 | try { 49 | await download.image(options) 50 | attachment.extname = extname 51 | attachment.filename = filename 52 | attachment.url = `/${attachment._id.toString()}${extname}` 53 | // 调用 Service 进行业务处理 54 | res = {} 55 | } catch (err) { 56 | throw err 57 | } 58 | ctx.helper.success({ctx, res}) 59 | } 60 | 61 | // 上传多个文件 62 | async multiple() { 63 | const { ctx, service } = this 64 | const parts = ctx.multipart() 65 | const res = {} 66 | const files = [] 67 | let part 68 | while ((part = await parts()) != null) { 69 | if (part.length) { 70 | // 如果是数组的话是 filed 71 | console.log('field: ' + part[0]) 72 | console.log('value: ' + part[1]) 73 | console.log('valueTruncated: ' + part[2]) 74 | console.log('fieldnameTruncated: ' + part[3]) 75 | } else { 76 | if (!part.filename) { 77 | // 这时是用户没有选择文件就点击了上传(part 是 file stream,但是 part.filename 为空) 78 | // 需要做出处理,例如给出错误提示消息 79 | return 80 | } 81 | // part 是上传的文件流 82 | console.log('field: ' + part.fieldname) 83 | console.log('filename: ' + part.filename) 84 | console.log('extname: ' + part.extname) 85 | console.log('encoding: ' + part.encoding) 86 | console.log('mime: ' + part.mime) 87 | const filename = part.filename.toLowerCase()// 文件名称 88 | const extname = path.extname(part.filename).toLowerCase() // 文件扩展名称 89 | const attachment = new ctx.model.Attachment 90 | attachment.extname = extname 91 | attachment.filename = filename 92 | attachment.url = `/${attachment._id.toString()}${extname}` 93 | const target = path.join(this.config.baseDir, this.config.llpath.upload , `${attachment._id.toString()}${extname}`) 94 | const writeStream = fs.createWriteStream(target) 95 | let res 96 | try { 97 | await awaitWriteStream(part.pipe(writeStream)) 98 | // 调用Service 99 | res = {} 100 | } catch (err) { 101 | await sendToWormhole(part) 102 | throw err 103 | } 104 | files.push(`${attachment._id}`) 105 | } 106 | } 107 | ctx.helper.success({ctx, res}) 108 | } 109 | 110 | } 111 | 112 | 113 | module.exports = testUploadController -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | 2 | 3 | // 控制已更新文件的自动保存。接受的值:“off”、"afterDelay”、“onFocusChange”(编辑器失去焦点)、“onWindowChange”(窗口失去焦点)。如果设置为“afterDelay”,则可在 "files.autoSaveDelay" 中配置延迟。 4 | "files.autoSave": "off", 5 | 6 | // 以像素为单位控制字号。 7 | "editor.fontSize": 12, 8 | 9 | // 控制字体系列。 10 | "editor.fontFamily": "Menlo, Monaco, 'Courier New', monospace", 11 | 12 | // 一个制表符等于的空格数。该设置在 `editor.detectIndentation` 启用时根据文件内容进行重写。 13 | "editor.tabSize": 2, 14 | 15 | // 控制编辑器中呈现空白字符的方式,可能为“无”、“边界”和“全部”。“边界”选项不会在单词之间呈现单空格。 16 | "editor.renderWhitespace": "none", 17 | 18 | // 控制光标样式,接受的值为 "block"、"block-outline"、"line"、"line-thin" 、"underline" 和 "underline-thin" 19 | "editor.cursorStyle": "line", 20 | 21 | // 用鼠标添加多个光标时使用的修改键。“ctrlCmd”映射为“Control”(Windows 和 Linux)或“Command”(OSX)。“转到定义”和“打开链接”功能的鼠标手势将会相应调整,不与多光标修改键冲突。 22 | "editor.multiCursorModifier": "alt", 23 | 24 | // 按 "Tab" 时插入空格。该设置在 `editor.detectIndentation` 启用时根据文件内容进行重写。 25 | "editor.insertSpaces": true, 26 | 27 | // 控制折行方式。可以选择: - “off” (禁用折行), - “on” (视区折行), - “wordWrapColumn”(在“editor.wordWrapColumn”处折行)或 - “bounded”(在视区与“editor.wordWrapColumn”两者的较小者处折行)。 28 | "editor.wordWrap": "off", 29 | 30 | // 配置 glob 模式以在搜索中排除文件和文件夹。例如,文件资源管理器根据此设置决定文件或文件夹的显示和隐藏。 31 | "files.exclude": { 32 | "**/.git": true, 33 | "**/.svn": true, 34 | "**/.hg": true, 35 | "**/CVS": true, 36 | "**/.DS_Store": true 37 | }, 38 | 39 | // 配置语言的文件关联(如: "*.extension": "html")。这些关联的优先级高于已安装语言的默认关联。 40 | "files.associations": {} 41 | 42 | } 43 | , 44 | { 45 | 46 | 47 | // 当其前缀匹配时插入代码段。当 "quickSuggestions" 未启用时,效果最佳。 48 | "editor.tabCompletion": false, 49 | 50 | // 控制字体系列。 51 | "editor.fontFamily": "Menlo, Monaco, 'Courier New', monospace", 52 | 53 | // 控制字体粗细。 54 | "editor.fontWeight": "normal", 55 | 56 | // 以像素为单位控制字号。 57 | "editor.fontSize": 12, 58 | 59 | // 控制行高。使用 0 通过字号计算行高。 60 | "editor.lineHeight": 0, 61 | 62 | // 以像素为单位控制字符间距。 63 | "editor.letterSpacing": 0, 64 | 65 | // 控制行号的显示。可能的值为“开”、“关”和“相对”。“相对”将显示从当前光标位置开始计数的行数。 66 | "editor.lineNumbers": "on", 67 | 68 | // 在一定数量的等宽字符后显示垂直标尺。输入多个值,显示多个标尺。若数组为空,则不绘制标尺。 69 | "editor.rulers": [], 70 | 71 | // 执行文字相关的导航或操作时将用作文字分隔符的字符 72 | "editor.wordSeparators": "`~!@#$%^&*()-=+[{]}\\|;:'\",.<>/?", 73 | 74 | // 一个制表符等于的空格数。该设置在 `editor.detectIndentation` 启用时根据文件内容进行重写。 75 | "editor.tabSize": 4, 76 | 77 | // 按 "Tab" 时插入空格。该设置在 `editor.detectIndentation` 启用时根据文件内容进行重写。 78 | "editor.insertSpaces": true, 79 | 80 | // 当打开文件时,将基于文件内容检测 "editor.tabSize" 和 "editor.insertSpaces"。 81 | "editor.detectIndentation": true, 82 | 83 | // 控制选取范围是否有圆角 84 | "editor.roundedSelection": true, 85 | 86 | // 控制编辑器是否可以滚动到最后一行之后 87 | "editor.scrollBeyondLastLine": true, 88 | 89 | // 控制编辑器是否在滚动时使用动画 90 | "editor.smoothScrolling": false, 91 | 92 | // 控制是否显示 minimap 93 | "editor.minimap.enabled": true, 94 | 95 | // 控制是否自动隐藏小地图滑块。可选值为 "always" 和 "mouseover" 96 | "editor.minimap.showSlider": "mouseover", 97 | 98 | // 呈现某行上的实际字符(与颜色块相反) 99 | "editor.minimap.renderCharacters": true, 100 | 101 | // 限制最小映射的宽度,尽量多地呈现特定数量的列 102 | "editor.minimap.maxColumn": 120, 103 | 104 | // 控制是否将编辑器的选中内容作为搜索词填入到查找组件 105 | "editor.find.seedSearchStringFromSelection": true, 106 | 107 | // 控制当编辑器中选中多个字符或多行文字时是否开启“在选定内容中查找”选项 108 | "editor.find.autoFindInSelection": false, 109 | 110 | // 控制折行方式。可以选择: - “off” (禁用折行), - “on” (视区折行), - “wordWrapColumn”(在“editor.wordWrapColumn”处折行)或 - “bounded”(在视区与“editor.wordWrapColumn”两者的较小者处折行)。 111 | "editor.wordWrap": "off", 112 | 113 | // 在 "editor.wordWrap" 为 "wordWrapColumn" 或 "bounded" 时控制编辑器列的换行。 114 | "editor.wordWrapColumn": 80, 115 | 116 | // 控制折行的缩进。可以是“none”、“same”或“indent”。 117 | "editor.wrappingIndent": "same", 118 | 119 | // 要对鼠标滚轮滚动事件的 "deltaX" 和 "deltaY" 使用的乘数 120 | "editor.mouseWheelScrollSensitivity": 1, 121 | 122 | // 用鼠标添加多个光标时使用的修改键。“ctrlCmd”映射为“Control”(Windows 和 Linux)或“Command”(OSX)。“转到定义”和“打开链接”功能的鼠标手势将会相应调整,不与多光标修改键冲突。 123 | "editor.multiCursorModifier": "alt", 124 | 125 | // 控制键入时是否应自动显示建议 126 | "editor.quickSuggestions": { 127 | "other": true, 128 | "comments": false, 129 | "strings": false 130 | }, 131 | 132 | // 控制延迟多少毫秒后将显示快速建议 133 | "editor.quickSuggestionsDelay": 10, 134 | 135 | // 启用在输入时显示含有参数文档和类型信息的小面板 136 | "editor.parameterHints": true, 137 | 138 | // 控制编辑器是否应该在左括号后自动插入右括号 139 | "editor.autoClosingBrackets": true, 140 | 141 | // 控制编辑器是否应在键入后自动设置行的格式 142 | "editor.formatOnType": false, 143 | 144 | // 控制编辑器是否应自动设置粘贴内容的格式。格式化程序必须可用并且能设置文档中某一范围的格式。 145 | "editor.formatOnPaste": false, 146 | 147 | // 控制编辑器是否在用户键入、粘贴或移动行时自动调整缩进。语言的缩进规则必须可用。 148 | "editor.autoIndent": true, 149 | 150 | // 控制键入触发器字符时是否应自动显示建议 151 | "editor.suggestOnTriggerCharacters": true, 152 | 153 | // 控制按“Enter”键是否像按“Tab”键一样接受建议。这能帮助避免“插入新行”和“接受建议”之间的歧义。值为“smart”时表示,仅当文字改变时,按“Enter”键才能接受建议 154 | "editor.acceptSuggestionOnEnter": "on", 155 | 156 | // 控制是否应在遇到提交字符时接受建议。例如,在 JavaScript 中,分号(";")可以为提交字符,可接受建议并键入该字符。 157 | "editor.acceptSuggestionOnCommitCharacter": true, 158 | 159 | // 控制是否将代码段与其他建议一起显示以及它们的排序方式。 160 | "editor.snippetSuggestions": "inline", 161 | 162 | // 控制没有选择内容的复制是否复制当前行。 163 | "editor.emptySelectionClipboard": true, 164 | 165 | // 控制是否应根据文档中的字数计算完成。 166 | "editor.wordBasedSuggestions": true, 167 | 168 | // 建议小组件的字号 169 | "editor.suggestFontSize": 0, 170 | 171 | // 建议小组件的行高 172 | "editor.suggestLineHeight": 0, 173 | 174 | // 控制编辑器是否应突出显示选项的近似匹配 175 | "editor.selectionHighlight": true, 176 | 177 | // 控制编辑器是否应该突出显示语义符号次数 178 | "editor.occurrencesHighlight": true, 179 | 180 | // 控制可在概述标尺同一位置显示的效果数量 181 | "editor.overviewRulerLanes": 3, 182 | 183 | // 控制概述标尺周围是否要绘制边框。 184 | "editor.overviewRulerBorder": true, 185 | 186 | // 控制光标动画样式,可能的值为 "blink"、"smooth"、"phase"、"expand" 和 "solid" 187 | "editor.cursorBlinking": "blink", 188 | 189 | // 通过使用鼠标滚轮同时按住 Ctrl 可缩放编辑器的字体 190 | "editor.mouseWheelZoom": false, 191 | 192 | // 控制光标样式,接受的值为 "block"、"block-outline"、"line"、"line-thin" 、"underline" 和 "underline-thin" 193 | "editor.cursorStyle": "line", 194 | 195 | // 启用字体连字 196 | "editor.fontLigatures": false, 197 | 198 | // 控制光标是否应隐藏在概述标尺中。 199 | "editor.hideCursorInOverviewRuler": false, 200 | 201 | // 控制编辑器中呈现空白字符的方式,可能为“无”、“边界”和“全部”。“边界”选项不会在单词之间呈现单空格。 202 | "editor.renderWhitespace": "none", 203 | 204 | // 控制编辑器是否应呈现控制字符 205 | "editor.renderControlCharacters": false, 206 | 207 | // 控制编辑器是否应呈现缩进参考线 208 | "editor.renderIndentGuides": true, 209 | 210 | // 控制编辑器应如何呈现当前行突出显示,可能为“无”、“装订线”、“线”和“全部”。 211 | "editor.renderLineHighlight": "line", 212 | 213 | // 控制编辑器是否显示代码滤镜 214 | "editor.codeLens": true, 215 | 216 | // 控制编辑器是否启用代码折叠功能 217 | "editor.folding": true, 218 | 219 | // 控制是否自动隐藏导航线上的折叠控件。 220 | "editor.showFoldingControls": "mouseover", 221 | 222 | // 当选择其中一项时,将突出显示匹配的括号。 223 | "editor.matchBrackets": true, 224 | 225 | // 控制编辑器是否应呈现垂直字形边距。字形边距最常用于调试。 226 | "editor.glyphMargin": true, 227 | 228 | // 在制表位后插入和删除空格 229 | "editor.useTabStops": true, 230 | 231 | // 删除尾随自动插入的空格 232 | "editor.trimAutoWhitespace": true, 233 | 234 | // 即使在双击编辑器内容或按 Esc 键时,也要保持速览编辑器的打开状态。 235 | "editor.stablePeek": false, 236 | 237 | // 控制编辑器是否应该允许通过拖放移动所选项。 238 | "editor.dragAndDrop": true, 239 | 240 | // 控制编辑器是否应运行在对屏幕阅读器进行优化的模式。 241 | "editor.accessibilitySupport": "auto", 242 | 243 | // 控制编辑器是否应检测链接并使它们可被点击 244 | "editor.links": true, 245 | 246 | // 控制编辑器是否显示内联颜色修饰器和颜色选取器。 247 | "editor.colorDecorators": true, 248 | 249 | // 启用代码操作小灯泡提示 250 | "editor.lightbulb.enabled": true, 251 | 252 | // 控制 Diff 编辑器以并排或内联形式显示差异 253 | "diffEditor.renderSideBySide": true, 254 | 255 | // 控制差异编辑器是否将对前导空格或尾随空格的更改显示为差异 256 | "diffEditor.ignoreTrimWhitespace": true, 257 | 258 | // 控制差异编辑器是否为已添加/删除的更改显示 +/- 指示符号 259 | "diffEditor.renderIndicators": true, 260 | 261 | // 保存时设置文件的格式。格式化程序必须可用,不能自动保存文件,并且不能关闭编辑器。 262 | "editor.formatOnSave": false, 263 | 264 | // 覆盖当前所选颜色主题中的编辑器颜色和字体样式。 265 | "editor.tokenColorCustomizations": {}, 266 | 267 | 268 | // 在未能恢复上一会话信息的情况下,控制启动时显示的编辑器。选择 "none" 表示启动时不打开编辑器,"welcomePage" 表示打开欢迎页面(默认),"newUntitledFile" 表示打开新的无标题文档(仅打开一个空工作区)。 269 | "workbench.startupEditor": "welcomePage", 270 | 271 | // 控制打开的编辑器是否显示在选项卡中。 272 | "workbench.editor.showTabs": true, 273 | 274 | // 控制编辑器标签的格式。修改这项设置会让文件的路径更容易理解: 275 | // - short: "parent" 276 | // - medium: "workspace/src/parent" 277 | // - long: "/home/user/workspace/src/parent" 278 | // - default: 当与另一选项卡标题相同时为 ".../parent"。选项卡被禁用时则为相对工作区路径 279 | "workbench.editor.labelFormat": "default", 280 | 281 | // 控制编辑器的选项卡关闭按钮的位置,或当设置为 "off" 时禁用关闭它们。 282 | "workbench.editor.tabCloseButton": "right", 283 | 284 | // 控制打开的编辑器是否随图标一起显示。这还需启用图标主题。 285 | "workbench.editor.showIcons": true, 286 | 287 | // 控制是否将打开的编辑器显示为预览。预览编辑器将会重用至其被保留(例如,通过双击或编辑),且其字体样式将为斜体。 288 | "workbench.editor.enablePreview": true, 289 | 290 | // 控制 Quick Open 中打开的编辑器是否显示为预览。预览编辑器可以重新使用,直到将其保留(例如,通过双击或编辑)。 291 | "workbench.editor.enablePreviewFromQuickOpen": true, 292 | 293 | // 控制打开编辑器的位置。选择“左侧”或“右侧”以在当前活动位置的左侧或右侧打开编辑器。选择“第一个”或“最后一个”以从当前活动位置独立打开编辑器。 294 | "workbench.editor.openPositioning": "right", 295 | 296 | // 控制打开时编辑器是否显示在任何可见组中。如果禁用,编辑器会优先在当前活动编辑器组中打开。如果启用,会显示已打开的编辑器而不是在当前活动编辑器组中再次打开。请注意,有些情况下会忽略此设置,例如强制编辑器在特定组中或在当前活动组的边侧打开时。 297 | "workbench.editor.revealIfOpen": false, 298 | 299 | // 控制命令面板中保留最近使用命令的数量。设置为 0 时禁用命令历史功能。 300 | "workbench.commandPalette.history": 50, 301 | 302 | // 控制是否在再次打开命令面板时恢复上一次的输入内容。 303 | "workbench.commandPalette.preserveInput": false, 304 | 305 | // 控制 Quick Open 是否应在失去焦点时自动关闭。 306 | "workbench.quickOpen.closeOnFocusLost": true, 307 | 308 | // 控制打开设置时是否打开显示所有默认设置的编辑器。 309 | "workbench.settings.openDefaultSettings": true, 310 | 311 | // 控制边栏的位置。它可显示在工作台的左侧或右侧。 312 | "workbench.sideBar.location": "left", 313 | 314 | // 控制面板的位置。它可显示在工作台的底部或右侧。 315 | "workbench.panel.location": "bottom", 316 | 317 | // 控制工作台底部状态栏的可见性。 318 | "workbench.statusBar.visible": true, 319 | 320 | // 控制工作台中活动栏的可见性。 321 | "workbench.activityBar.visible": true, 322 | 323 | // 控制文件被其他某些进程删除或重命名时是否应该自动关闭显示文件的编辑器。禁用此项会保持编辑器作为此类事件的脏文件打开。请注意,从应用程序内部进行删除操作会始终关闭编辑器,并且脏文件始终不会关闭以保存数据。 324 | "workbench.editor.closeOnFileDelete": true, 325 | 326 | // 控制工作台中字体的渲染方式 327 | // - default: 次像素平滑字体。将在大多数非 retina 显示器上显示最清晰的文字 328 | // - antialiased: 进行像素而不是次像素级别的字体平滑。可能会导致字体整体显示得更细 329 | // - none: 禁用字体平滑。将显示边缘粗糙、有锯齿的文字 330 | "workbench.fontAliasing": "default", 331 | 332 | // 使用三指横扫在打开的文件之间导航 333 | "workbench.editor.swipeToNavigate": false, 334 | 335 | // 启用后,当没有打开编辑器时将显示水印提示。 336 | "workbench.tips.enabled": true, 337 | 338 | // 指定工作台中使用的颜色主题。 339 | "workbench.colorTheme": "Default Dark+", 340 | 341 | // 指定在工作台中使用的图标主题,或指定 "null" 以不显示任何文件图标。 342 | "workbench.iconTheme": "vs-seti", 343 | 344 | // 覆盖当前所选颜色主题的颜色。 345 | "workbench.colorCustomizations": {}, 346 | 347 | 348 | // 控制是否应在新窗口中打开文件。 349 | // - default: 文件将在该文件的文件夹打开的窗口中打开,或在上一个活动窗口中打开,除非该文件通过平台或从查找程序(仅限 macOS)打开 350 | // - on: 文件将在新窗口中打开 351 | // - off: 文件将在该文件的文件夹打开的窗口中打开,或在上一个活动窗口中打开 352 | // 注意,可能仍会存在忽略此设置的情况(例如当使用 -new-window 或 -reuse-window 命令行选项时)。 353 | "window.openFilesInNewWindow": "off", 354 | 355 | // 控制文件夹应在新窗口中打开还是替换上一活动窗口。 356 | // - default: 文件夹将在新窗口中打开,除非文件是从应用程序内选取的(例如通过“文件”菜单) 357 | // - on: 文件夹将在新窗口中打开 358 | // - off: 文件夹将替换上一活动窗口 359 | // 注意,可能仍会存在忽略此设置的情况(例如当使用 -new-window 或 -reuse-window 命令行选项时)。 360 | "window.openFoldersInNewWindow": "default", 361 | 362 | // 控制重启后重新打开窗口的方式。选择 "none" 则永远在启动时打开一个空工作区,"one" 则重新打开最后使用的窗口,"folders" 则重新打开所有含有文件夹的窗口,"all" 则重新打开上次会话的所有窗口。 363 | "window.restoreWindows": "one", 364 | 365 | // 如果窗口已退出全屏模式,控制其是否应还原为全屏模式。 366 | "window.restoreFullscreen": false, 367 | 368 | // 调整窗口的缩放级别。原始大小是 0,每次递增(例如 1)或递减(例如 -1)表示放大或缩小 20%。也可以输入小数以便以更精细的粒度调整缩放级别。 369 | "window.zoomLevel": 0, 370 | 371 | // 根据活动编辑器控制窗口标题。变量基于上下文进行替换: 372 | // ${activeEditorShort}: 文件名 (如 myFile.txt) 373 | // ${activeEditorMedium}: 相对于工作区文件夹的文件路径 (如 myFolder/myFile.txt) 374 | // ${activeEditorLong}: 文件的完整路径 (如 /Users/Development/myProject/myFolder/myFile.txt) 375 | // ${folderName}: 文件所在工作区文件夹名称 (如 myFolder) 376 | // ${folderPath}: 文件所在工作区文件夹路径 (如 /Users/Development/myFolder) 377 | // ${rootName}: 工作区名称 (如 myFolder 或 myWorkspace) 378 | // ${rootPath}: 工作区路径 (如 /Users/Development/myWorkspace) 379 | // ${appName}: 如 VS Code 380 | // ${dirty}: 活动编辑器有更新时显示的更新指示器 381 | // ${separator}: 仅在被有值变量包围时显示的分隔符 (" - ") 382 | "window.title": "${activeEditorShort}${separator}${rootName}", 383 | 384 | // 控制在已有窗口时新打开窗口的尺寸。默认情况下,新窗口将以小尺寸在屏幕的中央打开。当设置为“inherit”时,新窗口将继承上一活动窗口的尺寸,设置为“maximized”时窗口将被最大化,设置为“fullscreen”时则变为全屏。请注意,此设置对第一个打开的窗口无效。第一个窗口总是会恢复关闭前的大小和位置。 385 | "window.newWindowDimensions": "default", 386 | 387 | // 控制关闭最后一个编辑器是否关闭整个窗口。此设置仅适用于不显示文件夹的窗口。 388 | "window.closeWhenEmpty": false, 389 | 390 | // 调整窗口标题栏的外观。更改需要在完全重启后才能应用。 391 | "window.titleBarStyle": "custom", 392 | 393 | // 394 | // 启用macOS Sierra窗口选项卡。请注意,更改需要完全重新启动程序才能生效。如果配置此选项,本机选项卡将禁用自定义标题栏样式。 395 | "window.nativeTabs": false, 396 | 397 | 398 | // 控制打开 Zen Mode 是否也会将工作台置于全屏模式。 399 | "zenMode.fullScreen": true, 400 | 401 | // 控制打开 Zen 模式是否也会隐藏工作台选项卡。 402 | "zenMode.hideTabs": true, 403 | 404 | // 控制打开 Zen 模式是否也会隐藏工作台底部的状态栏。 405 | "zenMode.hideStatusBar": true, 406 | 407 | // 控制打开 Zen 模式是否也会隐藏工作台左侧的活动栏。 408 | "zenMode.hideActivityBar": true, 409 | 410 | // 控制如果某窗口已退出 zen 模式,是否应还原到 zen 模式。 411 | "zenMode.restore": false, 412 | 413 | 414 | // 配置 glob 模式以在搜索中排除文件和文件夹。例如,文件资源管理器根据此设置决定文件或文件夹的显示和隐藏。 415 | "files.exclude": { 416 | "**/.git": true, 417 | "**/.svn": true, 418 | "**/.hg": true, 419 | "**/CVS": true, 420 | "**/.DS_Store": true 421 | }, 422 | 423 | // 配置语言的文件关联(如: "*.extension": "html")。这些关联的优先级高于已安装语言的默认关联。 424 | "files.associations": {}, 425 | 426 | // 读取和编写文件时使用的默认字符集编码。也可以根据语言配置此设置。 427 | "files.encoding": "utf8", 428 | 429 | // 如果启用,会在打开文件时尝试猜测字符集编码。也可以根据语言配置此设置。 430 | "files.autoGuessEncoding": false, 431 | 432 | // 默认行尾字符。使用 \n 表示 LF,\r\n 表示 CRLF。 433 | "files.eol": "\n", 434 | 435 | // 启用后,将在保存文件时剪裁尾随空格。 436 | "files.trimTrailingWhitespace": false, 437 | 438 | // 启用后,保存文件时在文件末尾插入一个最终新行。 439 | "files.insertFinalNewline": false, 440 | 441 | // 启用后,保存文件时将删除在最终新行后的所有新行。 442 | "files.trimFinalNewlines": false, 443 | 444 | // 控制已更新文件的自动保存。接受的值:“off”、"afterDelay”、“onFocusChange”(编辑器失去焦点)、“onWindowChange”(窗口失去焦点)。如果设置为“afterDelay”,则可在 "files.autoSaveDelay" 中配置延迟。 445 | "files.autoSave": "off", 446 | 447 | // 控制在多少毫秒后自动保存更改过的文件。仅在“files.autoSave”设置为“afterDelay”时适用。 448 | "files.autoSaveDelay": 1000, 449 | 450 | // 配置文件路径的 glob 模式以从文件监视排除。模式必须在绝对路径上匹配(例如 ** 前缀或完整路径需正确匹配)。更改此设置需要重启。如果在启动时遇到 Code 消耗大量 CPU 时间,则可以排除大型文件夹以减少初始加载。 451 | "files.watcherExclude": { 452 | "**/.git/objects/**": true, 453 | "**/.git/subtree-cache/**": true, 454 | "**/node_modules/**": true 455 | }, 456 | 457 | // 控制是否在会话间记住未保存的文件,以允许在退出编辑器时跳过保存提示。 458 | "files.hotExit": "onExit", 459 | 460 | // 使用新的试验文件观察程序。 461 | "files.useExperimentalFileWatcher": false, 462 | 463 | // 分配给新文件的默认语言模式。 464 | "files.defaultLanguage": "", 465 | 466 | 467 | // 在“打开的编辑器”窗格中显示的编辑器数量。将其设置为 0 可隐藏窗格。 468 | "explorer.openEditors.visible": 9, 469 | 470 | // 控制打开的编辑器部分的高度是否应动态适应元素数量。 471 | "explorer.openEditors.dynamicHeight": true, 472 | 473 | // 控制资源管理器是否应在打开文件时自动显示并选择它们。 474 | "explorer.autoReveal": true, 475 | 476 | // 控制资源管理器是否应该允许通过拖放移动文件和文件夹。 477 | "explorer.enableDragAndDrop": true, 478 | 479 | // 控制在资源管理器内拖放移动文件或文件夹时是否进行确认。 480 | "explorer.confirmDragAndDrop": true, 481 | 482 | // 控制资源管理器是否应在删除文件到回收站时进行确认。 483 | "explorer.confirmDelete": true, 484 | 485 | // 控制资源管理器文件和文件夹的排列顺序。除了默认排列顺序,你也可以设置为 "mixed" (文件和文件夹一起排序)、"type" (按文件类型排)、"modified" (按最后修改日期排)或是 "filesFirst" (将文件排在文件夹前)。 486 | "explorer.sortOrder": "default", 487 | 488 | // 控制文件修饰是否用颜色。 489 | "explorer.decorations.colors": true, 490 | 491 | // 控制文件修饰是否用徽章。 492 | "explorer.decorations.badges": true, 493 | 494 | 495 | // 配置 glob 模式以在搜索中排除文件和文件夹。从 files.exclude 设置中继承所有 glob 模式。 496 | "search.exclude": { 497 | "**/node_modules": true, 498 | "**/bower_components": true 499 | }, 500 | 501 | // 控制是否在文本和文件搜索中使用 ripgrep 502 | "search.useRipgrep": true, 503 | 504 | // 控制在新工作区中搜索文本时是否默认使用 .gitignore 和 .ignore 文件。 505 | "search.useIgnoreFilesByDefault": false, 506 | 507 | // 控制搜索文件时是否使用 .gitignore 和 .ignore 文件。 508 | "search.useIgnoreFiles": false, 509 | 510 | // 配置为在 Quick Open 文件结果中包括全局符号搜索的结果。 511 | "search.quickOpen.includeSymbols": false, 512 | 513 | // 控制是否在搜索中跟踪符号链接。 514 | "search.followSymlinks": true, 515 | 516 | 517 | // 要使用的代理设置。如果尚未设置,则将从 http_proxy 和 https_proxy 环境变量获取 518 | "http.proxy": "", 519 | 520 | // 是否应根据提供的 CA 列表验证代理服务器证书。 521 | "http.proxyStrictSSL": true, 522 | 523 | // 要作为每个网络请求的 "Proxy-Authorization" 标头发送的值。 524 | "http.proxyAuthorization": null, 525 | 526 | 527 | // 配置是否从更新通道接收自动更新。更改后需要重启。 528 | "update.channel": "default", 529 | 530 | 531 | // 控制按键的调度逻辑以使用“keydown.code”(推荐) 或“keydown.keyCode”。 532 | "keyboard.dispatch": "code", 533 | 534 | 535 | // 启用/禁用默认 HTML 格式化程序 536 | "html.format.enable": true, 537 | 538 | // 每行最大字符数(0 = 禁用)。 539 | "html.format.wrapLineLength": 120, 540 | 541 | // 以逗号分隔的标记列表不应重设格式。"null" 默认为所有列于 https://www.w3.org/TR/html5/dom.html#phrasing-content 的标记。 542 | "html.format.unformatted": "wbr", 543 | 544 | // 以逗号分隔的标记列表,不应在其中重新设置内容的格式。"null" 默认为 "pre" 标记。 545 | "html.format.contentUnformatted": "pre,code,textarea", 546 | 547 | // 缩进 和 部分。 548 | "html.format.indentInnerHtml": false, 549 | 550 | // 是否要保留元素前面的现有换行符。仅适用于元素前,不适用于标记内或文本。 551 | "html.format.preserveNewLines": true, 552 | 553 | // 要保留在一个区块中的换行符的最大数量。对于无限制使用 "null"。 554 | "html.format.maxPreserveNewLines": null, 555 | 556 | // 格式和缩进 {{#foo}} 和 {{/foo}}。 557 | "html.format.indentHandlebars": false, 558 | 559 | // 以新行结束。 560 | "html.format.endWithNewline": false, 561 | 562 | // 标记列表,以逗号分隔,其前应有额外新行。"null" 默认为“标头、正文、/html”。 563 | "html.format.extraLiners": "head, body, /html", 564 | 565 | // 对属性进行换行。 566 | "html.format.wrapAttributes": "auto", 567 | 568 | // 配置内置 HTML 语言支持是否建议 Angular V1 标记和属性。 569 | "html.suggest.angular1": true, 570 | 571 | // 配置内置 HTML 语言支持是否建议 Ionic 标记、属性和值。 572 | "html.suggest.ionic": true, 573 | 574 | // 配置内置 HTML 语言支持是否建议 HTML5 标记、属性和值。 575 | "html.suggest.html5": true, 576 | 577 | // 配置内置的 HTML 语言支持是否对嵌入的脚本进行验证。 578 | "html.validate.scripts": true, 579 | 580 | // 配置内置的 HTML 语言支持是否对嵌入的样式进行验证。 581 | "html.validate.styles": true, 582 | 583 | // 启用/禁用 HTML 标记的自动关闭。 584 | "html.autoClosingTags": true, 585 | 586 | // 跟踪 VS Code 与 HTML 语言服务器之间的通信。 587 | "html.trace.server": "off", 588 | 589 | 590 | // 将当前项目中的 JSON 文件与架构关联起来 591 | "json.schemas": [], 592 | 593 | // 启用/禁用默认 JSON 格式化程序(需要重启) 594 | "json.format.enable": true, 595 | 596 | // 跟踪 VS Code 与 JSON 语言服务器之间的通信。 597 | "json.trace.server": "off", 598 | 599 | 600 | // 要在 Markdown 预览中使用的 CSS 样式表的 URL 或本地路径列表。相对路径被解释为相对于资源管理器中打开的文件夹。如果没有任何打开的文件夹,则会被解释为相对于 Markdown 文件的位置。所有的 "\" 需写为 "\\"。 601 | "markdown.styles": [], 602 | 603 | // 设置如何在 Markdown 预览中呈现 YAML 扉页。“隐藏”会删除扉页。否则,扉页则被视为 Markdown 内容。 604 | "markdown.previewFrontMatter": "hide", 605 | 606 | // 设置换行符如何在 markdown 预览中呈现。将其设置为 "true" 会为每一个新行创建一个
。 607 | "markdown.preview.breaks": false, 608 | 609 | // 在 Markdown 预览中启用或禁用将类似 URL 的文本转换为链接。 610 | "markdown.preview.linkify": true, 611 | 612 | // 控制 Markdown 预览中使用的字体系列。 613 | "markdown.preview.fontFamily": "-apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'HelveticaNeue-Light', 'Ubuntu', 'Droid Sans', sans-serif", 614 | 615 | // 控制 Markdown 预览中使用的字号(以像素为单位)。 616 | "markdown.preview.fontSize": 14, 617 | 618 | // 控制 Markdown 预览中使用的行高。此数值与字号相关。 619 | "markdown.preview.lineHeight": 1.6, 620 | 621 | // 滚动 Markdown 预览以显示编辑器中当前所选的行。 622 | "markdown.preview.scrollPreviewWithEditorSelection": true, 623 | 624 | // 在 Markdown 预览中标记当前的编辑器选定内容。 625 | "markdown.preview.markEditorSelection": true, 626 | 627 | // 当 Markdown 预览滚动时,更新编辑器的视图。 628 | "markdown.preview.scrollEditorWithPreview": true, 629 | 630 | // 在 Markdown 预览中双击切换到编辑器。 631 | "markdown.preview.doubleClickToSwitchToEditor": true, 632 | 633 | // 对 Markdown 扩展启用调试日志记录。 634 | "markdown.trace": "off", 635 | 636 | 637 | // 如果已启用内置 PHP 语言建议,则进行配置。此支持建议 PHP 全局变量和变量。 638 | "php.suggest.basic": true, 639 | 640 | // 启用/禁用内置的 PHP 验证。 641 | "php.validate.enable": true, 642 | 643 | // 指向 PHP 可执行文件。 644 | "php.validate.executablePath": null, 645 | 646 | // 不管 linter 是在 save 还是在 type 上运行。 647 | "php.validate.run": "onSave", 648 | 649 | 650 | // 指定包含要使用的 tsserver 和 lib*.d.ts 文件的文件夹路径。 651 | "typescript.tsdk": null, 652 | 653 | // 禁用自动获取类型。需要 TypeScript >= 2.0.6。 654 | "typescript.disableAutomaticTypeAcquisition": false, 655 | 656 | // 指定用于自动获取类型的 NPM 可执行文件的路径。要求 TypeScript >= 2.3.4。 657 | "typescript.npm": null, 658 | 659 | // 检查是否安装了 NPM 以自动获取类型。 660 | "typescript.check.npmIsInstalled": true, 661 | 662 | // 启用/禁用在 JavaScript 文件中引用 CodeLens。 663 | "javascript.referencesCodeLens.enabled": false, 664 | 665 | // 启用/禁用在 TypeScript 文件中引用 CodeLens。要求 TypeScript >= 2.0.6。 666 | "typescript.referencesCodeLens.enabled": false, 667 | 668 | // 启用/禁用实现 CodeLens。要求 TypeScript >= 2.2.0。 669 | "typescript.implementationsCodeLens.enabled": false, 670 | 671 | // 将 TS 服务器的日志保存到一个文件。此日志可用于诊断 TS 服务器问题。日志可能包含你的项目中的文件路径、源代码和其他可能敏感的信息。 672 | "typescript.tsserver.log": "off", 673 | 674 | // 对发送到 TS 服务器的消息启用跟踪。此跟踪信息可用于诊断 TS 服务器问题。 跟踪信息可能包含你的项目中的文件路径、源代码和其他可能敏感的信息。 675 | "typescript.tsserver.trace": "off", 676 | 677 | // 完成函数的参数签名。 678 | "typescript.useCodeSnippetsOnMethodSuggest": false, 679 | 680 | // 启用/禁用 TypeScript 验证。 681 | "typescript.validate.enable": true, 682 | 683 | // 启用/禁用默认 TypeScript 格式化程序。 684 | "typescript.format.enable": true, 685 | 686 | // 定义逗号分隔符后面的空格处理。 687 | "typescript.format.insertSpaceAfterCommaDelimiter": true, 688 | 689 | // 定义构造器关键字后的空格处理。要求 TypeScript >= 2.3.0。 690 | "typescript.format.insertSpaceAfterConstructor": false, 691 | 692 | // 在 For 语句中,定义分号后面的空格处理。 693 | "typescript.format.insertSpaceAfterSemicolonInForStatements": true, 694 | 695 | // 定义二进制运算符后面的空格处理 696 | "typescript.format.insertSpaceBeforeAndAfterBinaryOperators": true, 697 | 698 | // 定义控制流语句中关键字后面的空格处理。 699 | "typescript.format.insertSpaceAfterKeywordsInControlFlowStatements": true, 700 | 701 | // 定义匿名函数的函数关键字后面的空格处理。 702 | "typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": true, 703 | 704 | // 在函数参数括号前定义空格处理。需要 TypeScript >= 2.1.5。 705 | "typescript.format.insertSpaceBeforeFunctionParenthesis": false, 706 | 707 | // 定义非空圆括号的左括号后面和右括号前面的空格处理。 708 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, 709 | 710 | // 定义非空方括号的左括号后面和右括号前面的空格处理。 711 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, 712 | 713 | // 定义非空括号的左括号后面和右括号前面的空格处理。要求 TypeScript >= 2.3.0。 714 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, 715 | 716 | // 定义模板字符串的左括号后面和右括号前面的空格处理。要求 TypeScript >= 2.0.6。 717 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, 718 | 719 | // 定义 JSX 表达式左括号后面和右括号前面的空格处理。要求 TypeScript >= 2.0.6。 720 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, 721 | 722 | // 定义 TypeScript 中类型断言后的空格处理。要求 TypeScript >= 2.4。 723 | "typescript.format.insertSpaceAfterTypeAssertion": false, 724 | 725 | // 定义函数的左大括号是否放置在新的一行。 726 | "typescript.format.placeOpenBraceOnNewLineForFunctions": false, 727 | 728 | // 定义控制块的左括号是否放置在新的一行。 729 | "typescript.format.placeOpenBraceOnNewLineForControlBlocks": false, 730 | 731 | // 启用/禁用 JavaScript 验证。 732 | "javascript.validate.enable": true, 733 | 734 | // 启用/禁用 JavaScript 格式化程序。 735 | "javascript.format.enable": true, 736 | 737 | // 定义逗号分隔符后面的空格处理。 738 | "javascript.format.insertSpaceAfterCommaDelimiter": true, 739 | 740 | // 定义构造器关键字后的空格处理。要求 TypeScript >= 2.3.0。 741 | "javascript.format.insertSpaceAfterConstructor": false, 742 | 743 | // 在 For 语句中,定义分号后面的空格处理。 744 | "javascript.format.insertSpaceAfterSemicolonInForStatements": true, 745 | 746 | // 定义二进制运算符后面的空格处理 747 | "javascript.format.insertSpaceBeforeAndAfterBinaryOperators": true, 748 | 749 | // 定义控制流语句中关键字后面的空格处理。 750 | "javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": true, 751 | 752 | // 定义匿名函数的函数关键字后面的空格处理。 753 | "javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": true, 754 | 755 | // 在函数参数括号前定义空格处理。需要 TypeScript >= 2.1.5。 756 | "javascript.format.insertSpaceBeforeFunctionParenthesis": false, 757 | 758 | // 定义非空圆括号的左括号后面和右括号前面的空格处理。 759 | "javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, 760 | 761 | // 定义非空方括号的左括号后面和右括号前面的空格处理。 762 | "javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, 763 | 764 | // 定义非空括号的左括号后面和右括号前面的空格处理。要求 TypeScript >= 2.3.0。 765 | "javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, 766 | 767 | // 定义模板字符串的左括号后面和右括号前面的空格处理。要求 TypeScript >= 2.0.6。 768 | "javascript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, 769 | 770 | // 定义 JSX 表达式左括号后面和右括号前面的空格处理。要求 TypeScript >= 2.0.6。 771 | "javascript.format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, 772 | 773 | // 定义函数的左大括号是否放置在新的一行。 774 | "javascript.format.placeOpenBraceOnNewLineForFunctions": false, 775 | 776 | // 定义控制块的左括号是否放置在新的一行。 777 | "javascript.format.placeOpenBraceOnNewLineForControlBlocks": false, 778 | 779 | // 启用/禁用自动 JSDoc 注释 780 | "jsDocCompletion.enabled": true, 781 | 782 | // 启用/禁用 JavaScript 文件的语义检查。现有的 jsconfig.json 或 783 | // tsconfig.json 文件会覆盖此设置。要求 TypeScript >=2.3.1。 784 | "javascript.implicitProjectConfig.checkJs": false, 785 | 786 | // 对不属于任何工程的 JavaScript 文件启用或禁用 "experimentalDecorators" 设置。现有的 jsconfig.json 或 787 | // tsconfig.json 文件会覆盖此设置。要求 TypeScript >=2.3.1。 788 | "javascript.implicitProjectConfig.experimentalDecorators": false, 789 | 790 | // 启用/禁用在 JavaScript 建议列表中包含文件中的唯一名称。 791 | "javascript.nameSuggestions": true, 792 | 793 | // 控制 tsc 任务的自动检测。"off" 关闭此功能。"build" 仅创建单次运行编译任务。"watch" 仅创建编译及监视任务。"on" 创建构建及监视任务。默认值为 "on"。 794 | "typescript.tsc.autoDetect": "on", 795 | 796 | // 当输入导入路径时启用或禁用快速建议。 797 | "typescript.quickSuggestionsForPaths": true, 798 | 799 | // 启用或禁用自动导入建议。要求 TypeScript >= 2.6.1 800 | "typescript.autoImportSuggestions.enabled": true, 801 | 802 | // 设置报告 TypeScript 错误时使用的区域设置。要求 TypeScript >= 2.6.0。默认 ("null") 将使用 VS Code 的区域设置。 803 | "typescript.locale": null, 804 | 805 | 806 | // 允许在任何文件中设置断点 807 | "debug.allowBreakpointsEverywhere": false, 808 | 809 | // 调试会话结束时自动打开资源管理器视图 810 | "debug.openExplorerOnEnd": false, 811 | 812 | // 调试时,在编辑器中显示变量值内联 813 | "debug.inlineValues": false, 814 | 815 | // 控制是否应该隐藏浮点调试操作栏 816 | "debug.hideActionBar": false, 817 | 818 | // 内部调试控制台的控制行为。 819 | "debug.internalConsoleOptions": "openOnFirstSessionStart", 820 | 821 | // 全局的调试启动配置。应用作跨工作区共享的 "launch.json" 的替代。 822 | "launch": {}, 823 | 824 | 825 | // 启用或禁用所有验证 826 | "css.validate": true, 827 | 828 | // 使用供应商特定前缀时,确保同时包括所有其他供应商特定属性 829 | "css.lint.compatibleVendorPrefixes": "ignore", 830 | 831 | // 使用供应商特定前缀时,还应包括标准属性 832 | "css.lint.vendorPrefix": "warning", 833 | 834 | // 不要使用重复的样式定义 835 | "css.lint.duplicateProperties": "ignore", 836 | 837 | // 不要使用空规则集 838 | "css.lint.emptyRules": "warning", 839 | 840 | // Import 语句不会并行加载 841 | "css.lint.importStatement": "ignore", 842 | 843 | // 使用边距或边框时,不要使用宽度或高度 844 | "css.lint.boxModel": "ignore", 845 | 846 | // 已知通配选择符 (*) 慢 847 | "css.lint.universalSelector": "ignore", 848 | 849 | // 零不需要单位 850 | "css.lint.zeroUnits": "ignore", 851 | 852 | // @font-face 规则必须定义 "src" 和 "font-family" 属性 853 | "css.lint.fontFaceProperties": "warning", 854 | 855 | // 十六进制颜色必须由三个或六个十六进制数字组成 856 | "css.lint.hexColorLength": "error", 857 | 858 | // 参数数量无效 859 | "css.lint.argumentsInColorFunction": "error", 860 | 861 | // 未知的属性。 862 | "css.lint.unknownProperties": "warning", 863 | 864 | // 仅当支持 IE7 及更低版本时,才需要 IE hack 865 | "css.lint.ieHack": "ignore", 866 | 867 | // 未知的供应商特定属性。 868 | "css.lint.unknownVendorSpecificProperties": "ignore", 869 | 870 | // 因显示而忽略属性。例如,使用 "display: inline"时,宽度、高度、上边距、下边距和 float 属性将不起作用 871 | "css.lint.propertyIgnoredDueToDisplay": "warning", 872 | 873 | // 避免使用 !important。它表明整个 CSS 的特异性已经失去控制且需要重构。 874 | "css.lint.important": "ignore", 875 | 876 | // 避免使用“float”。浮动会带来脆弱的 CSS,如果布局的某一方面更改,将很容易破坏 CSS。 877 | "css.lint.float": "ignore", 878 | 879 | // 选择器不应包含 ID,因为这些规则与 HTML 的耦合过于紧密。 880 | "css.lint.idSelector": "ignore", 881 | 882 | // 跟踪 VS Code 与 CSS 语言服务器之间的通信。 883 | "css.trace.server": "off", 884 | 885 | 886 | // 启用或禁用所有验证 887 | "less.validate": true, 888 | 889 | // 使用供应商特定前缀时,确保同时包括所有其他供应商特定属性 890 | "less.lint.compatibleVendorPrefixes": "ignore", 891 | 892 | // 使用供应商特定前缀时,还应包括标准属性 893 | "less.lint.vendorPrefix": "warning", 894 | 895 | // 不要使用重复的样式定义 896 | "less.lint.duplicateProperties": "ignore", 897 | 898 | // 不要使用空规则集 899 | "less.lint.emptyRules": "warning", 900 | 901 | // Import 语句不会并行加载 902 | "less.lint.importStatement": "ignore", 903 | 904 | // 使用边距或边框时,不要使用宽度或高度 905 | "less.lint.boxModel": "ignore", 906 | 907 | // 已知通配选择符 (*) 慢 908 | "less.lint.universalSelector": "ignore", 909 | 910 | // 零不需要单位 911 | "less.lint.zeroUnits": "ignore", 912 | 913 | // @font-face 规则必须定义 "src" 和 "font-family" 属性 914 | "less.lint.fontFaceProperties": "warning", 915 | 916 | // 十六进制颜色必须由三个或六个十六进制数字组成 917 | "less.lint.hexColorLength": "error", 918 | 919 | // 参数数量无效 920 | "less.lint.argumentsInColorFunction": "error", 921 | 922 | // 未知的属性。 923 | "less.lint.unknownProperties": "warning", 924 | 925 | // 仅当支持 IE7 及更低版本时,才需要 IE hack 926 | "less.lint.ieHack": "ignore", 927 | 928 | // 未知的供应商特定属性。 929 | "less.lint.unknownVendorSpecificProperties": "ignore", 930 | 931 | // 因显示而忽略属性。例如,使用 "display: inline"时,宽度、高度、上边距、下边距和 float 属性将不起作用 932 | "less.lint.propertyIgnoredDueToDisplay": "warning", 933 | 934 | // 避免使用 !important。它表明整个 CSS 的特异性已经失去控制且需要重构。 935 | "less.lint.important": "ignore", 936 | 937 | // 避免使用“float”。浮动会带来脆弱的 CSS,如果布局的某一方面更改,将很容易破坏 CSS。 938 | "less.lint.float": "ignore", 939 | 940 | // 选择器不应包含 ID,因为这些规则与 HTML 的耦合过于紧密。 941 | "less.lint.idSelector": "ignore", 942 | 943 | 944 | // 启用或禁用所有验证 945 | "scss.validate": true, 946 | 947 | // 使用供应商特定前缀时,确保同时包括所有其他供应商特定属性 948 | "scss.lint.compatibleVendorPrefixes": "ignore", 949 | 950 | // 使用供应商特定前缀时,还应包括标准属性 951 | "scss.lint.vendorPrefix": "warning", 952 | 953 | // 不要使用重复的样式定义 954 | "scss.lint.duplicateProperties": "ignore", 955 | 956 | // 不要使用空规则集 957 | "scss.lint.emptyRules": "warning", 958 | 959 | // Import 语句不会并行加载 960 | "scss.lint.importStatement": "ignore", 961 | 962 | // 使用边距或边框时,不要使用宽度或高度 963 | "scss.lint.boxModel": "ignore", 964 | 965 | // 已知通配选择符 (*) 慢 966 | "scss.lint.universalSelector": "ignore", 967 | 968 | // 零不需要单位 969 | "scss.lint.zeroUnits": "ignore", 970 | 971 | // @font-face 规则必须定义 "src" 和 "font-family" 属性 972 | "scss.lint.fontFaceProperties": "warning", 973 | 974 | // 十六进制颜色必须由三个或六个十六进制数字组成 975 | "scss.lint.hexColorLength": "error", 976 | 977 | // 参数数量无效 978 | "scss.lint.argumentsInColorFunction": "error", 979 | 980 | // 未知的属性。 981 | "scss.lint.unknownProperties": "warning", 982 | 983 | // 仅当支持 IE7 及更低版本时,才需要 IE hack 984 | "scss.lint.ieHack": "ignore", 985 | 986 | // 未知的供应商特定属性。 987 | "scss.lint.unknownVendorSpecificProperties": "ignore", 988 | 989 | // 因显示而忽略属性。例如,使用 "display: inline"时,宽度、高度、上边距、下边距和 float 属性将不起作用 990 | "scss.lint.propertyIgnoredDueToDisplay": "warning", 991 | 992 | // 避免使用 !important。它表明整个 CSS 的特异性已经失去控制且需要重构。 993 | "scss.lint.important": "ignore", 994 | 995 | // 避免使用“float”。浮动会带来脆弱的 CSS,如果布局的某一方面更改,将很容易破坏 CSS。 996 | "scss.lint.float": "ignore", 997 | 998 | // 选择器不应包含 ID,因为这些规则与 HTML 的耦合过于紧密。 999 | "scss.lint.idSelector": "ignore", 1000 | 1001 | 1002 | // 自动更新扩展 1003 | "extensions.autoUpdate": true, 1004 | 1005 | // 忽略推荐的扩展 1006 | "extensions.ignoreRecommendations": false, 1007 | 1008 | 1009 | // 自定义要启动的终端类型。 1010 | "terminal.explorerKind": "integrated", 1011 | 1012 | // 自定义要在 Windows 上运行的终端。 1013 | "terminal.external.windowsExec": "undefined\\System32\\cmd.exe", 1014 | 1015 | // 自定义要在 OS X 上运行的终端应用程序。 1016 | "terminal.external.osxExec": "Terminal.app", 1017 | 1018 | // 自定义要在 Linux 上运行的终端。 1019 | "terminal.external.linuxExec": "xterm", 1020 | 1021 | 1022 | // 终端在 Linux 上使用的 shell 的路径。 1023 | "terminal.integrated.shell.linux": "/bin/zsh", 1024 | 1025 | // 在 Linux 终端上时要使用的命令行参数。 1026 | "terminal.integrated.shellArgs.linux": [], 1027 | 1028 | // 终端在 OS X 上使用的 shell 的路径。 1029 | "terminal.integrated.shell.osx": "/bin/zsh", 1030 | 1031 | // 在 OS X 终端上时要使用的命令行参数。 1032 | "terminal.integrated.shellArgs.osx": [ 1033 | "-l" 1034 | ], 1035 | 1036 | // 终端在 Windows 使用的 shell 路径。使用随 Windows 一起提供的 shell (cmd、PowerShell 或 Bash on Ubuntu) 时。 1037 | "terminal.integrated.shell.windows": "cmd.exe", 1038 | 1039 | // 在 Windows 终端上时使用的命令行参数。 1040 | "terminal.integrated.shellArgs.windows": [], 1041 | 1042 | // 设置后,在终端内右键单击时,这将阻止显示上下文菜单,相反,它将在有选项时进行复制,并且在没有选项时进行粘贴。 1043 | "terminal.integrated.rightClickCopyPaste": false, 1044 | 1045 | // 控制终端的字体系列,这在编辑器中是默认的。fontFamily 的值。 1046 | "terminal.integrated.fontFamily": "", 1047 | 1048 | // 控制终端的字号(以像素为单位)。 1049 | "terminal.integrated.fontSize": 12, 1050 | 1051 | // 控制终端的行高,此数字乘以终端字号得到实际行高(以像素表示)。 1052 | "terminal.integrated.lineHeight": 1, 1053 | 1054 | // 是否在终端内启用粗体文本,注意这需要终端命令行的支持。 1055 | "terminal.integrated.enableBold": true, 1056 | 1057 | // 控制终端光标是否闪烁。 1058 | "terminal.integrated.cursorBlinking": false, 1059 | 1060 | // 控制终端游标的样式。 1061 | "terminal.integrated.cursorStyle": "block", 1062 | 1063 | // 控制终端保持在缓冲区的最大行数。 1064 | "terminal.integrated.scrollback": 1000, 1065 | 1066 | // 控制是否在终端启动时设置区域设置变量,在 OS X 上默认设置为 true,在其他平台上为 false。 1067 | "terminal.integrated.setLocaleVariables": true, 1068 | 1069 | // 将在其中启动终端的一个显式起始路径,它用作 shell 进程的当前工作目录(cwd)。当根目录为不方便的 cwd 时,此路径在工作区设置中可能十分有用。 1070 | "terminal.integrated.cwd": "", 1071 | 1072 | // 在存在活动终端会话的情况下,退出时是否要确认。 1073 | "terminal.integrated.confirmOnExit": false, 1074 | 1075 | // 一组命令 ID,其键绑定不发送到 shell 而始终由 Code 处理。这使得通常由 shell 使用的键绑定的使用效果与未将终端设为焦点时相同,例如按 Ctrl+P 启动 Quick Open。 1076 | "terminal.integrated.commandsToSkipShell": [ 1077 | "editor.action.toggleTabFocusMode", 1078 | "workbench.action.debug.continue", 1079 | "workbench.action.debug.pause", 1080 | "workbench.action.debug.restart", 1081 | "workbench.action.debug.run", 1082 | "workbench.action.debug.start", 1083 | "workbench.action.debug.stop", 1084 | "workbench.action.focusActiveEditorGroup", 1085 | "workbench.action.focusFirstEditorGroup", 1086 | "workbench.action.focusSecondEditorGroup", 1087 | "workbench.action.focusThirdEditorGroup", 1088 | "workbench.action.navigateDown", 1089 | "workbench.action.navigateLeft", 1090 | "workbench.action.navigateRight", 1091 | "workbench.action.navigateUp", 1092 | "workbench.action.openNextRecentlyUsedEditorInGroup", 1093 | "workbench.action.openPreviousRecentlyUsedEditorInGroup", 1094 | "workbench.action.quickOpen", 1095 | "workbench.action.quickOpenPreviousEditor", 1096 | "workbench.action.quickOpenView", 1097 | "workbench.action.showCommands", 1098 | "workbench.action.tasks.build", 1099 | "workbench.action.tasks.restartTask", 1100 | "workbench.action.tasks.runTask", 1101 | "workbench.action.tasks.showLog", 1102 | "workbench.action.tasks.showTasks", 1103 | "workbench.action.tasks.terminate", 1104 | "workbench.action.tasks.test", 1105 | "workbench.action.terminal.clear", 1106 | "workbench.action.terminal.copySelection", 1107 | "workbench.action.terminal.deleteWordLeft", 1108 | "workbench.action.terminal.deleteWordRight", 1109 | "workbench.action.terminal.findWidget.history.showNext", 1110 | "workbench.action.terminal.findWidget.history.showPrevious", 1111 | "workbench.action.terminal.focus", 1112 | "workbench.action.terminal.focusAtIndex1", 1113 | "workbench.action.terminal.focusAtIndex2", 1114 | "workbench.action.terminal.focusAtIndex3", 1115 | "workbench.action.terminal.focusAtIndex4", 1116 | "workbench.action.terminal.focusAtIndex5", 1117 | "workbench.action.terminal.focusAtIndex6", 1118 | "workbench.action.terminal.focusAtIndex7", 1119 | "workbench.action.terminal.focusAtIndex8", 1120 | "workbench.action.terminal.focusAtIndex9", 1121 | "workbench.action.terminal.focusFindWidget", 1122 | "workbench.action.terminal.focusNext", 1123 | "workbench.action.terminal.focusPrevious", 1124 | "workbench.action.terminal.hideFindWidget", 1125 | "workbench.action.terminal.kill", 1126 | "workbench.action.terminal.new", 1127 | "workbench.action.terminal.paste", 1128 | "workbench.action.terminal.runActiveFile", 1129 | "workbench.action.terminal.runSelectedText", 1130 | "workbench.action.terminal.scrollDown", 1131 | "workbench.action.terminal.scrollDownPage", 1132 | "workbench.action.terminal.scrollToBottom", 1133 | "workbench.action.terminal.scrollToTop", 1134 | "workbench.action.terminal.scrollUp", 1135 | "workbench.action.terminal.scrollUpPage", 1136 | "workbench.action.terminal.selectAll", 1137 | "workbench.action.terminal.toggleTerminal", 1138 | "workbench.action.togglePanel" 1139 | ], 1140 | 1141 | // 要添加到 VS Code 进程中的带有环境变量的对象,其会被 OS X 终端使用。 1142 | "terminal.integrated.env.osx": {}, 1143 | 1144 | // 要添加到 VS Code 进程中的带有环境变量的对象,其会被 Linux 终端使用。 1145 | "terminal.integrated.env.linux": {}, 1146 | 1147 | // 要添加到 VS Code 进程中的带有环境变量的对象,其会被 Windows 终端使用。 1148 | "terminal.integrated.env.windows": {}, 1149 | 1150 | 1151 | // 显示关于文件与文件夹的错误与警告。 1152 | "problems.decorations.enabled": false, 1153 | 1154 | // 控制问题预览是否应在打开文件时自动显示它们。 1155 | "problems.autoReveal": true, 1156 | 1157 | 1158 | // 启用要发送给 Microsoft 的故障报表。 1159 | // 此选项需重启才可生效。 1160 | "telemetry.enableCrashReporter": true, 1161 | 1162 | // 启用要发送给 Microsoft 的使用情况数据和错误。 1163 | "telemetry.enableTelemetry": true, 1164 | 1165 | 1166 | // A list of vscode language names where the extension should be used. 1167 | "vue-peek.supportedLanguages": [ 1168 | "vue" 1169 | ], 1170 | 1171 | // A list of extensions that should be tried for finding peeked files. These are tried in order as further extensions of the potential file name and also as alternative file endings instead of the existing file extension (if available). 1172 | "vue-peek.targetFileExtensions": [ 1173 | ".vue" 1174 | ], 1175 | 1176 | 1177 | // 针对 [git-commit] 语言,配置替代编辑器设置。 1178 | "[git-commit]": { 1179 | "editor.rulers": [ 1180 | 72 1181 | ] 1182 | }, 1183 | 1184 | // 针对 [go] 语言,配置替代编辑器设置。 1185 | "[go]": { 1186 | "editor.insertSpaces": false 1187 | }, 1188 | 1189 | // 针对 [json] 语言,配置替代编辑器设置。 1190 | "[json]": { 1191 | "editor.quickSuggestions": { 1192 | "strings": true 1193 | } 1194 | }, 1195 | 1196 | // 针对 [makefile] 语言,配置替代编辑器设置。 1197 | "[makefile]": { 1198 | "editor.insertSpaces": false 1199 | }, 1200 | 1201 | // 针对 [markdown] 语言,配置替代编辑器设置。 1202 | "[markdown]": { 1203 | "editor.wordWrap": "on", 1204 | "editor.quickSuggestions": false 1205 | }, 1206 | 1207 | // 针对 [yaml] 语言,配置替代编辑器设置。 1208 | "[yaml]": { 1209 | "editor.insertSpaces": true, 1210 | "editor.tabSize": 2 1211 | }, 1212 | 1213 | 1214 | // Controls whether eslint is enabled for JavaScript files or not. 1215 | "eslint.enable": true, 1216 | 1217 | // The package manager you use to install node modules. 1218 | "eslint.packageManager": "npm", 1219 | 1220 | // Always show the ESlint status bar item. 1221 | "eslint.alwaysShowStatus": false, 1222 | 1223 | // A path added to NODE_PATH when resolving the eslint module. 1224 | "eslint.nodePath": null, 1225 | 1226 | // Uses the legacy module resolving. 1227 | "eslint._legacyModuleResolve": false, 1228 | 1229 | // The eslint options object to provide args normally passed to eslint when executed from a command line (see http://eslint.org/docs/developer-guide/nodejs-api#cliengine). 1230 | "eslint.options": {}, 1231 | 1232 | // Traces the communication between VSCode and the eslint linter service. 1233 | "eslint.trace.server": "off", 1234 | 1235 | // Run the linter on save (onSave) or on type (onType) 1236 | "eslint.run": "onType", 1237 | 1238 | // Turns auto fix on save on or off. 1239 | "eslint.autoFixOnSave": false, 1240 | 1241 | // 1242 | "eslint.workingDirectories": [], 1243 | 1244 | // An array of language ids which should be validated by ESLint 1245 | "eslint.validate": [ 1246 | "javascript", 1247 | "javascriptreact" 1248 | ], 1249 | 1250 | 1251 | // 控制自动检测 Jake 任务是否打开。默认开启。 1252 | "jake.autoDetect": "on", 1253 | 1254 | 1255 | // A list of remote style sheets. 1256 | "css.remoteStyleSheets": [], 1257 | 1258 | // A list of style sheet file extensions you want the extension to look for. 1259 | "css.fileExtensions": [ 1260 | "css", 1261 | "scss" 1262 | ], 1263 | 1264 | 1265 | // 控制自动检测 Grunt 任务是否打开。默认开启。 1266 | "grunt.autoDetect": "on", 1267 | 1268 | 1269 | // Run npm commands in a terminal, otherwise shows the output in the output panel 1270 | "npm.runInTerminal": true, 1271 | 1272 | // Look for 'package.json' files in these directories 1273 | "npm.includeDirectories": [], 1274 | 1275 | // Look for 'package.json' in the root directory of the workspace 1276 | "npm.useRootDirectory": true, 1277 | 1278 | // npm bin name 1279 | "npm.bin": "npm", 1280 | 1281 | // Validate installed modules 1282 | "npm.validate.enable": true, 1283 | 1284 | 1285 | // 控制自动检测 npm 脚本是否打开。默认开启。 1286 | "npm.autoDetect": "on", 1287 | 1288 | // 使用 "--silent" 选项运行 npm 命令。 1289 | "npm.runSilent": false, 1290 | 1291 | // 用于运行脚本的程序包管理器。 1292 | "npm.packageManager": "npm", 1293 | 1294 | 1295 | // Set the languages that the extension will be activated. e.g. ["html","xml","php"]. Use ["*"] to activate for all languages. 1296 | "auto-close-tag.activationOnLanguage": [ 1297 | "xml", 1298 | "php", 1299 | "blade", 1300 | "ejs", 1301 | "jinja", 1302 | "javascript", 1303 | "javascriptreact", 1304 | "typescript", 1305 | "typescriptreact", 1306 | "plaintext", 1307 | "markdown", 1308 | "vue", 1309 | "liquid", 1310 | "erb", 1311 | "lang-cfml", 1312 | "cfml" 1313 | ], 1314 | 1315 | // Set the tag list that would not be auto closed. 1316 | "auto-close-tag.excludedTags": [ 1317 | "area", 1318 | "base", 1319 | "br", 1320 | "col", 1321 | "command", 1322 | "embed", 1323 | "hr", 1324 | "img", 1325 | "input", 1326 | "keygen", 1327 | "link", 1328 | "meta", 1329 | "param", 1330 | "source", 1331 | "track", 1332 | "wbr" 1333 | ], 1334 | 1335 | // Auto close tag when using eslint-plugin-vue 1490 | "vetur.validation.template": true, 1491 | 1492 | // Validate css/scss/less/postcss in