xielq 4 жил өмнө
parent
commit
1b98ebc854
100 өөрчлөгдсөн 4133 нэмэгдсэн , 0 устгасан
  1. 16 0
      Dockerfile
  2. 7 0
      README.md
  3. 36 0
      build/build.js
  4. 45 0
      build/check-versions.js
  5. 9 0
      build/dev-client.js
  6. 75 0
      build/dev-server.js
  7. 61 0
      build/utils.js
  8. 91 0
      build/webpack.base.conf.js
  9. 38 0
      build/webpack.dev.conf.js
  10. 101 0
      build/webpack.prod.conf.js
  11. 6 0
      config/dev.env.js
  12. 37 0
      config/index.js
  13. 3 0
      config/prod.env.js
  14. 22 0
      index.html
  15. 63 0
      package.json
  16. 9 0
      runtime/docker/config.js
  17. 10 0
      runtime/docker/run.sh
  18. 25 0
      runtime/docker/server.js
  19. 63 0
      src/App.vue
  20. BIN
      src/assets/logo-uas.png
  21. 54 0
      src/components/Common/Bread/Bread.vue
  22. 45 0
      src/components/Common/DialogInfo/DialogInfo.js
  23. 41 0
      src/components/Common/DialogInfo/DialogInfo.vue
  24. 2 0
      src/components/Common/DialogInfo/index.js
  25. 544 0
      src/components/Common/FormData/FormData.js
  26. 212 0
      src/components/Common/FormData/FormData.vue
  27. 2 0
      src/components/Common/FormData/index.js
  28. 179 0
      src/components/Common/HeadNav/HeadNav.js
  29. 194 0
      src/components/Common/HeadNav/HeadNav.vue
  30. 54 0
      src/components/Common/LeftMenu/LeftMenu.js
  31. 43 0
      src/components/Common/LeftMenu/LeftMenu.less
  32. 75 0
      src/components/Common/LeftMenu/LeftMenu.vue
  33. 255 0
      src/components/Common/ListData/ListData.js
  34. 173 0
      src/components/Common/ListData/ListData.vue
  35. 2 0
      src/components/Common/ListData/index.js
  36. 8 0
      src/components/Common/index.js
  37. 122 0
      src/components/Login/Login.js
  38. 36 0
      src/components/Login/Login.less
  39. 51 0
      src/components/Login/Login.vue
  40. 2 0
      src/components/Login/index.js
  41. 28 0
      src/components/Modules/Program/Artifact/List/List.js
  42. 39 0
      src/components/Modules/Program/Artifact/List/List.vue
  43. 2 0
      src/components/Modules/Program/Artifact/List/index.js
  44. 78 0
      src/components/Modules/Program/Artifact/Version/Version.js
  45. 51 0
      src/components/Modules/Program/Artifact/Version/Version.vue
  46. 2 0
      src/components/Modules/Program/Artifact/Version/index.js
  47. 4 0
      src/components/Modules/Program/Artifact/index.js
  48. 45 0
      src/components/Modules/Program/Deploy/Client/List.js
  49. 67 0
      src/components/Modules/Program/Deploy/Client/List.vue
  50. 2 0
      src/components/Modules/Program/Deploy/Client/index.js
  51. 45 0
      src/components/Modules/Program/Deploy/History/List.js
  52. 67 0
      src/components/Modules/Program/Deploy/History/List.vue
  53. 2 0
      src/components/Modules/Program/Deploy/History/index.js
  54. 0 0
      src/components/Modules/Program/Deploy/Home/index.js
  55. 5 0
      src/components/Modules/Program/Deploy/index.js
  56. 4 0
      src/components/Modules/Program/index.js
  57. 0 0
      src/components/Modules/Runtime/Client/Item/index.js
  58. 0 0
      src/components/Modules/Runtime/Client/List/index.js
  59. 4 0
      src/components/Modules/Runtime/Client/index.js
  60. 3 0
      src/components/Modules/Runtime/index.js
  61. 5 0
      src/components/Modules/index.js
  62. 38 0
      src/components/Routeview/Content.vue
  63. 32 0
      src/components/Routeview/Home.vue
  64. 29 0
      src/components/Routeview/NotFound.vue
  65. 17 0
      src/components/index.js
  66. 5 0
      src/config/index.js
  67. 21 0
      src/config/request.js
  68. 36 0
      src/config/request/program.js
  69. 18 0
      src/config/request/runtime.js
  70. 36 0
      src/config/request/user.js
  71. 29 0
      src/config/router.js
  72. 4 0
      src/config/router/index.js
  73. 54 0
      src/config/router/program.js
  74. 32 0
      src/config/router/runtime.js
  75. 66 0
      src/config/settings.js
  76. 69 0
      src/main.js
  77. 0 0
      src/mixin/Created/index.js
  78. 53 0
      src/mixin/Methods/Common/FormData.js
  79. 100 0
      src/mixin/Methods/Common/ListData.js
  80. 4 0
      src/mixin/Methods/Common/index.js
  81. 3 0
      src/mixin/Methods/index.js
  82. 0 0
      src/mixin/Mounted/index.js
  83. 29 0
      src/mixin/index.js
  84. 28 0
      src/plugins/index.js
  85. 35 0
      src/register/index.js
  86. 21 0
      src/store/global/actions.js
  87. 3 0
      src/store/global/getters.js
  88. 11 0
      src/store/global/index.js
  89. 11 0
      src/store/global/mutations.js
  90. 5 0
      src/store/global/mutations_types.js
  91. 3 0
      src/store/global/state.js
  92. 17 0
      src/store/index.js
  93. 14 0
      src/store/leftmenu/actions.js
  94. 2 0
      src/store/leftmenu/getters.js
  95. 11 0
      src/store/leftmenu/index.js
  96. 12 0
      src/store/leftmenu/mutations.js
  97. 5 0
      src/store/leftmenu/mutations_types.js
  98. 5 0
      src/store/leftmenu/state.js
  99. 9 0
      src/store/router/actions.js
  100. 2 0
      src/store/router/getters.js

+ 16 - 0
Dockerfile

@@ -0,0 +1,16 @@
+FROM 10.10.100.200:5000/node-webpack:0.0.1
+
+RUN mkdir -p /app
+WORKDIR /app
+
+RUN cnpm install
+
+RUN npm run build
+
+COPY dist/* /app
+
+COPY runtime/docker/* /app
+
+RUN chmod +x /app/run.sh
+
+CMD [ "/app/run.sh" ]

+ 7 - 0
README.md

@@ -0,0 +1,7 @@
+# UAS管理中心前端
+
+> 功能
+* 查看客户UAS系统软件部署详情
+* 查看客户UAS系统组件实时运行状况
+* 在线部署更新客户UAS系统软件
+* 在线在客户UAS系统执行命令

+ 36 - 0
build/build.js

@@ -0,0 +1,36 @@
+// https://github.com/shelljs/shelljs
+require('./check-versions')()
+require('shelljs/global')
+env.NODE_ENV = 'production'
+
+var path = require('path')
+var config = require('../config')
+var ora = require('ora')
+var webpack = require('webpack')
+var webpackConfig = require('./webpack.prod.conf')
+
+console.log(
+  '  Tip:\n' +
+  '  Built files are meant to be served over an HTTP server.\n' +
+  '  Opening index.html over file:// won\'t work.\n'
+)
+
+var spinner = ora('building for production...')
+spinner.start()
+
+var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory)
+rm('-rf', assetsPath)
+mkdir('-p', assetsPath)
+cp('-R', 'static/*', assetsPath)
+
+webpack(webpackConfig, function (err, stats) {
+  spinner.stop()
+  if (err) throw err
+  process.stdout.write(stats.toString({
+    colors: true,
+    modules: false,
+    children: false,
+    chunks: false,
+    chunkModules: false
+  }) + '\n')
+})

+ 45 - 0
build/check-versions.js

@@ -0,0 +1,45 @@
+var semver = require('semver')
+var chalk = require('chalk')
+var packageConfig = require('../package.json')
+var exec = function (cmd) {
+  return require('child_process')
+    .execSync(cmd).toString().trim()
+}
+
+var versionRequirements = [
+  {
+    name: 'node',
+    currentVersion: semver.clean(process.version),
+    versionRequirement: packageConfig.engines.node
+  },
+  {
+    name: 'npm',
+    currentVersion: exec('npm --version'),
+    versionRequirement: packageConfig.engines.npm
+  }
+]
+
+module.exports = function () {
+  var warnings = []
+  for (var i = 0; i < versionRequirements.length; i++) {
+    var mod = versionRequirements[i]
+    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
+      warnings.push(mod.name + ': ' +
+        chalk.red(mod.currentVersion) + ' should be ' +
+        chalk.green(mod.versionRequirement)
+      )
+    }
+  }
+
+  if (warnings.length) {
+    console.log('')
+    console.log(chalk.yellow('To use this template, you must update following to modules:'))
+    console.log()
+    for (var i = 0; i < warnings.length; i++) {
+      var warning = warnings[i]
+      console.log('  ' + warning)
+    }
+    console.log()
+    process.exit(1)
+  }
+}

+ 9 - 0
build/dev-client.js

@@ -0,0 +1,9 @@
+/* eslint-disable */
+require('eventsource-polyfill')
+var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
+
+hotClient.subscribe(function (event) {
+  if (event.action === 'reload') {
+    window.location.reload()
+  }
+})

+ 75 - 0
build/dev-server.js

@@ -0,0 +1,75 @@
+require('./check-versions')()
+var config = require('../config')
+if (!process.env.NODE_ENV) process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
+var path = require('path')
+var express = require('express')
+var webpack = require('webpack')
+var opn = require('opn')
+var proxyMiddleware = require('http-proxy-middleware')
+var webpackConfig = require('./webpack.dev.conf')
+
+// default port where dev server listens for incoming traffic
+var port = process.env.PORT || config.dev.port
+// Define HTTP proxies to your custom API backend
+// https://github.com/chimurai/http-proxy-middleware
+var proxyTable = config.dev.proxyTable
+
+var app = express()
+var compiler = webpack(webpackConfig)
+
+var devMiddleware = require('webpack-dev-middleware')(compiler, {
+  publicPath: webpackConfig.output.publicPath,
+  quiet: true
+})
+
+var hotMiddleware = require('webpack-hot-middleware')(compiler, {
+  log: () => {}
+})
+// force page reload when html-webpack-plugin template changes
+compiler.plugin('compilation', function (compilation) {
+  compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
+    hotMiddleware.publish({ action: 'reload' })
+    cb()
+  })
+})
+
+// proxy api requests
+Object.keys(proxyTable).forEach(function (context) {
+  var options = proxyTable[context]
+  if (typeof options === 'string') {
+    options = { target: options }
+  }
+  app.use(proxyMiddleware(context, options))
+})
+
+// handle fallback for HTML5 history API
+app.use(require('connect-history-api-fallback')())
+
+// serve webpack bundle output
+app.use(devMiddleware)
+
+// enable hot-reload and state-preserving
+// compilation error display
+app.use(hotMiddleware)
+
+// serve pure static assets
+var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
+app.use(staticPath, express.static('./static'))
+
+var uri = 'http://localhost:' + port
+
+devMiddleware.waitUntilValid(function () {
+  console.log('> Listening at ' + uri + '\n')
+})
+
+module.exports = app.listen(port, function (err) {
+  if (err) {
+    console.log(err)
+    return
+  }
+
+  // when env is testing, don't need open it
+  if (process.env.NODE_ENV !== 'testing') {
+    opn(uri)
+  }
+})

+ 61 - 0
build/utils.js

@@ -0,0 +1,61 @@
+var path = require('path')
+var config = require('../config')
+var ExtractTextPlugin = require('extract-text-webpack-plugin')
+
+exports.assetsPath = function (_path) {
+  var assetsSubDirectory = process.env.NODE_ENV === 'production'
+    ? config.build.assetsSubDirectory
+    : config.dev.assetsSubDirectory
+  return path.posix.join(assetsSubDirectory, _path)
+}
+
+exports.cssLoaders = function (options) {
+  options = options || {}
+  // generate loader string to be used with extract text plugin
+  function generateLoaders (loaders) {
+    var sourceLoader = loaders.map(function (loader) {
+      var extraParamChar
+      if (/\?/.test(loader)) {
+        loader = loader.replace(/\?/, '-loader?')
+        extraParamChar = '&'
+      } else {
+        loader = loader + '-loader'
+        extraParamChar = '?'
+      }
+      return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '')
+    }).join('!')
+
+    // Extract CSS when that option is specified
+    // (which is the case during production build)
+    if (options.extract) {
+      return ExtractTextPlugin.extract('vue-style-loader', sourceLoader)
+    } else {
+      return ['vue-style-loader', sourceLoader].join('!')
+    }
+  }
+
+  // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html
+  return {
+    css: generateLoaders(['css']),
+    postcss: generateLoaders(['css']),
+    less: generateLoaders(['css', 'less']),
+    sass: generateLoaders(['css', 'sass?indentedSyntax']),
+    scss: generateLoaders(['css', 'sass']),
+    stylus: generateLoaders(['css', 'stylus']),
+    styl: generateLoaders(['css', 'stylus'])
+  }
+}
+
+// Generate loaders for standalone style files (outside of .vue)
+exports.styleLoaders = function (options) {
+  var output = []
+  var loaders = exports.cssLoaders(options)
+  for (var extension in loaders) {
+    var loader = loaders[extension]
+    output.push({
+      test: new RegExp('\\.' + extension + '$'),
+      loader: loader
+    })
+  }
+  return output
+}

+ 91 - 0
build/webpack.base.conf.js

@@ -0,0 +1,91 @@
+var path = require('path')
+var config = require('../config')
+var utils = require('./utils')
+var projectRoot = path.resolve(__dirname, '../')
+
+var env = process.env.NODE_ENV
+    // check env & config/index.js to decide whether to enable CSS source maps for the
+    // various preprocessor loaders added to vue-loader at the end of this file
+var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap)
+var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap)
+var useCssSourceMap = cssSourceMapDev || cssSourceMapProd
+
+module.exports = {
+    entry: {
+        app: './src/main.js'
+    },
+    output: {
+        path: config.build.assetsRoot,
+        publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
+        filename: '[name].js'
+    },
+    resolve: {
+        extensions: ['', '.js', '.vue', '.json'],
+        fallback: [path.join(__dirname, '../node_modules')],
+        alias: {
+            'vue$': 'vue/dist/vue.common.js',
+            'src': path.resolve(__dirname, '../src'),
+            'assets': path.resolve(__dirname, '../src/assets'),
+
+            'components': path.resolve(__dirname, '../src/components'),
+
+            'common': path.resolve(__dirname, '../src/components/Common'),
+
+            'modules': path.resolve(__dirname, '../src/components/Modules'),
+
+            'demo': path.resolve(__dirname, '../src/components/Modules/Demo'),
+            'function': path.resolve(__dirname, '../src/components/Modules/Function'),
+
+            'config': path.resolve(__dirname, '../src/config'),
+            'store': path.resolve(__dirname, '../src/store'),
+            'libs': path.resolve(__dirname, '../src/libs'),
+            'util': path.resolve(__dirname, '../src/util'),
+            'register': path.resolve(__dirname, '../src/register'),
+            'plugins': path.resolve(__dirname, '../src/plugins'),
+            'mixin': path.resolve(__dirname, '../src/mixin'),
+        }
+    },
+    resolveLoader: {
+        fallback: [path.join(__dirname, '../node_modules')]
+    },
+    module: {
+        loaders: [{
+            test: /\.vue$/,
+            loader: 'vue'
+        }, {
+            test: /\.js$/,
+            loader: 'babel',
+            include: [
+                path.join(projectRoot, 'src')
+            ],
+            exclude: /node_modules/
+        }, {
+            test: /\.json$/,
+            loader: 'json'
+        }, {
+            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
+            loader: 'url',
+            query: {
+                limit: 10000,
+                name: utils.assetsPath('img/[name].[hash:7].[ext]')
+            }
+        }, {
+            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
+            loader: 'url',
+            query: {
+                limit: 10000,
+                name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
+            }
+        }]
+    },
+    vue: {
+        loaders: utils.cssLoaders({
+            sourceMap: useCssSourceMap
+        }),
+        postcss: [
+            require('autoprefixer')({
+                browsers: ['last 2 versions']
+            })
+        ]
+    }
+}

