Showing
38 changed files
with
1460 additions
and
0 deletions
.babelrc
0 → 100644
.editorconfig
0 → 100644
.eslintignore
0 → 100644
.eslintrc
0 → 100644
.gitignore
0 → 100644
1 | + | ||
2 | +# Created by https://www.gitignore.io/api/node,webstorm,netbeans,sublimetext,vim | ||
3 | + | ||
4 | +### Node ### | ||
5 | +# Logs | ||
6 | +logs | ||
7 | +*.log | ||
8 | +npm-debug.log* | ||
9 | + | ||
10 | +# Runtime data | ||
11 | +pids | ||
12 | +*.pid | ||
13 | +*.seed | ||
14 | + | ||
15 | +# Directory for instrumented libs generated by jscoverage/JSCover | ||
16 | +lib-cov | ||
17 | + | ||
18 | +# Coverage directory used by tools like istanbul | ||
19 | +coverage | ||
20 | + | ||
21 | +# nyc test coverage | ||
22 | +.nyc_output | ||
23 | + | ||
24 | +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
25 | +.grunt | ||
26 | + | ||
27 | +# node-waf configuration | ||
28 | +.lock-wscript | ||
29 | + | ||
30 | +# Compiled binary addons (http://nodejs.org/api/addons.html) | ||
31 | +build/Release | ||
32 | + | ||
33 | +# Dependency directories | ||
34 | +node_modules | ||
35 | +jspm_packages | ||
36 | + | ||
37 | +# Optional npm cache directory | ||
38 | +.npm | ||
39 | + | ||
40 | +# Optional REPL history | ||
41 | +.node_repl_history | ||
42 | + | ||
43 | + | ||
44 | +### WebStorm ### | ||
45 | +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm | ||
46 | +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 | ||
47 | +.idea/ | ||
48 | +# User-specific stuff: | ||
49 | +.idea/workspace.xml | ||
50 | +.idea/tasks.xml | ||
51 | +.idea/dictionaries | ||
52 | +.idea/vcs.xml | ||
53 | +.idea/jsLibraryMappings.xml | ||
54 | + | ||
55 | +# Sensitive or high-churn files: | ||
56 | +.idea/dataSources.ids | ||
57 | +.idea/dataSources.xml | ||
58 | +.idea/dataSources.local.xml | ||
59 | +.idea/sqlDataSources.xml | ||
60 | +.idea/dynamic.xml | ||
61 | +.idea/uiDesigner.xml | ||
62 | + | ||
63 | +# Gradle: | ||
64 | +.idea/gradle.xml | ||
65 | +.idea/libraries | ||
66 | + | ||
67 | +# Mongo Explorer plugin: | ||
68 | +.idea/mongoSettings.xml | ||
69 | + | ||
70 | +## File-based project format: | ||
71 | +*.iws | ||
72 | + | ||
73 | +## Plugin-specific files: | ||
74 | + | ||
75 | +# IntelliJ | ||
76 | +/out/ | ||
77 | + | ||
78 | +# mpeltonen/sbt-idea plugin | ||
79 | +.idea_modules/ | ||
80 | + | ||
81 | +# JIRA plugin | ||
82 | +atlassian-ide-plugin.xml | ||
83 | + | ||
84 | +# Crashlytics plugin (for Android Studio and IntelliJ) | ||
85 | +com_crashlytics_export_strings.xml | ||
86 | +crashlytics.properties | ||
87 | +crashlytics-build.properties | ||
88 | +fabric.properties | ||
89 | + | ||
90 | +### WebStorm Patch ### | ||
91 | +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 | ||
92 | + | ||
93 | +# *.iml | ||
94 | +# modules.xml | ||
95 | + | ||
96 | + | ||
97 | +### NetBeans ### | ||
98 | +nbproject/private/ | ||
99 | +public/build/bundle | ||
100 | +nbbuild/ | ||
101 | +dist/ | ||
102 | +nbdist/ | ||
103 | +nbactions.xml | ||
104 | +.nb-gradle/ | ||
105 | + | ||
106 | + | ||
107 | +### SublimeText ### | ||
108 | +# cache files for sublime text | ||
109 | +*.tmlanguage.cache | ||
110 | +*.tmPreferences.cache | ||
111 | +*.stTheme.cache | ||
112 | + | ||
113 | +# workspace files are user-specific | ||
114 | +*.sublime-workspace | ||
115 | + | ||
116 | +# project files should be checked into the repository, unless a significant | ||
117 | +# proportion of contributors will probably not be using SublimeText | ||
118 | +# *.sublime-project | ||
119 | + | ||
120 | +# sftp configuration file | ||
121 | +sftp-config.json | ||
122 | + | ||
123 | + | ||
124 | +### Vim ### | ||
125 | +# swap | ||
126 | +[._]*.s[a-w][a-z] | ||
127 | +[._]s[a-w][a-z] | ||
128 | +# session | ||
129 | +Session.vim | ||
130 | +# temporary | ||
131 | +.netrwhist | ||
132 | +*~ | ||
133 | +# auto-generated tag files | ||
134 | +tags | ||
135 | + | ||
136 | +### VS Code ### | ||
137 | +.vscode/ | ||
138 | + | ||
139 | +### YOHO ### | ||
140 | +public/dist/ | ||
141 | +public/img/sprite.* | ||
142 | +public/css/* | ||
143 | +public/bundle/* | ||
144 | +.eslintcache | ||
145 | +*.log.* | ||
146 | +nbproject/* | ||
147 | +.DS_Store | ||
148 | +.devhost | ||
149 | +bundle/ |
.npmrc
0 → 100644
.stylelintignore
0 → 100644
.stylelintrc
0 → 100644
build/build.js
0 → 100644
1 | +process.env.NODE_ENV = 'production'; | ||
2 | + | ||
3 | +let rm = require('rimraf'); | ||
4 | +let path = require('path'); | ||
5 | +let chalk = require('chalk'); | ||
6 | +let webpack = require('webpack'); | ||
7 | +let config = require('./config'); | ||
8 | +let webpackConfig = require('./webpack.prod.conf'); | ||
9 | + | ||
10 | + | ||
11 | +rm(path.join(config.build.assetsRoot), () => { | ||
12 | + webpack(webpackConfig, function(err, stats) { | ||
13 | + if (err) { | ||
14 | + throw err; | ||
15 | + } | ||
16 | + process.stdout.write(stats.toString({ | ||
17 | + colors: true, | ||
18 | + modules: false, | ||
19 | + children: false, | ||
20 | + chunks: false, | ||
21 | + chunkModules: false | ||
22 | + }) + '\n\n'); | ||
23 | + | ||
24 | + console.log(chalk.cyan(' Build complete.\n')); | ||
25 | + console.log(chalk.yellow( | ||
26 | + ' Tip: built files are meant to be served over an HTTP server.\n' + | ||
27 | + ' Opening index.html over file:// won\'t work.\n' | ||
28 | + )); | ||
29 | + }); | ||
30 | +}); |
build/config.js
0 → 100644
1 | +var path = require('path'); | ||
2 | + | ||
3 | +module.exports = { | ||
4 | + build: { | ||
5 | + env: { | ||
6 | + NODE_ENV: '"production"' | ||
7 | + }, | ||
8 | + assetsRoot: path.join(__dirname, '../dist'), | ||
9 | + assetsSubDirectory: 'static', | ||
10 | + assetsPublicPath: '/', | ||
11 | + productionSourceMap: true, | ||
12 | + }, | ||
13 | + dev: { | ||
14 | + env: { | ||
15 | + NODE_ENV: '"dev"' | ||
16 | + }, | ||
17 | + port: 6010, | ||
18 | + autoOpenBrowser: true, | ||
19 | + assetsSubDirectory: 'static', | ||
20 | + assetsPublicPath: '/', | ||
21 | + proxyTable: {}, | ||
22 | + cssSourceMap: false, | ||
23 | + } | ||
24 | +}; | ||
25 | + |
build/dev-server.js
0 → 100644
1 | +let config = require('./config'); | ||
2 | + | ||
3 | +if (!process.env.NODE_ENV) { | ||
4 | + process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV); | ||
5 | +} | ||
6 | + | ||
7 | +let opn = require('opn'); | ||
8 | +let path = require('path'); | ||
9 | +const compression = require('compression'); | ||
10 | +let express = require('express'); | ||
11 | +let webpack = require('webpack'); | ||
12 | +let proxyMiddleware = require('http-proxy-middleware'); | ||
13 | +let webpackConfig = require('./webpack.dev.conf'); | ||
14 | + | ||
15 | +// default port where dev server listens for incoming traffic | ||
16 | +let port = process.env.PORT || config.dev.port; | ||
17 | + | ||
18 | +// automatically open browser, if not set will be false | ||
19 | +let autoOpenBrowser = !!config.dev.autoOpenBrowser; | ||
20 | + | ||
21 | +// Define HTTP proxies to your custom API backend | ||
22 | +// https://github.com/chimurai/http-proxy-middleware | ||
23 | +let proxyTable = config.dev.proxyTable; | ||
24 | + | ||
25 | +let app = express(); | ||
26 | +let compiler = webpack(webpackConfig); | ||
27 | + | ||
28 | +let devMiddleware = require('webpack-dev-middleware')(compiler, { | ||
29 | + publicPath: webpackConfig.output.publicPath, | ||
30 | + quiet: true, | ||
31 | + headers: { | ||
32 | + 'Access-Control-Allow-Origin': '*' | ||
33 | + }, | ||
34 | +}); | ||
35 | + | ||
36 | +let hotMiddleware = require('webpack-hot-middleware')(compiler, { | ||
37 | + log: () => { } | ||
38 | +}); | ||
39 | + | ||
40 | + | ||
41 | +app.use(compression()); | ||
42 | + | ||
43 | +// proxy api requests | ||
44 | +Object.keys(proxyTable).forEach(function(context) { | ||
45 | + let options = proxyTable[context]; | ||
46 | + | ||
47 | + if (typeof options === 'string') { | ||
48 | + options = { target: options }; | ||
49 | + } | ||
50 | + app.use(proxyMiddleware(options.filter || context, options)); | ||
51 | +}); | ||
52 | + | ||
53 | +// handle fallback for HTML5 history API | ||
54 | +app.use(require('connect-history-api-fallback')({ | ||
55 | + rewrites: [ | ||
56 | + { from: /\.html$/, to: '/index.html' }, | ||
57 | + { | ||
58 | + from: /.*?\.(js)|(css)$/, | ||
59 | + to: (context) => { | ||
60 | + return context.parsedUrl.pathname; | ||
61 | + } | ||
62 | + } | ||
63 | + ] | ||
64 | +})); | ||
65 | + | ||
66 | +// serve webpack bundle output | ||
67 | +app.use(devMiddleware); | ||
68 | + | ||
69 | +// enable hot-reload and state-preserving | ||
70 | +// compilation error display | ||
71 | +app.use(hotMiddleware); | ||
72 | + | ||
73 | +// serve pure static assets | ||
74 | +let staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory); | ||
75 | + | ||
76 | +app.use(staticPath, express.static('./static')); | ||
77 | + | ||
78 | +let uri = 'http://localhost:' + port; | ||
79 | + | ||
80 | +let _resolve; | ||
81 | +let readyPromise = new Promise(resolve => { | ||
82 | + _resolve = resolve; | ||
83 | +}); | ||
84 | + | ||
85 | +console.log('> Starting dev server...'); | ||
86 | +devMiddleware.waitUntilValid(() => { | ||
87 | + console.log('> Listening at ' + uri + '\n'); | ||
88 | + | ||
89 | + // when env is testing, don't need open it | ||
90 | + if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { | ||
91 | + opn(uri); | ||
92 | + } | ||
93 | + _resolve(); | ||
94 | +}); | ||
95 | + | ||
96 | +let server = app.listen(port); | ||
97 | + | ||
98 | +module.exports = { | ||
99 | + ready: readyPromise, | ||
100 | + close: () => { | ||
101 | + server.close(); | ||
102 | + } | ||
103 | +}; |
build/utils.js
0 → 100644
1 | +let path = require('path'); | ||
2 | +let config = require('./config'); | ||
3 | +let ExtractTextPlugin = require('extract-text-webpack-plugin'); | ||
4 | + | ||
5 | +exports.assetsPath = function(_path) { | ||
6 | + let assetsSubDirectory = process.env.NODE_ENV === 'production' ? | ||
7 | + config.build.assetsSubDirectory : | ||
8 | + config.dev.assetsSubDirectory; | ||
9 | + | ||
10 | + return path.posix.join(assetsSubDirectory, _path); | ||
11 | +}; | ||
12 | + | ||
13 | +exports.cssLoaders = function(options) { | ||
14 | + options = options || {}; | ||
15 | + | ||
16 | + let cssLoader = { | ||
17 | + loader: 'css-loader', | ||
18 | + options: { | ||
19 | + minimize: process.env.NODE_ENV === 'production', | ||
20 | + sourceMap: options.sourceMap | ||
21 | + } | ||
22 | + }; | ||
23 | + let autoprefixerLoader = { | ||
24 | + loader: 'autoprefixer-loader' | ||
25 | + }; | ||
26 | + | ||
27 | + // generate loader string to be used with extract text plugin | ||
28 | + function generateLoaders(loader, loaderOptions) { | ||
29 | + let loaders = [cssLoader, autoprefixerLoader]; | ||
30 | + | ||
31 | + if (loader) { | ||
32 | + loaders.push({ | ||
33 | + loader: loader + '-loader', | ||
34 | + options: Object.assign({}, loaderOptions, { | ||
35 | + sourceMap: options.sourceMap | ||
36 | + }) | ||
37 | + }); | ||
38 | + } | ||
39 | + | ||
40 | + // Extract CSS when that option is specified | ||
41 | + // (which is the case during production build) | ||
42 | + if (options.extract) { | ||
43 | + return ExtractTextPlugin.extract({ | ||
44 | + use: loaders, | ||
45 | + fallback: 'vue-style-loader' | ||
46 | + }); | ||
47 | + } else { | ||
48 | + return ['vue-style-loader'].concat(loaders); | ||
49 | + } | ||
50 | + } | ||
51 | + | ||
52 | + // https://vue-loader.vuejs.org/en/configurations/extract-css.html | ||
53 | + return { | ||
54 | + css: generateLoaders(), | ||
55 | + scss: generateLoaders('sass'), | ||
56 | + }; | ||
57 | +}; | ||
58 | + | ||
59 | +// Generate loaders for standalone style files (outside of .vue) | ||
60 | +exports.styleLoaders = function(options) { | ||
61 | + let output = []; | ||
62 | + let loaders = exports.cssLoaders(options); | ||
63 | + | ||
64 | + for (let extension in loaders) { | ||
65 | + if (!extension) { | ||
66 | + continue; | ||
67 | + } | ||
68 | + let loader = loaders[extension]; | ||
69 | + | ||
70 | + output.push({ | ||
71 | + test: new RegExp('\\.' + extension + '$'), | ||
72 | + use: loader | ||
73 | + }); | ||
74 | + } | ||
75 | + return output; | ||
76 | +}; |
build/vue-loader.conf.js
0 → 100644
1 | +var utils = require('./utils'); | ||
2 | +var config = require('./config'); | ||
3 | +var isProduction = process.env.NODE_ENV === 'production'; | ||
4 | + | ||
5 | +module.exports = { | ||
6 | + loaders: Object.assign(utils.cssLoaders({ | ||
7 | + sourceMap: isProduction ? | ||
8 | + config.build.productionSourceMap : | ||
9 | + config.dev.cssSourceMap, | ||
10 | + extract: isProduction | ||
11 | + }), { | ||
12 | + js: 'babel-loader' | ||
13 | + }) | ||
14 | +}; |
build/webpack.base.conf.js
0 → 100644
1 | +'use strict'; | ||
2 | +const path = require('path'); | ||
3 | + | ||
4 | +let vueLoaderConfig = require('./vue-loader.conf'); | ||
5 | +let config = require('./config'); | ||
6 | +let utils = require('./utils'); | ||
7 | + | ||
8 | + | ||
9 | +function resolve(dir) { | ||
10 | + return path.join(__dirname, '../src', dir); | ||
11 | +} | ||
12 | +module.exports = { | ||
13 | + entry: { | ||
14 | + app: './src/app.js' | ||
15 | + }, | ||
16 | + output: { | ||
17 | + path: config.build.assetsRoot, | ||
18 | + filename: utils.assetsPath('js/[name].js'), | ||
19 | + chunkFilename: utils.assetsPath('js/[name].js'), | ||
20 | + publicPath: process.env.NODE_ENV === 'production' ? | ||
21 | + config.build.assetsPublicPath : | ||
22 | + config.dev.assetsPublicPath | ||
23 | + }, | ||
24 | + resolve: { | ||
25 | + extensions: ['.js', '.vue', '.json'], | ||
26 | + alias: { | ||
27 | + vue$: 'vue/dist/vue.esm.js' | ||
28 | + }, | ||
29 | + modules: [ | ||
30 | + resolve(''), | ||
31 | + 'node_modules' | ||
32 | + ] | ||
33 | + }, | ||
34 | + module: { | ||
35 | + rules: [ | ||
36 | + { | ||
37 | + test: /\.js$/, | ||
38 | + loader: 'babel-loader', | ||
39 | + exclude: /node_modules/ | ||
40 | + }, | ||
41 | + { | ||
42 | + test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, | ||
43 | + loader: 'url-loader', | ||
44 | + options: { | ||
45 | + limit: 10000, | ||
46 | + name: utils.assetsPath('img/[name].[hash:7].[ext]') | ||
47 | + } | ||
48 | + }, | ||
49 | + { | ||
50 | + test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, | ||
51 | + loader: 'url-loader', | ||
52 | + options: { | ||
53 | + limit: 10000, | ||
54 | + name: utils.assetsPath('fonts/[name].[hash:7].[ext]') | ||
55 | + } | ||
56 | + }, | ||
57 | + { | ||
58 | + test: /\.vue$/, | ||
59 | + use: [{ | ||
60 | + loader: 'vue-loader', | ||
61 | + options: vueLoaderConfig | ||
62 | + }, { | ||
63 | + loader: 'iview-loader', | ||
64 | + options: { | ||
65 | + prefix: true | ||
66 | + } | ||
67 | + }] | ||
68 | + } | ||
69 | + ] | ||
70 | + } | ||
71 | +}; |
build/webpack.dev.conf.js
0 → 100644
1 | +const webpack = require('webpack'); | ||
2 | +const merge = require('webpack-merge'); | ||
3 | +const HtmlWebpackPlugin = require('html-webpack-plugin'); | ||
4 | +const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin'); | ||
5 | + | ||
6 | +let baseConfig = require('./webpack.base.conf.js'); | ||
7 | +let config = require('./config'); | ||
8 | +let utils = require('./utils'); | ||
9 | + | ||
10 | + | ||
11 | +Object.keys(baseConfig.entry).forEach(function(name) { | ||
12 | + baseConfig.entry[name] = ['webpack-hot-middleware/client?noInfo=true&reload=true'].concat(baseConfig.entry[name]); | ||
13 | +}); | ||
14 | + | ||
15 | +module.exports = merge(baseConfig, { | ||
16 | + module: { | ||
17 | + rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) | ||
18 | + }, | ||
19 | + plugins: [ | ||
20 | + new webpack.DefinePlugin({ | ||
21 | + 'process.env': config.dev.env | ||
22 | + }), | ||
23 | + new webpack.HotModuleReplacementPlugin(), | ||
24 | + new webpack.NoEmitOnErrorsPlugin(), | ||
25 | + new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), | ||
26 | + new HtmlWebpackPlugin({ | ||
27 | + filename: 'index.html', | ||
28 | + template: './src/index.html', | ||
29 | + inject: true | ||
30 | + }), | ||
31 | + new FriendlyErrorsPlugin(), | ||
32 | + ] | ||
33 | +}); | ||
34 | + |
build/webpack.prod.conf.js
0 → 100644
1 | +const webpack = require('webpack'); | ||
2 | +const merge = require('webpack-merge'); | ||
3 | +const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin'); | ||
4 | +const ExtractTextPlugin = require('extract-text-webpack-plugin'); | ||
5 | +const HtmlWebpackPlugin = require('html-webpack-plugin'); | ||
6 | + | ||
7 | +let baseConfig = require('./webpack.base.conf.js'); | ||
8 | +let config = require('./config'); | ||
9 | +let utils = require('./utils'); | ||
10 | + | ||
11 | +let webpackConfig = merge(baseConfig, { | ||
12 | + module: { | ||
13 | + rules: utils.styleLoaders({ | ||
14 | + sourceMap: config.build.productionSourceMap, | ||
15 | + extract: true | ||
16 | + }) | ||
17 | + }, | ||
18 | + devtool: config.build.productionSourceMap ? '#source-map' : false, | ||
19 | + output: { | ||
20 | + filename: utils.assetsPath('js/[name].[chunkhash].js'), | ||
21 | + chunkFilename: utils.assetsPath('js/[name].[chunkhash].js') | ||
22 | + }, | ||
23 | + plugins: [ | ||
24 | + new webpack.DefinePlugin({ | ||
25 | + 'process.env': config.build.env | ||
26 | + }), | ||
27 | + new webpack.optimize.UglifyJsPlugin({ | ||
28 | + parallel: true, | ||
29 | + sourceMap: true | ||
30 | + }), | ||
31 | + new ExtractTextPlugin({ | ||
32 | + filename: utils.assetsPath('css/[name].[chunkhash].css') | ||
33 | + }), | ||
34 | + new OptimizeCSSPlugin({ | ||
35 | + cssProcessorOptions: { | ||
36 | + safe: true | ||
37 | + } | ||
38 | + }), | ||
39 | + new HtmlWebpackPlugin({ | ||
40 | + filename: 'index.html', | ||
41 | + template: './src/index.html', | ||
42 | + inject: true, | ||
43 | + minify: { | ||
44 | + removeComments: true, | ||
45 | + collapseWhitespace: true, | ||
46 | + removeAttributeQuotes: true | ||
47 | + } | ||
48 | + }) | ||
49 | + ] | ||
50 | +}); | ||
51 | + | ||
52 | + | ||
53 | + | ||
54 | +module.exports = webpackConfig; |
package.json
0 → 100644
1 | +{ | ||
2 | + "name": "yoho-api-doc", | ||
3 | + "version": "1.0.0", | ||
4 | + "description": "", | ||
5 | + "main": "src/app.js", | ||
6 | + "scripts": { | ||
7 | + "dev": "node ./build/dev-server.js", | ||
8 | + "build": "node ./build/build.js", | ||
9 | + "lint-js": "lint-js", | ||
10 | + "lint-css": "lint-css", | ||
11 | + "precommit": "lint-commit", | ||
12 | + "lint-all": "lint-all" | ||
13 | + }, | ||
14 | + "author": "", | ||
15 | + "license": "ISC", | ||
16 | + "dependencies": { | ||
17 | + "axios": "^0.16.2", | ||
18 | + "iview": "^2.4.0", | ||
19 | + "iview-loader": "^1.0.0-beta.4", | ||
20 | + "lodash": "^4.15.0", | ||
21 | + "vue": "^2.4.2", | ||
22 | + "vue-loader": "^13.0.2", | ||
23 | + "vue-markdown": "^2.2.4", | ||
24 | + "vue-router": "^2.7.0", | ||
25 | + "vue-template-compiler": "^2.4.2", | ||
26 | + "vuex": "^2.4.1", | ||
27 | + "yoho-cookie": "^1.2.0", | ||
28 | + "yoho-store": "^1.3.20" | ||
29 | + }, | ||
30 | + "devDependencies": { | ||
31 | + "autoprefixer": "^7.0.1", | ||
32 | + "autoprefixer-loader": "^3.2.0", | ||
33 | + "babel-core": "^6.24.1", | ||
34 | + "babel-eslint": "^7.2.3", | ||
35 | + "babel-loader": "^7.0.0", | ||
36 | + "babel-plugin-syntax-dynamic-import": "^6.18.0", | ||
37 | + "babel-plugin-syntax-jsx": "^6.18.0", | ||
38 | + "babel-plugin-transform-object-rest-spread": "^6.23.0", | ||
39 | + "babel-plugin-transform-runtime": "^6.22.0", | ||
40 | + "babel-plugin-transform-vue-jsx": "^3.4.3", | ||
41 | + "babel-preset-env": "^1.4.0", | ||
42 | + "babel-preset-es2015": "^6.14.0", | ||
43 | + "babel-runtime": "^6.11.6", | ||
44 | + "css-loader": "^0.28.1", | ||
45 | + "eslint": "^3.3.1", | ||
46 | + "eslint-config-yoho": "^1.0.1", | ||
47 | + "eslint-plugin-html": "^1.5.2", | ||
48 | + "extract-text-webpack-plugin": "^2.1.0", | ||
49 | + "file-loader": "^1.1.5", | ||
50 | + "friendly-errors-webpack-plugin": "^1.6.1", | ||
51 | + "html-webpack-plugin": "^2.28.0", | ||
52 | + "node-sass": "^4.5.3", | ||
53 | + "optimize-css-assets-webpack-plugin": "^3.2.0", | ||
54 | + "postcss-loader": "^2.0.5", | ||
55 | + "postcss-pxtorem": "^3.3.1", | ||
56 | + "postcss-scss": "^1.0.0", | ||
57 | + "precss": "^1.4.0", | ||
58 | + "sass-loader": "^6.0.6", | ||
59 | + "style-loader": "^0.17.0", | ||
60 | + "stylelint": "^7.1.0", | ||
61 | + "stylelint-config-yoho": "^1.2.7", | ||
62 | + "stylelint-processor-html": "^1.0.0", | ||
63 | + "url-loader": "^0.6.2", | ||
64 | + "vue-style-loader": "^3.0.1", | ||
65 | + "webpack": "3.3", | ||
66 | + "webpack-dev-middleware": "^1.10.2", | ||
67 | + "webpack-dev-server": "^2.6.1", | ||
68 | + "webpack-hot-middleware": "^2.18.0", | ||
69 | + "webpack-merge": "^4.1.0", | ||
70 | + "yoho-lint": "^1.0.1" | ||
71 | + } | ||
72 | +} |
src/app.js
0 → 100644
1 | +import Vue from 'vue'; | ||
2 | +import App from './app.vue'; | ||
3 | +import {createRouter} from './router'; | ||
4 | +import {createStore} from './store'; | ||
5 | +import pluginCore from './plugins/core'; | ||
6 | + | ||
7 | +Vue.use(pluginCore); | ||
8 | + | ||
9 | +const router = createRouter(); | ||
10 | +const store = createStore(); | ||
11 | + | ||
12 | +new Vue({ | ||
13 | + router, | ||
14 | + store, | ||
15 | + render: h => h(App), | ||
16 | + el: '#app' | ||
17 | +}); |
src/app.vue
0 → 100644
src/common/api.js
0 → 100644
1 | +import axios from 'axios'; | ||
2 | +import config from 'config'; | ||
3 | + | ||
4 | +axios.defaults.baseURL = config.axiosBaseUrl; | ||
5 | +axios.defaults.responseType = config.axiosResponseType; | ||
6 | +axios.defaults.headers = { | ||
7 | + 'X-Requested-With': 'XMLHttpRequest' | ||
8 | +}; | ||
9 | + | ||
10 | + | ||
11 | +const errHandle = error => { | ||
12 | + let msg = error && error.config ? `api:[${error.config.method}] ${error.config.url} ${error.config.params || ''} ${error.response && error.response.data}` : 'axios error'; | ||
13 | + | ||
14 | + return Promise.reject(msg); | ||
15 | +}; | ||
16 | +const request = (options) => { | ||
17 | + return axios(options).then(res => res.data, errHandle); | ||
18 | +}; | ||
19 | + | ||
20 | +export default { | ||
21 | + post(url, data, options) { | ||
22 | + return request(Object.assign({ | ||
23 | + url, | ||
24 | + data, | ||
25 | + method: 'post', | ||
26 | + }, options)); | ||
27 | + }, | ||
28 | + get(url, params, options) { | ||
29 | + return request(Object.assign({ | ||
30 | + url, | ||
31 | + params, | ||
32 | + method: 'get', | ||
33 | + }, options)); | ||
34 | + }, | ||
35 | + put(url, data, options) { | ||
36 | + return request(Object.assign({ | ||
37 | + url, | ||
38 | + data, | ||
39 | + method: 'put', | ||
40 | + }, options)); | ||
41 | + }, | ||
42 | + delete(url, params, options) { | ||
43 | + return request(Object.assign({ | ||
44 | + url, | ||
45 | + params, | ||
46 | + method: 'delete', | ||
47 | + }, options)); | ||
48 | + } | ||
49 | +}; |
src/components/doc-act-list.vue
0 → 100644
1 | +<template> | ||
2 | + <Collapse accordion v-model="openAct" @on-change="actChange"> | ||
3 | + <Panel :name="act.name" v-for="act in list" :key="act.name"> | ||
4 | + {{act.name}}({{act.desc}}) | ||
5 | + <div slot="content" v-if="act.__rendered"> | ||
6 | + <h2>接口路径</h2> | ||
7 | + <div class="path">{{act.path}}</div> | ||
8 | + <h2>提交参数</h2> | ||
9 | + <Table :columns="reqColumns" :data="act.paramInfo"></Table> | ||
10 | + <h2>返回参数</h2> | ||
11 | + <Table :columns="resColumns" :data="[act.responseInfo]"></Table> | ||
12 | + </div> | ||
13 | + </Panel> | ||
14 | + </Collapse> | ||
15 | +</template> | ||
16 | + | ||
17 | +<script> | ||
18 | +export default { | ||
19 | + name: 'DocActList', | ||
20 | + props: { | ||
21 | + list: Array | ||
22 | + }, | ||
23 | + data() { | ||
24 | + return { | ||
25 | + openAct: [], | ||
26 | + reqColumns: [{ | ||
27 | + title: '名称', | ||
28 | + key: 'name' | ||
29 | + }, { | ||
30 | + title: '类型', | ||
31 | + key: 'paramType' | ||
32 | + }, { | ||
33 | + title: '必填', | ||
34 | + key: 'required' | ||
35 | + }, { | ||
36 | + title: '默认值', | ||
37 | + key: 'defaultValue' | ||
38 | + }, { | ||
39 | + title: '描述', | ||
40 | + key: 'desc' | ||
41 | + }], | ||
42 | + resColumns: [{ | ||
43 | + title: '类型', | ||
44 | + key: 'clazz' | ||
45 | + }, { | ||
46 | + title: '描述', | ||
47 | + key: 'desc' | ||
48 | + }], | ||
49 | + reqData: [], | ||
50 | + resData: [] | ||
51 | + }; | ||
52 | + }, | ||
53 | + methods: { | ||
54 | + actChange(open) { | ||
55 | + let act = this.list.find(a => a.name === open[0]); | ||
56 | + | ||
57 | + if (act) { | ||
58 | + act.__rendered = true; | ||
59 | + } | ||
60 | + } | ||
61 | + } | ||
62 | +}; | ||
63 | +</script> | ||
64 | + | ||
65 | +<style lang="scss"> | ||
66 | +.path { | ||
67 | + margin-bottom: 10px; | ||
68 | +} | ||
69 | +</style> |
src/components/doc-ctrl-list.vue
0 → 100644
1 | +<template> | ||
2 | + <div class="ctrl-list-box"> | ||
3 | + <h2> | ||
4 | + <span v-if="store.groupName">分组:{{store.groupName}}</span> | ||
5 | + <span v-if="store.apiKeyword">关键词:{{store.apiKeyword}}</span> | ||
6 | + <span v-if="store.apis.length"> | ||
7 | + 共 | ||
8 | + <span v-if="store.featchApising">...</span> | ||
9 | + <span v-else>{{store.apiCount}}</span> | ||
10 | + 条: | ||
11 | + </span> | ||
12 | + </h2> | ||
13 | + <div class="ctrl-list"> | ||
14 | + <Collapse accordion v-if="store.apis.length"> | ||
15 | + <Panel :name="ctrl.name" v-for="ctrl in store.apis" :key="ctrl.name"> | ||
16 | + {{ctrl.name}}({{ctrl.desc}}) | ||
17 | + <div slot="content"> | ||
18 | + <doc-act-list :list="ctrl.operationInfoList"></doc-act-list> | ||
19 | + </div> | ||
20 | + </Panel> | ||
21 | + </Collapse> | ||
22 | + <p class="no-data" v-else> | ||
23 | + <span v-if="store.groupName || store.apiKeyword">未查询到结果</span> | ||
24 | + <span v-else>请选择分组或者输入查询条件</span> | ||
25 | + </p> | ||
26 | + </div> | ||
27 | + <Page | ||
28 | + v-if="store.apis.length" | ||
29 | + class="pager" | ||
30 | + :total="store.apiCount" | ||
31 | + :current="store.apiPage" | ||
32 | + :page-size="store.apiRows" | ||
33 | + show-sizer | ||
34 | + show-total | ||
35 | + @on-page-size-change="pageSizeChange" | ||
36 | + @on-change="pageChange"></Page> | ||
37 | + </div> | ||
38 | +</template> | ||
39 | + | ||
40 | +<script> | ||
41 | +import { | ||
42 | + FETCH_API_REQUEST | ||
43 | +} from 'store/types'; | ||
44 | +import {mapState} from 'vuex'; | ||
45 | +export default { | ||
46 | + name: 'DocCtrlList', | ||
47 | + computed: { | ||
48 | + ...mapState(['store']) | ||
49 | + }, | ||
50 | + methods: { | ||
51 | + pageChange(page) { | ||
52 | + this.$store.dispatch(FETCH_API_REQUEST, {page: page}); | ||
53 | + }, | ||
54 | + pageSizeChange(rows) { | ||
55 | + this.$store.dispatch(FETCH_API_REQUEST, {rows: rows}); | ||
56 | + } | ||
57 | + } | ||
58 | +}; | ||
59 | +</script> | ||
60 | + | ||
61 | +<style lang="scss"> | ||
62 | +.ctrl-list-box { | ||
63 | + h2 { | ||
64 | + margin-bottom: 12px; | ||
65 | + } | ||
66 | + padding: 20px; | ||
67 | + | ||
68 | + .ctrl-list { | ||
69 | + margin-bottom: 20px; | ||
70 | + } | ||
71 | + | ||
72 | + .no-data { | ||
73 | + text-align: center; | ||
74 | + line-height: 50px; | ||
75 | + font-size: 12px; | ||
76 | + color: #9ea7b4; | ||
77 | + } | ||
78 | + | ||
79 | + .pager { | ||
80 | + text-align: center; | ||
81 | + } | ||
82 | +} | ||
83 | +</style> |
src/components/doc-header.vue
0 → 100644
1 | +<template> | ||
2 | + <div class="layout-header"> | ||
3 | + <div class="header-nav"> | ||
4 | + <div class="logo"> | ||
5 | + <h1>YOHO接口文档</h1> | ||
6 | + </div> | ||
7 | + </div> | ||
8 | + </div> | ||
9 | +</template> | ||
10 | + | ||
11 | +<script> | ||
12 | +export default { | ||
13 | + name: 'DocHeader' | ||
14 | +}; | ||
15 | +</script> | ||
16 | + | ||
17 | +<style lang="scss"> | ||
18 | + | ||
19 | +.layout-header { | ||
20 | + height: 60px; | ||
21 | + background: #fff; | ||
22 | + box-shadow: 0 1px 1px rgba(0,0,0,.1); | ||
23 | + margin-bottom: 2px; | ||
24 | + | ||
25 | + .header-nav { | ||
26 | + width: 90%; | ||
27 | + margin: 0 auto; | ||
28 | + } | ||
29 | + | ||
30 | + .logo { | ||
31 | + line-height: 60px; | ||
32 | + } | ||
33 | +} | ||
34 | +</style> |
src/components/doc-menu.vue
0 → 100644
1 | +<template> | ||
2 | + <i-menu width="auto" class="doc-menu" :active-name="store.groupName" @on-select="selectGroup"> | ||
3 | + <i-menu-group title="分组"> | ||
4 | + <i-menu-item | ||
5 | + :name="group.name" | ||
6 | + v-for="group in store.groups" | ||
7 | + :key="group.name"> | ||
8 | + {{group.desc}} | ||
9 | + <i-spin class="group-spin" | ||
10 | + size="small" | ||
11 | + v-if="store.groupName === group.name && store.featchApising"> | ||
12 | + <Icon type="load-c" size="14" class="spin-icon-load"></Icon> | ||
13 | + </i-spin> | ||
14 | + </i-menu-item> | ||
15 | + </i-menu-group> | ||
16 | + </i-menu> | ||
17 | +</template> | ||
18 | + | ||
19 | +<script> | ||
20 | +import { | ||
21 | + FETCH_GROUP_REQUEST, | ||
22 | + FETCH_API_REQUEST | ||
23 | +} from 'store/types'; | ||
24 | +import {mapState} from 'vuex'; | ||
25 | +export default { | ||
26 | + name: 'DocMenu', | ||
27 | + computed: { | ||
28 | + ...mapState(['store']) | ||
29 | + }, | ||
30 | + created() { | ||
31 | + this.$store.dispatch(FETCH_GROUP_REQUEST); | ||
32 | + }, | ||
33 | + methods: { | ||
34 | + selectGroup(groupName) { | ||
35 | + this.$store.dispatch(FETCH_API_REQUEST, {groupName}).then(() => { | ||
36 | + window.scrollTo(0, 0); | ||
37 | + }); | ||
38 | + } | ||
39 | + } | ||
40 | +}; | ||
41 | +</script> | ||
42 | + | ||
43 | +<style lang="scss"> | ||
44 | +.doc-menu { | ||
45 | + .ivu-menu-item { | ||
46 | + word-wrap: break-word; | ||
47 | + } | ||
48 | + | ||
49 | + .group-spin { | ||
50 | + display: inline-block; | ||
51 | + float: right; | ||
52 | + } | ||
53 | + | ||
54 | + .spin-icon-load { | ||
55 | + animation: ani-spin 1s linear infinite; | ||
56 | + } | ||
57 | + @keyframes ani-spin { | ||
58 | + from { transform: rotate(0deg);} | ||
59 | + 50% { transform: rotate(180deg);} | ||
60 | + to { transform: rotate(360deg);} | ||
61 | + } | ||
62 | +} | ||
63 | +</style> |
src/components/doc-search.vue
0 → 100644
1 | +<template> | ||
2 | + <div class="search-box"> | ||
3 | + <i-form ref="formInline" inline> | ||
4 | + <i-form-item> | ||
5 | + <Input v-model="keyword" style="width: 300px;"> | ||
6 | + <Select v-model="searchType" slot="prepend" style="width: 100px"> | ||
7 | + <Option value="controller">controller</Option> | ||
8 | + <Option value="keyword">关键词</Option> | ||
9 | + </Select> | ||
10 | + </Input> | ||
11 | + </i-form-item> | ||
12 | + <i-form-item> | ||
13 | + <i-button type="primary" @click="searchGroup" v-show="store.groupName">搜当前分组</i-button> | ||
14 | + <i-button type="primary" @click="searchAll" >搜全部</i-button> | ||
15 | + <i-button type="warning" @click="reset">清空</i-button> | ||
16 | + </i-form-item> | ||
17 | + </i-form> | ||
18 | + </div> | ||
19 | +</template> | ||
20 | + | ||
21 | +<script> | ||
22 | +import { | ||
23 | + FETCH_API_REQUEST | ||
24 | +} from 'store/types'; | ||
25 | +import {mapState} from 'vuex'; | ||
26 | +export default { | ||
27 | + name: 'DocSearch', | ||
28 | + computed: { | ||
29 | + ...mapState(['store']) | ||
30 | + }, | ||
31 | + data() { | ||
32 | + return { | ||
33 | + searchType: 'controller', | ||
34 | + keyword: '' | ||
35 | + }; | ||
36 | + }, | ||
37 | + methods: { | ||
38 | + searchGroup() { | ||
39 | + if (this.keyword) { | ||
40 | + this.$store.dispatch(FETCH_API_REQUEST, { | ||
41 | + groupName: this.store.groupName, | ||
42 | + keyword: this.keyword, | ||
43 | + searchType: this.searchType | ||
44 | + }).then(() => { | ||
45 | + window.scrollTo(0, 0); | ||
46 | + }); | ||
47 | + } | ||
48 | + }, | ||
49 | + searchAll() { | ||
50 | + if (this.keyword) { | ||
51 | + this.$store.dispatch(FETCH_API_REQUEST, { | ||
52 | + groupName: '', | ||
53 | + keyword: this.keyword, | ||
54 | + searchType: this.searchType | ||
55 | + }).then(() => { | ||
56 | + window.scrollTo(0, 0); | ||
57 | + }); | ||
58 | + } | ||
59 | + }, | ||
60 | + reset() { | ||
61 | + if (this.store.apiSearchType) { | ||
62 | + this.keyword = ''; | ||
63 | + this.$store.dispatch(FETCH_API_REQUEST, { | ||
64 | + groupName: this.store.groupName, | ||
65 | + keyword: '', | ||
66 | + searchType: '' | ||
67 | + }).then(() => { | ||
68 | + window.scrollTo(0, 0); | ||
69 | + }); | ||
70 | + } | ||
71 | + } | ||
72 | + } | ||
73 | +}; | ||
74 | +</script> | ||
75 | + | ||
76 | +<style lang="scss"> | ||
77 | +.search-box { | ||
78 | + padding: 20px; | ||
79 | + border-bottom: solid 1px #dddee1; | ||
80 | + | ||
81 | + .ivu-form-item { | ||
82 | + margin-bottom: 0; | ||
83 | + } | ||
84 | +} | ||
85 | +</style> |
src/components/index.js
0 → 100644
1 | +import DocMenu from './doc-menu'; | ||
2 | +import DocSearch from './doc-search'; | ||
3 | +import DocCtrlList from './doc-ctrl-list'; | ||
4 | +import DocActList from './doc-act-list'; | ||
5 | +import DocHeader from './doc-header'; | ||
6 | + | ||
7 | +export default { | ||
8 | + DocMenu, | ||
9 | + DocSearch, | ||
10 | + DocCtrlList, | ||
11 | + DocActList, | ||
12 | + DocHeader | ||
13 | +}; |
src/config/index.js
0 → 100644
src/index.html
0 → 100644
1 | +<!DOCTYPE html> | ||
2 | +<html lang="en"> | ||
3 | +<head> | ||
4 | + <meta charset="utf-8"> | ||
5 | + <title></title> | ||
6 | + <meta name="keywords" content=""> | ||
7 | + <meta name="description" content=""> | ||
8 | + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> | ||
9 | + <meta name="apple-mobile-web-app-status-bar-style" content="black"> | ||
10 | + <meta content="telephone=no" name="format-detection"> | ||
11 | + <meta content="email=no" name="format-detection"> | ||
12 | +</head> | ||
13 | +<body> | ||
14 | + <div id="app"></div> | ||
15 | +</body> | ||
16 | +</html> |
src/pages/home/home.vue
0 → 100644
1 | +<template> | ||
2 | + <div class="layout"> | ||
3 | + <doc-header></doc-header> | ||
4 | + <div class="layout-content"> | ||
5 | + <div class="layout-left"> | ||
6 | + <doc-menu></doc-menu> | ||
7 | + </div> | ||
8 | + <div class="layout-right"> | ||
9 | + <article> | ||
10 | + <doc-search></doc-search> | ||
11 | + <doc-ctrl-list></doc-ctrl-list> | ||
12 | + </article> | ||
13 | + </div> | ||
14 | + </div> | ||
15 | + </div> | ||
16 | +</template> | ||
17 | + | ||
18 | +<script> | ||
19 | +export default { | ||
20 | + name: 'home' | ||
21 | +}; | ||
22 | +</script> | ||
23 | + | ||
24 | +<style lang="scss"> | ||
25 | +.layout { | ||
26 | + display: flex; | ||
27 | + flex-direction: column; | ||
28 | + background: #f5f7f9; | ||
29 | +} | ||
30 | +.layout-content { | ||
31 | + background: #fff; | ||
32 | + width: 90%; | ||
33 | + margin: 30px auto 20px; | ||
34 | + border-radius: 6px; | ||
35 | + box-shadow: 0 1px 1px 0 rgba(0,0,0,.1); | ||
36 | + display: flex; | ||
37 | + flex-direction: row; | ||
38 | + flex: auto; | ||
39 | +} | ||
40 | +.layout-left { | ||
41 | + width: 200px; | ||
42 | + padding-top: 5px; | ||
43 | + padding-bottom: 5px; | ||
44 | +} | ||
45 | +.layout-right { | ||
46 | + flex: auto; | ||
47 | + position: relative; | ||
48 | + | ||
49 | + & article:after { | ||
50 | + content: ""; | ||
51 | + display: block; | ||
52 | + width: 1px; | ||
53 | + height: 100%; | ||
54 | + background: #dddee1; | ||
55 | + position: absolute; | ||
56 | + top: 0; | ||
57 | + bottom: 0; | ||
58 | + left: -1px; | ||
59 | + z-index: 1 | ||
60 | + } | ||
61 | +} | ||
62 | +</style> |
src/pages/home/index.js
0 → 100644
src/plugins/core.js
0 → 100644
1 | +/** | ||
2 | + * 插件 | ||
3 | + */ | ||
4 | +import store from 'yoho-store'; | ||
5 | +import cookie from 'yoho-cookie'; | ||
6 | +import iView from 'iview'; | ||
7 | +import 'iview/dist/styles/iview.css'; | ||
8 | +import components from '../components'; | ||
9 | +import _ from 'lodash/core'; | ||
10 | + | ||
11 | +export default { | ||
12 | + loadGlobalComponents(Vue) { | ||
13 | + _.each(components, component => { | ||
14 | + if (component.length) { | ||
15 | + Vue.component(component[0], component[1]); | ||
16 | + } else { | ||
17 | + Vue.component(component.name, component); | ||
18 | + } | ||
19 | + }); | ||
20 | + }, | ||
21 | + defineVueProp(Vue) { | ||
22 | + Vue.prop = (key, value) => { | ||
23 | + Vue[`$${key}`] = Vue.prototype[`$${key}`] = value; | ||
24 | + }; | ||
25 | + }, | ||
26 | + install(Vue) { | ||
27 | + // 定义Vue全局属性 | ||
28 | + this.defineVueProp(Vue); | ||
29 | + | ||
30 | + // 加载核心组件 | ||
31 | + this.loadGlobalComponents(Vue); | ||
32 | + | ||
33 | + // 附加Vue原型属性 | ||
34 | + Vue.prop('store', store); | ||
35 | + Vue.prop('cookie', cookie); | ||
36 | + | ||
37 | + Vue.use(iView); | ||
38 | + } | ||
39 | +}; |
src/router/index.js
0 → 100644
1 | +import Vue from 'vue'; | ||
2 | +import Router from 'vue-router'; | ||
3 | +import pages from '../pages'; | ||
4 | +import _ from 'lodash'; | ||
5 | + | ||
6 | +Vue.use(Router); | ||
7 | + | ||
8 | +const loadRoutes = (rous, paths, children) => { | ||
9 | + if (_.has(rous, 'path')) { | ||
10 | + let ps = _.flattenDeep(paths).filter(p => p); | ||
11 | + | ||
12 | + if (_.last(ps) === rous.name) { | ||
13 | + ps.splice(ps.length - 1, 1); | ||
14 | + } | ||
15 | + if (!children) { | ||
16 | + if (rous.path) { | ||
17 | + rous.path = '/' + ps.join('/') + (rous.path[0] === '/' ? '' : '/') + rous.path; | ||
18 | + } else { | ||
19 | + rous.path = ps.join('/') + '.html'; | ||
20 | + } | ||
21 | + } | ||
22 | + rous.name = _.concat(ps, [rous.name]).join('.'); | ||
23 | + | ||
24 | + if (rous.children) { | ||
25 | + _.each(rous.children, child => loadRoutes(child, [paths, child.name], true)); | ||
26 | + return [rous]; | ||
27 | + } | ||
28 | + return [rous]; | ||
29 | + } | ||
30 | + if (rous.length) { | ||
31 | + return _.map(rous, r => { | ||
32 | + return loadRoutes(r, [paths]); | ||
33 | + }); | ||
34 | + } else { | ||
35 | + return _.map(rous, (rou, k) => { | ||
36 | + return loadRoutes(rou, [paths, k]); | ||
37 | + }); | ||
38 | + } | ||
39 | +}; | ||
40 | + | ||
41 | +const routes = _.flattenDeep(loadRoutes(pages)); | ||
42 | + | ||
43 | +export function createRouter() { | ||
44 | + return new Router({ | ||
45 | + mode: 'history', | ||
46 | + routes, | ||
47 | + scrollBehavior(to, from, savedPosition) { | ||
48 | + if (savedPosition) { | ||
49 | + return savedPosition; | ||
50 | + } else { | ||
51 | + return { x: 0, y: 0 }; | ||
52 | + } | ||
53 | + } | ||
54 | + }); | ||
55 | +} |
src/store/index.js
0 → 100644
src/store/store.js
0 → 100644
1 | +import { | ||
2 | + FETCH_API_FAILURE, | ||
3 | + FETCH_API_REQUEST, | ||
4 | + FETCH_API_SUCCESS, | ||
5 | + FETCH_GROUP_FAILURE, | ||
6 | + FETCH_GROUP_REQUEST, | ||
7 | + FETCH_GROUP_SUCCESS | ||
8 | +} from './types'; | ||
9 | +import api from 'common/api'; | ||
10 | + | ||
11 | +export default { | ||
12 | + state: { | ||
13 | + cacheApis: {}, | ||
14 | + groups: [], | ||
15 | + fetchGroupsing: false, | ||
16 | + apis: [], | ||
17 | + featchApising: false, | ||
18 | + groupName: '', | ||
19 | + apiPage: 1, | ||
20 | + apiRows: 10, | ||
21 | + apiCount: 0, | ||
22 | + apiKeyword: '', | ||
23 | + apiSearchType: '' | ||
24 | + }, | ||
25 | + mutations: { | ||
26 | + [FETCH_GROUP_REQUEST](state) { | ||
27 | + state.fetchGroupsing = true; | ||
28 | + }, | ||
29 | + [FETCH_GROUP_FAILURE](state) { | ||
30 | + state.fetchGroupsing = false; | ||
31 | + }, | ||
32 | + [FETCH_GROUP_SUCCESS](state, params) { | ||
33 | + state.fetchGroupsing = false; | ||
34 | + state.groups = params.list; | ||
35 | + | ||
36 | + params.list.forEach(group => { | ||
37 | + state.cacheApis[group.name] = { | ||
38 | + rows: [], | ||
39 | + total: 0 | ||
40 | + }; | ||
41 | + }); | ||
42 | + }, | ||
43 | + [FETCH_API_REQUEST](state, params) { | ||
44 | + if (params.groupName === '') { | ||
45 | + state.groupName = ''; | ||
46 | + } else if (params.groupName) { | ||
47 | + state.groupName = params.groupName; | ||
48 | + } | ||
49 | + state.apiSearchType = params.searchType; | ||
50 | + state.apiKeyword = params.keyword; | ||
51 | + state.apiPage = params.page || 1; | ||
52 | + state.apiRows = params.rows || state.apiRows; | ||
53 | + state.featchApising = true; | ||
54 | + }, | ||
55 | + [FETCH_API_FAILURE](state) { | ||
56 | + state.featchApising = false; | ||
57 | + }, | ||
58 | + [FETCH_API_SUCCESS](state, params) { | ||
59 | + state.featchApising = false; | ||
60 | + state.apiCount = params.data.total; | ||
61 | + state.apis = params.data.rows; | ||
62 | + | ||
63 | + if (!state.apiSearchType && state.groupName && !params.cache) { | ||
64 | + const groupCache = state.cacheApis[state.groupName]; | ||
65 | + const start = (state.apiPage - 1) * state.apiRows; | ||
66 | + | ||
67 | + if (groupCache.rows.length >= start) { | ||
68 | + groupCache.rows.splice(start, state.apiRows, params.data.rows); | ||
69 | + groupCache.total = params.data.total; | ||
70 | + } | ||
71 | + } | ||
72 | + } | ||
73 | + }, | ||
74 | + actions: { | ||
75 | + [FETCH_GROUP_REQUEST]({commit}) { | ||
76 | + commit(FETCH_GROUP_REQUEST); | ||
77 | + return api.get('/gateway/api/findGroup').then(res => { | ||
78 | + commit(FETCH_GROUP_SUCCESS, {list: res}); | ||
79 | + }, () => { | ||
80 | + commit(FETCH_GROUP_FAILURE); | ||
81 | + }); | ||
82 | + }, | ||
83 | + [FETCH_API_REQUEST]({commit, state}, params) { | ||
84 | + let apiPromise; | ||
85 | + | ||
86 | + if (state.apiSearchType === 'controller') { | ||
87 | + apiPromise = api.get('/gateway/api/findByName', { | ||
88 | + groupName: state.groupName || void 0, | ||
89 | + key: state.apiKeyword, | ||
90 | + page: state.apiPage, | ||
91 | + rows: state.apiRows | ||
92 | + }); | ||
93 | + } else if (state.apiSearchType === 'keyword') { | ||
94 | + apiPromise = api.get('/gateway/api/find', { | ||
95 | + groupName: state.groupName || void 0, | ||
96 | + key: state.apiKeyword, | ||
97 | + page: state.apiPage, | ||
98 | + rows: state.apiRows | ||
99 | + }); | ||
100 | + } else { | ||
101 | + const cacheGroup = state.cacheApis[state.groupName]; | ||
102 | + const start = (state.apiPage - 1) * state.apiRows; | ||
103 | + | ||
104 | + if (cacheGroup.rows.length >= (start + state.apiRows)) { | ||
105 | + commit(FETCH_API_SUCCESS, { | ||
106 | + data: { | ||
107 | + total: cacheGroup.total, | ||
108 | + rows: cacheGroup.rows.slice(start, state.apiRows) | ||
109 | + }, | ||
110 | + cache: true | ||
111 | + }); | ||
112 | + return Promise.resolve(); | ||
113 | + } | ||
114 | + apiPromise = api.get('/gateway/api/findByGroup', { | ||
115 | + key: state.groupName, | ||
116 | + page: state.apiPage, | ||
117 | + rows: state.apiRows | ||
118 | + }); | ||
119 | + } | ||
120 | + commit(FETCH_API_REQUEST, params); | ||
121 | + return apiPromise.then(res => { | ||
122 | + if (res.code === 200) { | ||
123 | + setTimeout(function() { | ||
124 | + commit(FETCH_API_SUCCESS, {data: res.data}); | ||
125 | + }, 1000); | ||
126 | + } else { | ||
127 | + commit(FETCH_API_FAILURE); | ||
128 | + } | ||
129 | + }, () => { | ||
130 | + commit(FETCH_API_FAILURE); | ||
131 | + }); | ||
132 | + } | ||
133 | + } | ||
134 | +}; |
src/store/types.js
0 → 100644
1 | +export const FETCH_GROUP_REQUEST = 'FETCH_GROUP_REQUEST'; | ||
2 | +export const FETCH_GROUP_SUCCESS = 'FETCH_GROUP_SUCCESS'; | ||
3 | +export const FETCH_GROUP_FAILURE = 'FETCH_GROUP_FAILURE'; | ||
4 | + | ||
5 | +export const FETCH_API_REQUEST = 'FETCH_API_REQUEST'; | ||
6 | +export const FETCH_API_SUCCESS = 'FETCH_API_SUCCESS'; | ||
7 | +export const FETCH_API_FAILURE = 'FETCH_API_FAILURE'; | ||
8 | + |
yarn.lock
0 → 100644
This diff could not be displayed because it is too large.
-
Please register or login to post a comment