Authored by 陈峰

init

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