+ 38 - 0
build/webpack.dev.conf.js

@@ -0,0 +1,38 @@
+var config = require('../config')
+var webpack = require('webpack')
+var merge = require('webpack-merge')
+var utils = require('./utils')
+var baseWebpackConfig = require('./webpack.base.conf')
+var HtmlWebpackPlugin = require('html-webpack-plugin')
+var FriendlyErrors = require('friendly-errors-webpack-plugin')
+
+// add hot-reload related code to entry chunks
+Object.keys(baseWebpackConfig.entry).forEach(function(name) {
+    baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
+})
+
+module.exports = merge(baseWebpackConfig, {
+    module: {
+        loaders: utils.styleLoaders({
+            sourceMap: config.dev.cssSourceMap
+        })
+    },
+    // eval-source-map is faster for development
+    devtool: '#eval-source-map',
+    plugins: [
+        new webpack.DefinePlugin({
+            'process.env': config.dev.env
+        }),
+        // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
+        new webpack.optimize.OccurrenceOrderPlugin(),
+        new webpack.HotModuleReplacementPlugin(),
+        new webpack.NoErrorsPlugin(),
+        // https://github.com/ampedandwired/html-webpack-plugin
+        new HtmlWebpackPlugin({
+            filename: 'index.html',
+            template: 'index.html',
+            inject: true
+        }),
+        new FriendlyErrors()
+    ]
+})

+ 101 - 0
build/webpack.prod.conf.js

@@ -0,0 +1,101 @@
+var path = require('path')
+var config = require('../config')
+var utils = require('./utils')
+var webpack = require('webpack')
+var merge = require('webpack-merge')
+var baseWebpackConfig = require('./webpack.base.conf')
+var ExtractTextPlugin = require('extract-text-webpack-plugin')
+var HtmlWebpackPlugin = require('html-webpack-plugin')
+var env = config.build.env
+
+var webpackConfig = merge(baseWebpackConfig, {
+    module: {
+        loaders: utils.styleLoaders({
+            sourceMap: config.build.productionSourceMap,
+            extract: true
+        })
+    },
+    devtool: config.build.productionSourceMap ? '#source-map' : false,
+    output: {
+        path: config.build.assetsRoot,
+        filename: utils.assetsPath('js/[name].[chunkhash].js'),
+        chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
+    },
+    vue: {
+        loaders: utils.cssLoaders({
+            sourceMap: config.build.productionSourceMap,
+            extract: true
+        })
+    },
+    plugins: [
+        // http://vuejs.github.io/vue-loader/en/workflow/production.html
+        new webpack.DefinePlugin({
+            'process.env': env
+        }),
+        new webpack.optimize.UglifyJsPlugin({
+            compress: {
+                warnings: false
+            }
+        }),
+        new webpack.optimize.OccurrenceOrderPlugin(),
+        // extract css into its own file
+        new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')),
+        // generate dist index.html with correct asset hash for caching.
+        // you can customize output by editing /index.html
+        // see https://github.com/ampedandwired/html-webpack-plugin
+        new HtmlWebpackPlugin({
+            filename: config.build.index,
+            template: 'index.html',
+            inject: true,
+            minify: {
+                removeComments: true,
+                collapseWhitespace: true,
+                removeAttributeQuotes: true
+                    // more options:
+                    // https://github.com/kangax/html-minifier#options-quick-reference
+            },
+            // necessary to consistently work with multiple chunks via CommonsChunkPlugin
+            chunksSortMode: 'dependency'
+        }),
+        // split vendor js into its own file
+        new webpack.optimize.CommonsChunkPlugin({
+            name: 'vendor',
+            minChunks: function(module, count) {
+                // any required modules inside node_modules are extracted to vendor
+                return (
+                    module.resource &&
+                    /\.js$/.test(module.resource) &&
+                    module.resource.indexOf(
+                        path.join(__dirname, '../node_modules')
+                    ) === 0
+                )
+            }
+        }),
+        // extract webpack runtime and module manifest to its own file in order to
+        // prevent vendor hash from being updated whenever app bundle is updated
+        new webpack.optimize.CommonsChunkPlugin({
+            name: 'manifest',
+            chunks: ['vendor']
+        })
+    ]
+})
+
+if (config.build.productionGzip) {
+    var CompressionWebpackPlugin = require('compression-webpack-plugin')
+
+    webpackConfig.plugins.push(
+        new CompressionWebpackPlugin({
+            asset: '[path].gz[query]',
+            algorithm: 'gzip',
+            test: new RegExp(
+                '\\.(' +
+                config.build.productionGzipExtensions.join('|') +
+                ')$'
+            ),
+            threshold: 10240,
+            minRatio: 0.8
+        })
+    )
+}
+
+module.exports = webpackConfig

+ 6 - 0
config/dev.env.js

@@ -0,0 +1,6 @@
+var merge = require('webpack-merge')
+var prodEnv = require('./prod.env')
+
+module.exports = merge(prodEnv, {
+  NODE_ENV: '"development"'
+})

+ 37 - 0
config/index.js

@@ -0,0 +1,37 @@
+// see http://vuejs-templates.github.io/webpack for documentation.
+var path = require('path');
+
+module.exports = {
+    build: {
+        env: require('./prod.env'),
+        index: path.resolve(__dirname, '../dist/index.html'),
+        assetsRoot: path.resolve(__dirname, '../dist'),
+        assetsSubDirectory: 'static',
+        assetsPublicPath: './',
+        productionSourceMap: true,
+        // Gzip off by default as many popular static hosts such as
+        // Surge or Netlify already gzip all static assets for you.
+        // Before setting to `true`, make sure to:
+        // npm install --save-dev compression-webpack-plugin
+        productionGzip: false,
+        productionGzipExtensions: ['js', 'css']
+    },
+    dev: {
+        env: require('./dev.env'),
+        port: 23002,
+        assetsSubDirectory: 'static',
+        assetsPublicPath: '/',
+        proxyTable: {
+          '/uas_manage_server': {
+            target: 'http://localhost:23001',
+            changeOrigin: true
+          }
+        },
+        // CSS Sourcemaps off by default because relative paths are "buggy"
+        // with this option, according to the CSS-Loader README
+        // (https://github.com/webpack/css-loader#sourcemaps)
+        // In our experience, they generally work as expected,
+        // just be aware of this issue when enabling this option.
+        cssSourceMap: false
+    }
+}

+ 3 - 0
config/prod.env.js

@@ -0,0 +1,3 @@
+module.exports = {
+  NODE_ENV: '"production"'
+}

+ 22 - 0
index.html

@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
+        <link rel="stylesheet" href="static/font-awesome/css/font-awesome.min.css">
+        <title>UAS系统管理中心</title>
+        <style>
+            *{
+                -webkit-box-sizing: border-box;
+                -moz-box-sizing: border-box;
+                box-sizing: border-box;
+                margin:0px;
+                padding:0px;
+            }
+        </style>
+    </head>
+    <body>
+        <div id="app"></div>
+        <script src='static/libs/jquery/jquery.min.js'></script>
+    </body>
+</html>

+ 63 - 0
package.json

@@ -0,0 +1,63 @@
+{
+  "name": "uas-manage-server-web",
+  "version": "1.0.0",
+  "description": "uas-manage-server-web",
+  "private": true,
+  "scripts": {
+    "dev": "node build/dev-server.js",
+    "build": "node build/build.js"
+  },
+  "dependencies": {
+    "axios": "^0.15.3",
+    "css-loader": "^0.25.0",
+    "element-ui": "^1.3.0-beta.3",
+    "font-awesome": "^4.7.0",
+    "less": "^2.7.2",
+    "less-loader": "^2.2.3",
+    "nprogress": "^0.2.0",
+    "qs": "^6.4.0",
+    "vue": "^2.3.2",
+    "vue-axios": "^1.2.2",
+    "vue-loader": "^10.3.0",
+    "vue-router": "^2.1.1",
+    "vue-template-compiler": "^2.3.2",
+    "vuex": "^2.1.1",
+    "http-proxy-middleware": "^0.17.2"
+  },
+  "devDependencies": {
+    "autoprefixer": "^6.4.0",
+    "babel-core": "^6.0.0",
+    "babel-loader": "^6.0.0",
+    "babel-plugin-transform-runtime": "^6.0.0",
+    "babel-preset-es2015": "^6.0.0",
+    "babel-preset-stage-2": "^6.0.0",
+    "babel-register": "^6.0.0",
+    "chalk": "^1.1.3",
+    "connect-history-api-fallback": "^1.1.0",
+    "css-loader": "^0.25.0",
+    "eventsource-polyfill": "^0.9.6",
+    "express": "^4.13.3",
+    "extract-text-webpack-plugin": "^1.0.1",
+    "file-loader": "^0.9.0",
+    "friendly-errors-webpack-plugin": "^1.1.2",
+    "function-bind": "^1.0.2",
+    "html-webpack-plugin": "^2.8.1",
+    "json-loader": "^0.5.4",
+    "opn": "^4.0.2",
+    "ora": "^0.3.0",
+    "semver": "^5.3.0",
+    "shelljs": "^0.7.4",
+    "url-loader": "^0.5.7",
+    "vue-loader": "^10.0.0",
+    "vue-style-loader": "^1.0.0",
+    "vue-template-compiler": "^2.1.0",
+    "webpack": "^1.13.2",
+    "webpack-dev-middleware": "^1.8.3",
+    "webpack-hot-middleware": "^2.12.2",
+    "webpack-merge": "^0.14.1"
+  },
+  "engines": {
+    "node": ">= 4.0.0",
+    "npm": ">= 3.0.0"
+  }
+}

+ 9 - 0
runtime/docker/config.js

@@ -0,0 +1,9 @@
+module.exports = {
+  port: 23002,
+  proxyTable: {
+    '/uas_manage_server': {
+      target: process.env.UAS_MANAGE_SERVER,
+      changeOrigin: true
+    }
+  }
+}

+ 10 - 0
runtime/docker/run.sh

@@ -0,0 +1,10 @@
+#!/bin/sh
+
+if [ ! "$UAS_MANAGE_SERVER" ]; then
+  UAS_MANAGE_SERVER = "http://localhost:23001"
+fi
+
+echo "NODE_ENV: $NODE_ENV"
+echo "UAS_MANAGE_SERVER: $UAS_MANAGE_SERVER"
+
+node server.js

+ 25 - 0
runtime/docker/server.js

@@ -0,0 +1,25 @@
+var config = require('./config')
+var express = require('express')
+var proxyMiddleware = require('http-proxy-middleware')
+
+var port = process.env.PORT || config.port
+
+var proxyTable = config.proxyTable
+
+var app = express()
+
+// proxy api requests
+Object.keys(proxyTable).forEach(function (context) {
+  var options = proxyTable[context]
+  if (typeof options === 'string') {
+    options = { target: options }
+  }
+  app.use(proxyMiddleware(context, options))
+})
+
+module.exports = app.listen(port, function (err) {
+  if (err) {
+    console.log(err)
+    return
+  }
+})

+ 63 - 0
src/App.vue

@@ -0,0 +1,63 @@
+<template>
+    <div id="app">
+        <transition name="bounce">
+            <router-view></router-view>
+        </transition>
+    </div>
+</template>
+
+<script>
+    export default {
+        name: 'app',
+        components: {},
+        methods:{
+
+        },
+        mounted(){
+            // console.log(this.$$ajax);
+        },
+        watch:{
+            $route(to,from){
+                console.log(to);
+                if (!to.matched.length) {
+                    //this.$router.push('/404');
+                }
+            }
+        }
+    }
+</script>
+<style scoped lang='less'>
+    .bounce-enter-active {
+        animation: bounce-in .5s;
+        -webkit-animation:bounce-in .5s;
+    }
+
+    .bounce-leave-active {
+        animation: bounce-out .2s;
+        -webkit-animation: bounce-out .2s;
+    }
+
+    @keyframes bounce-in {
+        0% {
+            transform: scale(0);
+        }
+        50% {
+            transform: scale(1.05);
+        }
+        100% {
+            transform: scale(1);
+        }
+    }
+
+    @keyframes bounce-out {
+        0% {
+            transform: scale(1);
+        }
+        50% {
+            transform: scale(0.95);
+        }
+        100% {
+            transform: scale(0);
+        }
+    }
+</style>

BIN
src/assets/logo-uas.png


+ 54 - 0
src/components/Common/Bread/Bread.vue

@@ -0,0 +1,54 @@
+<template>
+    <div class='bread'>
+        <strong>
+            {{strong}}
+        </strong>
+        <el-breadcrumb separator="/" class='el-bread'>
+            <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
+            <el-breadcrumb-item v-for='(item,index) in $route.matched'>{{item.name}}</el-breadcrumb-item>
+        </el-breadcrumb>
+    </div>
+</template>
+
+<script>
+    export default {
+        name: 'bread',
+        data () {
+            return {
+                strong:''
+            }
+        },
+        methods:{
+            getPageText(name){
+                return name=name.replace('编辑',this.$route.query.id ? '修改' : '添加');
+            }
+        },
+        mounted(){
+
+        },
+        created(){
+            if (this.$route.matched.length) {
+                var name=this.$route.matched[this.$route.matched.length-1].name;
+                this.strong=this.getPageText(name);
+            }
+        },
+        watch:{
+            $route(to,from){
+                this.strong=this.getPageText(to.name);
+            }
+        }
+    }
+</script>
+
+<style scoped lang='less'>
+    .bread{
+        height: 40px;
+        line-height: 26px;
+        .el-bread{
+            display: inline-block;
+            float: right;
+            text-align: right;
+            line-height: 26px;
+        }
+    }
+</style>

+ 45 - 0
src/components/Common/DialogInfo/DialogInfo.js

@@ -0,0 +1,45 @@
+module.exports = {
+    name: 'dialog-info',
+    data() {
+        return {
+            dialog: this.Dialog || {}
+        }
+    },
+    methods: {
+        onClose() {
+            this.dialog.show = false;
+        }
+    },
+
+    computed: {
+        show() {
+            return this.dialog.show;
+        }
+    },
+
+    mounted() {
+        // console.log(this.Show);
+    },
+
+    /**
+     * 接收参数
+     * @type {Object}
+     */
+    props: {
+        Dialog: {
+            type: Object,
+            validator: (v) => {
+                return true;
+            }
+        }
+    },
+
+
+    /**
+     * 监控参数
+     * @type {Object}
+     */
+    watch: {
+
+    }
+}

+ 41 - 0
src/components/Common/DialogInfo/DialogInfo.vue

