├── .babelrc
├── .editorconfig
├── .gitignore
├── .postcssrc.js
├── Dockerfile
├── LICENSE
├── README.md
├── build
├── build.js
├── check-versions.js
├── utils.js
├── vue-loader.conf.js
├── webpack.base.conf.js
├── webpack.dev.conf.js
└── webpack.prod.conf.js
├── config
├── dev.env.js
├── index.js
└── prod.env.js
├── default.conf
├── index.html
├── package-lock.json
├── package.json
├── src
├── App.vue
├── assets
│ ├── images
│ │ ├── bottom-left.png
│ │ └── bottom-right.png
│ └── styles
│ │ ├── home.css
│ │ ├── icon-font
│ │ ├── iconfont.eot
│ │ ├── iconfont.svg
│ │ ├── iconfont.ttf
│ │ └── iconfont.woff
│ │ ├── iconfont.css
│ │ ├── reports.css
│ │ ├── swagger.css
│ │ └── tree.css
├── main.js
├── pages
│ ├── auth
│ │ ├── Login.vue
│ │ ├── Register.vue
│ │ └── components
│ │ │ ├── Login.vue
│ │ │ └── Register.vue
│ ├── config
│ │ ├── RecordConfig.vue
│ │ └── components
│ │ │ ├── ConfigBody.vue
│ │ │ └── ConfigList.vue
│ ├── fastrunner
│ │ ├── api
│ │ │ ├── RecordApi.vue
│ │ │ └── components
│ │ │ │ ├── ApiBody.vue
│ │ │ │ └── ApiList.vue
│ │ ├── case
│ │ │ ├── AutoTest.vue
│ │ │ └── components
│ │ │ │ ├── EditTest.vue
│ │ │ │ ├── TestBody.vue
│ │ │ │ └── TestList.vue
│ │ └── config
│ │ │ ├── RecordConfig.vue
│ │ │ └── components
│ │ │ ├── ConfigBody.vue
│ │ │ └── ConfigList.vue
│ ├── home
│ │ ├── Home.vue
│ │ └── components
│ │ │ ├── Header.vue
│ │ │ └── Side.vue
│ ├── httprunner
│ │ ├── DebugTalk.vue
│ │ └── components
│ │ │ ├── Extract.vue
│ │ │ ├── Headers.vue
│ │ │ ├── Hooks.vue
│ │ │ ├── Parameters.vue
│ │ │ ├── Request.vue
│ │ │ ├── Validate.vue
│ │ │ └── Variables.vue
│ ├── project
│ │ ├── DataBase.vue
│ │ ├── ProjectDetail.vue
│ │ └── ProjectList.vue
│ ├── reports
│ │ ├── DebugReport.vue
│ │ └── ReportList.vue
│ ├── task
│ │ ├── AddTasks.vue
│ │ └── Tasks.vue
│ └── variables
│ │ ├── GlobalEnv.vue
│ │ └── HostAddress.vue
├── restful
│ └── api.js
├── router
│ └── index.js
└── store
│ ├── index.js
│ ├── mutations.js
│ └── state.js
└── static
├── .gitkeep
└── favicon.ico
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false,
5 | "targets": {
6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
7 | }
8 | }],
9 | "stage-2"
10 | ],
11 | "plugins": ["transform-vue-jsx", "transform-runtime"]
12 | }
13 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Editor directories and files
9 | .idea
10 | .vscode
11 | *.suo
12 | *.ntvs*
13 | *.njsproj
14 | *.sln
15 |
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | "postcss-import": {},
6 | "postcss-url": {},
7 | // to edit target browsers: use "browserslist" field in package.json
8 | "autoprefixer": {}
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM hub.c.163.com/library/nginx
2 |
3 | MAINTAINER yinquanwang
4 |
5 | RUN rm /etc/nginx/conf.d/default.conf
6 |
7 | RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
8 |
9 | ADD default.conf /etc/nginx/conf.d/
10 |
11 | COPY dist/ /usr/share/nginx/html/
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 yinquanwang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FasterWeb
2 |
3 | 
4 | > FasterWeb that depends FasterRunner
5 |
6 | ## 本地开发环境部署
7 |
8 | ``` bash
9 | # install dependencies
10 | npm install
11 |
12 | # serve with hot reload at localhost:8080
13 | npm run dev
14 |
15 | ```
16 |
17 | 测试
18 | -----------
19 |
20 | 1. open url(recommend chrome): http://localhost:8080/fastrunner/register
21 |
22 | ## Docker 部署 nginx模式
23 | --------------
24 | 1. 修改default.conf配置文件 server_name的ip(宿主机IP), 端口默认8080
25 | 2. 修改/src/restful/api.js baseUrl地址, 即为fastrunner容器运行的宿主机地址
26 | 3. 执行npm install, npm run build # 生成生产环境包
27 | 3. docker build -t fasterweb:latest . # 构建docker镜像
28 | 4. docker run -d --name fasterweb --net=host --restart always fasterweb:latest # 后台运行docker容器
29 | 5. open url: http://宿主机ip:8080/fastrunner/register
30 |
--------------------------------------------------------------------------------
/build/build.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | require('./check-versions')()
3 |
4 | process.env.NODE_ENV = 'production'
5 |
6 | const ora = require('ora')
7 | const rm = require('rimraf')
8 | const path = require('path')
9 | const chalk = require('chalk')
10 | const webpack = require('webpack')
11 | const config = require('../config')
12 | const webpackConfig = require('./webpack.prod.conf')
13 |
14 | const spinner = ora('building for production...')
15 | spinner.start()
16 |
17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
18 | if (err) throw err
19 | webpack(webpackConfig, (err, stats) => {
20 | spinner.stop()
21 | if (err) throw err
22 | process.stdout.write(stats.toString({
23 | colors: true,
24 | modules: false,
25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
26 | chunks: false,
27 | chunkModules: false
28 | }) + '\n\n')
29 |
30 | if (stats.hasErrors()) {
31 | console.log(chalk.red(' Build failed with errors.\n'))
32 | process.exit(1)
33 | }
34 |
35 | console.log(chalk.cyan(' Build complete.\n'))
36 | console.log(chalk.yellow(
37 | ' Tip: built files are meant to be served over an HTTP server.\n' +
38 | ' Opening index.html over file:// won\'t work.\n'
39 | ))
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/build/check-versions.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const chalk = require('chalk')
3 | const semver = require('semver')
4 | const packageConfig = require('../package.json')
5 | const shell = require('shelljs')
6 |
7 | function exec (cmd) {
8 | return require('child_process').execSync(cmd).toString().trim()
9 | }
10 |
11 | const versionRequirements = [
12 | {
13 | name: 'node',
14 | currentVersion: semver.clean(process.version),
15 | versionRequirement: packageConfig.engines.node
16 | }
17 | ]
18 |
19 | if (shell.which('npm')) {
20 | versionRequirements.push({
21 | name: 'npm',
22 | currentVersion: exec('npm --version'),
23 | versionRequirement: packageConfig.engines.npm
24 | })
25 | }
26 |
27 | module.exports = function () {
28 | const warnings = []
29 |
30 | for (let i = 0; i < versionRequirements.length; i++) {
31 | const mod = versionRequirements[i]
32 |
33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
34 | warnings.push(mod.name + ': ' +
35 | chalk.red(mod.currentVersion) + ' should be ' +
36 | chalk.green(mod.versionRequirement)
37 | )
38 | }
39 | }
40 |
41 | if (warnings.length) {
42 | console.log('')
43 | console.log(chalk.yellow('To use this template, you must update following to modules:'))
44 | console.log()
45 |
46 | for (let i = 0; i < warnings.length; i++) {
47 | const warning = warnings[i]
48 | console.log(' ' + warning)
49 | }
50 |
51 | console.log()
52 | process.exit(1)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/build/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const config = require('../config')
4 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
5 | const packageConfig = require('../package.json')
6 |
7 | exports.assetsPath = function (_path) {
8 | const assetsSubDirectory = process.env.NODE_ENV === 'production'
9 | ? config.build.assetsSubDirectory
10 | : config.dev.assetsSubDirectory
11 |
12 | return path.posix.join(assetsSubDirectory, _path)
13 | }
14 |
15 | exports.cssLoaders = function (options) {
16 | options = options || {}
17 |
18 | const cssLoader = {
19 | loader: 'css-loader',
20 | options: {
21 | sourceMap: options.sourceMap
22 | }
23 | }
24 |
25 | const postcssLoader = {
26 | loader: 'postcss-loader',
27 | options: {
28 | sourceMap: options.sourceMap
29 | }
30 | }
31 |
32 | // generate loader string to be used with extract text plugin
33 | function generateLoaders (loader, loaderOptions) {
34 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
35 |
36 | if (loader) {
37 | loaders.push({
38 | loader: loader + '-loader',
39 | options: Object.assign({}, loaderOptions, {
40 | sourceMap: options.sourceMap
41 | })
42 | })
43 | }
44 |
45 | // Extract CSS when that option is specified
46 | // (which is the case during production build)
47 | if (options.extract) {
48 | return ExtractTextPlugin.extract({
49 | use: loaders,
50 | fallback: 'vue-style-loader'
51 | })
52 | } else {
53 | return ['vue-style-loader'].concat(loaders)
54 | }
55 | }
56 |
57 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html
58 | return {
59 | css: generateLoaders(),
60 | postcss: generateLoaders(),
61 | less: generateLoaders('less'),
62 | sass: generateLoaders('sass', { indentedSyntax: true }),
63 | scss: generateLoaders('sass'),
64 | stylus: generateLoaders('stylus'),
65 | styl: generateLoaders('stylus')
66 | }
67 | }
68 |
69 | // Generate loaders for standalone style files (outside of .vue)
70 | exports.styleLoaders = function (options) {
71 | const output = []
72 | const loaders = exports.cssLoaders(options)
73 |
74 | for (const extension in loaders) {
75 | const loader = loaders[extension]
76 | output.push({
77 | test: new RegExp('\\.' + extension + '$'),
78 | use: loader
79 | })
80 | }
81 |
82 | return output
83 | }
84 |
85 | exports.createNotifierCallback = () => {
86 | const notifier = require('node-notifier')
87 |
88 | return (severity, errors) => {
89 | if (severity !== 'error') return
90 |
91 | const error = errors[0]
92 | const filename = error.file && error.file.split('!').pop()
93 |
94 | notifier.notify({
95 | title: packageConfig.name,
96 | message: severity + ': ' + error.name,
97 | subtitle: filename || '',
98 | icon: path.join(__dirname, 'logo.png')
99 | })
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/build/vue-loader.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const config = require('../config')
4 | const isProduction = process.env.NODE_ENV === 'production'
5 | const sourceMapEnabled = isProduction
6 | ? config.build.productionSourceMap
7 | : config.dev.cssSourceMap
8 |
9 | module.exports = {
10 | loaders: utils.cssLoaders({
11 | sourceMap: sourceMapEnabled,
12 | extract: isProduction
13 | }),
14 | cssSourceMap: sourceMapEnabled,
15 | cacheBusting: config.dev.cacheBusting,
16 | transformToRequire: {
17 | video: ['src', 'poster'],
18 | source: 'src',
19 | img: 'src',
20 | image: 'xlink:href'
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const config = require('../config')
5 | const vueLoaderConfig = require('./vue-loader.conf')
6 |
7 | function resolve(dir) {
8 | return path.join(__dirname, '..', dir)
9 | }
10 |
11 |
12 | module.exports = {
13 | context: path.resolve(__dirname, '../'),
14 | entry: {
15 | app: './src/main.js'
16 | },
17 | output: {
18 | path: config.build.assetsRoot,
19 | filename: '[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 | '@': resolve('src'),
29 | 'styles': resolve('src/assets/styles'),
30 | }
31 | },
32 | module: {
33 | rules: [
34 | {
35 | test: /\.vue$/,
36 | loader: 'vue-loader',
37 | options: vueLoaderConfig
38 | },
39 | {
40 | test: /\.js$/,
41 | loader: 'babel-loader',
42 | include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
43 | },
44 | {
45 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
46 | loader: 'url-loader',
47 | options: {
48 | limit: 10000,
49 | name: utils.assetsPath('img/[name].[hash:7].[ext]')
50 | }
51 | },
52 | {
53 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
54 | loader: 'url-loader',
55 | options: {
56 | limit: 10000,
57 | name: utils.assetsPath('media/[name].[hash:7].[ext]')
58 | }
59 | },
60 | {
61 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
62 | loader: 'url-loader',
63 | options: {
64 | limit: 10000,
65 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
66 | }
67 | }
68 | ]
69 | },
70 | node: {
71 | // prevent webpack from injecting useless setImmediate polyfill because Vue
72 | // source contains it (although only uses it if it's native).
73 | setImmediate: false,
74 | // prevent webpack from injecting mocks to Node native modules
75 | // that does not make sense for the client
76 | dgram: 'empty',
77 | fs: 'empty',
78 | net: 'empty',
79 | tls: 'empty',
80 | child_process: 'empty'
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const webpack = require('webpack')
4 | const config = require('../config')
5 | const merge = require('webpack-merge')
6 | const path = require('path')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
11 | const portfinder = require('portfinder')
12 |
13 | const HOST = process.env.HOST
14 | const PORT = process.env.PORT && Number(process.env.PORT)
15 |
16 | const devWebpackConfig = merge(baseWebpackConfig, {
17 | module: {
18 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
19 | },
20 | // cheap-module-eval-source-map is faster for development
21 | devtool: config.dev.devtool,
22 |
23 | // these devServer options should be customized in /config/index.js
24 | devServer: {
25 | clientLogLevel: 'warning',
26 | historyApiFallback: {
27 | rewrites: [
28 | { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
29 | ],
30 | },
31 | hot: true,
32 | contentBase: false, // since we use CopyWebpackPlugin.
33 | compress: true,
34 | host: HOST || config.dev.host,
35 | port: PORT || config.dev.port,
36 | open: config.dev.autoOpenBrowser,
37 | overlay: config.dev.errorOverlay
38 | ? { warnings: false, errors: true }
39 | : false,
40 | publicPath: config.dev.assetsPublicPath,
41 | proxy: config.dev.proxyTable,
42 | quiet: true, // necessary for FriendlyErrorsPlugin
43 | watchOptions: {
44 | poll: config.dev.poll,
45 | }
46 | },
47 | plugins: [
48 | new webpack.DefinePlugin({
49 | 'process.env': require('../config/dev.env')
50 | }),
51 | new webpack.HotModuleReplacementPlugin(),
52 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
53 | new webpack.NoEmitOnErrorsPlugin(),
54 | // https://github.com/ampedandwired/html-webpack-plugin
55 | new HtmlWebpackPlugin({
56 | filename: 'index.html',
57 | template: 'index.html',
58 | inject: true
59 | }),
60 | // copy custom static assets
61 | new CopyWebpackPlugin([
62 | {
63 | from: path.resolve(__dirname, '../static'),
64 | to: config.dev.assetsSubDirectory,
65 | ignore: ['.*']
66 | }
67 | ])
68 | ]
69 | })
70 |
71 | module.exports = new Promise((resolve, reject) => {
72 | portfinder.basePort = process.env.PORT || config.dev.port
73 | portfinder.getPort((err, port) => {
74 | if (err) {
75 | reject(err)
76 | } else {
77 | // publish the new Port, necessary for e2e tests
78 | process.env.PORT = port
79 | // add port to devServer config
80 | devWebpackConfig.devServer.port = port
81 |
82 | // Add FriendlyErrorsPlugin
83 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
84 | compilationSuccessInfo: {
85 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
86 | },
87 | onErrors: config.dev.notifyOnErrors
88 | ? utils.createNotifierCallback()
89 | : undefined
90 | }))
91 |
92 | resolve(devWebpackConfig)
93 | }
94 | })
95 | })
96 |
--------------------------------------------------------------------------------
/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const webpack = require('webpack')
5 | const config = require('../config')
6 | const merge = require('webpack-merge')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
12 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
13 |
14 | const env = require('../config/prod.env')
15 |
16 | const webpackConfig = merge(baseWebpackConfig, {
17 | module: {
18 | rules: utils.styleLoaders({
19 | sourceMap: config.build.productionSourceMap,
20 | extract: true,
21 | usePostCSS: true
22 | })
23 | },
24 | devtool: config.build.productionSourceMap ? config.build.devtool : false,
25 | output: {
26 | path: config.build.assetsRoot,
27 | filename: utils.assetsPath('js/[name].[chunkhash].js'),
28 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
29 | },
30 | plugins: [
31 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
32 | new webpack.DefinePlugin({
33 | 'process.env': env
34 | }),
35 | new UglifyJsPlugin({
36 | uglifyOptions: {
37 | compress: {
38 | warnings: false
39 | }
40 | },
41 | sourceMap: config.build.productionSourceMap,
42 | parallel: true
43 | }),
44 | // extract css into its own file
45 | new ExtractTextPlugin({
46 | filename: utils.assetsPath('css/[name].[contenthash].css'),
47 | // Setting the following option to `false` will not extract CSS from codesplit chunks.
48 | // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
49 | // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
50 | // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
51 | allChunks: true,
52 | }),
53 | // Compress extracted CSS. We are using this plugin so that possible
54 | // duplicated CSS from different components can be deduped.
55 | new OptimizeCSSPlugin({
56 | cssProcessorOptions: config.build.productionSourceMap
57 | ? { safe: true, map: { inline: false } }
58 | : { safe: true }
59 | }),
60 | // generate dist index.html with correct asset hash for caching.
61 | // you can customize output by editing /index.html
62 | // see https://github.com/ampedandwired/html-webpack-plugin
63 | new HtmlWebpackPlugin({
64 | filename: config.build.index,
65 | template: 'index.html',
66 | inject: true,
67 | minify: {
68 | removeComments: true,
69 | collapseWhitespace: true,
70 | removeAttributeQuotes: true
71 | // more options:
72 | // https://github.com/kangax/html-minifier#options-quick-reference
73 | },
74 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
75 | chunksSortMode: 'dependency'
76 | }),
77 | // keep module.id stable when vendor modules does not change
78 | new webpack.HashedModuleIdsPlugin(),
79 | // enable scope hoisting
80 | new webpack.optimize.ModuleConcatenationPlugin(),
81 | // split vendor js into its own file
82 | new webpack.optimize.CommonsChunkPlugin({
83 | name: 'vendor',
84 | minChunks (module) {
85 | // any required modules inside node_modules are extracted to vendor
86 | return (
87 | module.resource &&
88 | /\.js$/.test(module.resource) &&
89 | module.resource.indexOf(
90 | path.join(__dirname, '../node_modules')
91 | ) === 0
92 | )
93 | }
94 | }),
95 | // extract webpack runtime and module manifest to its own file in order to
96 | // prevent vendor hash from being updated whenever app bundle is updated
97 | new webpack.optimize.CommonsChunkPlugin({
98 | name: 'manifest',
99 | minChunks: Infinity
100 | }),
101 | // This instance extracts shared chunks from code splitted chunks and bundles them
102 | // in a separate chunk, similar to the vendor chunk
103 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
104 | new webpack.optimize.CommonsChunkPlugin({
105 | name: 'app',
106 | async: 'vendor-async',
107 | children: true,
108 | minChunks: 3
109 | }),
110 |
111 | // copy custom static assets
112 | new CopyWebpackPlugin([
113 | {
114 | from: path.resolve(__dirname, '../static'),
115 | to: config.build.assetsSubDirectory,
116 | ignore: ['.*']
117 | }
118 | ])
119 | ]
120 | })
121 |
122 | if (config.build.productionGzip) {
123 | const CompressionWebpackPlugin = require('compression-webpack-plugin')
124 |
125 | webpackConfig.plugins.push(
126 | new CompressionWebpackPlugin({
127 | asset: '[path].gz[query]',
128 | algorithm: 'gzip',
129 | test: new RegExp(
130 | '\\.(' +
131 | config.build.productionGzipExtensions.join('|') +
132 | ')$'
133 | ),
134 | threshold: 10240,
135 | minRatio: 0.8
136 | })
137 | )
138 | }
139 |
140 | if (config.build.bundleAnalyzerReport) {
141 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
142 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
143 | }
144 |
145 | module.exports = webpackConfig
146 |
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const merge = require('webpack-merge')
3 | const prodEnv = require('./prod.env')
4 |
5 | module.exports = merge(prodEnv, {
6 | NODE_ENV: '"development"',
7 | })
8 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // Template version: 1.3.1
3 | // see http://vuejs-templates.github.io/webpack for documentation.
4 |
5 | const path = require('path')
6 |
7 | module.exports = {
8 | dev: {
9 |
10 | // Paths
11 | assetsSubDirectory: 'static',
12 | assetsPublicPath: '/',
13 | proxyTable: {
14 | /* '/httprunner': {
15 | target: 'http://localhost:8000',//设置你调用的接口域名和端口号 别忘了加http
16 | changeOrigin: true,
17 | pathRewrite: {
18 | '^/httprunner': ''
19 | }
20 | }*/
21 | },
22 |
23 | // Various Dev Server settings
24 | host: 'localhost', // can be overwritten by process.variables.HOST
25 | port: 8080, // can be overwritten by process.variables.PORT, if port is in use, a free one will be determined
26 | autoOpenBrowser: false,
27 | errorOverlay: true,
28 | notifyOnErrors: true,
29 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
30 |
31 |
32 | /**
33 | * Source Maps
34 | */
35 |
36 | // https://webpack.js.org/configuration/devtool/#development
37 | devtool: 'cheap-module-eval-source-map',
38 |
39 | // If you have problems debugging vue-files in devtools,
40 | // set this to false - it *may* help
41 | // https://vue-loader.vuejs.org/en/options.html#cachebusting
42 | cacheBusting: true,
43 |
44 | cssSourceMap: true
45 | },
46 |
47 | build: {
48 | // Template for index.html
49 | index: path.resolve(__dirname, '../dist/index.html'),
50 |
51 | // Paths
52 | assetsRoot: path.resolve(__dirname, '../dist'),
53 | assetsSubDirectory: 'static',
54 | assetsPublicPath: '/',
55 |
56 | /**
57 | * Source Maps
58 | */
59 |
60 | productionSourceMap: true,
61 | // https://webpack.js.org/configuration/devtool/#production
62 | devtool: '#source-map',
63 |
64 | // Gzip off by default as many popular static hosts such as
65 | // Surge or Netlify already gzip all static assets for you.
66 | // Before setting to `true`, make sure to:
67 | // npm install --save-dev compression-webpack-plugin
68 | productionGzip: false,
69 | productionGzipExtensions: ['js', 'css'],
70 |
71 | // Run the build command with an extra argument to
72 | // View the bundle analyzer report after build finishes:
73 | // `npm run build --report`
74 | // Set to `true` or `false` to always turn it on or off
75 | bundleAnalyzerReport: process.env.npm_config_report
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | NODE_ENV: '"production"',
4 | }
5 |
--------------------------------------------------------------------------------
/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 8080;
3 | server_name localhost; # 修改为docker服务宿主机的ip
4 |
5 | location / {
6 | root /usr/share/nginx/html;
7 | index index.html index.htm;
8 | try_files $uri $uri/ /index.html =404;
9 | }
10 |
11 | error_page 500 502 503 504 /50x.html;
12 | location = /50x.html {
13 | root html;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | FastRunner
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "api-web",
3 | "version": "1.0.0",
4 | "description": "A Vue.js project",
5 | "author": "尹全旺 <1263374981@qq.com>",
6 | "private": true,
7 | "scripts": {
8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
9 | "start": "npm run dev",
10 | "build": "node build/build.js"
11 | },
12 | "dependencies": {
13 | "axios": "^0.18.0",
14 | "element-ui": "^2.4.6",
15 | "vue": "^2.5.2",
16 | "vue-monaco-editor": "0.0.19",
17 | "vue-router": "^3.0.1",
18 | "vuedraggable": "^2.16.0",
19 | "vuex": "^3.0.1"
20 | },
21 | "devDependencies": {
22 | "autoprefixer": "^7.1.2",
23 | "babel-core": "^6.22.1",
24 | "babel-helper-vue-jsx-merge-props": "^2.0.3",
25 | "babel-loader": "^7.1.1",
26 | "babel-plugin-syntax-jsx": "^6.18.0",
27 | "babel-plugin-transform-runtime": "^6.22.0",
28 | "babel-plugin-transform-vue-jsx": "^3.5.0",
29 | "babel-preset-env": "^1.3.2",
30 | "babel-preset-stage-2": "^6.22.0",
31 | "chalk": "^2.0.1",
32 | "copy-webpack-plugin": "^4.0.1",
33 | "css-loader": "^0.28.0",
34 | "extract-text-webpack-plugin": "^3.0.0",
35 | "file-loader": "^1.1.4",
36 | "friendly-errors-webpack-plugin": "^1.6.1",
37 | "html-webpack-plugin": "^2.30.1",
38 | "node-notifier": "^5.1.2",
39 | "optimize-css-assets-webpack-plugin": "^3.2.0",
40 | "ora": "^1.2.0",
41 | "portfinder": "^1.0.13",
42 | "postcss-import": "^11.0.0",
43 | "postcss-loader": "^2.0.8",
44 | "postcss-url": "^7.2.1",
45 | "rimraf": "^2.6.0",
46 | "semver": "^5.3.0",
47 | "shelljs": "^0.7.6",
48 | "uglifyjs-webpack-plugin": "^1.1.1",
49 | "url-loader": "^0.5.8",
50 | "vue-easytable": "^1.7.1",
51 | "vue-loader": "^13.3.0",
52 | "vue-style-loader": "^3.0.1",
53 | "vue-template-compiler": "^2.5.2",
54 | "vue2-ace-editor": "0.0.11",
55 | "webpack": "^3.6.0",
56 | "webpack-bundle-analyzer": "^2.9.0",
57 | "webpack-dev-server": "^2.9.1",
58 | "webpack-merge": "^4.1.0"
59 | },
60 | "engines": {
61 | "node": ">= 6.0.0",
62 | "npm": ">= 3.0.0"
63 | },
64 | "browserslist": [
65 | "> 1%",
66 | "last 2 versions",
67 | "not ie <= 8"
68 | ]
69 | }
70 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
29 |
--------------------------------------------------------------------------------
/src/assets/images/bottom-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/httprunner/FasterWeb/10b5c2471802c52cefd478c237c884fc36ba1f95/src/assets/images/bottom-left.png
--------------------------------------------------------------------------------
/src/assets/images/bottom-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/httprunner/FasterWeb/10b5c2471802c52cefd478c237c884fc36ba1f95/src/assets/images/bottom-right.png
--------------------------------------------------------------------------------
/src/assets/styles/home.css:
--------------------------------------------------------------------------------
1 | #form-content {
2 | width: 450px;
3 | margin: 40px auto;
4 | background-color: #FFFFFF;
5 | padding: 40px 50px;
6 | text-align: center;
7 | border-radius: 2px;
8 | -webkit-box-shadow: 0px 16px 44px 0 RGBA(0, 0, 1, 0.2);
9 | -moz-box-shadow: 0px 16px 44px 0 RGBA(0, 0, 1, 0.2);
10 | box-shadow: 0px 16px 44px 0 RGBA(0, 0, 1, 0.2);
11 | }
12 |
13 | .bottom-right {
14 | position: fixed;
15 | right: 0px;
16 | bottom: 0px;
17 | }
18 |
19 | .bottom-left {
20 | position: fixed;
21 | left: 0px;
22 | bottom: 0px;
23 | }
24 |
25 | .bottom-right img {
26 | width: 364px;
27 | height: 208px;
28 | }
29 |
30 | .bottom-left img {
31 | width: 332px;
32 | height: 271px;
33 | }
34 |
35 | img {
36 | vertical-align: middle;
37 | }
38 |
39 | img {
40 | border: 0;
41 | }
42 |
43 | .form-input-div .icon {
44 | position: relative;
45 | left: 16px;
46 | top: 8px;
47 | color: #172B4D;
48 | font-size: 18px;
49 | }
50 |
51 | .form-input-div input.has-error {
52 | border-color: #fc4949;
53 | }
54 |
55 | #form-msg {
56 | color: #172B4D;
57 | font-size: 30px;
58 | text-align: left;
59 | font-weight: 300;
60 | }
61 |
62 | .form-submit .btn-primary {
63 | width: 100%;
64 | height: 42px;
65 | font-size: 15px;
66 | color: #fff;
67 | background: #1F5DEA;
68 | border: 1px solid #1F5DEA;
69 | border-radius: 2px;
70 | }
71 |
72 | .form-foot {
73 | position: relative;
74 | margin-top: 20px;
75 | color: #A8ACB9;
76 | font-size: 12px;
77 | text-align: left;
78 | }
79 |
80 | .form-foot a, .form-foot a:hover, .form-foot a:active {
81 | color: #1F5DEA;
82 | text-decoration: none;
83 | }
84 |
85 | body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, button, textarea, p, blockquote, th, td {
86 | margin: 0;
87 | padding: 0;
88 | -webkit-box-sizing: border-box;
89 | -moz-box-sizing: border-box;
90 | box-sizing: border-box;
91 | }
92 |
93 | a:hover, a:active, a:visited, a:focus {
94 | text-decoration: none !important;
95 | cursor: pointer;
96 | }
97 |
98 | .btn:active {
99 | background: #19A8FF;
100 | }
101 |
102 | .btn {
103 | display: inline-block;
104 | padding: 6px 10px;
105 | margin-bottom: 0;
106 | font-size: 13px;
107 | font-weight: normal;
108 | line-height: 1.42857143;
109 | text-align: center;
110 | white-space: nowrap;
111 | vertical-align: middle;
112 | -ms-touch-action: manipulation;
113 | touch-action: manipulation;
114 | cursor: pointer;
115 | -webkit-user-select: none;
116 | -moz-user-select: none;
117 | -ms-user-select: none;
118 | user-select: none;
119 | background-image: none;
120 | border: 1px solid transparent;
121 | border-radius: 2px;
122 | }
123 |
124 | input, button, select, textarea {
125 | font-family: inherit;
126 | font-size: inherit;
127 | line-height: inherit;
128 | }
129 |
130 | .form-input-div input {
131 | width: 350px;
132 | height: 42px;
133 | padding-left: 39px;
134 | border: 1px solid #E1E2E6;
135 | }
136 |
137 | .err_msg {
138 | position: relative;
139 | color: #fc4949;
140 | height: 20px;
141 | line-height: 20px;
142 | }
143 |
144 | #form-inputs {
145 | width: 350px;
146 | margin-top: 30px;
147 | text-align: left;
148 | }
149 |
150 | #form-title {
151 | font-size: 40px;
152 | color: #172B4D;
153 | text-align: center;
154 | margin-top: 60px;
155 | }
156 |
157 | .login {
158 | height: 1024px;
159 | background-color: #f7f8fa;
160 | font-family: "PingFang SC", "Helvetica Neue", Helvetica, "Hiragino Sans GB", STHeitiSC-Light, "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
161 | font-size: 13px;
162 | line-height: 1.42857143;
163 | color: #333;
164 | }
165 |
--------------------------------------------------------------------------------
/src/assets/styles/icon-font/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/httprunner/FasterWeb/10b5c2471802c52cefd478c237c884fc36ba1f95/src/assets/styles/icon-font/iconfont.eot
--------------------------------------------------------------------------------
/src/assets/styles/icon-font/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/httprunner/FasterWeb/10b5c2471802c52cefd478c237c884fc36ba1f95/src/assets/styles/icon-font/iconfont.ttf
--------------------------------------------------------------------------------
/src/assets/styles/icon-font/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/httprunner/FasterWeb/10b5c2471802c52cefd478c237c884fc36ba1f95/src/assets/styles/icon-font/iconfont.woff
--------------------------------------------------------------------------------
/src/assets/styles/iconfont.css:
--------------------------------------------------------------------------------
1 | @font-face {font-family: "iconfont";
2 | src: url('./icon-font/iconfont.eot?t=1551323395845'); /* IE9 */
3 | src: url('./icon-font/iconfont.eot?t=1551323395845#iefix') format('embedded-opentype'), /* IE6-IE8 */
4 | url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),
5 | url('./icon-font/iconfont.woff?t=1551323395845') format('woff'),
6 | url('./icon-font/iconfont.ttf?t=1551323395845') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
7 | url('./icon-font/iconfont.svg?t=1551323395845#iconfont') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .iconfont {
11 | font-family: "iconfont" !important;
12 | font-size: 16px;
13 | font-style: normal;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | .icon-youxiang:before {
19 | content: "\e668";
20 | }
21 |
22 | .icon-baogao:before {
23 | content: "\e66e";
24 | }
25 |
26 | .icon-ybbindex:before {
27 | content: "\e631";
28 | }
29 |
30 | .icon-02:before {
31 | content: "\e64a";
32 | }
33 |
34 | .icon-iconset0196:before {
35 | content: "\e65f";
36 | }
37 |
38 | .icon-17:before {
39 | content: "\e610";
40 | }
41 |
42 | .icon-xiazai:before {
43 | content: "\e600";
44 | }
45 |
46 | .icon-index:before {
47 | content: "\e66d";
48 | }
49 |
50 | .icon-fuzhifuzhi:before {
51 | content: "\e636";
52 | }
53 |
54 | .icon-debug:before {
55 | content: "\e606";
56 | }
57 |
58 | .icon-shijian:before {
59 | content: "\e63b";
60 | }
61 |
62 | .icon-language-python-text:before {
63 | content: "\e7ca";
64 | }
65 |
66 | .icon-xiangmu:before {
67 | content: "\e63c";
68 | }
69 |
70 | .icon-jiankong:before {
71 | content: "\e61f";
72 | }
73 |
74 | .icon-houtui:before {
75 | content: "\e617";
76 | }
77 |
78 | .icon-dingshirenwu:before {
79 | content: "\e61e";
80 | }
81 |
82 | .icon-xiangmu1:before {
83 | content: "\e707";
84 | }
85 |
86 | .icon-ceshi:before {
87 | content: "\e6da";
88 | }
89 |
90 | .icon-mima:before {
91 | content: "\e652";
92 | }
93 |
94 | .icon-quanju_yuming:before {
95 | content: "\e609";
96 | }
97 |
98 | .icon-jiekou:before {
99 | content: "\e74a";
100 | }
101 |
102 | .icon-shujuku:before {
103 | content: "\e615";
104 | }
105 |
106 | .icon-yali:before {
107 | content: "\e632";
108 | }
109 |
110 | .icon-xingmingyonghumingnicheng:before {
111 | content: "\e61c";
112 | }
113 |
114 | .icon-xiugai:before {
115 | content: "\e67d";
116 | }
117 |
118 | .icon-houtui1:before {
119 | content: "\e66f";
120 | }
121 |
122 | .icon-yumingguanli:before {
123 | content: "\e6cc";
124 | }
125 |
126 | .icon-yonghuming:before {
127 | content: "\e60d";
128 | }
129 |
130 | .icon-houtui2:before {
131 | content: "\e613";
132 | }
133 |
134 | .icon-171:before {
135 | content: "\e601";
136 | }
137 |
138 | .icon-bendibianliang:before {
139 | content: "\e692";
140 | }
141 |
142 | .icon-youxiang1:before {
143 | content: "\e650";
144 | }
145 |
146 | .icon-config:before {
147 | content: "\ee32";
148 | }
149 |
150 | .icon-fuzhi:before {
151 | content: "\e63d";
152 | }
153 |
154 | .icon-shujuku1:before {
155 | content: "\e782";
156 | }
157 |
158 | .icon-xiangmuliebiao:before {
159 | content: "\e7a7";
160 | }
161 |
162 | .icon-python:before {
163 | content: "\f216";
164 | }
165 |
166 | .icon-yunhang:before {
167 | content: "\e616";
168 | }
169 |
170 | .icon-shanchu:before {
171 | content: "\e608";
172 | }
173 |
174 | .icon-xiazai1:before {
175 | content: "\e602";
176 | }
177 |
178 |
--------------------------------------------------------------------------------
/src/assets/styles/reports.css:
--------------------------------------------------------------------------------
1 | .success {
2 | font-weight: bold;
3 | font-size: medium;
4 | color: #67c23a;
5 | }
6 |
7 | .error {
8 | font-weight: bold;
9 | font-size: medium;
10 | color: red;
11 | }
12 |
13 | .failure {
14 | font-weight: bold;
15 | font-size: medium;
16 | color: salmon;
17 | }
18 |
19 | .skipped {
20 | font-weight: bold;
21 | font-size: medium;
22 | color: #909399;
23 | }
24 |
25 | .POST {
26 | color: #49cc90;
27 | }
28 |
29 |
30 | .PUT {
31 | color: #fca130;
32 | }
33 |
34 | .GET {
35 | color: #61affe;
36 | }
37 |
38 |
39 | .DELETE {
40 | color: #f93e3e;
41 | }
42 |
43 |
44 | .PATCH {
45 | color: #50e3c2;
46 | }
47 |
48 | .HEAD {
49 | color: #e6a23c;
50 | }
51 |
52 | .OPTIONS {
53 | color: #409eff;
54 | }
55 |
56 |
57 | .code-block {
58 |
59 | border: 1px solid #ebedef;
60 | border-radius: 4px;
61 | color: #222 !important;
62 | font-family: Consolas,monospace;
63 | font-size: 13px;
64 | margin: 0;
65 | padding: 7px 10px;
66 | overflow: auto;
67 | }
68 |
--------------------------------------------------------------------------------
/src/assets/styles/swagger.css:
--------------------------------------------------------------------------------
1 | .block_post {
2 | border: 1px solid #49cc90;
3 | background-color: rgba(73, 204, 144, .1)
4 | }
5 |
6 | .block_method_post {
7 | background-color: #49cc90;
8 | }
9 |
10 | .block_put {
11 | border: 1px solid #fca130;
12 | background-color: rgba(252, 161, 48, .1)
13 | }
14 |
15 | .block_method_put {
16 | background-color: #fca130;
17 | }
18 |
19 | .block_get {
20 | border: 1px solid #61affe;
21 | background-color: rgba(97, 175, 254, .1)
22 | }
23 |
24 | .block_method_get {
25 | background-color: #61affe;
26 | }
27 |
28 | .block_delete {
29 | border: 1px solid #f93e3e;
30 | background-color: rgba(249, 62, 62, .1)
31 | }
32 |
33 | .block_method_delete {
34 | background-color: #f93e3e;
35 | }
36 |
37 | .block_patch {
38 | border: 1px solid #50e3c2;
39 | background-color: rgba(80, 227, 194, .1)
40 | }
41 |
42 | .block_method_patch {
43 | background-color: #50e3c2;
44 | }
45 |
46 | .block_head {
47 | border: 1px solid #e6a23c;
48 | background-color: rgba(230, 162, 60, .1)
49 | }
50 |
51 | .block_method_head {
52 | background-color: #e6a23c;
53 | }
54 |
55 | .block_options {
56 | border: 1px solid #409eff;
57 | background-color: rgba(64, 158, 255, .1)
58 | }
59 |
60 | .block_method_options {
61 | background-color: #409eff;
62 | }
63 |
64 | .block {
65 | position: relative;
66 | border-radius: 4px;
67 | height: 43.6px;
68 | padding: 5px;
69 | display: flex;
70 | align-items: center;
71 | }
72 |
73 | .block_url {
74 | word-break: normal;
75 | width: auto;
76 | display: block;
77 | white-space: pre-wrap;
78 | word-wrap: break-word;
79 | overflow: hidden;
80 | -webkit-box-flex: 1;
81 | -ms-flex: 1;
82 | font-family: Open Sans, sans-serif;
83 | color: #3b4151;
84 | }
85 |
86 | .block_name {
87 | padding-left: 5px;
88 | word-break: normal;
89 | width: auto;
90 | display: block;
91 | white-space: pre-wrap;
92 | word-wrap: break-word;
93 | overflow: hidden;
94 | -webkit-box-flex: 1;
95 | -ms-flex: 1;
96 | font-family: Open Sans, sans-serif;
97 | color: #3b4151;
98 | }
99 |
100 | .block_method_color {
101 | cursor: pointer;
102 | color: #fff;
103 | }
104 |
105 | .block-method {
106 | font-size: 14px;
107 | font-weight: 600;
108 | min-width: 80px;
109 | padding: 6px 15px;
110 | text-align: center;
111 | border-radius: 3px;
112 | text-shadow: 0 1px 0 rgba(0, 0, 0, .1);
113 | font-family: Titillium Web, sans-serif;
114 | }
115 |
116 | .block-summary-description {
117 | word-break: normal;
118 | width: auto;
119 | display: block;
120 | white-space: pre-wrap;
121 | word-wrap: break-word;
122 | overflow: hidden;
123 | -webkit-box-flex: 1;
124 | -ms-flex: 1;
125 | font-family: Open Sans, sans-serif;
126 | color: #3b4151;
127 | }
128 |
129 | h4 {
130 | display: block;
131 | -webkit-margin-before: 1.33em;
132 | -webkit-margin-after: 1.33em;
133 | -webkit-margin-start: 0px;
134 | -webkit-margin-end: 0px;
135 | font-weight: bold;
136 | }
137 |
--------------------------------------------------------------------------------
/src/assets/styles/tree.css:
--------------------------------------------------------------------------------
1 | ul li {
2 | list-style: none;
3 | }
4 |
5 | .operation-li {
6 | line-height: 60px;
7 | color: #555;
8 | font-size: 12px;
9 | width: 240px;
10 | margin-top: 1px;
11 | }
12 |
13 | .api-tree {
14 | padding: 0;
15 | margin: 0;
16 | }
17 |
18 | .nav-api-header {
19 | height: 48px;
20 | border-bottom: 1px solid #ddd;
21 | background-color: #F7F7F7;
22 |
23 | }
24 |
25 | .nav-api-side {
26 | overflow: auto;
27 | border: 1px solid #ddd;
28 | width: 280px;
29 | margin-left: 10px;
30 | border-radius: 4px;
31 | position: fixed;
32 | top: 110px;
33 | bottom: 0;
34 |
35 | }
36 |
37 | .custom-tree-node {
38 | flex: 1;
39 | display: flex;
40 | align-items: center;
41 | justify-content: space-between;
42 | font-size: 14px;
43 | padding-right: 8px;
44 | }
45 |
46 |
47 | .tree {
48 | overflow-y: auto;
49 | overflow-x: auto;
50 | width: 280px;
51 | height: 500px;
52 | }
53 |
54 | .el-tree {
55 | min-width: 100%;
56 | display: inline-block !important;
57 | }
58 |
59 | .el-tree-node__expand-icon {
60 | padding: 4px !important;
61 | }
62 |
63 | .el-tree-node__content {
64 | height: 50px;
65 | }
66 |
67 | .el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content {
68 | background-color: rgba(64, 158, 255, .1);
69 | color: #409EFF;
70 | }
71 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import ElementUI from 'element-ui'
5 | import 'element-ui/lib/theme-chalk/index.css'
6 | import App from './App'
7 | import router from './router'
8 | import 'styles/iconfont.css'
9 | import 'styles/swagger.css'
10 | import 'styles/tree.css'
11 | import 'styles/home.css'
12 | import 'styles/reports.css'
13 | import * as api from './restful/api'
14 | import store from './store'
15 |
16 | Vue.config.productionTip = false
17 | Vue.use(ElementUI)
18 | Vue.prototype.$api = api
19 |
20 | Vue.filter('datetimeFormat', function (time, format = 'YY-MM-DD hh:mm:ss') {
21 | let date = new Date(time);
22 | let year = date.getFullYear(),
23 | month = date.getMonth() + 1,
24 | day = date.getDate(),
25 | hour = date.getHours(),
26 | min = date.getMinutes(),
27 | sec = date.getSeconds();
28 | let preArr = Array.apply(null, Array(10)).map(function (elem, index) {
29 | return '0' + index;
30 | });
31 |
32 | let newTime = format.replace(/YY/g, year)
33 | .replace(/MM/g, preArr[month] || month)
34 | .replace(/DD/g, preArr[day] || day)
35 | .replace(/hh/g, preArr[hour] || hour)
36 | .replace(/mm/g, preArr[min] || min)
37 | .replace(/ss/g, preArr[sec] || sec);
38 |
39 | return newTime;
40 | });
41 |
42 | Vue.filter("timestampToTime", function (timestamp) {
43 | let date = new Date(timestamp * 1000);
44 | const Y = date.getFullYear() + '-';
45 | const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
46 | const D = date.getDate() + ' ';
47 | const h = date.getHours() + ':';
48 | const m = date.getMinutes() + ':';
49 | const s = date.getSeconds();
50 |
51 | return Y + M + D + h + m + s;
52 |
53 | });
54 | Vue.prototype.setLocalValue = function (name, value) {
55 | if (window.localStorage) {
56 | localStorage.setItem(name, value);
57 | } else {
58 | alert('This browser does NOT support localStorage');
59 | }
60 | };
61 | Vue.prototype.getLocalValue = function (name) {
62 | const value = localStorage.getItem(name);
63 | if (value) {
64 | return value;
65 | } else {
66 | return '';
67 | }
68 | };
69 |
70 | router.beforeEach((to, from, next) => {
71 | /* 路由发生变化修改页面title */
72 | setTimeout((res) => {
73 | if (to.meta.title) {
74 | document.title = to.meta.title
75 | }
76 |
77 | if (to.meta.requireAuth) {
78 | if (store.state.token !== '') {
79 | next();
80 | } else {
81 | next({
82 | name: 'Login',
83 | })
84 | }
85 | } else {
86 | next()
87 | }
88 | })
89 |
90 | })
91 |
92 | /* eslint-disable no-new */
93 | new Vue({
94 | el: '#app',
95 | router,
96 | store,
97 | components: {App},
98 | template: '',
99 | created() {
100 | if (this.getLocalValue("token") === null) {
101 | this.setLocalValue("token", "");
102 | }
103 | if (this.getLocalValue("user") === null) {
104 | this.setLocalValue("user", "");
105 | }
106 | if (this.getLocalValue("routerName") === null) {
107 | this.setLocalValue("routerName", "ProjectList");
108 | }
109 | this.$store.commit("isLogin", this.getLocalValue("token"));
110 | this.$store.commit("setUser", this.getLocalValue("user"));
111 | this.$store.commit("setRouterName", this.getLocalValue("routerName"));
112 |
113 | }
114 | })
115 |
--------------------------------------------------------------------------------
/src/pages/auth/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |

21 |
22 |
23 |
24 |
25 |
26 |
FasterRunner
27 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |

62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
129 |
130 |
133 |
--------------------------------------------------------------------------------
/src/pages/auth/Register.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |

20 |
21 |
22 |
23 |
24 |
25 |
FasterRunner
26 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |

79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
165 |
166 |
169 |
--------------------------------------------------------------------------------
/src/pages/auth/components/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |

21 |
22 |
23 |
24 |
25 |
26 |
FasterRunner接口测试平台
27 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |

62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
131 |
132 |
135 |
--------------------------------------------------------------------------------
/src/pages/auth/components/Register.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |

20 |
21 |
22 |
23 |
24 |
25 |
FasterRunner接口测试平台
26 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |

79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
165 |
166 |
169 |
--------------------------------------------------------------------------------
/src/pages/config/RecordConfig.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
163 |
164 |
168 |
--------------------------------------------------------------------------------
/src/pages/config/components/ConfigBody.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 | 配置信息录入
11 |
12 | Save
18 |
19 |
20 |
21 |
22 |
28 | 配置请求地址
29 |
30 |
31 |
32 |
33 |
37 |
38 |
42 |
43 |
44 |
45 |
46 |
51 |
52 |
53 |
54 |
55 |
60 |
61 |
62 |
63 |
64 |
65 |
70 |
71 |
72 |
73 |
74 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
231 |
232 |
248 |
--------------------------------------------------------------------------------
/src/pages/config/components/ConfigList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
30 |
33 |
34 |
35 |
39 |
40 | {{scope.row.name}}
41 |
42 |
43 |
44 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
58 |
59 | {{scope.row.update_time|datetimeFormat}}
60 |
61 |
62 |
63 |
64 |
67 |
68 |
69 |
75 |
76 |
82 |
83 |
84 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
225 |
226 |
231 |
--------------------------------------------------------------------------------
/src/pages/fastrunner/case/components/TestBody.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 | 接口信息录入
12 |
13 | Save
19 |
20 |
21 |
22 |
23 | Back
28 |
29 |
30 |
36 |
37 |
38 |
39 |
40 |
46 |
51 |
57 |
58 |
59 |
60 |
61 |
66 |
73 |
74 |
75 |
76 |
81 |
82 |
83 |
84 |
85 |
86 |
90 |
91 |
96 |
97 |
98 |
99 |
100 |
105 |
106 |
107 |
108 |
109 |
114 |
115 |
116 |
117 |
118 |
123 |
124 |
125 |
126 |
127 |
128 |
133 |
134 |
135 |
136 |
137 |
138 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
309 |
310 |
326 |
--------------------------------------------------------------------------------
/src/pages/fastrunner/config/RecordConfig.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
163 |
164 |
168 |
--------------------------------------------------------------------------------
/src/pages/fastrunner/config/components/ConfigBody.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 | 配置信息录入
11 |
12 | Save
18 |
19 |
20 |
21 |
22 |
28 | 配置请求地址
29 |
30 |
31 |
32 |
33 |
37 |
38 |
42 |
43 |
44 |
45 |
46 |
51 |
52 |
53 |
54 |
55 |
60 |
61 |
62 |
63 |
64 |
65 |
70 |
71 |
72 |
73 |
74 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
223 |
224 |
240 |
--------------------------------------------------------------------------------
/src/pages/fastrunner/config/components/ConfigList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
40 |
44 |
45 |
46 |
50 |
51 | {{scope.row.name}}
52 |
53 |
54 |
55 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
69 |
70 | {{scope.row.update_time|datetimeFormat}}
71 |
72 |
73 |
74 |
75 |
78 |
79 |
80 |
86 |
87 |
93 |
94 |
95 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
242 |
243 |
247 |
--------------------------------------------------------------------------------
/src/pages/home/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
34 |
35 |
41 |
--------------------------------------------------------------------------------
/src/pages/home/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
18 |
19 |
20 |
21 |
22 |
36 |
37 |
75 |
--------------------------------------------------------------------------------
/src/pages/home/components/Side.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 | 首 页
13 |
14 |
15 |
20 |
21 |
22 |
23 | {{item.name}}
24 |
25 |
27 |
30 |
31 |
32 |
33 |
34 |
35 |
62 |
63 |
75 |
--------------------------------------------------------------------------------
/src/pages/httprunner/DebugTalk.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 | 点击保存
15 |
16 |
17 |
24 | 在线运行
25 |
26 |
27 |
28 | 调试控制台
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
52 |
53 |
54 |
55 |
56 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
125 |
126 |
138 |
--------------------------------------------------------------------------------
/src/pages/httprunner/components/Extract.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
138 |
139 |
141 |
--------------------------------------------------------------------------------
/src/pages/httprunner/components/Headers.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
214 |
215 |
217 |
--------------------------------------------------------------------------------
/src/pages/httprunner/components/Hooks.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
15 |
16 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
45 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
135 |
136 |
138 |
--------------------------------------------------------------------------------
/src/pages/httprunner/components/Parameters.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
15 |
16 |
23 |
24 |
25 |
26 |
29 |
30 |
37 |
38 |
39 |
40 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
150 |
151 |
153 |
--------------------------------------------------------------------------------
/src/pages/httprunner/components/Validate.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
15 |
16 |
22 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
49 |
50 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
78 |
79 |
80 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
307 |
308 |
310 |
--------------------------------------------------------------------------------
/src/pages/httprunner/components/Variables.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
62 |
63 |
64 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
245 |
246 |
249 |
--------------------------------------------------------------------------------
/src/pages/project/ProjectDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 | {{projectInfo.name}}
7 | {{projectInfo.desc}}
8 |
9 |
10 |
11 |
12 |
13 | -
14 |
{{projectInfo.api_count}} 个接口
15 | 接口总数
16 |
17 |
18 | -
19 |
{{projectInfo.case_count}} 个用例
20 | 用例集总数
21 |
22 |
23 | -
24 |
{{projectInfo.config_count}} 套配置
25 | 配置总数
26 |
27 |
28 | -
29 |
{{projectInfo.variables_count}} 对变量
30 | 全局变量对数
31 |
32 |
33 |
34 |
35 | -
36 |
{{projectInfo.host_count}} 套环境
37 | 环境总数
38 |
39 |
40 | -
41 |
{{projectInfo.task_count}} 项任务
42 | 定时任务个数
43 |
44 |
45 | -
46 |
{{projectInfo.report_count}} 个报告
47 | 测试报告总数
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
92 |
93 |
154 |
--------------------------------------------------------------------------------
/src/pages/reports/DebugReport.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
16 |
17 | {{scope.row.time.start_at|timestampToTime}}
18 |
19 |
20 |
21 |
25 |
26 |
27 |
28 |
29 |
30 |
34 |
35 | {{ scope.row.stat.testsRun }}
36 |
37 |
38 |
39 |
43 |
44 | {{ scope.row.stat.successes }}
45 |
46 |
47 |
48 |
52 |
53 | {{ scope.row.stat.failures }}
54 |
55 |
56 |
57 |
61 |
62 | {{ scope.row.stat.errors }}
63 |
64 |
65 |
66 |
70 |
71 | {{ scope.row.stat.skipped }}
72 |
73 |
74 |
75 |
78 |
79 |
80 | HttpRunner: {{ scope.row.platform.httprunner_version }}
81 | Python: {{ scope.row.platform.python_version }}
82 |
83 | {{ scope.row.platform.platform }}
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
{{item.name}}
97 |
102 | {{item.in_out}}
103 | parameters & output
104 |
105 |
106 |
107 |
114 |
115 |
116 |
119 |
120 | {{ scope.row.name }}
121 |
122 |
123 |
124 |
127 |
128 | {{ scope.row.meta_data.request.url }}
129 |
130 |
131 |
132 |
135 |
136 | {{ scope.row.meta_data.request.method }}
138 |
139 |
140 |
141 |
144 |
145 | {{ scope.row.meta_data.response.elapsed_ms }}
146 |
147 |
148 |
149 |
152 |
153 | {{ scope.row.status }}
154 |
155 |
156 |
157 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
227 |
228 |
231 |
--------------------------------------------------------------------------------
/src/pages/task/Tasks.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
25 |
26 |
27 |
28 |
29 |
30 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
55 |
59 |
60 | {{scope.row.name}}
61 |
62 |
63 |
64 |
65 |
69 |
70 | {{scope.row.kwargs.corntab}}
71 |
72 |
73 |
74 |
78 |
79 | {{scope.row.kwargs.strategy}}
80 |
81 |
82 |
83 |
84 |
85 |
89 |
90 |
95 |
96 |
97 |
98 |
102 |
103 | {{scope.row.kwargs.receiver}}
104 |
105 |
106 |
110 |
111 | {{scope.row.kwargs.copy}}
112 |
113 |
114 |
115 |
118 |
119 |
120 |
125 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
216 |
217 |
221 |
--------------------------------------------------------------------------------
/src/restful/api.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import store from '../store/state'
3 | import router from '../router'
4 | import {Message} from 'element-ui';
5 |
6 |
7 |
8 | export const baseUrl = "http://localhost:8000";
9 | axios.defaults.withCredentials = true;
10 | axios.defaults.baseURL = baseUrl;
11 |
12 | axios.interceptors.request.use(function (config) {
13 | if (config.url.indexOf("/api/fastrunner/project/?cursor=") !== -1 ) {
14 | }
15 | else if (!config.url.startsWith("/api/user/")) {
16 | config.url = config.url + "?token=" + store.token;
17 | }
18 | return config;
19 | }, function (error) {
20 | return Promise.reject(error);
21 | });
22 |
23 | axios.interceptors.response.use(function (response) {
24 |
25 | return response;
26 | }, function (error) {
27 | try {
28 | if (error.response.status === 401) {
29 | router.replace({
30 | name: 'Login'
31 | })
32 | }
33 |
34 | if (error.response.status === 500) {
35 | Message.error({
36 | message: '服务器内部异常, 请检查',
37 | duration: 1000
38 | })
39 | }
40 | }
41 | catch (e) {
42 | Message.error({
43 | message: '服务器连接超时,请重试',
44 | duration: 1000
45 | })
46 | }
47 | });
48 |
49 | // user api
50 | export const register = params => {
51 | return axios.post('/api/user/register/', params).then(res => res.data)
52 | };
53 |
54 | export const login = params => {
55 | return axios.post('/api/user/login/', params).then(res => res.data)
56 | };
57 |
58 |
59 | // fastrunner api
60 | export const addProject = params => {
61 | return axios.post('/api/fastrunner/project/', params).then(res => res.data)
62 | };
63 |
64 | export const deleteProject = config => {
65 | return axios.delete('/api/fastrunner/project/', config).then(res => res.data)
66 | };
67 |
68 | export const getProjectList = params => {
69 | return axios.get('/api/fastrunner/project/').then(res => res.data)
70 | };
71 |
72 | export const getProjectDetail = pk => {
73 | return axios.get('/api/fastrunner/project/' + pk + '/').then(res => res.data)
74 | };
75 |
76 | export const getPagination = url => {
77 | return axios.get(url).then(res => res.data)
78 | };
79 |
80 | export const updateProject = params => {
81 | return axios.patch('/api/fastrunner/project/', params).then(res => res.data)
82 | };
83 |
84 | export const getDebugtalk = url => {
85 | return axios.get('/api/fastrunner/debugtalk/' + url + '/').then(res => res.data)
86 | };
87 |
88 | export const updateDebugtalk = params => {
89 | return axios.patch('/api/fastrunner/debugtalk/', params).then(res => res.data)
90 | };
91 |
92 | export const runDebugtalk = params => {
93 | return axios.post('/api/fastrunner/debugtalk/', params).then(res => res.data)
94 | };
95 |
96 | export const getTree = (url, params) => {
97 | return axios.get('/api/fastrunner/tree/' + url + '/', params).then(res => res.data)
98 | };
99 |
100 | export const updateTree = (url, params) => {
101 | return axios.patch('/api/fastrunner/tree/' + url + '/', params).then(res => res.data)
102 | };
103 |
104 | export const uploadFile = url => {
105 | return baseUrl + '/api/fastrunner/file/?token=' + store.token
106 | };
107 |
108 | export const addAPI = params => {
109 | return axios.post('/api/fastrunner/api/', params).then(res => res.data)
110 | };
111 |
112 | export const updateAPI = (url, params) => {
113 | return axios.patch('/api/fastrunner/api/' + url + '/', params).then(res => res.data)
114 | };
115 |
116 | export const apiList = params => {
117 | return axios.get('/api/fastrunner/api/', params).then(res => res.data)
118 | };
119 |
120 | export const delAPI = url => {
121 | return axios.delete('/api/fastrunner/api/' + url + '/').then(res => res.data)
122 | };
123 |
124 | export const delAllAPI = params => {
125 | return axios.delete('/api/fastrunner/api/', params).then(res => res.data)
126 | };
127 |
128 | export const getAPISingle = url => {
129 | return axios.get('/api/fastrunner/api/' + url + '/').then(res => res.data)
130 | };
131 |
132 |
133 |
134 | export const getPaginationBypage = params => {
135 | return axios.get('/api/fastrunner/api/', params).then(res => res.data)
136 | };
137 |
138 |
139 |
140 | export const addTestCase = params => {
141 | return axios.post('/api/fastrunner/test/', params).then(res => res.data)
142 | };
143 |
144 | export const updateTestCase = (url, params) => {
145 | return axios.patch('/api/fastrunner/test/' + url + '/', params).then(res => res.data)
146 | };
147 |
148 | export const testList = params => {
149 | return axios.get('/api/fastrunner/test/', params).then(res => res.data)
150 | };
151 |
152 | export const deleteTest = url => {
153 | return axios.delete('/api/fastrunner/test/' + url + '/').then(res => res.data)
154 | };
155 |
156 | export const delAllTest = params => {
157 | return axios.delete('/api/fastrunner/test/', params).then(res => res.data)
158 | };
159 |
160 | export const coptTest = (url, params) => {
161 | return axios.post('/api/fastrunner/test/' + url + '/', params).then(res => res.data)
162 | };
163 |
164 | export const editTest = url => {
165 | return axios.get('/api/fastrunner/teststep/' + url + '/').then(res => res.data)
166 | };
167 |
168 | export const getTestPaginationBypage = params => {
169 | return axios.get('/api/fastrunner/test/', params).then(res => res.data)
170 | };
171 |
172 | export const addConfig = params => {
173 | return axios.post('/api/fastrunner/config/', params).then(res => res.data)
174 | };
175 |
176 | export const updateConfig = (url, params) => {
177 | return axios.patch('/api/fastrunner/config/' + url + '/', params).then(res => res.data)
178 | };
179 |
180 |
181 | export const configList = params => {
182 | return axios.get('/api/fastrunner/config/', params).then(res => res.data)
183 | };
184 |
185 | export const copyConfig = (url, params) => {
186 | return axios.post('/api/fastrunner/config/' + url + '/', params).then(res => res.data)
187 | };
188 |
189 | export const copyAPI = (url, params) => {
190 | return axios.post('/api/fastrunner/api/' + url + '/', params).then(res => res.data)
191 | };
192 |
193 | export const deleteConfig = url => {
194 | return axios.delete('/api/fastrunner/config/' + url + '/').then(res => res.data)
195 | };
196 | export const delAllConfig = params => {
197 | return axios.delete('/api/fastrunner/config/', params).then(res => res.data)
198 | };
199 |
200 | export const getConfigPaginationBypage = params => {
201 | return axios.get('/api/fastrunner/config/', params).then(res => res.data)
202 | };
203 |
204 | export const getAllConfig = url => {
205 | return axios.get('/api/fastrunner/config/' + url + '/').then(res => res.data)
206 | };
207 |
208 |
209 | export const runSingleAPI = params => {
210 | return axios.post('/api/fastrunner/run_api/', params).then(res => res.data)
211 | };
212 |
213 | export const runAPIByPk = (url, params) => {
214 | return axios.get('/api/fastrunner/run_api_pk/' + url + '/', params).then(res => res.data)
215 | };
216 |
217 | export const runAPITree = params => {
218 | return axios.post('/api/fastrunner/run_api_tree/', params).then(res => res.data)
219 | };
220 |
221 | export const runSingleTestSuite = params => {
222 | return axios.post('/api/fastrunner/run_testsuite/', params).then(res => res.data)
223 | };
224 |
225 | export const runSingleTest = params => {
226 | return axios.post('/api/fastrunner/run_test/', params).then(res => res.data)
227 | };
228 |
229 | export const runTestByPk = (url, params) => {
230 | return axios.get('/api/fastrunner/run_testsuite_pk/' + url + '/', params).then(res => res.data)
231 | };
232 |
233 | export const runSuiteTree = params => {
234 | return axios.post('/api/fastrunner/run_suite_tree/', params).then(res => res.data)
235 | };
236 |
237 | export const addVariables = params => {
238 | return axios.post('/api/fastrunner/variables/', params).then(res => res.data)
239 | };
240 |
241 | export const variablesList = params => {
242 | return axios.get('/api/fastrunner/variables/', params).then(res => res.data)
243 | };
244 |
245 | export const getVariablesPaginationBypage = params => {
246 | return axios.get('/api/fastrunner/variables/', params).then(res => res.data)
247 | };
248 |
249 |
250 | export const updateVariables = (url, params) => {
251 | return axios.patch('/api/fastrunner/variables/' + url + '/', params).then(res => res.data)
252 | };
253 |
254 | export const deleteVariables = url => {
255 | return axios.delete('/api/fastrunner/variables/' + url + '/').then(res => res.data)
256 | };
257 |
258 | export const delAllVariabels = params => {
259 | return axios.delete('/api/fastrunner/variables/', params).then(res => res.data)
260 | };
261 |
262 | export const reportList = params => {
263 | return axios.get('/api/fastrunner/reports/', params).then(res => res.data)
264 | };
265 |
266 | export const deleteReports = url => {
267 | return axios.delete('/api/fastrunner/reports/' + url + '/').then(res => res.data)
268 | };
269 |
270 | export const getReportsPaginationBypage = params => {
271 | return axios.get('/api/fastrunner/reports/', params).then(res => res.data)
272 | };
273 |
274 | export const delAllReports = params => {
275 | return axios.delete('/api/fastrunner/reports/', params).then(res => res.data)
276 | };
277 |
278 | export const watchSingleReports = url => {
279 | return axios.get('/api/fastrunner/reports/' + url + '/').then(res => res.data)
280 | };
281 |
282 | export const addTask = params => {
283 | return axios.post('/api/fastrunner/schedule/', params).then(res => res.data)
284 | };
285 | export const taskList = params => {
286 | return axios.get('/api/fastrunner/schedule/', params).then(res => res.data)
287 | };
288 | export const getTaskPaginationBypage = params => {
289 | return axios.get('/api/fastrunner/schedule/', params).then(res => res.data)
290 | };
291 | export const deleteTasks = url => {
292 | return axios.delete('/api/fastrunner/schedule/' + url + '/').then(res => res.data)
293 | };
294 |
295 | export const addHostIP = params => {
296 | return axios.post('/api/fastrunner/host_ip/', params).then(res => res.data)
297 | };
298 |
299 | export const hostList = params => {
300 | return axios.get('/api/fastrunner/host_ip/', params).then(res => res.data)
301 | };
302 |
303 | export const updateHost = (url, params) => {
304 | return axios.patch('/api/fastrunner/host_ip/' + url + '/', params).then(res => res.data)
305 | };
306 |
307 | export const deleteHost = url => {
308 | return axios.delete('/api/fastrunner/host_ip/' + url + '/').then(res => res.data)
309 | };
310 |
311 | export const getHostPaginationBypage = params => {
312 | return axios.get('/api/fastrunner/host_ip/', params).then(res => res.data)
313 | };
314 |
315 | export const getAllHost = url => {
316 | return axios.get('/api/fastrunner/host_ip/' + url + '/').then(res => res.data)
317 | };
318 |
319 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import Home from '@/pages/home/Home'
4 | import Register from '@/pages/auth/Register'
5 | import Login from '@/pages/auth/Login'
6 | import ProjectList from '@/pages/project/ProjectList'
7 | import ProjectDetail from '@/pages/project/ProjectDetail'
8 | import DebugTalk from '@/pages/httprunner/DebugTalk'
9 | import RecordApi from '@/pages/fastrunner/api/RecordApi'
10 | import AutoTest from '@/pages/fastrunner/case/AutoTest'
11 | import GlobalEnv from '@/pages/variables/GlobalEnv'
12 | import ReportList from '@/pages/reports/ReportList'
13 | import RecordConfig from '@/pages/fastrunner/config/RecordConfig'
14 | import Tasks from '@/pages/task/Tasks'
15 | import HostAddress from '@/pages/variables/HostAddress'
16 |
17 | Vue.use(Router);
18 |
19 | export default new Router({
20 | mode:'history',
21 | routes: [
22 | {
23 | path: '/fastrunner/register',
24 | name: 'Register',
25 | component: Register,
26 | meta: {
27 | title: '用户注册'
28 | }
29 | }, {
30 | path: '/fastrunner/login',
31 | name: 'Login',
32 | component: Login,
33 | meta: {
34 | title: '用户登录'
35 | }
36 | }, {
37 |
38 | path: '/fastrunner',
39 | name: 'Index',
40 | component: Home,
41 | meta: {
42 | title: '首页',
43 | requireAuth: true
44 | },
45 | children: [
46 | {
47 | name: 'ProjectList',
48 | path: 'project_list',
49 | component: ProjectList,
50 | meta: {
51 | title: '项目列表',
52 | requireAuth: true,
53 | }
54 | },
55 | {
56 | name: 'ProjectDetail',
57 | path: 'project/:id/dashbord',
58 | component: ProjectDetail,
59 | meta: {
60 | title: '项目预览',
61 | requireAuth: true,
62 | }
63 |
64 | },
65 | {
66 | name: 'DebugTalk',
67 | path: 'debugtalk/:id',
68 | component: DebugTalk,
69 | meta: {
70 | title: '编辑驱动',
71 | requireAuth: true,
72 | }
73 |
74 | },
75 | {
76 | name: 'RecordApi',
77 | path: 'api_record/:id',
78 | component: RecordApi,
79 | meta: {
80 | title: '接口模板',
81 | requireAuth: true
82 | }
83 |
84 | },
85 | {
86 | name: 'AutoTest',
87 | path: 'auto_test/:id',
88 | component: AutoTest,
89 | meta: {
90 | title: '自动化测试',
91 | requireAuth: true
92 | }
93 |
94 | },
95 | {
96 | name: 'RecordConfig',
97 | path: 'record_config/:id',
98 | component: RecordConfig,
99 | meta: {
100 | title: '配置管理',
101 | requireAuth: true
102 | }
103 |
104 | },
105 | {
106 | name: 'GlobalEnv',
107 | path: 'global_env/:id',
108 | component: GlobalEnv,
109 | meta: {
110 | title: '全局变量',
111 | requireAuth: true
112 | }
113 |
114 | },
115 | {
116 | name: 'Reports',
117 | path: 'reports/:id',
118 | component: ReportList,
119 | meta: {
120 | title: '历史报告',
121 | requireAuth: true
122 | }
123 |
124 | },
125 | {
126 | name: 'Task',
127 | path: 'tasks/:id',
128 | component: Tasks,
129 | meta: {
130 | title: '定时任务',
131 | requireAuth: true
132 | }
133 |
134 | },
135 | {
136 | name: 'HostIP',
137 | path: 'host_ip/:id',
138 | component: HostAddress,
139 | meta: {
140 | title: 'HOST配置',
141 | requireAuth: true
142 | }
143 |
144 | }
145 | ]
146 | },
147 |
148 | ]
149 | })
150 |
151 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import state from './state'
4 | import mutations from './mutations'
5 |
6 | Vue.use(Vuex)
7 |
8 | export default new Vuex.Store({
9 | state,
10 | mutations
11 | })
12 |
--------------------------------------------------------------------------------
/src/store/mutations.js:
--------------------------------------------------------------------------------
1 | export default {
2 |
3 | isLogin(state, value) {
4 | state.token = value;
5 | },
6 |
7 | setUser(state, value) {
8 | state.user = value;
9 | },
10 | setRouterName(state, value) {
11 | state.routerName = value
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/store/state.js:
--------------------------------------------------------------------------------
1 | export default {
2 | routerName: null,
3 | token:null,
4 | user: null
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/static/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/httprunner/FasterWeb/10b5c2471802c52cefd478c237c884fc36ba1f95/static/.gitkeep
--------------------------------------------------------------------------------
/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/httprunner/FasterWeb/10b5c2471802c52cefd478c237c884fc36ba1f95/static/favicon.ico
--------------------------------------------------------------------------------