Authored by 陈峰

init

  1 +{
  2 + "presets": ["es2015"],
  3 + "plugins": [
  4 + "transform-runtime",
  5 + "transform-vue-jsx",
  6 + "transform-object-rest-spread",
  7 + "syntax-dynamic-import"
  8 + ]
  9 +}
  1 +root = true
  2 +
  3 +[*]
  4 +indent_style = space
  5 +indent_size = 4
  6 +end_of_line = lf
  7 +charset = utf-8
  8 +trim_trailing_whitespace = true
  9 +insert_final_newline = true
  10 +
  11 +[*.md]
  12 +trim_trailing_whitespace = false
  1 +**/bundle/**/*.js
  2 +**/dist/**/*.js
  3 +coverage
  1 +{
  2 + "parser": "babel-eslint",
  3 + "env": {
  4 + "es6": true
  5 + },
  6 + "extends": "yoho",
  7 + "parserOptions": {
  8 + "sourceType": "module"
  9 + },
  10 + "plugins": [
  11 + "html"
  12 + ],
  13 + "rules": {
  14 + "camelcase": "off",
  15 + "max-len": "off"
  16 + }
  17 +}
  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/
  1 +phantomjs_cdnurl=http://npm.taobao.org/mirrors/phantomjs
  2 +sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
  1 +**/css/**/*.css
  2 +**/dist/**/*.css
  1 +{
  2 + "extends": "stylelint-config-yoho",
  3 + "processors": ["stylelint-processor-html"]
  4 +}
  1 +## YOHO-API-DOC
  2 +接口文档
  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 +});
  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 +
  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 +};
  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 +};
  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 +};
  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 +};
  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 +
  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;
  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 +}
  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 +});
  1 +<template>
  2 + <div id="app">
  3 + <router-view></router-view>
  4 + </div>
  5 +</template>
  6 +
  7 +<script>
  8 +export default {
  9 + name: 'App'
  10 +};
  11 +</script>
  12 +
  13 +<style>
  14 +</style>
  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 +};
  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>
  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>
  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>
  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>
  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>
  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 +};
  1 +const config = {
  2 + dev: {
  3 + axiosBaseUrl: 'http://172.16.6.201:8080',
  4 + axiosResponseType: 'json',
  5 + },
  6 + production: {
  7 + axiosBaseUrl: 'http://172.16.6.201:8080',
  8 + axiosResponseType: 'json',
  9 + }
  10 +};
  11 +
  12 +
  13 +export default config[process.env.NODE_ENV];
  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>
  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>
  1 +export default {
  2 + path: '/home.html',
  3 + alias: '/',
  4 + name: 'home',
  5 + component: () => import(/* webpackChunkName: "home.home" */'./home'),
  6 +};
  1 +import home from './home';
  2 +
  3 +export default {
  4 + home
  5 +};
  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 +};
  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 +}
  1 +import Vue from 'vue';
  2 +import Vuex from 'vuex';
  3 +
  4 +import store from './store';
  5 +
  6 +
  7 +Vue.use(Vuex);
  8 +
  9 +export function createStore() {
  10 + return new Vuex.Store({
  11 + modules: {
  12 + store
  13 + },
  14 + strict: process.env.NODE_ENV !== 'production'
  15 + });
  16 +}
  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 +};
  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 +
This diff could not be displayed because it is too large.