@@ -0,0 +1,41 @@
+<template>
+    <div class="">
+        <el-dialog size="tiny" 
+            :title="dialog.title" 
+            v-model="show"
+            @close='onClose'>
+            <el-form style="margin:20px;width:60%;min-width:100%" 
+                label-width="100px">
+                <el-form-item class='edit-form'
+                    v-for='field in dialog.fields'
+                    :label='field.label'>
+                    {{dialog.data[field.key]}}
+                </el-form-item>
+            </el-form>
+            <span slot="footer" class="dialog-footer">
+                <el-button type="primary" @click="onClose">关 闭</el-button>
+            </span>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+    import DialogInfoJs from './DialogInfo.js';
+    module.exports=DialogInfoJs;
+</script>
+<style scoped lang='less'>
+    .demo-form-inline{
+        display: inline-block;
+        float: right;
+    }
+    .btm-action{
+        margin-top: 20px;
+        text-align: center;
+    }
+    .actions-top{
+        height: 46px;
+    }
+    .pagination{
+        display: inline-block;
+    }
+</style>

+ 2 - 0
src/components/Common/DialogInfo/index.js

@@ -0,0 +1,2 @@
+import DialogInfo from './DialogInfo.vue';
+module.exports = DialogInfo;

+ 544 - 0
src/components/Common/FormData/FormData.js

@@ -0,0 +1,544 @@
+//noinspection JSAnnotator
+module.exports = {
+	name   : 'list',
+	data() {
+		return {
+			checkall_temp: '_checkall_temp',
+
+			fields     : this.FieldList || [],
+			editor     : this.Editor || {},
+			submit_data: this.DefaultValue || {},
+			rules      : this.Rules || {},
+
+			/**
+			 * 富文本编辑器信息
+			 * @type {Object}
+			 */
+			wangEditor: {
+				//存富文本实例的对象,支持多个
+				//key为富文本对象ID,value为实例
+				editor: {},
+				//默认为单个编辑器,如果为多个,此值为true,因为多个编辑器时,地图菜单不可用
+				many  : false,
+				has   : false,
+				//默认显示菜单,支持自定义
+				bar   : [
+					'source', '|',
+					'bold',
+					'underline',
+					'italic',
+					'strikethrough',
+					'eraser',
+					'forecolor',
+					'bgcolor', '|',
+					'quote',
+					'fontfamily',
+					'fontsize',
+					'head',
+					'unorderlist',
+					'orderlist',
+					'alignleft',
+					'aligncenter',
+					'alignright', '|',
+					'link',
+					'unlink',
+					'table',
+					'emotion', '|',
+					'img',
+					'video',
+					// 'location',
+					'insertcode', '|',
+					'undo',
+					'redo',
+					'fullscreen'
+				],
+				temp  : {},
+			},
+		}
+	},
+	methods: {
+		/**
+		 * 初始化编辑器
+		 * @param  {string} id     编辑器ID属性
+		 * @param  {object} config 初始化配置
+		 * @return {object}        所有编辑器所在对象,属性已ID为key
+		 */
+		initEditor(id, config) {
+			if (id) {
+				this.wangEditor.editor[id] = new wangEditor(id);
+				this.wangEditor.temp[id]   = {
+					html: '',
+					text: ''
+				};
+			}
+			this.configEditor(id, config).eventEditor(id).createEditor(id);
+		},
+
+
+		/**
+		 * 配置编辑器参数
+		 * @param  {string} id     编辑器ID
+		 * @param  {object} config 编辑器配置信息
+		 */
+		configEditor(id, config) {
+			if (id && config) {
+				this.wangEditor.editor[id].config={};
+				this.wangEditor.editor[id].config.uploadImgFns={};
+				this.wangEditor.editor[id].config.uploadImgFileName = config.name || this.editor.name || 'sls-admin';
+				this.wangEditor.editor[id].config.uploadImgUrl      = config.url || this.editor.url || '';
+				this.wangEditor.editor[id].config.uploadParams      = config.params || this.editor.params || {};
+
+				/**
+				 * 显示的菜单,分四种情况
+				 * 1-只传显示的菜单,直接赋值
+				 * 2-只传隐藏的菜单,过滤不需要显示的
+				 * 3-显示隐藏都传了,显示优先级高于隐藏优先级
+				 * 4-啥都不传,取默认全部显示
+				 * @type {object}
+				 */
+				if (Array.isArray(config.show_bar) && config.show_bar.length) {
+					var bar = config.show_bar;
+				} else if (Array.isArray(config.hide_bar) && config.hide_bar.length) {
+					var bar = this.wangEditor.bar.filter((item) => {
+						return config.hide_bar.indexOf(item) === -1;
+					});
+				} else if (Array.isArray(this.editor.show_bar) && this.editor.show_bar.length) {
+					var bar = this.editor.show_bar;
+				} else if (Array.isArray(this.editor.hide_bar) && this.editor.hide_bar.length) {
+					var bar = this.wangEditor.bar.filter((item) => {
+						return this.editor.hide_bar.indexOf(item) === -1;
+					});
+				} else {
+					var bar = this.wangEditor.bar;
+				}
+
+				if (this.wangEditor.many === true && bar.indexOf('location') !== -1) {
+					var bar = bar.splice(bar.indexOf('location'), 1);
+				}
+
+				this.wangEditor.editor[id].config.menus = bar;
+				console.log(this.wangEditor.editor[id].config.menus);
+			}
+
+			return this;
+		},
+
+
+		/**
+		 * 编辑器常用事件
+		 * @param  {string} id 编辑器ID
+		 */
+		eventEditor(id) {
+			var self                                              = this;
+			this.wangEditor.editor[id].config.uploadImgFns.onload = function (data) {
+				if (data.status === 200) {
+					var originalName = this.uploadImgOriginalName || '';
+
+					this.command(null, 'insertHtml', '<img src="' + data.data.fileinfo.getSaveName + '" alt="' + originalName + '" style="max-width:100%;"/>');
+				} else {
+					if (data.status === 404) {
+						self.$message.error('上传错误信息:token无效!');
+					} else {
+						self.$message.error('上传错误信息:' + data.msg);
+					}
+				}
+
+			};
+
+			this.wangEditor.editor[id].config.uploadImgFns.onerror = (xhr) => {
+				this.$message.error('上传错误信息:网络错误!');
+			};
+
+			this.wangEditor.editor[id].onchange = function () {
+				var text = this.$txt.text().replace(/(^\s*)|(\s*$)/g, ""),
+					html = this.$txt.html();
+
+				self.wangEditor.temp[id].html = html;
+				self.wangEditor.temp[id].text = text;
+
+				self.$emit('onEditorChange', {
+					id,
+					data: {
+						html,
+						text
+					}
+				});
+			};
+
+			return this;
+		},
+
+
+		/**
+		 * 创建编辑器
+		 * @param  {string} id 编辑器ID
+		 */
+		createEditor(id) {
+			console.log(this.wangEditor.editor[id]);
+			this.wangEditor.editor[id].create();
+			console.log(id);
+		},
+
+
+		/**
+		 * 处理全选全部选
+		 * @param  {object} field 字段对象
+		 */
+		initCheckall(field) {
+			var temp            = {};
+			temp.text           = field.checkall.text;
+			temp.value          = field.checkall.value;
+			temp.indeterminate  = field.checkall.indeterminate;
+			temp.checkbox_list  = field.value.list;
+			temp.checkbox_value = field.value.default;
+			this.$set(this.submit_data, field.key + this.checkall_temp, temp);
+		},
+
+
+		/**
+		 * 日期时间空间增加改变回掉
+		 * @param  {array} fields 字段数组
+		 * @param  {number} i      当前对象索引
+		 */
+		onDateTimeChange(fields, i, type) {
+			//如果没有传改变事件回调,需要补回调
+			if (!fields[i].change || typeof fields[i].change !== 'function') {
+				this.$set(fields[i], 'change', v => {
+					switch (type) {
+						case 'range':
+							var temp                        = v.split(' - ');
+							this.submit_data[fields[i].key] = temp;
+							break;
+						default:
+							this.submit_data[fields[i].key] = v;
+					}
+				});
+			}
+		},
+
+
+		/**
+		 * 日期时间设置一些参数
+		 * @param  {array} fields 字段数组
+		 * @param  {number} i      [当前对象索引]
+		 */
+		onDateOptions(fields, i, type) {
+			var field = fields[i];
+
+			if (!field.options) {
+				var options      = {},
+
+					//默认快捷方式
+					shortcuts    = [{
+						text: '今天',
+						onClick(picker) {
+							picker.$emit('pick', new Date());
+						}
+					}, {
+						text: '昨天',
+						onClick(picker) {
+							const date = new Date();
+							date.setTime(date.getTime() - 3600 * 1000 * 24);
+							picker.$emit('pick', date);
+						}
+					}, {
+						text: '一周前',
+						onClick(picker) {
+							const date = new Date();
+							date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
+							picker.$emit('pick', date);
+						}
+					}],
+					//默认禁止今天以前的日期
+					disabledDate = function (time) {
+						return time.getTime() < Date.now() - 8.64e7;
+					};
+
+
+				if (field.shortcuts === true) {
+					options.shortcuts = shortcuts;
+				}
+				if (field.disabledDate === true) {
+					options.disabledDate = disabledDate;
+				}
+
+				if (field.disabledDate && field.disabledDate.constructor === Function) {
+					options.disabledDate = field.disabledDate;
+				}
+				if (field.shortcuts && field.shortcuts.constructor === Array) {
+					options.shortcuts = field.shortcuts;
+				}
+
+
+				this.$set(fields[i], 'options', options);
+			}
+		},
+
+
+		/**
+		 * 设置时间参数
+		 * @param fields	字段数组
+		 * @param i			当前索引
+		 * @param type		类型
+		 */
+		onTimeOptions(fields, i, type) {
+			var field = fields[i];
+
+			if (!field.options) {
+				var options = {};
+
+
+				this.$set(fields[i], 'options', options);
+			}
+		},
+
+
+		/**
+		 * 处理日期
+		 * @param  {array} fields 字段数组
+		 * @param  {number} i      当前日期对象的索引
+		 */
+		initDate(fields, i, type) {
+			//设置回调
+			this.onDateTimeChange(fields, i, type);
+
+			//设置日期参数
+			this.onDateOptions(fields, i, type);
+		},
+
+
+		/**
+		 * 处理时间
+		 * @param  {array} fields 字段数组
+		 * @param  {number} i      当前日期对象的索引
+		 */
+		initTime(fields, i, type) {
+			//设置回调
+			this.onDateTimeChange(fields, i, type);
+
+			//设置日期参数
+			this.onTimeOptions(fields, i, type);
+		},
+
+
+		initYear(fields, i) {
+			//设置回调
+			this.onDateTimeChange(fields, i);
+		},
+
+		initMonth(fields, i) {
+			//设置回调
+			this.onDateTimeChange(fields, i);
+		},
+
+		initWeek(fields, i) {
+			//设置回调
+			this.onDateTimeChange(fields, i);
+
+			if (!fields[i].format) {
+				this.$set(fields[i], 'format', 'yyyy 第 WW 周');
+			}
+		},
+
+
+		/**
+		 * 从字段列表中提取出来表单字段
+		 * @return {object} [表单需要的字段]
+		 */
+		deepObj() {
+			if (this.fields) {
+				var fields = this.fields,
+					k      = 0,
+					update = this.submit_data.id ? true : false;
+				for (var i = 0; i < fields.length; i++) {
+					var field = fields[i];
+
+					if (field.value && field.value.constructor === Object) {
+						if (field.checkall && typeof field.checkall === 'object') {
+							this.initCheckall(field);
+						} else {
+							this.$set(this.submit_data, field.key, field.value.default);
+						}
+					} else {
+						this.$set(this.submit_data, field.key, field.value);
+					}
+
+
+					if (field.type) {
+						switch (field.type) {
+							case 'editor':
+								k++;
+								this.initEditor(field.id, field.config || {});
+								if (k == 2) {
+									this.wangEditor.many = true;
+								}
+								if (k == 1) {
+									this.wangEditor.has = true;
+								}
+								break;
+
+							case 'date':
+								this.initDate(fields, i);
+								break;
+
+							case 'daterange':
+								this.initDate(fields, i, 'range');
+								break;
+
+							case 'year':
+								this.initYear(fields, i);
+								break;
+
+							case 'month':
+								this.initMonth(fields, i);
+								break;
+
+							case 'week':
+								this.initWeek(fields, i);
+								break;
+
+							case 'time':
+								this.initTime(fields, i);
+								break;
+
+							case 'datetime':
+								this.initDate(fields, i);
+								break;
+
+							case 'datetimerange':
+								this.initDate(fields, i, 'range');
+								break;
+
+						}
+					}
+				}
+
+				// console.log(this.submit_data);
+			}
+		},
+
+
+		/**
+		 * 表单提交事件
+		 */
+		onSubmit(ref) {
+			var data = {
+				data: this.submit_data,
+			};
+			if (this.wangEditor.has === true) {
+				data.editor_temp_data = this.wangEditor.temp;
+			}
+
+			if (this.rules) {
+				this.$refs[ref].validate((valid) => {
+					if (valid) {
+						this.$emit('onSubmit', data);
+					}
+				});
+			} else {
+				this.$emit('onSubmit', data);
+			}
+		},
+
+
+		/**
+		 * checkbox改变时触发
+		 * @param  {string} key 当前元素的key
+		 */
+		onCheckboxChange(key) {
+			var checkall_temp = this.submit_data[key + this.checkall_temp];
+
+			if (checkall_temp.checkbox_value.length > 0 && checkall_temp.checkbox_value.length < checkall_temp.checkbox_list.length) {
+				checkall_temp.indeterminate = true;
+			} else {
+				checkall_temp.indeterminate = false;
+			}
+
+			checkall_temp.value = checkall_temp.checkbox_value.length === checkall_temp.checkbox_list.length;
+		},
+
+
+		/**
+		 * checkallbox改变时触发
+		 * @param  {string} key 当前元素的key
+		 */
+		onCheckallChange(key) {
+			var checkall_temp           = this.submit_data[key + this.checkall_temp];
+			checkall_temp.indeterminate = false;
+
+			var value = [];
+			if (checkall_temp.value == true) {
+				for (var i = 0; i < checkall_temp.checkbox_list.length; i++) {
+					value.push(checkall_temp.checkbox_list[i].value);
+				}
+			}
+
+			checkall_temp.checkbox_value = value;
+		},
+
+
+		onCascaderItemChange(value) {
+			// console.log(value);
+		},
+
+
+		onChangeDateTime(v) {
+			console.log(v + '    formdata');
+		}
+	},
+
+
+	created() {
+		this.deepObj();
+	},
+
+
+	/**
+	 * ready
+	 */
+	mounted() {
+		// this.deepObj();
+	},
+
+
+	/**
+	 * 接收参数
+	 * @type {Object}
+	 */
+	props: {
+		FieldList   : {
+			type    : Array,
+			required: true
+		},
+		Editor      : {
+			type: Object
+		},
+		Rules       : {
+			type: Object
+		},
+		DefaultValue: {
+			type: Object
+		}
+	},
+
+
+	/**
+	 * 监控参数
+	 * @type {Object}
+	 */
+	watch: {
+		FieldList: {
+			deep: true,
+			handler(v){
+				if (v) {
+					this.fields = v;
+				}
+			}
+		},
+		DefaultValue(v) {
+			if (v) {
+				this.submit_data = v;
+			}
+		}
+	}
+}

+ 212 - 0
src/components/Common/FormData/FormData.vue

@@ -0,0 +1,212 @@
+<template>
+    <div class="form">
+        <el-form style=""
+                 label-width="100px"
+                 ref='form-data'
+                 :rules='rules'
+                 :model='submit_data'>
+            <el-form-item
+                    class='edit-form'
+                    v-for='(field,index) in fields'
+                    :label="field.label"
+                    :prop='field.key'
+                    :style="field.item_style">
+
+                <!-- 单选CheckBox -->
+                <el-checkbox
+                        v-if='field.type==="checkbox" && field.multiple!==true'
+                        v-model="submit_data[field.key]">{{field.label}}
+                </el-checkbox>
+
+                <el-cascader
+                        v-if='field.type==="cascader"'
+                        :options="field.value.list"
+                        :props="field.props || {}"
+                        @active-item-change='onCascaderItemChange'></el-cascader>
+
+
+                <!-- 复选CheckBox -->
+                <!-- 是否全选全不选 -->
+                <el-checkbox
+                        v-if='field.checkall && typeof field.checkall==="object" && submit_data[field.key+checkall_temp]'
+                        :indeterminate="submit_data[field.key+checkall_temp].indeterminate"
+                        v-model="submit_data[field.key+checkall_temp].value"
+                        @change='onCheckallChange(field.key)'>{{submit_data[field.key+checkall_temp].text}}
+                </el-checkbox>
+                <!-- CheckBox选项列表 -->
+                <el-checkbox-group
+                        v-if='(field.type==="checkbox" && field.multiple===true && !field.checkall) || (field.type==="checkbox" && field.multiple===true && field.checkall && submit_data[field.key+checkall_temp])'
+                        v-model="submit_data[field.key+checkall_temp].checkbox_value"
+                        @change='onCheckboxChange(field.key)'>
+                    <el-checkbox
+                            v-for='item in submit_data[field.key+checkall_temp].checkbox_list'
+                            :label="item.value">{{item.text}}
+                    </el-checkbox>
+                </el-checkbox-group>
+
+                <!-- wangeditor -->
+                <div
+                        v-if='field.type==="editor"'
+                        :id="field.id"
+                        :style="field.style"
+                        v-html='submit_data[field.key]'></div>
+
+                <!--
+                    input,textarea 
+                 -->
+                <el-input
+                        v-if='!field.type || field.type==="input" || field.type==="textarea"'
+                        :type='!field.type ? "input" : field.type'
+                        v-model="submit_data[field.key]"
+                        :placeholder='field.desc'></el-input>
+
+                <!-- 
+                    radia,单选
+                 -->
+                <el-radio-group
+                        v-if='field.type==="radio"'
+                        v-model="submit_data[field.key]">
+                    <el-radio
+                            v-for='item in field.value.list'
+                            :label="item.value">{{item.text || item.value}}
+                    </el-radio>
+                </el-radio-group>
+
+                <!-- select,下拉框 -->
+                <el-select
+                        v-if='field.type==="select"'
+                        v-model="submit_data[field.key]"
+                        :multiple='field.multiple ? true : false'
+                        :placeholder="field.desc">
+                    <el-option
+                            v-for='item in field.value.list'
+                            :value="item.value"
+                            :label="item.text"></el-option>
+                </el-select>
+
+                <!-- 
+                    switch,开关
+                 -->
+                <el-switch
+                        v-if='field.type==="switch"'
+                        :on-text="field.value.on"
+                        :off-text="field.value.off"
+                        :disabled='field.disabled'
+                        v-model="submit_data[field.key]"></el-switch>
+
+                <!-- date,日期类型 -->
+                <el-date-picker
+                        v-if='field.type==="date"'
+                        v-model="submit_data[field.key]"
+                        :type="field.type"
+                        :placeholder="field.placeholder"
+                        @change='field.change'
+                        :picker-options="field.options">
+                </el-date-picker>
+
+                <!-- date,日期类型-选择范围 -->
+                <!-- 
+                    @change='field.change'
+                 -->
+                <el-date-picker
+                        v-if='field.type==="daterange"'
+                        v-model="submit_data[field.key]"
+                        :type="field.type"
+                        :placeholder="field.placeholder"
+                        @change='field.change'>
+                </el-date-picker>
+
+                <!-- date,日期类型-年 -->
+                <el-date-picker
+                        v-if='field.type==="year"'
+                        v-model="submit_data[field.key]"
+                        :type="field.type"
+                        :placeholder="field.placeholder"
+                        @change='field.change'>
+                </el-date-picker>
+
+                <!-- date,日期类型-月 -->
+                <el-date-picker
+                        v-if='field.type==="month"'
+                        v-model="submit_data[field.key]"
+                        :type="field.type"
+                        :placeholder="field.placeholder"
+                        @change='field.change'>
+                </el-date-picker>
+
+                <!-- date,日期类型-周 -->
+                <el-date-picker
+                        v-if='field.type==="week"'
+                        v-model="submit_data[field.key]"
+                        :type="field.type"
+                        :format="field.format"
+                        :placeholder="field.placeholder"
+                        @change='field.change'>
+                </el-date-picker>
+
+
+                <!-- time,时间类型 -->
+                <el-time-select
+                        v-if='field.type==="time"'
+                        v-model="submit_data[field.key]"
+                        :type="field.type"
+                        :placeholder="field.placeholder"
+                        @change='field.change'
+                        :picker-options="field.options">
+                </el-time-select>
+
+
+                <!-- 日期时间组合 -->
+                <el-date-picker
+                        v-if='field.type==="datetime"'
+                        v-model="submit_data[field.key]"
+                        :type="field.type"
+                        @change='field.change'
+                        :placeholder="field.placeholder"
+                        :picker-options="field.options">
+                </el-date-picker>
+
+
+                <!-- datetime,日期时间类型-选择范围 -->
+                <!--
+                    @change='field.change'
+                 -->
+                <el-date-picker
+                        v-if='field.type==="datetimerange"'
+                        v-model="submit_data[field.key]"
+                        :type="field.type"
+                        :placeholder="field.placeholder"
+                        @change='field.change'>
+                </el-date-picker>
+            </el-form-item>
+
+            <el-form-item>
+                <el-button type="primary" @click='onSubmit("form-data")'>提交</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+
+<script>
+	import FormDataJs from './FormData.js';
+	module.exports = FormDataJs;
+</script>
+<style scoped lang='less'>
+    .demo-form-inline {
+        display: inline-block;
+        float: right;
+    }
+
+    .btm-action {
+        margin-top: 20px;
+        text-align: center;
+    }
+
+    .actions-top {
+        height: 46px;
+    }
+
+    .pagination {
+        display: inline-block;
+    }
+</style>

+ 2 - 0
src/components/Common/FormData/index.js

@@ -0,0 +1,2 @@
+import FormData from './FormData.vue';
+module.exports = FormData;

+ 179 - 0
src/components/Common/HeadNav/HeadNav.js

@@ -0,0 +1,179 @@
+import {
+    user as UserApi,
+    system as SystemApi
+} from '../../../config/request.js';
+
+module.exports = {
+    name: 'head-nav',
+    data() {
+        return {
+            dialog: {
+                show_access: false,
+                show_set: false,
+                show_pass: false,
+                title: '修改密码',
+                user_info: this.$store.state.user.userinfo,
+
+                set_info: {
+                    login_style: '',
+                    disabled_update_pass: [],
+                    select_users: []
+                },
+
+                user_info_rules: {
+                    old_password: [{
+                        required: true,
+                        message: '旧密码不能为空!',
+                        trigger: 'blur'
+                    }],
+                    password: [{
+                        required: true,
+                        message: '新密码不能为空!',
+                        trigger: 'blur'
+                    }, {
+                        trigger: 'blur',
+                        validator: (rule, value, callback) => {
+                            if (value === '') {
+                                callback(new Error('请再次输入密码'));
+                            } else {
+                                if ('' !== this.dialog.user_info.password) {
+                                    this.$refs.user_info.validateField('password_confirm');
+                                }
+                                callback();
+                            }
+                        }
+                    }],
+                    password_confirm: [{
+                        required: true,
+                        message: '确认密码不能为空!',
+                        trigger: 'blur'
+                    }, {
+                        trigger: 'blur',
+                        validator: (rule, value, callback) => {
+                            if (value === '') {
+                                callback(new Error('请再次输入密码'));
+                            } else if (value !== this.dialog.user_info.password) {
+                                callback(new Error('两次输入密码不一致!'));
+                            } else {
+                                callback();
+                            }
+                        }
+                    }],
+                }
+            }
+        }
+    },
+    mounted() {
+        // this.setDialogInfo('access');
+
+        // this.onGetSetting();
+    },
+    methods: {
+        /**
+         * 退出登录
+         */
+        logout() {
+            this.$confirm('你确定退出登录么?', '确认退出', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning'
+            }).then(() => {
+                this.$store.dispatch('remove_userinfo').then(() => {
+                    this.$router.push('/login');
+                });
+            });
+        },
+
+        /**
+         * 弹出框-修改密码或者系统设置   
+         * @param {string} cmditem 弹框类型
+         */
+        setDialogInfo(cmditem) {
+            if (!cmditem) {
+                console.log('test');
+                this.$message('菜单选项缺少command属性');
+                return;
+            }
+            switch (cmditem) {
+                case 'info':
+                    this.$router.push({
+                        path: '/demo/user/edit',
+                        query: {
+                            id: this.$store.state.user.userinfo.id
+                        }
+                    });
+                    break;
+                case 'pass':
+                    this.dialog.show_pass = true;
+                    this.dialog.title = '修改密码';
+                    break;
+                case 'set':
+                    this.onGetSetting();
+                    this.dialog.show_set = true;
+                    this.dialog.title = '系统设置';
+                    break;
+            }
+        },
+
+        /**
+         * 修改密码
+         * @param  {object} userinfo 当前修改密码的表单信息
+         */
+        updUserPass(userinfo) {
+            this.$refs[userinfo].validate((valid) => {
+                if (valid) {
+                    UserApi.updPass.call(this, {
+                        old_password: this.dialog[userinfo].old_password,
+                        password: this.dialog[userinfo].password,
+                        password_confirm: this.dialog[userinfo].password_confirm
+                    }, (data) => {
+                        this.dialog.show_pass = false;
+                        // this.$nextTick(() => {
+                        this.$message.success('修改成功!');
+                        // });
+                    });
+                }
+            });
+        },
+
+        /**
+         * 获取系统设置信息
+         */
+        onGetSetting() {
+            //获取系统设置信息
+            if (this.$store.state.user.userinfo.pid == 0) {
+                SystemApi.getSetting.call(this, (data) => {
+                    // console.log(data);
+                    if (data.setting_info.disabled_update_pass) {
+                        data.setting_info.disabled_update_pass = data.setting_info.disabled_update_pass.split(',');
+                    } else {
+                        data.setting_info.disabled_update_pass = [];
+                    }
+                    data.setting_info.login_style = data.setting_info.login_style + '';
+
+                    this.dialog.set_info = data.setting_info;
+                });
+            } else {
+                this.$message.error('只有管理员才能操作!');
+            }
+        },
+
+        /**
+         * 修改系统设置信息
+         */
+        onUpdateSetting() {
+            // console.log(this.dialog.set_info.login_style);
+            // console.log(this.dialog.set_info.disabled_update_pass);
+            // console.log(this.dialog.set_info.id);
+
+            SystemApi.updateSetting.call(this, {
+                id: this.dialog.set_info.id,
+                login_style: this.dialog.set_info.login_style,
+                disabled_update_pass: this.dialog.set_info.disabled_update_pass && this.dialog.set_info.disabled_update_pass.length ? this.dialog.set_info.disabled_update_pass.join(',') : ''
+            }, (data) => {
+                // console.log(data);
+                this.dialog.show_set = false;
+            });
+        }
+    }
+}

+ 194 - 0
src/components/Common/HeadNav/HeadNav.vue

@@ -0,0 +1,194 @@
+<template>
+    <div>
+
+        <header class="head-nav">
+            <el-row>
+                <el-col :span="4" class='logo-container'>
+                    <img src="../../../assets/logo-uas.png" class='logo' alt="">
+                </el-col>
+                <el-col :span="16">
+                    <el-menu theme="dark" :default-active="$store.state.router.headerCurRouter" class="el-menu-demo"
+                             mode="horizontal" unique-opened router>
+                        <!-- v-if='!item.hidden && (($store.state.user.userinfo.access_status===1 && $store.state.user.userinfo.web_routers[item.path]) || $store.state.user.userinfo.access_status!==1)' -->
+                        <el-menu-item
+                                :index="item.path"
+                                v-for='(item,index) in $router.options.routes'
+                                v-if='!item.hidden && (($store.state.user.userinfo.access_status===1 && $store.state.user.userinfo.web_routers[item.path]) || $store.state.user.userinfo.access_status!==1)'>
+                            {{item.name}}<!-- {{item.path}} -->
+                        </el-menu-item>
+                    </el-menu>
+                </el-col>
+                <el-col :span="4" class="userinfo">
+                    <!-- <span class='username'><i class='fa fa-user'></i>{{this.$store.state.user.userinfo.username}}</span> -->
+                    <span class='username'>
+                        <el-dropdown
+                                trigger="click"
+                                @command='setDialogInfo'>
+                            <span class="el-dropdown-link">
+                                {{this.$store.state.user.userinfo.username}}<i
+                                    class="el-icon-caret-bottom el-icon--right"></i>
+                            </span>
+                            <el-dropdown-menu slot="dropdown">
+                                <el-dropdown-item command='info'>修改信息</el-dropdown-item>
+                                <el-dropdown-item
+                                        command='pass'
+                                        v-if='$store.state.user.userinfo.is_update_pass'>修改密码</el-dropdown-item>
+                                <el-dropdown-item
+                                        command='set'
+                                        v-if='$store.state.user.userinfo.pid==0'>系统设置</el-dropdown-item>
+                            </el-dropdown-menu>
+                        </el-dropdown>
+                    </span>
+                    <i class="fa fa-sign-out logout" @click='logout'></i>
+                </el-col>
+            </el-row>
+        </header>
+
+
+        <el-dialog size="small" :title="dialog.title"
+                   v-model="dialog.show_pass">
+            <el-form style="margin:20px;width:80%;"
+                     label-width="100px"
+                     :model="dialog.user_info"
+                     :rules="dialog.user_info_rules"
+                     ref='user_info'>
+                <el-form-item class='edit-form'
+                              label="邮箱"
+                              prop='email'>
+                    <el-input v-model="dialog.user_info.email" disabled placeholder='常用邮箱'></el-input>
+                </el-form-item>
+                <el-form-item class='edit-form'
+                              label="用户名称"
+                              prop='username'>
+                    <el-input v-model="dialog.user_info.username" disabled placeholder='用户名'></el-input>
+                </el-form-item>
+                <el-form-item class='edit-form'
+                              label="当前密码"
+                              prop='old_password'>
+                    <el-input
+                            type='password'
+                            placeholder='当前密码'
+                            auto-complete='off'
+                            v-model="dialog.user_info.old_password"></el-input>
+                </el-form-item>
+                <el-form-item class='edit-form'
+                              label="新密码"
+                              prop='password'>
+                    <el-input
+                            type='password'
+                            placeholder='新密码'
+                            auto-complete='off'
+                            v-model="dialog.user_info.password"></el-input>
+                </el-form-item>
+                <el-form-item class='edit-form'
+                              label="确认密码"
+                              prop='password_confirm'>
+                    <el-input
+                            type='password'
+                            placeholder='确认密码'
+                            auto-complete='off'
+                            v-model="dialog.user_info.password_confirm"></el-input>
+                </el-form-item>
+            </el-form>
+            <span slot="footer" class="dialog-footer">
+                <el-button @click="dialog.show_pass = false">取 消</el-button>
+                <el-button type="primary" @click="updUserPass('user_info')">确 定</el-button>
+            </span>
+        </el-dialog>
+
+
+        <el-dialog size="small" :title="dialog.title"
+                   v-model="dialog.show_set">
+            <el-form style="margin:20px;width:80%;"
+                     label-width="100px"
+                     v-model='dialog.set_info'
+                     ref='set_info'>
+                <el-form-item label="登录方式">
+                    <el-select placeholder="请选择登录方式"
+                               v-model='dialog.set_info.login_style'>
+                        <el-option label="单一登录" value="1"></el-option>
+                        <el-option label="多点登录" value="2"></el-option>
+                    </el-select>
+                </el-form-item>
+                <el-form-item label="禁止修改密码">
+                    <el-select placeholder="请选择用户"
+                               multiple
+                               v-model='dialog.set_info.disabled_update_pass'>
+                        <!-- value的值的ID是number,disabled_update_pass的元素中的是字符串,
+                            所以在value上,需要拼装一个空串,来转化
+                            因为elementUI内部用了===
+                        -->
+                        <el-option
+                                v-for='user in dialog.set_info.select_users'
+                                :label='user.username'
+                                :value='user.id+""'></el-option>
+                    </el-select>
+                </el-form-item>
+            </el-form>
+            <span slot="footer" class="dialog-footer">
+                <el-button @click="dialog.show_set = false">取 消</el-button>
+                <el-button type="primary" @click="onUpdateSetting">确 定</el-button>
+            </span>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+	import HeadNavJs from './HeadNav.js';
+	export default HeadNavJs;
+</script>
+
+<style scoped lang='less'>
+    .logo-container {
+        height: 60px;
+    }
+
+    .logo {
+        height: 26px;
+        width: auto;
+        margin-left: 20px;
+        margin-top: 17px;
+    }
+
+    .fa-user {
+        position: relative;
+        top: -2px;
+        margin-right: 4px;
+    }
+
+    .head-nav {
+        width: 100%;
+        height: 60px;
+        background: #324057;
+        position: fixed;
+        top: 0px;
+        left: 0px;
+        z-index: 99;
+        color: #FFF;
+        border-bottom: 1px solid #1F2D3D;
+
+    .logout {
+        width: 60px;
+        height: 60px;
+        line-height: 60px;
+        text-align: center;
+        float: right;
+        cursor: pointer;
+    }
+
+    }
+    .userinfo {
+        text-align: right;
+    }
+
+    .username {
+        height: 60px;
+        line-height: 60px;
+        cursor: pointer;
+
+    .el-dropdown {
+        color: #FFF;
+    }
+
+    }
+</style>

+ 54 - 0
src/components/Common/LeftMenu/LeftMenu.js

@@ -0,0 +1,54 @@
+    export default {
+        name: 'left-menu',
+        data() {
+            return {
+                menu_list: [],
+                win_size: {
+                    height: '',
+                }
+            }
+        },
+        methods: {
+            setSize() {
+                this.win_size.height = $(window).height() + "px";
+            },
+            toggleMenu() {
+                this.$store.dispatch(this.$store.state.leftmenu.menu_flag ? 'set_menu_close' : 'set_menu_open');
+            },
+            updateCurMenu(route) {
+                var route = route || this.$route;
+                if (route.matched.length) {
+                    var rootPath = route.matched[0].path,
+                        fullPath = route.path;
+                    this.$store.dispatch('set_cur_route', {
+                        rootPath,
+                        fullPath
+                    });
+                    var routes = this.$router.options.routes;
+                    for (var i = 0; i < routes.length; i++) {
+                        if (routes[i].path === rootPath && !routes[i].hidden) {
+                            this.menu_list = routes[i].children;
+                            break;
+                        }
+                    }
+                } else {
+                    this.$router.push('/404');
+                }
+            }
+        },
+        created() {
+            this.setSize();
+            $(window).resize(() => {
+                this.setSize();
+            });
+            this.updateCurMenu();
+        },
+        mounted() {
+            // console.log(this.$store.state.user.userinfo.access);
+        },
+        watch: {
+            $route(to, from) {
+                this.updateCurMenu(to);
+            }
+        }
+    }

+ 43 - 0
src/components/Common/LeftMenu/LeftMenu.less

@@ -0,0 +1,43 @@
+.fa {
+    margin-right: 8px;
+}
+.left-fixed-right-auto {
+    padding-top: 60px;
+}
+.left {
+    position: fixed;
+    float: left;
+    /*width:190px;
+    margin-right:-190px;*/
+    top: 60px;
+}
+.right-content {
+    float: right;
+    width: 100%;
+}
+#left-menu {
+    height: 100%;
+    background: #324057;
+    //position: relative;
+    overflow-x: hidden;
+}
+.toggle-menu {
+    width: 40px;
+    height: 40px;
+    background: #1f2f3d;
+    position: absolute;
+    top: 0px;
+    /*left: 190px;*/
+    z-index: 1000;
+    cursor: pointer;
+    line-height: 40px;
+    text-align: center;
+    color: #fff;
+    font-size: 14px;
+    opacity: 0.2;
+    transition: opacity .3s ease-out;
+    
+    &:hover {
+        opacity: 1;
+    }
+}

+ 75 - 0
src/components/Common/LeftMenu/LeftMenu.vue

@@ -0,0 +1,75 @@
+<template>
+    <div class="left" :style="{'height':win_size.height,'width':$store.state.leftmenu.width}" id='admin-left'>
+        <div id='left-menu'>
+            <el-row class='tac'
+                    v-for="(route,index) in $router.options.routes"
+                    v-if='!route.hidden && $route.matched.length && $route.matched[0].path===route.path'>
+                <el-col :span="24">
+                    <el-menu
+                            class="el-menu-vertical-demo"
+                            theme="dark"
+                            :default-active="$route.path"
+                            unique-opened
+                            router>
+                        <!-- v-if="!item.hidden && (($store.state.user.userinfo.access_status===1 && $store.state.user.userinfo.web_routers[route.path+'/'+item.path]) || $store.state.user.userinfo.access_status!==1)" -->
+                        <template
+                                v-for="(item,index) in route.children"
+                                v-if="!item.hidden && (($store.state.user.userinfo.access_status===1 && $store.state.user.userinfo.web_routers[route.path+'/'+item.path]) || $store.state.user.userinfo.access_status!==1)">
+                            <el-submenu
+                                    :index="item.path">
+                                <template
+                                        slot="title">
+                                    <el-tooltip
+                                            class="item"
+                                            effect="dark"
+                                            placement="right"
+                                            :disabled="$store.state.leftmenu.menu_flag"
+                                            :content="item.name">
+                                        <i :class="'fa fa-'+item.icon"></i>
+                                    </el-tooltip>
+                                    <span
+                                            class='menu-name'
+                                            v-if="$store.state.leftmenu.menu_flag">{{item.name}}
+                                        <!-- {{route.path+'/'+item.path}} --></span>
+                                </template>
+
+                                <!-- v-if="!child.hidden && (($store.state.user.userinfo.access_status===1 && $store.state.user.userinfo.web_routers[route.path+'/'+item.path+'/'+child.path]) || $store.state.user.userinfo.access_status!==1)" -->
+                                <el-menu-item
+                                        v-for='(child,cindex) in item.children'
+                                        v-if="!child.hidden && (($store.state.user.userinfo.access_status===1 && $store.state.user.userinfo.web_routers[route.path+'/'+item.path+'/'+child.path]) || $store.state.user.userinfo.access_status!==1)"
+                                        :style="{'padding-left':$store.state.leftmenu.menu_flag? '40px' : '23px'}"
+                                        :index='$store.state.router.headerCurRouter+"/"+item.path+"/"+child.path'>
+                                    <el-tooltip
+                                            class="item"
+                                            effect="dark"
+                                            placement="right"
+                                            :disabled="$store.state.leftmenu.menu_flag"
+                                            :content="child.name">
+                                        <i :class="'fa fa-'+child.icon"></i>
+                                    </el-tooltip>
+                                    <span
+                                            class='menu-name'
+                                            v-if="$store.state.leftmenu.menu_flag">{{child.name}}
+                                        <!-- {{route.path+'/'+item.path+'/'+child.path}} --></span>
+                                </el-menu-item>
+                            </el-submenu>
+                        </template>
+                    </el-menu>
+                </el-col>
+            </el-row>
+            <div class="toggle-menu"
+                 @click='toggleMenu'
+                 :style='{left:$store.state.leftmenu.width}'>
+                <i :class='[{"el-icon-arrow-left":$store.state.leftmenu.menu_flag},{"el-icon-arrow-right":!$store.state.leftmenu.menu_flag}]'></i>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+	module.exports = require('./LeftMenu.js');
+</script>
+
+<style scoped lang='less'>
+    @import url(./LeftMenu.less);
+</style>

+ 255 - 0
src/components/Common/ListData/ListData.js

@@ -0,0 +1,255 @@
+module.exports = {
+    name: 'list-data',
+    data() {
+        return {
+            batch_flag: true, //符合批量删除为true,否则为false
+            batch_datas: [],
+            batch_ids: [],
+
+            image_host: this.ImageHost, //如果列表中有图片,并且不是绝对路径的话,可以传入这个参数
+
+            list: this.List, //列表数组
+            fields: this.FieldList, //字段数组
+            selection: this.Selection, //是否需要批量选择
+            expand:this.Expand,
+            btn_info: this.BtnInfo,
+
+            pagination: this.Pagination,
+        }
+    },
+    methods: {
+        /**
+         * 表格列表触发CheckBox的事件
+         * @param  {array} val 当前选中的用户信息数组,每个元素是用户信息对象
+         */
+        onSelectionChange(val) {
+            this.batch_datas = val;
+
+            this.batch_ids = [];
+            if (val.length) {
+                this.batch_flag = false;
+                for (var i = 0; i < val.length; i++) {
+                    this.batch_ids.push(val[i].id);
+                }
+            } else {
+                this.batch_flag = true;
+            }
+
+            /**
+             * 改变CheckBox事件,第一个参数是ID数组,第二个参数二维数组,每个数组是选中的对象
+             */
+            this.$emit('onSelectionChange', this.batch_ids, this.batch_datas);
+            this.$emit('onSelectionChangeObj', {
+                ids: this.batch_ids,
+                datas: this.batch_datas
+            });
+        },
+
+
+
+        /**
+         * 删除事件
+         * @param  {object || boolean} user  当前信息对象或者为布尔值,为布尔值时,代表是批量删除
+         * @param  {number} index 当前列表索引
+         */
+        onDelete(data, index) {
+            var opts = {};
+            if (data === true) {
+                opts.batch_ids = this.batch_ids;
+                opts.batch_datas = this.batch_datas;
+            } else {
+                opts.data = data;
+                opts.index = index;
+            }
+
+            /**
+             * 删除事件,参数为对象
+             * 分两种情况,一种是单个删除,一种是批量删除,属性分别如下
+             * 1:单个删除
+             *     opts.data 当前要删除的数据对象
+             *     opts.index 当前要删除的索引
+             *     opts.list 当前列表数组
+             * 2:批量删除
+             *     opts.batch_ids 一维数组,需要删除的ID数组
+             *     opts.batch_datas 二维数组,每个元素为对象(需要删除的数据对象)
+             */
+            this.$emit('onDelete', opts);
+        },
+
+        onAdd(){
+            this.$emit('onAdd', {});
+        },
+
+        /**
+         * 获取行信息事件
+         * @param  {object} row   当前行对象
+         * @param  {number} index 当前行索引
+         * @param  {array} list  当前列表数组
+         */
+        onGetInfo(row, index, list, type) {
+            this.$emit('onGetInfo', {
+                row,
+                index,
+                list,
+                type
+            });
+        },
+
+
+        onBtnEvent(type,row={},index=-1,list=[]){
+            this.$emit('onBtn'+type, {
+                row,
+                index,
+                list
+            });
+        },
+
+
+        onUpdateBtn(data, index, list) {
+            if (this.btn_info.update && this.btn_info.update.path) {
+                var path = this.btn_info.update.path,
+                    param_keys = this.btn_info.update.param_keys || [],
+                    query_keys = this.btn_info.update.query_keys || [],
+                    query = {};
+
+                for (var i = 0; i < param_keys.length; i++) {
+                    path += '/' + data[param_keys[i]];
+                }
+                for (var i = 0; i < query_keys.length; i++) {
+                    query[query_keys[i]] = data[query_keys[i]];
+                }
+
+                // console.log(path);
+                // console.log(query);
+
+                this.$router.push({
+                    path: path,
+                    query: query
+                });
+            } else {
+                this.onGetInfo(data, index, list, 'update');
+            }
+
+        },
+
+
+        /**
+         * 内置删除事件执行成功后,更新列表方法
+         * 分两种情况,一种是批量删除,一种是单个删除
+         * 1:单个删除
+         *     row 当前需要删除行的索引
+         * 2:批量删除
+         *     row 一维数组,需要删除的ID数组
+         */
+        onUpdateList(row) {
+            if (!Array.isArray(row)) {
+                this.list.splice(row, 1);
+            } else {
+                this.list = this.list.filter(function(item, idx) {
+                    return row.indexOf(item.id) === -1;
+                });
+            }
+        },
+
+
+        /**
+         * 改变当前页码事件
+         * @param  {number} page 当前页面
+         */
+        onChangeCurrentPage(page) {
+            this.$emit('onChangeCurrentPage', page);
+        },
+
+
+        /**
+         * 改变每页显示的数量事件
+         * @param  {number} page_size 每页显示的数量
+         */
+        onChangePageSize(page_size) {
+            this.$emit('onChangePageSize', page_size);
+        }
+    },
+
+    mounted() {
+        // console.log(this.list);
+    },
+
+    /**
+     * 接收参数
+     * @type {Object}
+     */
+    props: {
+        ImageHost: {
+            type: String,
+            default: ''
+        },
+        List: {
+            type: Array,
+            required: true
+        },
+        FieldList: {
+            type: Array,
+            required: true
+        },
+        BtnInfo: {
+            type: Object,
+            default () {
+                return {};
+            }
+        },
+        Selection: {
+            type: Boolean,
+            default: false
+        },
+        Expand: {
+            type: Object,
+            default(){
+                return {
+                    show:false,
+                    position:"left"
+                };
+            }
+        },
+        Pagination: {
+            type: Object,
+            default () {
+                return {};
+            }
+        }
+    },
+
+
+    /**
+     * 监控参数
+     * @type {Object}
+     */
+    watch: {
+        ImageHost(v) {
+            if (v) {
+                this.image_host = v;
+            }
+        },
+        List(v) {
+            if (v) {
+                this.list = v;
+            }
+        },
+        FieldList(v) {
+            if (v) {
+                this.fields = v;
+            }
+        },
+        Selection(v) {
+            this.selection = v;
+        },
+        Expand(v){
+            this.expand=v;
+        },
+        BtnInfo(v) {
+            this.btn_info = v;
+        },
+        Pagination(v) {
+            this.pagination = v;
+        }
+    }
+}

+ 173 - 0
src/components/Common/ListData/ListData.vue

@@ -0,0 +1,173 @@
+<template>
+    <div class="list">
+        <el-col :span="24" class='actions-top'>
+            <el-button
+                    type='danger'
+                    icon='delete'
+                    v-if='selection'
+                    :disabled='batch_flag'
+                    @click='onBtnEvent("BatchDelete")'>删除选中
+            </el-button>
+
+            <el-button
+                    type='primary'
+                    icon='add'
+                    @click='onBtnEvent("Add")'>添加
+            </el-button>
+
+            <div class='list-header'>
+                <slot name='list-header'></slot>
+            </div>
+        </el-col>
+
+        <el-table border style="width: 100%" align='center'
+                  :data="list"
+                  @selection-change='onSelectionChange'>
+
+
+            <el-table-column type="expand"
+                             v-if='expand && expand.show && expand.show===true && (!expand.position || expand.position==="left")'>
+                <template scope="props">
+                </template>
+            </el-table-column>
+
+            <el-table-column v-if='selection'
+                             type="selection"
+                             width="55">
+            </el-table-column>
+
+            <template
+                    v-for='field in fields'>
+                <el-table-column
+                        v-if='!field.type || field.type!=="image"'
+                        :prop="field.key"
+                        :label="field.label"
+                        :align="field.align || 'center'"
+                        :sortable="field.sort || false"
+                        :formatter='field.formatter'
+                        :filters='field.filter_list'
+                        :filter-method="field.filter_method"
+                        :filter-multiple="field.filter_multiple"
+                        :style='field.style'
+                        :width='field.width'>
+                </el-table-column>
+                <el-table-column
+                        v-if='field.type && field.type==="image"'
+                        :prop="field.key"
+                        :label="field.label"
+                        :align="field.align || 'center'"
+                        :width='field.width'>
+                    <template scope='scope'>
+                        <img :src="(image_host || '')+scope.row[field.key]" alt="">
+                    </template>
+                </el-table-column>
+            </template>
+
+
+            <el-table-column
+                    v-if='btn_info.show!==false'
+                    :label="btn_info.label || '操作'"
+                    :width="btn_info.width || 160"
+                    :context="_self">
+                <template scope='scope'>
+                    <!-- @click='onGetInfo(scope.row,scope.$index,list,"select")' -->
+                    <el-button
+                            v-if='btn_info.select!==false'
+                            type="info"
+                            icon='view'
+                            size="mini"
+                            @click='onBtnEvent("Select",scope.row,scope.$index,list)'></el-button>
+                    <el-button
+                            v-if='btn_info.update!==false'
+                            type="info"
+                            icon='edit'
+                            size="mini"
+                            @click='onBtnEvent("Update",scope.row,scope.$index,list)'></el-button>
+                    <el-button
+                            v-if='btn_info.delete!==false'
+                            type="danger"
+                            icon='delete'
+                            size="mini"
+                            @click='onBtnEvent("Delete",scope.row,scope.$index,list)'></el-button>
+
+
+                    <el-button
+                            v-if='btn_info.list'
+                            v-for='btn in btn_info.list'
+                            :type="btn.type || 'info'"
+                            size="mini"
+                            @click='onGetInfo(scope.row,scope.$index,list,btn.fn_type || btn.text)'>{{btn.text}}
+                    </el-button>
+                </template>
+            </el-table-column>
+
+
+            <el-table-column type="expand"
+                             :context="_self"
+                             v-if='expand && expand.show && expand.show===true && expand.position && expand.position==="right"'>
+                <!--<slot name="list-expand" index="index"></slot>-->
+                <template scope="scope">
+                    <slot name="list-expand"
+                          :data="scope.row"
+                          :index="scope.$index"></slot>
+                </template>
+            </el-table-column>
+        </el-table>
+        <el-col :span="24" class='btm-action'>
+            <!-- 
+     
+             -->
+            <el-pagination
+                    v-if='pagination  && pagination.total && pagination.total>0'
+                    class='pagination'
+                    :page-sizes="pagination.page_sizes"
+                    :page-size="pagination.page_size"
+                    :layout="pagination.layout"
+                    :total="pagination.total"
+                    :current-page='pagination.current_page'
+                    @current-change='onChangeCurrentPage'
+                    @size-change='onChangePageSize'>
+            </el-pagination>
+        </el-col>
+    </div>
+</template>
+
+<script>
+	import ListDataJs from './ListData.js';
+	module.exports = ListDataJs;
+</script>
+<style scoped lang='less'>
+    .demo-form-inline {
+        display: inline-block;
+        float: right;
+    }
+
+    .btm-action {
+        margin-top: 20px;
+        text-align: center;
+    }
+
+    .actions-top {
+        height: 46px;
+    }
+
+    .pagination {
+        display: inline-block;
+    }
+
+    .list {
+
+    table {
+
+    img {
+        max-width: 100%;
+        height: auto;
+    }
+
+    }
+    }
+
+    .list-header {
+        display: inline-block;
+    }
+</style>

+ 2 - 0
src/components/Common/ListData/index.js

@@ -0,0 +1,2 @@
+import ListData from './ListData.vue';
+module.exports = ListData;

+ 8 - 0
src/components/Common/index.js

@@ -0,0 +1,8 @@
+module.exports = {
+	Bread: require('./Bread/Bread.vue'),
+	HeadNav: require('./HeadNav/HeadNav.vue'),
+	LeftMenu: require('./LeftMenu/LeftMenu.vue'),
+	ListData: require('./ListData/'),
+	FormData: require('./FormData/'),
+	DialogInfo: require('./DialogInfo/'),
+};

+ 122 - 0
src/components/Login/Login.js

@@ -0,0 +1,122 @@
+module.exports = {
+  name: 'login',
+  data() {
+    return {
+      winSize: {
+        width: '',
+        height: ''
+      },
+
+      formOffset: {
+        position: 'absolute',
+        left: '',
+        top: ''
+      },
+
+      remumber: this.$store.state.user.remumber,
+
+      login_actions: {
+        disabled: false
+      },
+
+      data: {
+        username: '',
+        password: ''
+      },
+
+      rule_data: {
+        username: [{
+          validator: (rule, value, callback) => {
+            if (value === '') {
+              callback(new Error('请输入用户名'));
+            } else {
+              if (/^[a-zA-Z0-9_-]{1,16}$/.test(value)) {
+                callback();
+              } else {
+                callback(new Error('用户名至少6位,由大小写字母和数字,-,_组成'));
+              }
+            }
+          },
+          trigger: 'blur'
+        }],
+        password: [{
+          validator: (rule, value, callback) => {
+            if (value === '') {
+              callback(new Error('请输入密码'));
+            } else {
+              if (!(/^[a-zA-Z0-9_-]{6,16}$/.test(value))) {
+                callback(new Error('密码至少6位,由大小写字母和数字,-,_组成'));
+              } else {
+                callback();
+              }
+            }
+          },
+          trigger: 'blur'
+        }]
+      }
+    }
+  },
+  methods: {
+    setSize() {
+      this.winSize.width = $(window).width() + "px";
+      this.winSize.height = $(window).height() + "px";
+
+      this.formOffset.left = (parseInt(this.winSize.width) / 2 - 175) + 'px';
+      this.formOffset.top = (parseInt(this.winSize.height) / 2 - 178) + 'px';
+    },
+
+    onLogin(ref, type) {
+      this.$refs[ref].validate((valid) => {
+        if (valid) {
+          this.login_actions.disabled = true;
+          //如果记住密码,提交的信息包括真实token,密码则是假的
+          //服务端登录验证优先级:用户名必须,其次先取token,不存在时再取密码
+          this.$$api_user_login(this[ref], data => {
+            //登录成功之后,验证是否记住密码,如果记住密码,本地保存记住信息
+            //如果没有记住,就初始化本地记住信息
+            if (this.remumber.remumber_flag === true) {
+              this.$store.dispatch('update_remumber', {
+                remumber_flag: this.remumber.remumber_flag,
+                remumber_login_info: {
+                  username: this[ref].username,
+                  token: data.content.token
+                }
+              });
+            } else {
+              this.$store.dispatch('remove_remumber');
+            }
+            data.content.username = this[ref].username;
+            this.$store.dispatch('update_userinfo', {
+              userinfo: data.content
+            }).then(() => {
+              this.$router.push('/server');
+            });
+          }, {
+            errFn: () => {
+              this.login_actions.disabled = false;
+            },
+            tokenFlag: true
+          });
+        }
+      });
+    },
+
+    resetForm(ref) {
+      this.$refs[ref].resetFields();
+    }
+  },
+  created() {
+    this.setSize();
+    $(window).resize(() => {
+      this.setSize();
+    });
+  },
+  mounted() {
+    //如果上次登录选择的是记住密码并登录成功,则会保存状态,用户名以及token
+    if (this.remumber.remumber_flag === true) {
+      this.data.username = this.remumber.remumber_login_info.username;
+      this.data.password = this.remumber.remumber_login_info.token.substring(0, 16);
+      this.$set(this.data, 'token', this.remumber.remumber_login_info.token);
+    }
+  }
+}

+ 36 - 0
src/components/Login/Login.less

@@ -0,0 +1,36 @@
+.login {
+    background : #1F2D3D;
+
+    .card-box {
+        box-shadow            : 0 0px 8px 0 rgba(0, 0, 0, 0.06), 0 1px 0px 0 rgba(0, 0, 0, 0.02);
+        -webkit-border-radius : 5px;
+        border-radius         : 5px;
+        -moz-border-radius    : 5px;
+        background-clip       : padding-box;
+        margin-bottom         : 20px;
+        background-color      : #F9FAFC;
+        border                : 2px solid #8492A6;
+    }
+
+    .title {
+        margin      : 0px auto 40px auto;
+        text-align  : center;
+        color       : #505458;
+        font-weight : normal;
+        font-size   : 16px;
+
+        span {
+            cursor : pointer;
+
+            &.active {
+                font-weight : bold;
+                font-size   : 18px;
+            }
+        }
+    }
+
+    .loginform {
+        width   : 350px;
+        padding : 35px 35px 15px 35px;
+    }
+}

+ 51 - 0
src/components/Login/Login.vue

@@ -0,0 +1,51 @@
+<template>
+    <div class="login" :style="winSize">
+        <el-row>
+            <el-col :span='24'>
+                <div class="content">
+                    <el-form label-position="left" label-width="0px" class="demo-ruleForm card-box loginform"
+                             v-loading="login_actions.disabled"
+                             :element-loading-text="'正在登录...'"
+                             :style="formOffset"
+                             :model='data'
+                             :rules="rule_data"
+                             ref='data'>
+                        <h3 class="title">系统登录</h3>
+                        <el-form-item
+                                prop='username'>
+                            <el-input type="text" auto-complete="off" placeholder="账号"
+                                      v-model='data.username'></el-input>
+                        </el-form-item>
+
+                        <el-form-item
+                                prop='password'>
+                            <el-input type="password" auto-complete="off" placeholder="密码"
+                                      v-model='data.password'
+                                      @keyup.native.enter="onLogin('data',true)"></el-input>
+                        </el-form-item>
+
+                        <el-checkbox style="margin:0px 0px 35px 0px;"
+                                     :checked='remumber.remumber_flag'
+                                     v-model='remumber.remumber_flag'>记住密码
+                        </el-checkbox>
+                        <el-form-item style="width:100%;">
+                            <el-button type="primary"
+                                       @click='onLogin("data")'>登录
+                            </el-button>
+                            <el-button @click='resetForm("data")'>重置</el-button>
+                        </el-form-item>
+                    </el-form>
+                </div>
+            </el-col>
+        </el-row>
+    </div>
+</template>
+
+<script>
+	import LoginJs from './Login.js';
+	module.exports = LoginJs;
+</script>
+
+<style scoped lang='less'>
+    @import url(Login.less);
+</style>

+ 2 - 0
src/components/Login/index.js

@@ -0,0 +1,2 @@
+import Login from './Login.vue';
+module.exports = Login;

+ 28 - 0
src/components/Modules/Program/Artifact/List/List.js

@@ -0,0 +1,28 @@
+module.exports = {
+  data() {
+    return {
+      artifact_list: [{
+        groupId: 'com.uas.erp',
+        artifactId: 'uas',
+        description: 'UAS1.0程序'
+      },{
+        groupId: 'com.uas.mes',
+        artifactId: 'mes',
+        description: 'MES1.0程序'
+      }]
+    }
+  },
+  methods: {
+    onVersionItemsClick(artifact) {
+      this.$router.push({
+        path: '/program/artifact/version',
+        query: {
+          groupId: artifact.groupId,
+          artifactId: artifact.artifactId
+        }
+      });
+    }
+  },
+  mounted() {
+  }
+}

+ 39 - 0
src/components/Modules/Program/Artifact/List/List.vue

@@ -0,0 +1,39 @@
+<template>
+  <el-row :gutter="20">
+    <el-col :span="6" v-for="artifact in artifact_list">
+      <el-card :body-style="{ padding: '0px' }">
+        <div class="card-body">
+          <span class="left icon"><i class="el-icon-document"></i></span>
+          <span>{{ artifact.description }}</span>
+          <div class="bottom clearfix">
+            <el-button type="text" class="button" @click="onVersionItemsClick(artifact)">版本列表</el-button>
+          </div>
+        </div>
+      </el-card>
+    </el-col>
+  </el-row>
+</template>
+
+<script>
+    import ListJs from './List.js';
+    module.exports=ListJs;
+</script>
+<style scoped>
+    .left {
+      float: left;
+      margin-right: 14px
+    }
+    .tag {
+      margin-left: 10px
+    }
+    .icon {
+      font-size: 36px;
+    }
+    .card-body {
+      height: 83px;
+      padding: 14px;
+    }
+    .text-center {
+      text-align: center;
+    }
+</style>

+ 2 - 0
src/components/Modules/Program/Artifact/List/index.js

@@ -0,0 +1,2 @@
+import List from './List.vue';
+module.exports = List;

+ 78 - 0
src/components/Modules/Program/Artifact/Version/Version.js

@@ -0,0 +1,78 @@
+module.exports = {
+  data() {
+    return {
+      version_list : [],
+      pagination: {
+        current_page: 1,
+        total: 0,
+        page_size: 12,
+        page_sizes: [9, 12, 24],
+        layout: "total, sizes, prev, pager, next, jumper"
+      }
+    }
+  },
+  methods: {
+    getList({page, page_size, where, fn} = {}){
+      var query = this.$route.query;
+      this.pagination.current_page = page || parseInt(query.page) || 1;
+      this.pagination.page_size = page_size || parseInt(query.page_size) || this.pagination.page_size;
+
+      var data = {
+        groupId: this.$route.query.groupId,
+        artifactId: this.$route.query.artifactId,
+        // 接口里面page从0开始
+        page: this.pagination.current_page - 1,
+        size: this.pagination.page_size
+      };
+
+      this.$$api_program_getArtifactVersions(data, (data) => {
+        this.version_list = data.content.content;
+        this.pagination.total = data.content.totalElements;
+      });
+      fn && fn.call();
+    },
+    onDeployClick(version_data) {
+      this.$$api_program_saveDeployTask({
+        groupId: version_data.groupId,
+        artifactId: version_data.artifactId,
+        version: version_data.version
+      }, (data) => {
+        this.$message.success('任务已添加');
+      });
+    },
+    setPath(field, value) {
+      var path = this.$route.path,
+        query = Object.assign({}, this.$route.query);
+
+      if (typeof field === 'object') {
+        query = field;
+      } else {
+        query[field] = value;
+      }
+
+      this.$router.push({
+        path,
+        query
+      });
+    },
+    onChangeCurrentPage(page) {
+      this.getList({
+        page,
+        fn: () => {
+          this.setPath('page', page);
+        }
+      });
+    },
+    onChangePageSize(page_size) {
+      this.getList({
+        page_size,
+        fn: () => {
+          this.setPath('page_size', page_size);
+        }
+      });
+    }
+  },
+  mounted() {
+    this.getList();
+  }
+}

+ 51 - 0
src/components/Modules/Program/Artifact/Version/Version.vue

@@ -0,0 +1,51 @@
+<template>
+  <div class="list">
+    <el-table border style="width: 100%" align='center'
+              :data="version_list">
+      <el-table-column
+        prop="version"
+        label="版本"
+        align="center"
+        width="80">
+      </el-table-column>
+      <el-table-column
+        label="程序提交时间"
+        align="center">
+        <template scope="scope">
+          <span>{{ scope.row.versionTime | time }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="软件编译时间"
+        align="center">
+        <template scope="scope">
+          <span>{{ scope.row.createTime | time }}</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <el-col :span="24">
+      <el-pagination
+        v-if='pagination.total>0'
+        class='pagination'
+        :page-sizes="pagination.page_sizes"
+        :page-size="pagination.page_size"
+        :layout="pagination.layout"
+        :total="pagination.total"
+        :current-page='pagination.current_page'
+        @current-change='onChangeCurrentPage'
+        @size-change='onChangePageSize'>
+      </el-pagination>
+    </el-col>
+  </div>
+</template>
+
+<script>
+	import VersionJs from './Version.js';
+	module.exports = VersionJs;
+</script>
+<style scoped>
+  .pagination {
+    margin-top: 20px;
+    text-align: center;
+  }
+</style>

+ 2 - 0
src/components/Modules/Program/Artifact/Version/index.js

@@ -0,0 +1,2 @@
+import Version from './Version.vue';
+module.exports = Version;

+ 4 - 0
src/components/Modules/Program/Artifact/index.js

@@ -0,0 +1,4 @@
+module.exports = {
+  List:require('./List'),
+  Version:require('./Version')
+};

+ 45 - 0
src/components/Modules/Program/Deploy/Client/List.js

@@ -0,0 +1,45 @@
+module.exports = {
+  data() {
+    return {
+      setting_list : [],
+      setting_data: {},
+      dialog: {
+        show: false,
+        setting_rules: {
+          value: [{
+            required: true,
+            message : '请填写属性值!',
+            trigger : 'blur'
+          }]
+        }
+      }
+    }
+  },
+  methods: {
+    getList(){
+      this.$$api_setting_getSettings({
+        group: 'api'
+      }, (data) => {
+        this.setting_list = data.content;
+      });
+    },
+    onEditClick(setting) {
+      this.setting_data = setting;
+      this.dialog.show = true;
+    },
+    onSaveClick(ref) {
+      this.$refs[ref].validate((valid) => {
+        if (valid) {
+          this.$$api_setting_saveSetting(this[ref], data => {
+            this.$message.success('保存成功');
+            this.dialog.show = false;
+            this.getList();
+          });
+        }
+      });
+    }
+  },
+  mounted() {
+    this.getList();
+  }
+}

+ 67 - 0
src/components/Modules/Program/Deploy/Client/List.vue

@@ -0,0 +1,67 @@
+<template>
+  <div class="list">
+    <el-table border style="width: 100%" align='center'
+              :data="setting_list">
+      <el-table-column
+        prop="key"
+        label="名称"
+        align="center"
+        width="200">
+      </el-table-column>
+      <el-table-column
+        prop="description"
+        label="描述"
+        width="240">
+      </el-table-column>
+      <el-table-column
+        prop="value"
+        label="值">
+      </el-table-column>
+      <el-table-column
+        label="操作"
+        :width="80"
+        :context="_self">
+        <template scope='scope'>
+          <el-button
+            type="info"
+            icon='edit'
+            size="mini"
+            @click='onEditClick(scope.row)'></el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <el-dialog title="设置" v-model="dialog.show" size="tiny">
+      <el-form style="padding:20px;width:100%;"
+               label-width="60px"
+               :rules="dialog.setting_rules"
+               :model="setting_data"
+               ref='setting_data'>
+        <el-form-item class='edit-form'
+                      label="名称"
+                      prop='key'>
+          {{setting_data.key}}
+        </el-form-item>
+        <el-form-item class='edit-form'
+                      label="描述"
+                      prop='description'>
+          {{setting_data.description}}
+        </el-form-item>
+        <el-form-item class="edit-form"
+                      label='值'
+                      prop='value'>
+          <el-input v-model="setting_data.value"></el-input>
+        </el-form-item>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="dialog.show = false">取 消</el-button>
+        <el-button type="primary" @click='onSaveClick("setting_data")'>确 定</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+	import ListJs from './List.js';
+	module.exports = ListJs;
+</script>

+ 2 - 0
src/components/Modules/Program/Deploy/Client/index.js

@@ -0,0 +1,2 @@
+import List from './List.vue';
+module.exports = List;

+ 45 - 0
src/components/Modules/Program/Deploy/History/List.js

@@ -0,0 +1,45 @@
+module.exports = {
+  data() {
+    return {
+      setting_list : [],
+      setting_data: {},
+      dialog: {
+        show: false,
+        setting_rules: {
+          value: [{
+            required: true,
+            message : '请填写属性值!',
+            trigger : 'blur'
+          }]
+        }
+      }
+    }
+  },
+  methods: {
+    getList(){
+      this.$$api_setting_getSettings({
+        group: 'api'
+      }, (data) => {
+        this.setting_list = data.content;
+      });
+    },
+    onEditClick(setting) {
+      this.setting_data = setting;
+      this.dialog.show = true;
+    },
+    onSaveClick(ref) {
+      this.$refs[ref].validate((valid) => {
+        if (valid) {
+          this.$$api_setting_saveSetting(this[ref], data => {
+            this.$message.success('保存成功');
+            this.dialog.show = false;
+            this.getList();
+          });
+        }
+      });
+    }
+  },
+  mounted() {
+    this.getList();
+  }
+}

+ 67 - 0
src/components/Modules/Program/Deploy/History/List.vue

@@ -0,0 +1,67 @@
+<template>
+  <div class="list">
+    <el-table border style="width: 100%" align='center'
+              :data="setting_list">
+      <el-table-column
+        prop="key"
+        label="名称"
+        align="center"
+        width="200">
+      </el-table-column>
+      <el-table-column
+        prop="description"
+        label="描述"
+        width="240">
+      </el-table-column>
+      <el-table-column
+        prop="value"
+        label="值">
+      </el-table-column>
+      <el-table-column
+        label="操作"
+        :width="80"
+        :context="_self">
+        <template scope='scope'>
+          <el-button
+            type="info"
+            icon='edit'
+            size="mini"
+            @click='onEditClick(scope.row)'></el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <el-dialog title="设置" v-model="dialog.show" size="tiny">
+      <el-form style="padding:20px;width:100%;"
+               label-width="60px"
+               :rules="dialog.setting_rules"
+               :model="setting_data"
+               ref='setting_data'>
+        <el-form-item class='edit-form'
+                      label="名称"
+                      prop='key'>
+          {{setting_data.key}}
+        </el-form-item>
+        <el-form-item class='edit-form'
+                      label="描述"
+                      prop='description'>
+          {{setting_data.description}}
+        </el-form-item>
+        <el-form-item class="edit-form"
+                      label='值'
+                      prop='value'>
+          <el-input v-model="setting_data.value"></el-input>
+        </el-form-item>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="dialog.show = false">取 消</el-button>
+        <el-button type="primary" @click='onSaveClick("setting_data")'>确 定</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+	import ListJs from './List.js';
+	module.exports = ListJs;
+</script>

+ 2 - 0
src/components/Modules/Program/Deploy/History/index.js

@@ -0,0 +1,2 @@
+import List from './List.vue';
+module.exports = List;

+ 0 - 0
src/components/Modules/Program/Deploy/Home/index.js


+ 5 - 0
src/components/Modules/Program/Deploy/index.js

@@ -0,0 +1,5 @@
+module.exports = {
+  Client:require('./Client'),
+  History:require('./History'),
+  Home:require('./Home')
+};

+ 4 - 0
src/components/Modules/Program/index.js

@@ -0,0 +1,4 @@
+module.exports = {
+  Artifact:require('./Artifact'),
+  Deploy:require('./Deploy')
+};

+ 0 - 0
src/components/Modules/Runtime/Client/Item/index.js


+ 0 - 0
src/components/Modules/Runtime/Client/List/index.js


+ 4 - 0
src/components/Modules/Runtime/Client/index.js

@@ -0,0 +1,4 @@
+module.exports = {
+  Item:require('./Item'),
+  List:require('./List')
+};

+ 3 - 0
src/components/Modules/Runtime/index.js

@@ -0,0 +1,3 @@
+module.exports = {
+  Client:require('./Client')
+};

+ 5 - 0
src/components/Modules/index.js

@@ -0,0 +1,5 @@
+module.exports = {
+  Program:require('./Program'),
+  Runtime:require('./Runtime')/*,
+  Database:require('./Database')*/
+};

+ 38 - 0
src/components/Routeview/Content.vue

@@ -0,0 +1,38 @@
+<template>
+    <div class="">
+        <transition name="fade">
+            <router-view></router-view>
+        </transition>
+    </div>
+</template>
+<script>
+    export default {
+        name: 'content',
+        data () {
+            return {
+                
+            }
+        },
+        methods:{
+            
+        },
+        created(){
+            
+        },
+        mounted(){
+
+        }
+    }
+</script>
+
+<style scoped lang='less'>
+    .fade-enter-active,
+    .fade-leave-active {
+        transition: opacity .3s
+    }
+    
+    .fade-enter,
+    .fade-leave-active {
+        opacity: 0
+    }
+</style>

+ 32 - 0
src/components/Routeview/Home.vue

@@ -0,0 +1,32 @@
+<template v-loading.fullscreen.lock="$store.state.global.ajax_loading">
+    <div class="home">
+        <head-nav></head-nav>
+        <div class="left-fixed-right-auto">
+            <left-menu></left-menu>
+            <div class="right-content">
+                <div class="content" :style="{marginLeft:$store.state.leftmenu.width}">
+                    <bread></bread>
+                    <router-view></router-view>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+    import Common from '../Common/';
+    export default {
+        name: 'home',
+        components:Common
+    }
+</script>
+<style scoped lang='less'>
+    .content{
+        margin-top: 60px;
+        /*background: #f1f2f7;*/
+        background: #FFF;
+        padding: 16px;
+    }
+    .right-content{
+        margin-bottom: 60px;
+    }
+</style>

+ 29 - 0
src/components/Routeview/NotFound.vue

@@ -0,0 +1,29 @@
+<template>
+    <div class="not-found">
+        没有找到页面
+        <a href="#/function/open/test404">回测试404页面</a>
+    </div>
+</template>
+
+<script>
+    export default {
+        name: 'not-found',
+        data () {
+            return {
+                
+            }
+        },
+        methods:{
+             
+        },
+        created(){
+        },
+        mounted(){
+
+        }
+    }
+</script>
+
+<style scoped lang='less'>
+    
+</style>

+ 17 - 0
src/components/index.js

@@ -0,0 +1,17 @@
+import Login from './Login/';
+
+import Home from './Routeview/Home.vue';
+import Content from './Routeview/Content.vue';
+import NotFound from './Routeview/NotFound.vue';
+
+import Modules from './Modules/';
+
+module.exports = {
+    Login,
+
+    Home,
+    Content,
+    NotFound,
+
+    Modules
+};

+ 5 - 0
src/config/index.js

@@ -0,0 +1,5 @@
+module.exports = {
+	routes: require('./router.js'),
+	settings: require('./settings.js'),
+	request: require('./request.js')
+};

+ 21 - 0
src/config/request.js

@@ -0,0 +1,21 @@
+/**
+ * 导出所有模块需要用到接口
+ * 一级属性:模块名
+ * 一级属性中的方法:当前模块需要用的接口
+ * @type {Object}
+ */
+module.exports=[{
+  module:'user',
+  name:'用户管理',
+  list:require('./request/user.js')
+},{
+  module:'program',
+  name:'软件管理',
+  list:require('./request/program.js')
+},{
+  module:'runtime',
+  name:'运行环境',
+  list:require('./request/runtime.js')
+}];
+
+

+ 36 - 0
src/config/request/program.js

@@ -0,0 +1,36 @@
+/**
+ * 软件管理
+ * @type {Object}
+ */
+module.exports = [
+  {
+    name:'获取软件列表',
+    method:'getArtifacts',
+    path:'/v1/program/artifact/list',
+    type:'get'
+  },
+  {
+    name:'获取软件版本列表',
+    method:'getArtifactVersions',
+    path:'/v1/program/artifact/versions',
+    type:'get'
+  },
+  {
+    name:'获取部署任务列表',
+    method:'getDeployTasks',
+    path:'/v1/program/deploy/list',
+    type:'get'
+  },
+  {
+    name:'获取部署任务结果列表',
+    method:'getDeployTaskDetails',
+    path:'/v1/program/deploy/{id}/result',
+    type:'get'
+  },
+  {
+    name:'部署任务',
+    method:'getDeployTaskDetails',
+    path:'/v1/program/deploy',
+    type:'post'
+  }
+];

+ 18 - 0
src/config/request/runtime.js

@@ -0,0 +1,18 @@
+/**
+ * 客户端管理
+ * @type {Object}
+ */
+module.exports = [
+  {
+    name:'获取客户端列表',
+    method:'getClients',
+    path:'/v1/runtime/client/list',
+    type:'get'
+  },
+  {
+    name:'获取客户端项目列表',
+    method:'getClientProjects',
+    path:'/v1/runtime/client/{id}/projects',
+    type:'post'
+  }
+];

+ 36 - 0
src/config/request/user.js

@@ -0,0 +1,36 @@
+/**
+ * 用户模块
+ * @type {Object}
+ */
+module.exports = [
+	{
+		name  : '登录',
+		method: 'login',
+		path  : '/login',
+		type  : 'post',
+	},
+	{
+		name  : '获取用户列表',
+		method: 'getUsers',
+		path  : '/v1/user/list',
+		type  : 'get',
+	},
+	{
+		name  : '添加修改用户公用接口',
+		method: 'saveUser',
+		path  : '/v1/user',
+		type  : 'post',
+	},
+	{
+		name  : '获取用户信息',
+		method: 'getUser',
+		path  : '/v1/user/{userId}',
+		type  : 'get',
+	},
+	{
+		name  : '修改密码',
+		method: 'updatePassword',
+		path  : '/v1/user/password',
+		type  : 'post',
+	}
+];

+ 29 - 0
src/config/router.js

@@ -0,0 +1,29 @@
+import {
+	Login,
+	Home,
+	NotFound,
+	Content,
+	Modules
+} from '../components/';
+
+module.exports = [{
+	path    : '/',
+	redirect: to => {
+		return 'login';
+	},
+	hidden  : true
+}, {
+	path     : '/login',
+	component: Login,
+	hidden   : true
+}, {
+	path     : '/404',
+	component: Home,
+	hidden   : true,
+	children : [{
+		path     : '',
+		component: NotFound
+	}]
+}]
+  .concat(require('./router/program.js'))
+  .concat(require('./router/runtime.js'));

+ 4 - 0
src/config/router/index.js

@@ -0,0 +1,4 @@
+module.exports={
+  program:require('./program'),
+  runtime:require('./runtime')
+};

+ 54 - 0
src/config/router/program.js

@@ -0,0 +1,54 @@
+import {
+  Home,
+  Content,
+  Modules
+} from '../../components/';
+
+module.exports = [{
+  path: '/program',
+  name: '软件部署',
+  icon: 'inbox',
+  component: Home,
+  redirect: '/program/artifact',
+  children: [ {
+    path: 'artifact',
+    name: '软件仓库',
+    icon: 'inbox',
+    component: Content,
+    redirect: '/program/artifact/list',
+    children: [{
+      path: 'list',
+      name: '所有软件',
+      icon: 'reorder',
+      component: Modules.Program.Artifact.List
+    },{
+      path: 'version',
+      name: '软件详细版本',
+      icon: 'reorder',
+      component: Modules.Program.Artifact.Version,
+      hidden: true
+    }]
+  }, {
+    path: 'deploy',
+    name: '部署管理',
+    icon: 'hdd-o',
+    component: Content,
+    redirect: '/program/deploy/home',
+    children: [{
+      path: 'home',
+      name: '快速部署',
+      icon: 'reorder',
+      component: Modules.Program.Deploy.Home
+    },{
+      path: 'client',
+      name: '客户端部署',
+      icon: 'reorder',
+      component: Modules.Program.Deploy.Client
+    },{
+      path: 'history',
+      name: '部署日志',
+      icon: 'reorder',
+      component: Modules.Program.Deploy.History
+    }]
+  }]
+}];

+ 32 - 0
src/config/router/runtime.js

@@ -0,0 +1,32 @@
+import {
+  Home,
+  Content,
+  Modules
+} from '../../components/';
+
+module.exports = [{
+  path: '/runtime',
+  name: '运行环境',
+  icon: 'inbox',
+  component: Home,
+  redirect: '/runtime/client',
+  children: [ {
+    path: 'info',
+    name: '客户端环境',
+    icon: 'inbox',
+    component: Content,
+    redirect: '/runtime/client/list',
+    children: [{
+      path: 'list',
+      name: '客户端列表',
+      icon: 'reorder',
+      component: Modules.Runtime.Client.List
+    },{
+      path: 'item',
+      name: '客户端详细配置',
+      icon: 'reorder',
+      component: Modules.Runtime.Client.Item,
+      hidden: true
+    }]
+  }]
+}];

+ 66 - 0
src/config/settings.js

@@ -0,0 +1,66 @@
+var env = process.env;
+
+var settings = {
+
+	//全局设置
+	gbs: {
+		host: '/uas_manage_server',// 接口根地址
+    db_prefix: 'uas_manage_server'// 本地存储key
+	},
+
+	//回调
+	cbs: {
+		/**
+		 * ajax请求成功,返回的状态码不是200时调用
+		 * @param  {object} err 返回的对象,包含错误码和错误信息
+		 */
+		statusError(err) {
+			if (err.status !== 404) {
+				this.$message({
+					showClose: true,
+					message: '返回错误:' + err.msg,
+					type: 'error'
+				});
+			} else {
+				this.$store.dispatch('remove_userinfo').then(() => {
+					this.$alert(err.status + ',' + err.msg + '!', '登录错误', {
+						confirmButtonText: '确定',
+						callback: action => {
+							this.$router.push('/login');
+						}
+					});
+				});
+			}
+		},
+    /**
+     * 逻辑错误返回错误信息及错误码
+     * @param resp
+     */
+    badRequest(resp) {
+      if (401 == resp.code) {
+        this.$store.dispatch('remove_userinfo').then(() => {
+          this.$router.push('/login');
+        });
+      } else {
+        this.$message({
+          showClose: true,
+          message: (resp.message || (resp.code ? ('错误码:' + resp.code) : '返回错误')),
+          type: 'error'
+        });
+      }
+    },
+
+		/**
+		 * ajax请求网络出错时调用
+		 */
+		requestError(err) {
+			this.$message({
+				showClose: true,
+				message: '请求错误:' + (err.response ? err.response.status : '') + ',' + (err.response ? err.response.statusText : ''),
+				type: 'error'
+			});
+		}
+	}
+};
+
+module.exports = settings;

+ 69 - 0
src/main.js

@@ -0,0 +1,69 @@
+import Vue from 'vue';
+
+// element-ui
+import ElementUI from 'element-ui';
+import 'element-ui/lib/theme-default/index.css';
+Vue.use(ElementUI);
+
+// router
+import VueRouter from 'vue-router';
+Vue.use(VueRouter);
+
+// vuex
+import Vuex from 'vuex';
+Vue.use(Vuex);
+
+//页面顶部进度条
+import NProgress from 'nprogress';
+import 'nprogress/nprogress.css';
+
+
+// root component
+import App from './App';
+
+//vuex store
+import store from './store/';
+
+
+import routes from './config/router.js';
+
+import 'register/';
+import 'mixin/';
+
+const router = new VueRouter({
+  routes
+});
+
+router.beforeEach((to, from, next) => {
+  window.scroll(0, 0);
+
+  var userinfo = store.state.user.userinfo;
+
+  if (!userinfo.token && to.path !== '/login') {
+    store.dispatch('remove_userinfo');
+    next('/login');
+  } else {
+    if (userinfo.token && to.path === '/login') {
+      next({
+        path: '/server'
+      });
+    } else {
+      NProgress.start();
+      next();
+    }
+  }
+})
+
+router.afterEach(transition => {
+  NProgress.done();
+});
+
+const appAdmin = new Vue({
+  el    : '#app',
+  data() {
+    return {};
+  },
+  router,
+  store,
+  render: h => h(App)
+})

+ 0 - 0
src/mixin/Created/index.js


+ 53 - 0
src/mixin/Methods/Common/FormData.js

@@ -0,0 +1,53 @@
+module.exports = {
+	/**
+	 * 检测富文本内容
+	 * @param  {object} 			object 						富文本对象集
+	 * @param  {object} 			object.editor_temp_data 	富文本对象集
+	 * @param  {object} 			object.field_infos      	富文本对象说明
+	 * @param  {boolean} 			object.type             	是否返回boolean值
+	 * @return {object or boolean}                  			如果传了type返回Boolean,否则返回验证信息
+	 */
+	onCheckEditor({
+		editor_temp_data,
+		field_infos,
+		type
+	}) {
+		var obj = {
+			status: 200
+		};
+		for (var id in editor_temp_data) {
+			if (!editor_temp_data[id].text) {
+				if ((editor_temp_data[id].html.indexOf('<iframe') == -1 || editor_temp_data[id].html.indexOf('</iframe>') == -1) && (editor_temp_data[id].html.indexOf('<img') == -1)) {
+					if (field_infos && field_infos[id]) {
+						this.$message.error(field_infos[id].msg);
+					}
+					obj.status = 1;
+					obj.id = id;
+					break;
+				}
+			}
+		}
+		return type === true ? obj.status === 200 : obj;
+	},
+
+	onSubmit({
+		data,
+		editor_temp_data
+	}) {
+		if (editor_temp_data) {
+			var check = this.onCheckEditor({
+				editor_temp_data,
+				field_infos: this.tips,
+				type: true
+			});
+			if (check) {
+				for (var f in this.tips) {
+					data[this.tips[f].field] = editor_temp_data[f].html;
+				}
+				this.onSubmitFn && this.onSubmitFn(data);
+			}
+		} else {
+			this.onSubmitFn && this.onSubmitFn(data);
+		}
+	}
+};

+ 100 - 0
src/mixin/Methods/Common/ListData.js

@@ -0,0 +1,100 @@
+module.exports = {
+	getDataList() {
+		var query = this.$route.query;
+		var params = Object.assign((this.pagination ? {
+			page_size: this.pagination.page_size,
+			page: this.pagination.current_page
+		} : {}), query);
+
+		this[this.apis.method.get_list](params, (resp) => {
+      if (this.pagination) {
+        this.list = resp.content.data;
+        this.pagination.total = resp.content.total;
+      } else {
+        this.list = resp.content;
+      }
+		});
+	},
+
+	onChangeCurrentPage(page) {
+		this.setRoutePath({
+			page
+		});
+	},
+	onChangePageSize(page_size) {
+		this.setRoutePath({
+			page_size
+		});
+	},
+
+	setRoutePath(q) {
+		var query = this.$route.query;
+		var params = Object.assign({}, query, q);
+		var path = this.$route.path;
+
+		this.$router.push({
+			path,
+			query: params
+		});
+
+		this.getDataList();
+
+	},
+
+	/**
+	 * 点击按钮通用事件
+	 * @param  {object} opts 返回参数
+	 */
+	onGetInfo(opts) {
+		switch (opts.type) {
+			case 'select':
+				break;
+			case 'update':
+				this.$router.push({
+					path: this.apis.route.update_path,
+					query: {
+						id: opts.row.id
+					}
+				});
+				break;
+		}
+	},
+
+
+	/**
+	 * 点击删除按钮事件
+	 * @param  {object} opts 返回参数
+	 */
+	onDelete(opts) {
+		if (opts.index >= 0) {
+			var batch = false;
+			var id = opts.data.id;
+		} else {
+			var batch = true;
+			var id = opts.batch_ids.join(',');
+		}
+
+		this[this.apis.method.delete_data]({
+			id: id
+		}, data => {
+			if (batch === true) {
+				this.list = this.list.filter((item) => {
+					return opts.batch_ids.indexOf(item.id) === -1;
+				});
+			} else {
+				this.list.splice(opts.index, 1);
+			}
+		});
+	},
+
+	onSelectionChange(ids, datas) {
+		console.log('on-selection-change');
+	},
+
+	onSelectionChangeObj({
+		ids,
+		datas
+	}) {
+		console.log('on-selection-change-obj');
+	},
+};

+ 4 - 0
src/mixin/Methods/Common/index.js

@@ -0,0 +1,4 @@
+module.exports = {
+	ListData: require('./ListData.js'),
+	FormData: require('./FormData.js')
+};

+ 3 - 0
src/mixin/Methods/index.js

@@ -0,0 +1,3 @@
+module.exports = {
+	Common: require('./Common/')
+};

+ 0 - 0
src/mixin/Mounted/index.js


+ 29 - 0
src/mixin/index.js

@@ -0,0 +1,29 @@
+import Vue from 'vue';
+
+/**
+ * 递归提取一个对象中的所有函数
+ * @param  {object} obj 对象
+ * @return {object}     所有函数都将被包装到这个对象中
+ */
+function mergeManyObjToOneObj(obj) {
+	var newObj = {};
+	if (obj && typeof obj === 'object') {
+		for (var f in obj) {
+			if (typeof obj[f] === 'function') {
+				newObj[f] = obj[f];
+			}
+			if (typeof obj[f] === 'object') {
+				Object.assign(newObj, mergeManyObjToOneObj(obj[f]));
+			}
+		}
+	}
+	return newObj;
+}
+
+//导入自定义的全局混合
+var mixins = {
+	methods: mergeManyObjToOneObj(require('./Methods/'))
+};
+
+//注册全局混合
+Vue.mixin(mixins);

+ 28 - 0
src/plugins/index.js

@@ -0,0 +1,28 @@
+import {
+	request
+} from 'config/';
+
+import {
+    ajax
+} from 'util/';
+
+var api_methods={};
+
+for (var i = 0; i < request.length; i++) {
+    if (typeof request[i]==='object' && request[i].list && Array.isArray(request[i].list)) {
+        for(var j=0;j<request[i].list.length;j++){
+            api_methods['api_'+request[i].module+'_'+request[i].list[j].method]=(function(n,m){
+                return function(data, fn, opts){
+                    this.$$ajax(request[n].list[m].type, request[n].list[m].path, data, fn, opts);
+                };
+            })(i,j);
+        }
+    }
+}
+
+module.exports = {
+	plugins: {
+		api_methods,
+		ajax
+	}
+};

+ 35 - 0
src/register/index.js

@@ -0,0 +1,35 @@
+import Vue from 'vue';
+
+
+/**
+ * 导入需要注册的对象
+ */
+import {
+	plugins
+} from 'plugins/';
+
+
+/**
+ * 注册到Vue对象中
+ */
+Vue.use({
+	install(Vue, options) {
+
+		/**
+		 * 递归把需要用到的方法以插件形式注册到Vue上
+		 * @param  {object} target 注册目标对象,即Vue
+		 * @param  {object} source 需要注册的对象
+		 */
+		var deepRegister = function(target, source) {
+			for (var k in source) {
+				if (typeof source[k] === 'object') {
+					deepRegister(target, source[k]);
+				} else {
+					target.prototype['$$' + k] = source[k];
+				}
+			}
+		}
+
+		deepRegister(Vue, plugins);
+	}
+});

+ 21 - 0
src/store/global/actions.js

@@ -0,0 +1,21 @@
+import * as types from './mutations_types';
+
+module.exports = {
+	show_loading: ({
+		commit
+	}) => {
+		return new Promise((resolve, reject) => {
+			commit(types.SHOW_LOADING);
+			resolve()
+		});
+	},
+
+	hide_loading: ({
+		commit
+	}) => {
+		return new Promise((resolve, reject) => {
+			commit(types.HIDE_LOADING);
+			resolve()
+		});
+	}
+};

+ 3 - 0
src/store/global/getters.js

@@ -0,0 +1,3 @@
+module.exports = {
+
+};

+ 11 - 0
src/store/global/index.js

@@ -0,0 +1,11 @@
+import state from './state';
+import mutations from './mutations';
+import getters from './getters';
+import actions from './actions';
+
+module.exports = {
+    state,
+    mutations,
+    getters,
+    actions
+};

+ 11 - 0
src/store/global/mutations.js

@@ -0,0 +1,11 @@
+import * as types from './mutations_types'
+
+module.exports = {
+    [types.SHOW_LOADING](state) {
+        state.ajax_loading = true;
+    },
+
+    [types.HIDE_LOADING](state) {
+        state.ajax_loading = false;
+    }
+};

+ 5 - 0
src/store/global/mutations_types.js

@@ -0,0 +1,5 @@
+//显示加载
+export const SHOW_LOADING = 'SHOW_LOADING';
+
+//关闭加载
+export const HIDE_LOADING = 'HIDE_LOADING';

+ 3 - 0
src/store/global/state.js

@@ -0,0 +1,3 @@
+module.exports = {
+    ajax_loading: false
+};

+ 17 - 0
src/store/index.js

@@ -0,0 +1,17 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+Vue.use(Vuex);
+
+import router from './router/';
+import leftmenu from './leftmenu/';
+import user from './userinfo/';
+import global from './global/';
+
+module.exports = new Vuex.Store({
+    modules: {
+        global,
+        router,
+        leftmenu,
+        user
+    }
+});

+ 14 - 0
src/store/leftmenu/actions.js

@@ -0,0 +1,14 @@
+import * as types from './mutations_types';
+
+module.exports = {
+    set_menu_open: ({
+        commit
+    }) => {
+        commit(types.SET_MENU_OPEN);
+    },
+    set_menu_close: ({
+        commit
+    }) => {
+        commit(types.SET_MENU_CLOSE);
+    }
+};

+ 2 - 0
src/store/leftmenu/getters.js

@@ -0,0 +1,2 @@
+module.exports = {
+};

+ 11 - 0
src/store/leftmenu/index.js

@@ -0,0 +1,11 @@
+import state from './state';
+import mutations from './mutations';
+import getters from './getters';
+import actions from './actions';
+
+module.exports = {
+    state,
+    mutations,
+    getters,
+    actions
+};

+ 12 - 0
src/store/leftmenu/mutations.js

@@ -0,0 +1,12 @@
+import * as types from './mutations_types'
+
+module.exports = {
+    [types.SET_MENU_OPEN](state) {
+        state.width = '190px';
+        state.menu_flag = true;
+    },
+    [types.SET_MENU_CLOSE](state) {
+        state.width = '50px';
+        state.menu_flag = false;
+    },
+};

+ 5 - 0
src/store/leftmenu/mutations_types.js

@@ -0,0 +1,5 @@
+//展开菜单
+export const SET_MENU_OPEN = 'SET_MENU_OPEN';
+
+//关闭菜单
+export const SET_MENU_CLOSE = 'SET_MENU_CLOSE';

+ 5 - 0
src/store/leftmenu/state.js

@@ -0,0 +1,5 @@
+module.exports = {
+    //左侧菜单宽度
+    width: '190px',
+    menu_flag: true,
+};

+ 9 - 0
src/store/router/actions.js

@@ -0,0 +1,9 @@
+import * as types from './mutations_types';
+
+module.exports = {
+    set_cur_route: ({
+        commit
+    }, paths) => {
+        commit(types.SET_CUR_ROUTE, paths);
+    }
+};

+ 2 - 0
src/store/router/getters.js

@@ -0,0 +1,2 @@
+module.exports = {
+};

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно