liujie 5 роки тому
коміт
cc8ca44956
60 змінених файлів з 19513 додано та 0 видалено
  1. 12 0
      .babelrc
  2. 9 0
      .editorconfig
  3. 4 0
      .eslintignore
  4. 29 0
      .eslintrc.js
  5. 14 0
      .gitignore
  6. 10 0
      .postcssrc.js
  7. 21 0
      README.md
  8. 41 0
      build/build.js
  9. 54 0
      build/check-versions.js
  10. BIN
      build/logo.png
  11. 101 0
      build/utils.js
  12. 22 0
      build/vue-loader.conf.js
  13. 92 0
      build/webpack.base.conf.js
  14. 95 0
      build/webpack.dev.conf.js
  15. 145 0
      build/webpack.prod.conf.js
  16. 7 0
      config/dev.env.js
  17. 85 0
      config/index.js
  18. 4 0
      config/prod.env.js
  19. BIN
      dist_mq.zip
  20. 12 0
      index.html
  21. 12773 0
      package-lock.json
  22. 80 0
      package.json
  23. 21 0
      src/App.vue
  24. 539 0
      src/assets/icon/demo.css
  25. 1412 0
      src/assets/icon/demo_index.html
  26. 233 0
      src/assets/icon/iconfont.css
  27. BIN
      src/assets/icon/iconfont.eot
  28. 1 0
      src/assets/icon/iconfont.js
  29. 387 0
      src/assets/icon/iconfont.json
  30. 188 0
      src/assets/icon/iconfont.svg
  31. BIN
      src/assets/icon/iconfont.ttf
  32. BIN
      src/assets/icon/iconfont.woff
  33. BIN
      src/assets/icon/iconfont.woff2
  34. BIN
      src/assets/images/monitor/1.png
  35. BIN
      src/assets/images/monitor/11.png
  36. BIN
      src/assets/images/monitor/12.png
  37. BIN
      src/assets/images/monitor/122.png
  38. BIN
      src/assets/images/monitor/2.png
  39. BIN
      src/assets/images/monitor/22.png
  40. BIN
      src/assets/images/monitor/9.png
  41. BIN
      src/assets/images/monitor/99.png
  42. BIN
      src/assets/images/monitor/addequip.png
  43. BIN
      src/assets/images/monitor/direction-btn.png
  44. BIN
      src/assets/images/monitor/fS.png
  45. BIN
      src/assets/images/monitor/fS2.png
  46. BIN
      src/assets/images/monitor/h_bg.jpg
  47. BIN
      src/assets/images/monitor/icon.png
  48. BIN
      src/assets/images/monitor/playback-btn.png
  49. BIN
      src/assets/images/monitor/playtype0.png
  50. BIN
      src/assets/images/monitor/playtype1.png
  51. BIN
      src/assets/images/monitor/zoom-btn.png
  52. BIN
      src/assets/logo.png
  53. 136 0
      src/components/Index.vue
  54. 262 0
      src/components/Login.vue
  55. 39 0
      src/main.js
  56. 927 0
      src/pages/Monitor.vue
  57. 115 0
      src/plugin/elementUi.js
  58. 1614 0
      src/plugin/ezuikit.js
  59. 29 0
      src/router/index.js
  60. 0 0
      static/.gitkeep

+ 12 - 0
.babelrc

@@ -0,0 +1,12 @@
+{
+  "presets": [
+    ["env", {
+      "modules": false,
+      "targets": {
+        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
+      }
+    }],
+    "stage-2"
+  ],
+  "plugins": ["transform-vue-jsx", "transform-runtime"]
+}

+ 9 - 0
.editorconfig

@@ -0,0 +1,9 @@
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true

+ 4 - 0
.eslintignore

@@ -0,0 +1,4 @@
+/build/
+/config/
+/dist/
+/*.js

+ 29 - 0
.eslintrc.js

@@ -0,0 +1,29 @@
+// https://eslint.org/docs/user-guide/configuring
+
+module.exports = {
+  root: true,
+  parserOptions: {
+    parser: 'babel-eslint'
+  },
+  env: {
+    browser: true,
+  },
+  extends: [
+    // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
+    // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
+    'plugin:vue/essential', 
+    // https://github.com/standard/standard/blob/master/docs/RULES-en.md
+    'standard'
+  ],
+  // required to lint *.vue files
+  plugins: [
+    'vue'
+  ],
+  // add your custom rules here
+  rules: {
+    // allow async-await
+    'generator-star-spacing': 'off',
+    // allow debugger during development
+    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
+  }
+}

+ 14 - 0
.gitignore

@@ -0,0 +1,14 @@
+.DS_Store
+node_modules/
+/dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln

+ 10 - 0
.postcssrc.js

@@ -0,0 +1,10 @@
+// https://github.com/michael-ciniawsky/postcss-load-config
+
+module.exports = {
+  "plugins": {
+    "postcss-import": {},
+    "postcss-url": {},
+    // to edit target browsers: use "browserslist" field in package.json
+    "autoprefixer": {}
+  }
+}

+ 21 - 0
README.md

@@ -0,0 +1,21 @@
+# newjk
+
+> A Vue.js project
+
+## Build Setup
+
+``` bash
+# install dependencies
+npm install
+
+# serve with hot reload at localhost:8080
+npm run dev
+
+# build for production with minification
+npm run build
+
+# build for production and view the bundle analyzer report
+npm run build --report
+```
+
+For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).

+ 41 - 0
build/build.js

@@ -0,0 +1,41 @@
+'use strict'
+require('./check-versions')()
+
+process.env.NODE_ENV = 'production'
+
+const ora = require('ora')
+const rm = require('rimraf')
+const path = require('path')
+const chalk = require('chalk')
+const webpack = require('webpack')
+const config = require('../config')
+const webpackConfig = require('./webpack.prod.conf')
+
+const spinner = ora('building for production...')
+spinner.start()
+
+rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
+  if (err) throw err
+  webpack(webpackConfig, (err, stats) => {
+    spinner.stop()
+    if (err) throw err
+    process.stdout.write(stats.toString({
+      colors: true,
+      modules: false,
+      children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
+      chunks: false,
+      chunkModules: false
+    }) + '\n\n')
+
+    if (stats.hasErrors()) {
+      console.log(chalk.red('  Build failed with errors.\n'))
+      process.exit(1)
+    }
+
+    console.log(chalk.cyan('  Build complete.\n'))
+    console.log(chalk.yellow(
+      '  Tip: built files are meant to be served over an HTTP server.\n' +
+      '  Opening index.html over file:// won\'t work.\n'
+    ))
+  })
+})

+ 54 - 0
build/check-versions.js

@@ -0,0 +1,54 @@
+'use strict'
+const chalk = require('chalk')
+const semver = require('semver')
+const packageConfig = require('../package.json')
+const shell = require('shelljs')
+
+function exec (cmd) {
+  return require('child_process').execSync(cmd).toString().trim()
+}
+
+const versionRequirements = [
+  {
+    name: 'node',
+    currentVersion: semver.clean(process.version),
+    versionRequirement: packageConfig.engines.node
+  }
+]
+
+if (shell.which('npm')) {
+  versionRequirements.push({
+    name: 'npm',
+    currentVersion: exec('npm --version'),
+    versionRequirement: packageConfig.engines.npm
+  })
+}
+
+module.exports = function () {
+  const warnings = []
+
+  for (let i = 0; i < versionRequirements.length; i++) {
+    const 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 (let i = 0; i < warnings.length; i++) {
+      const warning = warnings[i]
+      console.log('  ' + warning)
+    }
+
+    console.log()
+    process.exit(1)
+  }
+}

BIN
build/logo.png


+ 101 - 0
build/utils.js

@@ -0,0 +1,101 @@
+'use strict'
+const path = require('path')
+const config = require('../config')
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
+const packageConfig = require('../package.json')
+
+exports.assetsPath = function (_path) {
+  const assetsSubDirectory = process.env.NODE_ENV === 'production'
+    ? config.build.assetsSubDirectory
+    : config.dev.assetsSubDirectory
+
+  return path.posix.join(assetsSubDirectory, _path)
+}
+
+exports.cssLoaders = function (options) {
+  options = options || {}
+
+  const cssLoader = {
+    loader: 'css-loader',
+    options: {
+      sourceMap: options.sourceMap
+    }
+  }
+
+  const postcssLoader = {
+    loader: 'postcss-loader',
+    options: {
+      sourceMap: options.sourceMap
+    }
+  }
+
+  // generate loader string to be used with extract text plugin
+  function generateLoaders (loader, loaderOptions) {
+    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
+
+    if (loader) {
+      loaders.push({
+        loader: loader + '-loader',
+        options: Object.assign({}, loaderOptions, {
+          sourceMap: options.sourceMap
+        })
+      })
+    }
+
+    // Extract CSS when that option is specified
+    // (which is the case during production build)
+    if (options.extract) {
+      return ExtractTextPlugin.extract({
+        use: loaders,
+        fallback: 'vue-style-loader'
+      })
+    } else {
+      return ['vue-style-loader'].concat(loaders)
+    }
+  }
+
+  // https://vue-loader.vuejs.org/en/configurations/extract-css.html
+  return {
+    css: generateLoaders(),
+    postcss: generateLoaders(),
+    less: generateLoaders('less'),
+    sass: generateLoaders('sass', { indentedSyntax: true }),
+    scss: generateLoaders('sass'),
+    stylus: generateLoaders('stylus'),
+    styl: generateLoaders('stylus')
+  }
+}
+
+// Generate loaders for standalone style files (outside of .vue)
+exports.styleLoaders = function (options) {
+  const output = []
+  const loaders = exports.cssLoaders(options)
+
+  for (const extension in loaders) {
+    const loader = loaders[extension]
+    output.push({
+      test: new RegExp('\\.' + extension + '$'),
+      use: loader
+    })
+  }
+
+  return output
+}
+
+exports.createNotifierCallback = () => {
+  const notifier = require('node-notifier')
+
+  return (severity, errors) => {
+    if (severity !== 'error') return
+
+    const error = errors[0]
+    const filename = error.file && error.file.split('!').pop()
+
+    notifier.notify({
+      title: packageConfig.name,
+      message: severity + ': ' + error.name,
+      subtitle: filename || '',
+      icon: path.join(__dirname, 'logo.png')
+    })
+  }
+}

+ 22 - 0
build/vue-loader.conf.js

@@ -0,0 +1,22 @@
+'use strict'
+const utils = require('./utils')
+const config = require('../config')
+const isProduction = process.env.NODE_ENV === 'production'
+const sourceMapEnabled = isProduction
+  ? config.build.productionSourceMap
+  : config.dev.cssSourceMap
+
+module.exports = {
+  loaders: utils.cssLoaders({
+    sourceMap: sourceMapEnabled,
+    extract: isProduction
+  }),
+  cssSourceMap: sourceMapEnabled,
+  cacheBusting: config.dev.cacheBusting,
+  transformToRequire: {
+    video: ['src', 'poster'],
+    source: 'src',
+    img: 'src',
+    image: 'xlink:href'
+  }
+}

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

@@ -0,0 +1,92 @@
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const config = require('../config')
+const vueLoaderConfig = require('./vue-loader.conf')
+
+function resolve (dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const createLintingRule = () => ({
+  test: /\.(js|vue)$/,
+  loader: 'eslint-loader',
+  enforce: 'pre',
+  include: [resolve('src'), resolve('test')],
+  options: {
+    formatter: require('eslint-friendly-formatter'),
+    emitWarning: !config.dev.showEslintErrorsInOverlay
+  }
+})
+
+module.exports = {
+  context: path.resolve(__dirname, '../'),
+  entry: {
+    app: './src/main.js'
+  },
+  output: {
+    path: config.build.assetsRoot,
+    filename: '[name].js',
+    publicPath: process.env.NODE_ENV === 'production'
+      ? config.build.assetsPublicPath
+      : config.dev.assetsPublicPath
+  },
+  resolve: {
+    extensions: ['.js', '.vue', '.json'],
+    alias: {
+      'vue$': 'vue/dist/vue.esm.js',
+      '@': resolve('src'),
+    }
+  },
+  module: {
+    rules: [
+      // ...(config.dev.useEslint ? [createLintingRule()] : []),
+      {
+        test: /\.vue$/,
+        loader: 'vue-loader',
+        options: vueLoaderConfig
+      },
+      {
+        test: /\.js$/,
+        loader: 'babel-loader',
+        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
+      },
+      {
+        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('img/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('media/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
+        }
+      }
+    ]
+  },
+  node: {
+    // prevent webpack from injecting useless setImmediate polyfill because Vue
+    // source contains it (although only uses it if it's native).
+    setImmediate: false,
+    // prevent webpack from injecting mocks to Node native modules
+    // that does not make sense for the client
+    dgram: 'empty',
+    fs: 'empty',
+    net: 'empty',
+    tls: 'empty',
+    child_process: 'empty'
+  }
+}

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

@@ -0,0 +1,95 @@
+'use strict'
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const path = require('path')
+const baseWebpackConfig = require('./webpack.base.conf')
+const CopyWebpackPlugin = require('copy-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
+const portfinder = require('portfinder')
+
+const HOST = process.env.HOST
+const PORT = process.env.PORT && Number(process.env.PORT)
+
+const devWebpackConfig = merge(baseWebpackConfig, {
+  module: {
+    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
+  },
+  // cheap-module-eval-source-map is faster for development
+  devtool: config.dev.devtool,
+
+  // these devServer options should be customized in /config/index.js
+  devServer: {
+    clientLogLevel: 'warning',
+    historyApiFallback: {
+      rewrites: [
+        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
+      ],
+    },
+    hot: true,
+    contentBase: false, // since we use CopyWebpackPlugin.
+    compress: true,
+    host: HOST || config.dev.host,
+    port: PORT || config.dev.port,
+    open: config.dev.autoOpenBrowser,
+    overlay: config.dev.errorOverlay
+      ? { warnings: false, errors: true }
+      : false,
+    publicPath: config.dev.assetsPublicPath,
+    proxy: config.dev.proxyTable,
+    quiet: true, // necessary for FriendlyErrorsPlugin
+    watchOptions: {
+      poll: config.dev.poll,
+    }
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env': require('../config/dev.env')
+    }),
+    new webpack.HotModuleReplacementPlugin(),
+    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
+    new webpack.NoEmitOnErrorsPlugin(),
+    // https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: 'index.html',
+      template: 'index.html',
+      inject: true
+    }),
+    // copy custom static assets
+    new CopyWebpackPlugin([
+      {
+        from: path.resolve(__dirname, '../static'),
+        to: config.dev.assetsSubDirectory,
+        ignore: ['.*']
+      }
+    ])
+  ]
+})
+
+module.exports = new Promise((resolve, reject) => {
+  portfinder.basePort = process.env.PORT || config.dev.port
+  portfinder.getPort((err, port) => {
+    if (err) {
+      reject(err)
+    } else {
+      // publish the new Port, necessary for e2e tests
+      process.env.PORT = port
+      // add port to devServer config
+      devWebpackConfig.devServer.port = port
+
+      // Add FriendlyErrorsPlugin
+      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
+        compilationSuccessInfo: {
+          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
+        },
+        onErrors: config.dev.notifyOnErrors
+        ? utils.createNotifierCallback()
+        : undefined
+      }))
+
+      resolve(devWebpackConfig)
+    }
+  })
+})

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

@@ -0,0 +1,145 @@
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const baseWebpackConfig = require('./webpack.base.conf')
+const CopyWebpackPlugin = require('copy-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
+const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
+const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
+
+const env = require('../config/prod.env')
+
+const webpackConfig = merge(baseWebpackConfig, {
+  module: {
+    rules: utils.styleLoaders({
+      sourceMap: config.build.productionSourceMap,
+      extract: true,
+      usePostCSS: true
+    })
+  },
+  devtool: config.build.productionSourceMap ? config.build.devtool : false,
+  output: {
+    path: config.build.assetsRoot,
+    filename: utils.assetsPath('js/[name].[chunkhash].js'),
+    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
+  },
+  plugins: [
+    // http://vuejs.github.io/vue-loader/en/workflow/production.html
+    new webpack.DefinePlugin({
+      'process.env': env
+    }),
+    new UglifyJsPlugin({
+      uglifyOptions: {
+        compress: {
+          warnings: false
+        }
+      },
+      sourceMap: config.build.productionSourceMap,
+      parallel: true
+    }),
+    // extract css into its own file
+    new ExtractTextPlugin({
+      filename: utils.assetsPath('css/[name].[contenthash].css'),
+      // Setting the following option to `false` will not extract CSS from codesplit chunks.
+      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
+      // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 
+      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
+      allChunks: true,
+    }),
+    // Compress extracted CSS. We are using this plugin so that possible
+    // duplicated CSS from different components can be deduped.
+    new OptimizeCSSPlugin({
+      cssProcessorOptions: config.build.productionSourceMap
+        ? { safe: true, map: { inline: false } }
+        : { safe: true }
+    }),
+    // 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'
+    }),
+    // keep module.id stable when vendor modules does not change
+    new webpack.HashedModuleIdsPlugin(),
+    // enable scope hoisting
+    new webpack.optimize.ModuleConcatenationPlugin(),
+    // split vendor js into its own file
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'vendor',
+      minChunks (module) {
+        // 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',
+      minChunks: Infinity
+    }),
+    // This instance extracts shared chunks from code splitted chunks and bundles them
+    // in a separate chunk, similar to the vendor chunk
+    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'app',
+      async: 'vendor-async',
+      children: true,
+      minChunks: 3
+    }),
+
+    // copy custom static assets
+    new CopyWebpackPlugin([
+      {
+        from: path.resolve(__dirname, '../static'),
+        to: config.build.assetsSubDirectory,
+        ignore: ['.*']
+      }
+    ])
+  ]
+})
+
+if (config.build.productionGzip) {
+  const 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
+    })
+  )
+}
+
+if (config.build.bundleAnalyzerReport) {
+  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
+  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
+}
+
+module.exports = webpackConfig

+ 7 - 0
config/dev.env.js

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

+ 85 - 0
config/index.js

@@ -0,0 +1,85 @@
+'use strict'
+// Template version: 1.3.1
+// see http://vuejs-templates.github.io/webpack for documentation.
+
+const path = require('path')
+
+module.exports = {
+  dev: {
+
+    // Paths
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+    proxyTable: {
+      '/api': {
+        // target: 'http://192.168.1.8:8000/',
+        target: 'http://192.168.1.4:8000/',
+        changeOrigin: true,
+        pathRewrite: {
+          '^/api': '' //重写接口
+        }
+      },
+    },
+
+    // Various Dev Server settings
+    host: '192.168.1.7', // can be overwritten by process.env.HOST
+    port: 8000, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
+    autoOpenBrowser: false,
+    errorOverlay: true,
+    notifyOnErrors: true,
+    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
+
+    // Use Eslint Loader?
+    // If true, your code will be linted during bundling and
+    // linting errors and warnings will be shown in the console.
+    useEslint: true,
+    // If true, eslint errors and warnings will also be shown in the error overlay
+    // in the browser.
+    showEslintErrorsInOverlay: false,
+
+    /**
+     * Source Maps
+     */
+
+    // https://webpack.js.org/configuration/devtool/#development
+    devtool: 'cheap-module-eval-source-map',
+
+    // If you have problems debugging vue-files in devtools,
+    // set this to false - it *may* help
+    // https://vue-loader.vuejs.org/en/options.html#cachebusting
+    cacheBusting: true,
+
+    cssSourceMap: true
+  },
+
+  build: {
+    // Template for index.html
+    index: path.resolve(__dirname, '../dist/index.html'),
+
+    // Paths
+    assetsRoot: path.resolve(__dirname, '../dist'),
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+
+    /**
+     * Source Maps
+     */
+
+    productionSourceMap: false,
+    // https://webpack.js.org/configuration/devtool/#production
+    devtool: '#source-map',
+
+    // 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'],
+
+    // Run the build command with an extra argument to
+    // View the bundle analyzer report after build finishes:
+    // `npm run build --report`
+    // Set to `true` or `false` to always turn it on or off
+    bundleAnalyzerReport: process.env.npm_config_report
+  }
+}

+ 4 - 0
config/prod.env.js

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


+ 12 - 0
index.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <title>newjk</title>
+  </head>
+  <body>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

Різницю між файлами не показано, бо вона завелика
+ 12773 - 0
package-lock.json


+ 80 - 0
package.json

@@ -0,0 +1,80 @@
+{
+  "name": "newjk",
+  "version": "1.0.0",
+  "description": "A Vue.js project",
+  "author": "liujie <1464516907@qq.com>",
+  "private": true,
+  "scripts": {
+    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+    "start": "npm run dev",
+    "lint": "eslint --ext .js,.vue src",
+    "build": "node build/build.js"
+  },
+  "dependencies": {
+    "axios": "^0.21.0",
+    "babel-polyfill": "^6.26.0",
+    "element-ui": "^2.14.1",
+    "es6-promise": "^4.2.8",
+    "vue": "^2.5.2",
+    "vue-router": "^3.0.1"
+  },
+  "devDependencies": {
+    "autoprefixer": "^7.1.2",
+    "babel-core": "^6.22.1",
+    "babel-eslint": "^8.2.1",
+    "babel-helper-vue-jsx-merge-props": "^2.0.3",
+    "babel-loader": "^7.1.1",
+    "babel-plugin-syntax-jsx": "^6.18.0",
+    "babel-plugin-transform-runtime": "^6.22.0",
+    "babel-plugin-transform-vue-jsx": "^3.5.0",
+    "babel-preset-env": "^1.3.2",
+    "babel-preset-stage-2": "^6.22.0",
+    "chalk": "^2.0.1",
+    "copy-webpack-plugin": "^4.0.1",
+    "css-loader": "^0.28.11",
+    "eslint": "^4.15.0",
+    "eslint-config-standard": "^10.2.1",
+    "eslint-friendly-formatter": "^3.0.0",
+    "eslint-loader": "^1.7.1",
+    "eslint-plugin-import": "^2.7.0",
+    "eslint-plugin-node": "^5.2.0",
+    "eslint-plugin-promise": "^3.4.0",
+    "eslint-plugin-standard": "^3.0.1",
+    "eslint-plugin-vue": "^4.0.0",
+    "extract-text-webpack-plugin": "^3.0.0",
+    "file-loader": "^1.1.4",
+    "friendly-errors-webpack-plugin": "^1.6.1",
+    "html-webpack-plugin": "^2.30.1",
+    "less": "^3.9",
+    "less-loader": "^5.0.0",
+    "node-notifier": "^5.1.2",
+    "optimize-css-assets-webpack-plugin": "^3.2.0",
+    "ora": "^1.2.0",
+    "portfinder": "^1.0.13",
+    "postcss-import": "^11.0.0",
+    "postcss-loader": "^2.0.8",
+    "postcss-url": "^7.2.1",
+    "qs": "^6.9.4",
+    "rimraf": "^2.6.0",
+    "semver": "^5.3.0",
+    "shelljs": "^0.7.6",
+    "uglifyjs-webpack-plugin": "^1.1.1",
+    "url-loader": "^0.5.8",
+    "vue-loader": "^13.7.3",
+    "vue-style-loader": "^3.1.2",
+    "vue-template-compiler": "^2.5.2",
+    "webpack": "^3.6.0",
+    "webpack-bundle-analyzer": "^2.9.0",
+    "webpack-dev-server": "^2.9.1",
+    "webpack-merge": "^4.1.0"
+  },
+  "engines": {
+    "node": ">= 6.0.0",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
+}

+ 21 - 0
src/App.vue

@@ -0,0 +1,21 @@
+<template>
+  <div id="app">
+    <router-view/>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'App'
+}
+</script>
+
+<style lang="less">
+html,body{
+  height:100%;
+  margin:0;
+    #app {
+    height: 100%;
+  }
+}
+</style>

+ 539 - 0
src/assets/icon/demo.css

@@ -0,0 +1,539 @@
+/* Logo 字体 */
+@font-face {
+  font-family: "iconfont logo";
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
+}
+
+.logo {
+  font-family: "iconfont logo";
+  font-size: 160px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+/* tabs */
+.nav-tabs {
+  position: relative;
+}
+
+.nav-tabs .nav-more {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  height: 42px;
+  line-height: 42px;
+  color: #666;
+}
+
+#tabs {
+  border-bottom: 1px solid #eee;
+}
+
+#tabs li {
+  cursor: pointer;
+  width: 100px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  font-size: 16px;
+  border-bottom: 2px solid transparent;
+  position: relative;
+  z-index: 1;
+  margin-bottom: -1px;
+  color: #666;
+}
+
+
+#tabs .active {
+  border-bottom-color: #f00;
+  color: #222;
+}
+
+.tab-container .content {
+  display: none;
+}
+
+/* 页面布局 */
+.main {
+  padding: 30px 100px;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.main .logo {
+  color: #333;
+  text-align: left;
+  margin-bottom: 30px;
+  line-height: 1;
+  height: 110px;
+  margin-top: -50px;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.main .logo a {
+  font-size: 160px;
+  color: #333;
+}
+
+.helps {
+  margin-top: 40px;
+}
+
+.helps pre {
+  padding: 20px;
+  margin: 10px 0;
+  border: solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists {
+  width: 100% !important;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.icon_lists li {
+  width: 100px;
+  margin-bottom: 10px;
+  margin-right: 20px;
+  text-align: center;
+  list-style: none !important;
+  cursor: default;
+}
+
+.icon_lists li .code-name {
+  line-height: 1.2;
+}
+
+.icon_lists .icon {
+  display: block;
+  height: 100px;
+  line-height: 100px;
+  font-size: 42px;
+  margin: 10px auto;
+  color: #333;
+  -webkit-transition: font-size 0.25s linear, width 0.25s linear;
+  -moz-transition: font-size 0.25s linear, width 0.25s linear;
+  transition: font-size 0.25s linear, width 0.25s linear;
+}
+
+.icon_lists .icon:hover {
+  font-size: 100px;
+}
+
+.icon_lists .svg-icon {
+  /* 通过设置 font-size 来改变图标大小 */
+  width: 1em;
+  /* 图标和文字相邻时,垂直对齐 */
+  vertical-align: -0.15em;
+  /* 通过设置 color 来改变 SVG 的颜色/fill */
+  fill: currentColor;
+  /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
+      normalize.css 中也包含这行 */
+  overflow: hidden;
+}
+
+.icon_lists li .name,
+.icon_lists li .code-name {
+  color: #666;
+}
+
+/* markdown 样式 */
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p {
+  margin: 1em 0;
+}
+
+.markdown>p,
+.markdown>blockquote,
+.markdown>.highlight,
+.markdown>ol,
+.markdown>ul {
+  width: 80%;
+}
+
+.markdown ul>li {
+  list-style: circle;
+}
+
+.markdown>ul li,
+.markdown blockquote ul>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown>ul li p,
+.markdown>ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol>li {
+  list-style: decimal;
+}
+
+.markdown>ol li,
+.markdown blockquote ol>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown>table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown>table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+}
+
+.markdown>table th,
+.markdown>table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown>table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown>br,
+.markdown>p>br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+/* 代码高亮 */
+/* PrismJS 1.15.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+code[class*="language-"],
+pre[class*="language-"] {
+  color: black;
+  background: none;
+  text-shadow: 0 1px white;
+  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+  text-align: left;
+  white-space: pre;
+  word-spacing: normal;
+  word-break: normal;
+  word-wrap: normal;
+  line-height: 1.5;
+
+  -moz-tab-size: 4;
+  -o-tab-size: 4;
+  tab-size: 4;
+
+  -webkit-hyphens: none;
+  -moz-hyphens: none;
+  -ms-hyphens: none;
+  hyphens: none;
+}
+
+pre[class*="language-"]::-moz-selection,
+pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection,
+code[class*="language-"] ::-moz-selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+pre[class*="language-"]::selection,
+pre[class*="language-"] ::selection,
+code[class*="language-"]::selection,
+code[class*="language-"] ::selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+@media print {
+
+  code[class*="language-"],
+  pre[class*="language-"] {
+    text-shadow: none;
+  }
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+  padding: 1em;
+  margin: .5em 0;
+  overflow: auto;
+}
+
+:not(pre)>code[class*="language-"],
+pre[class*="language-"] {
+  background: #f5f2f0;
+}
+
+/* Inline code */
+:not(pre)>code[class*="language-"] {
+  padding: .1em;
+  border-radius: .3em;
+  white-space: normal;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+  color: slategray;
+}
+
+.token.punctuation {
+  color: #999;
+}
+
+.namespace {
+  opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
+  color: #905;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+  color: #690;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+  color: #9a6e3a;
+  background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+  color: #07a;
+}
+
+.token.function,
+.token.class-name {
+  color: #DD4A68;
+}
+
+.token.regex,
+.token.important,
+.token.variable {
+  color: #e90;
+}
+
+.token.important,
+.token.bold {
+  font-weight: bold;
+}
+
+.token.italic {
+  font-style: italic;
+}
+
+.token.entity {
+  cursor: help;
+}

Різницю між файлами не показано, бо вона завелика
+ 1412 - 0
src/assets/icon/demo_index.html


Різницю між файлами не показано, бо вона завелика
+ 233 - 0
src/assets/icon/iconfont.css


BIN
src/assets/icon/iconfont.eot


Різницю між файлами не показано, бо вона завелика
+ 1 - 0
src/assets/icon/iconfont.js


+ 387 - 0
src/assets/icon/iconfont.json

@@ -0,0 +1,387 @@
+{
+  "id": "1738837",
+  "name": "农业大数据",
+  "font_family": "iconfont",
+  "css_prefix_text": "icon-",
+  "description": "",
+  "glyphs": [
+    {
+      "icon_id": "2678622",
+      "name": "全屏",
+      "font_class": "quanping",
+      "unicode": "e656",
+      "unicode_decimal": 58966
+    },
+    {
+      "icon_id": "772252",
+      "name": "扫描 识别 380%",
+      "font_class": "saomiaoshibie380",
+      "unicode": "e686",
+      "unicode_decimal": 59014
+    },
+    {
+      "icon_id": "11893490",
+      "name": "添加",
+      "font_class": "tianjia",
+      "unicode": "e615",
+      "unicode_decimal": 58901
+    },
+    {
+      "icon_id": "16364328",
+      "name": "统计",
+      "font_class": "tongji",
+      "unicode": "e636",
+      "unicode_decimal": 58934
+    },
+    {
+      "icon_id": "17709313",
+      "name": "未命名 -34",
+      "font_class": "weimingming-34",
+      "unicode": "e60b",
+      "unicode_decimal": 58891
+    },
+    {
+      "icon_id": "5327411",
+      "name": "臭虫bug",
+      "font_class": "chouchongbug",
+      "unicode": "e6e1",
+      "unicode_decimal": 59105
+    },
+    {
+      "icon_id": "802969",
+      "name": "楼房",
+      "font_class": "loufang",
+      "unicode": "e64f",
+      "unicode_decimal": 58959
+    },
+    {
+      "icon_id": "4348068",
+      "name": "电脑",
+      "font_class": "diannao1",
+      "unicode": "e623",
+      "unicode_decimal": 58915
+    },
+    {
+      "icon_id": "8835594",
+      "name": "图片",
+      "font_class": "tupian-xianxing",
+      "unicode": "e635",
+      "unicode_decimal": 58933
+    },
+    {
+      "icon_id": "10392628",
+      "name": "详情-",
+      "font_class": "xiangqing-",
+      "unicode": "e608",
+      "unicode_decimal": 58888
+    },
+    {
+      "icon_id": "36107",
+      "name": "面积",
+      "font_class": "mianji",
+      "unicode": "e602",
+      "unicode_decimal": 58882
+    },
+    {
+      "icon_id": "883904",
+      "name": "电话 (2)",
+      "font_class": "dianhua2",
+      "unicode": "e611",
+      "unicode_decimal": 58897
+    },
+    {
+      "icon_id": "1183130",
+      "name": "定位",
+      "font_class": "dingwei",
+      "unicode": "e675",
+      "unicode_decimal": 58997
+    },
+    {
+      "icon_id": "6129144",
+      "name": "102绑定",
+      "font_class": "bangding",
+      "unicode": "e784",
+      "unicode_decimal": 59268
+    },
+    {
+      "icon_id": "6970030",
+      "name": "用户",
+      "font_class": "yonghu11",
+      "unicode": "e705",
+      "unicode_decimal": 59141
+    },
+    {
+      "icon_id": "1106935",
+      "name": "雨",
+      "font_class": "yu",
+      "unicode": "e63a",
+      "unicode_decimal": 58938
+    },
+    {
+      "icon_id": "2155826",
+      "name": "温度",
+      "font_class": "thermometer_icon",
+      "unicode": "e67a",
+      "unicode_decimal": 59002
+    },
+    {
+      "icon_id": "4236632",
+      "name": "湿度",
+      "font_class": "shidu",
+      "unicode": "e60a",
+      "unicode_decimal": 58890
+    },
+    {
+      "icon_id": "7983631",
+      "name": "摄像头",
+      "font_class": "xingzhuang",
+      "unicode": "e614",
+      "unicode_decimal": 58900
+    },
+    {
+      "icon_id": "13638685",
+      "name": "电",
+      "font_class": "dian",
+      "unicode": "e655",
+      "unicode_decimal": 58965
+    },
+    {
+      "icon_id": "13638743",
+      "name": "温度",
+      "font_class": "wendu",
+      "unicode": "e660",
+      "unicode_decimal": 58976
+    },
+    {
+      "icon_id": "14095260",
+      "name": "定时",
+      "font_class": "dingshi",
+      "unicode": "e77e",
+      "unicode_decimal": 59262
+    },
+    {
+      "icon_id": "397065",
+      "name": "诱虫灯",
+      "font_class": "fangzhi",
+      "unicode": "e75c",
+      "unicode_decimal": 59228
+    },
+    {
+      "icon_id": "519489",
+      "name": "首页",
+      "font_class": "shouye",
+      "unicode": "e61e",
+      "unicode_decimal": 58910
+    },
+    {
+      "icon_id": "552767",
+      "name": "农药化肥",
+      "font_class": "nongchangguanli",
+      "unicode": "e62c",
+      "unicode_decimal": 58924
+    },
+    {
+      "icon_id": "689284",
+      "name": "设置 设定 配置 扳手",
+      "font_class": "shouhou",
+      "unicode": "e80e",
+      "unicode_decimal": 59406
+    },
+    {
+      "icon_id": "1119123",
+      "name": "系统",
+      "font_class": "xitong",
+      "unicode": "e60f",
+      "unicode_decimal": 58895
+    },
+    {
+      "icon_id": "1320048",
+      "name": "数据统计",
+      "font_class": "shujuzhanshi",
+      "unicode": "e621",
+      "unicode_decimal": 58913
+    },
+    {
+      "icon_id": "3483768",
+      "name": "地址",
+      "font_class": "jidi",
+      "unicode": "e672",
+      "unicode_decimal": 58994
+    },
+    {
+      "icon_id": "6756289",
+      "name": "专家",
+      "font_class": "zhuanjia",
+      "unicode": "e607",
+      "unicode_decimal": 58887
+    },
+    {
+      "icon_id": "7562834",
+      "name": "农事行为",
+      "font_class": "nongshiguanli",
+      "unicode": "e60c",
+      "unicode_decimal": 58892
+    },
+    {
+      "icon_id": "10544904",
+      "name": "多云转晴",
+      "font_class": "huanjingjiance",
+      "unicode": "e610",
+      "unicode_decimal": 58896
+    },
+    {
+      "icon_id": "13190141",
+      "name": "设备",
+      "font_class": "shebei",
+      "unicode": "e622",
+      "unicode_decimal": 58914
+    },
+    {
+      "icon_id": "13837385",
+      "name": "虫情监测 - 简",
+      "font_class": "cebaoguanli",
+      "unicode": "e776",
+      "unicode_decimal": 59254
+    },
+    {
+      "icon_id": "15282842",
+      "name": "树苗",
+      "font_class": "suyuan",
+      "unicode": "e6e8",
+      "unicode_decimal": 59112
+    },
+    {
+      "icon_id": "15631425",
+      "name": "监控",
+      "font_class": "jiankong",
+      "unicode": "e629",
+      "unicode_decimal": 58921
+    },
+    {
+      "icon_id": "992522",
+      "name": "信息",
+      "font_class": "xinxi1",
+      "unicode": "e64b",
+      "unicode_decimal": 58955
+    },
+    {
+      "icon_id": "1135940",
+      "name": "用户",
+      "font_class": "yonghu1",
+      "unicode": "e612",
+      "unicode_decimal": 58898
+    },
+    {
+      "icon_id": "7501066",
+      "name": "密码",
+      "font_class": "mima1",
+      "unicode": "e620",
+      "unicode_decimal": 58912
+    },
+    {
+      "icon_id": "715831",
+      "name": "电脑",
+      "font_class": "diannao",
+      "unicode": "e605",
+      "unicode_decimal": 58885
+    },
+    {
+      "icon_id": "4186778",
+      "name": "标签",
+      "font_class": "biaoqian",
+      "unicode": "e634",
+      "unicode_decimal": 58932
+    },
+    {
+      "icon_id": "6682541",
+      "name": "地址",
+      "font_class": "dizhi",
+      "unicode": "e606",
+      "unicode_decimal": 58886
+    },
+    {
+      "icon_id": "7404314",
+      "name": "时间",
+      "font_class": "shijian",
+      "unicode": "e77c",
+      "unicode_decimal": 59260
+    },
+    {
+      "icon_id": "8094230",
+      "name": "页面操作",
+      "font_class": "yemiancaozuo",
+      "unicode": "e64e",
+      "unicode_decimal": 58958
+    },
+    {
+      "icon_id": "10995780",
+      "name": "用户",
+      "font_class": "yonghu",
+      "unicode": "e60e",
+      "unicode_decimal": 58894
+    },
+    {
+      "icon_id": "354570",
+      "name": "编辑",
+      "font_class": "iconfontedit",
+      "unicode": "e61f",
+      "unicode_decimal": 58911
+    },
+    {
+      "icon_id": "813727",
+      "name": "充值",
+      "font_class": "chongzhi",
+      "unicode": "e633",
+      "unicode_decimal": 58931
+    },
+    {
+      "icon_id": "1761485",
+      "name": "禁用",
+      "font_class": "jinyong",
+      "unicode": "e641",
+      "unicode_decimal": 58945
+    },
+    {
+      "icon_id": "11391516",
+      "name": "密码",
+      "font_class": "mima",
+      "unicode": "e638",
+      "unicode_decimal": 58936
+    },
+    {
+      "icon_id": "9783463",
+      "name": "文档",
+      "font_class": "wendang",
+      "unicode": "e613",
+      "unicode_decimal": 58899
+    },
+    {
+      "icon_id": "4641118",
+      "name": "删除",
+      "font_class": "shanchu",
+      "unicode": "e625",
+      "unicode_decimal": 58917
+    },
+    {
+      "icon_id": "12685010",
+      "name": "铃",
+      "font_class": "icon_huabanfuben",
+      "unicode": "e62b",
+      "unicode_decimal": 58923
+    },
+    {
+      "icon_id": "2512619",
+      "name": "BAI-屋子",
+      "font_class": "BAI-wuzi",
+      "unicode": "e69c",
+      "unicode_decimal": 59036
+    },
+    {
+      "icon_id": "5387843",
+      "name": "主题_调色盘_o",
+      "font_class": "zhuti_tiaosepan_o",
+      "unicode": "eb6e",
+      "unicode_decimal": 60270
+    }
+  ]
+}

Різницю між файлами не показано, бо вона завелика
+ 188 - 0
src/assets/icon/iconfont.svg


BIN
src/assets/icon/iconfont.ttf


BIN
src/assets/icon/iconfont.woff


BIN
src/assets/icon/iconfont.woff2


BIN
src/assets/images/monitor/1.png


BIN
src/assets/images/monitor/11.png


BIN
src/assets/images/monitor/12.png


BIN
src/assets/images/monitor/122.png


BIN
src/assets/images/monitor/2.png


BIN
src/assets/images/monitor/22.png


BIN
src/assets/images/monitor/9.png


BIN
src/assets/images/monitor/99.png


BIN
src/assets/images/monitor/addequip.png


BIN
src/assets/images/monitor/direction-btn.png


BIN
src/assets/images/monitor/fS.png


BIN
src/assets/images/monitor/fS2.png


BIN
src/assets/images/monitor/h_bg.jpg


BIN
src/assets/images/monitor/icon.png


BIN
src/assets/images/monitor/playback-btn.png


BIN
src/assets/images/monitor/playtype0.png


BIN
src/assets/images/monitor/playtype1.png


BIN
src/assets/images/monitor/zoom-btn.png


BIN
src/assets/logo.png


+ 136 - 0
src/components/Index.vue

@@ -0,0 +1,136 @@
+<template>
+  <el-container style="height: 100%">
+    <el-header class="header" v-show="flag">
+      <div class="logInfo">
+        <img :src="'api'+logo" alt="" />
+        <h3>{{header}}</h3>
+      </div>
+      <div class="sysName">
+        <h2>苗情监测应用系统  实时监测作物生长状态</h2>
+        <p>
+          The application system of seedling condition monitoring monitors the crop growth status in real time
+        </p>
+      </div>
+      <span class="header_btn" @click="hCheckFun">[隐藏]</span>
+    </el-header>
+    <el-header class="header2" v-show="!flag">
+      <h3>可视农业应用系统</h3>
+      <span class="header_btn" @click="hCheckFun">[展开]</span>
+    </el-header>
+    <el-container style="overflow: auto">
+      <el-aside width="200px">
+        <div>
+          <i :class="iconObj[20]"></i>
+          <span slot="title">可视农业应用系统</span>
+        </div>
+      </el-aside>
+      <el-main>
+        <router-view></router-view>
+      </el-main>
+    </el-container>
+  </el-container>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      isRouter: true,
+      iconObj: {
+        20: "iconfont icon-jiankong",
+        22: "iconfont icon-jiankong",
+      },
+      flag: true,
+      header: "",
+      logo: "",
+    };
+  },
+  created: function () {
+    this.getUserInfo();
+  },
+  computed: {},
+  methods: {
+    getUserInfo() {
+      this.$axios({
+        method: "POST",
+        url: "logoheader",
+      }).then((res) => {
+        this.header = res.data.header;
+        this.logo = res.data.logo;
+      });
+    },
+    hCheckFun() {
+      this.flag = !this.flag;
+    },
+  },
+};
+</script>
+
+<style scoped lang="less">
+.header {
+  position: relative;
+  width: 100%;
+  height: 177px !important;
+  border-bottom: 2px solid #272b3a;
+  background: #272b3a no-repeat center / 100% 100%
+    url(../assets/images/monitor/h_bg.jpg);
+  .sysName {
+    color: #295206;
+    text-align: center;
+    h2 {
+      color: #295206;
+      font-weight: 800;
+      text-shadow: #fff 1px 0 0, #fff 0 1px 0, #fff -1px 0 0, #fff 0 -1px 0;
+      font-size: 20px;
+    }
+    p {
+      color: #295206;
+      font-weight: 600;
+      text-shadow: #fff 1px 0 0, #fff 0 1px 0, #fff -1px 0 0, #fff 0 -1px 0;
+      font-size: 14px;
+    }
+    margin-top: 50px;
+  }
+  .logInfo {
+    color: #fff;
+    position: absolute;
+    top: 10px;
+    left: 20px;
+    display:flex;
+    flex-direction: row;
+    align-items: center;
+    img{width:auto;height:40px;}
+    h3{margin:0;margin-left:20px;}
+  }
+}
+.header2 {
+  border-bottom: 2px solid #397b0c;
+  position: relative;
+  background-color: #397b0c;
+  color: #fff;
+}
+.header_btn {
+  position: absolute;
+  color: #999;
+  font-size: 14px;
+  right: 20px;
+  bottom: 10px;
+  cursor: pointer;
+}
+.header_btn:hover {
+  color: #fff;
+}
+
+.el-aside {
+  background: #f0f0f0;
+  div {
+    background: #5aae22;
+    font-size: 14px;
+    line-height: 44px;
+    text-align: center;
+    color: #000;
+  }
+}
+.el-main {
+  padding: 0;
+}
+</style>

+ 262 - 0
src/components/Login.vue

@@ -0,0 +1,262 @@
+<template>
+	<div class="login_container">
+		<div class="login_box">
+			<div class="tit-box">
+				<div class="tit-con">
+					<p class="txt">
+						欢迎来到
+						<span class="arrow">
+							<i class="el-icon-arrow-right"></i>
+						</span>
+					</p>
+					<p class="tit">智慧农业大数据平台</p>
+				</div>
+			</div>
+			<div class="f-box">
+				<ul class="loginItems">
+					<li>
+						<i class="iconfont icon-yonghu1"></i>
+						<input
+							type="text"
+							@keyup="fillPass()"
+							id="username"
+							v-model="username"
+							placeholder="请输入用户名"
+						/>
+					</li>
+					<li>
+						<i class="iconfont icon-mima1"></i>
+						<input
+							type="password"
+							id="password"
+							v-model="pass"
+							placeholder="请输入密码"
+						/>
+					</li>
+					<li>
+						<div class="pass">
+							<input type="checkbox" id="brand" v-model="cState" />
+							<label for="brand">
+								<span>
+									<i class="el-icon-check"></i>
+								</span>
+								记住密码
+							</label>
+							<a>忘记密码?</a>
+						</div>
+					</li>
+					<li>
+						<button class="logon-btn" @click="submit()">登录</button>
+					</li>
+				</ul>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			username: '',
+			pass: '',
+			cState: true
+		}
+	},
+	methods: {
+		submit() {
+			if (this.username == '' || this.pass == '') {
+				this.$message.error('请输入用户名和密码!')
+				return
+			}
+			this.$axios({
+				method: 'POST',
+				url: 'login',
+				data: this.qs.stringify({
+					username: this.username,
+					password: this.pass
+				})
+			}).then((res) => {
+				if (res.data.message == '') {
+					if (this.cState == true) {
+						//是否记住密码
+						localStorage.setItem('username', this.username)
+						localStorage.setItem('password', this.pass)
+					} else {
+						localStorage.removeItem(username, password)
+					}
+					localStorage.setItem('isLogin', true)
+					let selHome = sessionStorage.getItem('selHome')
+					if (selHome) {
+						this.$router.push(selHome) //登录后默认选择首页
+					} else {
+						this.$router.push('/index/home')
+					}
+				} else {
+					this.$message.error(res.data.message)
+				}
+			})
+		},
+		fillPass() {
+			let username = localStorage.getItem('username')
+			if (username == this.username) {
+				this.pass = localStorage.getItem('password')
+			}
+		}
+	}
+}
+</script>
+
+<style lang='less' scoped>
+.login_container {
+	height: 100%;
+	background-size: 100% 100%;
+	.login_box {
+		width: 900px;
+		height: 450px;
+		position: absolute;
+		left: 50%;
+		top: 50%;
+		transform: translate(-50%, -50%);
+		display: flex;
+		.tit-box {
+			position: relative;
+			flex: 1;
+			background: rgba(0, 0, 0, 0.6);
+			color: #fff;
+			letter-spacing: 5px;
+			.tit-con {
+				display: block;
+				padding: 180px 50px;
+				.txt {
+					font-size: 24px;
+					padding-bottom: 15px;
+					border-bottom: 1px solid #fff;
+					position: relative;
+					.arrow {
+						position: absolute;
+						top: 4px;
+						margin-left: 10px;
+						background: #fff;
+						width: 25px;
+						height: 25px;
+						border-radius: 50%;
+						i {
+							color: #000;
+							font-size: 18px;
+							position: absolute;
+							left: 4px;
+							top: 4px;
+						}
+						i:before {
+							font-weight: 800;
+						}
+					}
+				}
+				.tit {
+					font-size: 32px;
+					padding-top: 10px;
+				}
+			}
+		}
+		.f-box {
+			flex: 1;
+			background: #fff;
+			.loginItems {
+				padding: 80px 50px 0 50px;
+				li {
+					width: 100%;
+					margin-bottom: 45px;
+					position: relative;
+					i.iconfont {
+						position: absolute;
+						font-size: 22px;
+						left: 0;
+						top: 5px;
+						color: #b5b5b5;
+					}
+				}
+				input::-webkit-input-placeholder {
+					/* WebKit browsers 适配谷歌 */
+					color: #b5b5b5;
+				}
+				input:-moz-placeholder {
+					/* Mozilla Firefox 4 to 18 适配火狐 */
+					color: #b5b5b5;
+				}
+				input::-moz-placeholder {
+					/* Mozilla Firefox 19+ 适配火狐 */
+					color: #b5b5b5;
+				}
+				input:-ms-input-placeholder {
+					/* Internet Explorer 10+  适配ie*/
+					color: #b5b5b5;
+				}
+				input[type='text'],
+				input[type='password'] {
+					border: none;
+					padding: 10px 20px 10px 30px;
+					box-sizing: border-box;
+					border-bottom: 1px solid #b5b5b5;
+					width: 100%;
+					font-size: 15px;
+					outline: none;
+					box-shadow: 0 0 0px 1000px white inset !important;
+					-webkit-box-shadow: 0 0 0px 1000px white inset !important;
+				}
+				input[type='checkbox'] {
+					display: none;
+				}
+				input[type='checkbox'] + label span {
+					display: inline-block;
+					width: 16px;
+					height: 16px;
+					border-radius: 3px;
+					border: 1px solid #b5b5b5;
+					float: left;
+					margin-right: 10px;
+					i {
+						display: none;
+					}
+				}
+				input[type='checkbox']:checked + label span {
+					background: #2f3945;
+					i {
+						display: block;
+						font-size: 15px;
+						color: #fff;
+					}
+					i:before {
+						font-weight: 800;
+					}
+				}
+				.pass {
+					display: flex;
+					justify-content: space-between;
+					font-size: 14px;
+					label {
+						color: #b5b5b5;
+					}
+					a {
+						color: red;
+					}
+				}
+				button {
+					width: 100%;
+					border: none;
+					background: #3d4c5a;
+					border-radius: 30px;
+					color: #fff;
+					line-height: 40px;
+					height: 40px;
+					cursor: pointer;
+					outline: none;
+				}
+				button:hover {
+					background: #4b647b;
+				}
+			}
+		}
+	}
+}
+</style>

+ 39 - 0
src/main.js

@@ -0,0 +1,39 @@
+import Vue from 'vue'
+import ElementUI from 'element-ui';
+import 'element-ui/lib/theme-chalk/index.css';
+import App from './App'
+import router from './router'
+
+import axios from 'axios'
+Vue.prototype.$axios = axios //全局注册,使用方法为:this.$axios
+
+import qs from 'qs'
+Vue.prototype.qs = qs //全局注册,使用方法为:this.qs
+
+Vue.use(ElementUI);
+
+axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
+axios.defaults.timeout = 30000;
+axios.defaults.baseURL = 'http://47.104.218.216:8006/' //线下杨明明
+axios.defaults.withCredentials = true //axios请求时携带session
+axios.defaults.crossDomain = true 
+
+
+Vue.config.productionTip = false
+
+import 'babel-polyfill' //兼容IE11
+require("babel-polyfill")
+
+import promise from 'es6-promise'
+promise.polyfill();
+
+
+import './assets/icon/iconfont.css'
+
+/* eslint-disable no-new */
+new Vue({
+  el: '#app',
+  router,
+  components: { App },
+  template: '<App/>'
+})

+ 927 - 0
src/pages/Monitor.vue

@@ -0,0 +1,927 @@
+<template>
+  <div class="monitor-container">
+    <div class="monitor-wrap">
+      <div class="video-box">
+        <div class="fbg" v-if="fScreen"></div>
+        <div
+          class="fbgBtn"
+          @click="fScreenFun()"
+          v-if="!oneFScreen && fScreen"
+        ></div>
+        <div
+          :class="{ 'video-container': true, fScreen: fScreen }"
+          ref="videoContainerRef"
+        >
+          <!-- 非插件播放 ,默认非插件播放-->
+          <div
+            v-show="playType == 0"
+            :class="{
+              videoItem: true,
+              a1: divNum == 1,
+              a2: divNum == 2,
+              a9: divNum == 9,
+              a12: divNum == 12,
+              selected: count == selected,
+            }"
+            v-for="count in divNum"
+            :key="String(count) + divNum"
+            @click="selectVideo($event, count, 'my-video' + divNum + count)"
+          >
+            <span style="display: none" class="current">{{
+              Idlist[count - 1]
+            }}</span>
+            <div class="vedio_btn_control">
+              <div class="direc">
+                <div
+                  @click.stop="configCamera(oneId, 'takephoto', '')"
+                  class="cameraCtr"
+                ></div>
+                <div
+                  @mousedown.stop="configCamera(oneId, 'move', 0)"
+                  @mouseup.stop="stopConfigCamera(oneId)"
+                  class="upCtr"
+                ></div>
+                <div
+                  @mousedown.stop="configCamera(oneId, 'move', 1)"
+                  @mouseup="stopConfigCamera(oneId)"
+                  class="downCtr"
+                ></div>
+                <div
+                  @mousedown.stop="configCamera(oneId, 'move', 2)"
+                  @mouseup="stopConfigCamera(oneId)"
+                  class="leftCtr"
+                ></div>
+                <div
+                  @mousedown.stop="configCamera(oneId, 'move', 3)"
+                  @mouseup="stopConfigCamera(oneId)"
+                  class="rightCtr"
+                ></div>
+              </div>
+              <div class="zoom">
+                <!-- 无论插件还是费插件都可以放大缩小 -->
+                <span
+                  class="addCtr"
+                  @mousedown.stop="configCamera(oneId, 'move', 8)"
+                  @mouseup="stopConfigCamera(oneId)"
+                ></span>
+                <span
+                  class="reduceCtr"
+                  @mousedown.stop="configCamera(oneId, 'move', 9)"
+                  @mouseup="stopConfigCamera(oneId)"
+                ></span>
+              </div>
+            </div>
+            <i
+              @click.stop="oneFullFun($event, count)"
+              class="iconfont icon-quanping fSBtn"
+            ></i>
+            <div
+              style="width: 100%; height: 100%"
+              :id="'my-video' + divNum + count"
+            ></div>
+          </div>
+        </div>
+        <div v-show="playType == 0" class="split-screen">
+          <span
+            :class="divNum == 1 ? 'sp0 sp' : 'sp00 sp'"
+            @click="splitView(1)"
+          ></span>
+          <span
+            :class="divNum == 2 ? 'sp1 sp' : 'sp01 sp'"
+            @click="splitView(2)"
+          ></span>
+          <span
+            :class="divNum == 9 ? 'sp2 sp' : 'sp02 sp'"
+            @click="splitView(9)"
+          ></span>
+          <span
+            :class="divNum == 12 ? 'sp3 sp' : 'sp03 sp'"
+            @click="splitView(12)"
+          ></span>
+        </div>
+      </div>
+      <div class="nav-box">
+        <ul class="viewLists">
+          <li
+            v-for="(item, index) in Idlist"
+            :key="index"
+            :class="{ active: activeIndex == index }"
+            @click="selectEquip(item.device_id, item.jktype, index)"
+          >
+            <span
+              :class="['dot', item.status == 1 ? 'onLine' : 'outLine']"
+            ></span>
+            {{ item | formatName }}
+          </li>
+        </ul>
+        <div class="splitPage" onselectstart="return false">
+          <span
+            class="arrow el-icon-caret-top"
+            @click="splitPage('jian')"
+          ></span>
+          <span>{{ currPage }}</span>
+          <span>/</span>
+          <span>{{ totalPage }}</span>
+          <span
+            class="arrow el-icon-caret-bottom"
+            @click="splitPage('jia')"
+          ></span>
+        </div>
+        <div class="direc">
+          <div
+            @click="configCamera(id, 'takephoto', '')"
+            class="cameraCtr"
+          ></div>
+          <div
+            @mousedown="configCamera(id, 'move', 0)"
+            @mouseup="stopConfigCamera(id)"
+            class="upCtr"
+          ></div>
+          <div
+            @mousedown="configCamera(id, 'move', 1)"
+            @mouseup="stopConfigCamera(id)"
+            class="downCtr"
+          ></div>
+          <div
+            @mousedown="configCamera(id, 'move', 2)"
+            @mouseup="stopConfigCamera(id)"
+            class="leftCtr"
+          ></div>
+          <div
+            @mousedown="configCamera(id, 'move', 3)"
+            @mouseup="stopConfigCamera(id)"
+            class="rightCtr"
+          ></div>
+        </div>
+        <div class="btnBox">
+          <div class="zoom">
+            <!-- 无论插件还是费插件都可以放大缩小 -->
+            <span
+              class="addCtr"
+              @mousedown="configCamera(id, 'move', 8)"
+              @mouseup="stopConfigCamera(id)"
+            ></span>
+            <span
+              class="reduceCtr"
+              @mousedown="configCamera(id, 'move', 9)"
+              @mouseup="stopConfigCamera(id)"
+            ></span>
+          </div>
+          <div
+            v-show="jktype == 1"
+            class="playBack"
+            @click="playBackDialogVisible = true"
+          ></div>
+          <!-- <div @click="addEquip()" class="addequip"></div> -->
+          <div @click="fScreenFun()" class="fSBtn1"></div>
+        </div>
+      </div>
+    </div>
+    <!-- 拍照 -->
+    <el-dialog
+      title="手动下载"
+      :visible.sync="takePhotoDialogVisible"
+      width="30%"
+    >
+      <el-input type="textarea" id="picUrl" v-model="picUrl"></el-input>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="takePhotoDialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="copyPicUrl">复制</el-button>
+      </span>
+    </el-dialog>
+    <!-- 查看回放 -->
+    <el-dialog
+      title="查看回放"
+      :visible.sync="playBackDialogVisible"
+      width="30%"
+    >
+      <el-form ref="backFormRef" :model="backForm" label-width="80px">
+        <el-form-item label="时间范围">
+          <el-date-picker
+            v-model="backForm.time"
+            type="datetimerange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+          >
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="通道">
+          <el-select v-model="backForm.aisle" placeholder="请选择">
+            <el-option label="通道一" value="1"> </el-option>
+            <el-option label="通道二" value="2"> </el-option>
+            <el-option label="通道三" value="3"> </el-option>
+            <el-option label="通道四" value="4"> </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="default" @click="playBackDialogVisible = false"
+            >取消</el-button
+          >
+          <el-button type="primary" @click="playBackSubmit">确定</el-button>
+        </el-form-item>
+      </el-form>
+      <div id="videoBack"></div>
+    </el-dialog>
+  </div>
+</template>
+
+
+<script>
+import "@/plugin/ezuikit.js";
+export default {
+  data() {
+    return {
+      currPage: 1, //当前分页
+      totalPage: 0, //总分页
+      id: "", //监控选中状态selected,右侧菜单控制的ID
+      oneId: "", //单个监控全屏时的监控id
+      activeIndex: null, //控制设备列表选中状态
+      jktype: "", //为1有回放,否则无回放
+      divNum: 1, //默认分屏数量
+      hlsHdSrc: "",
+      rtmpHdSrc: "",
+      player: null, //videojs的对象
+      takePhotoDialogVisible: false, //拍照弹框
+      Idlist: [], //右侧设备列表
+      divMainHeight: "", //视频盒子高度
+      selected: "", //默认不选中视频窗口
+      divName: "", //选中的监控的id
+      playType: 0, //0:直播 ; 1:插件
+      html: "", //插件播放内容
+      picUrl: "", //视频拍照地址
+      playBackDialogVisible: false,
+      fScreen: false, //默认多个监控非全屏
+      oneFScreen: false, //单个监控全屏状态
+      btnFlag: true, //全屏按钮显示控制
+      backForm: {
+        //回放
+        time: "",
+        start: "",
+        end: "",
+        aisle: "",
+      },
+    };
+  },
+  filters: {
+    formatName: function (value) {
+      //设备名字
+      if (value.device_name) {
+        return value.device_name;
+      } else {
+        return "设备" + value.device_id;
+      }
+    },
+  },
+  created() {
+    this.getJkList();
+  },
+  watch: {},
+  methods: {
+    //获取视频列表
+    getJkList() {
+      this.$axios({
+        method: "POST",
+        url: "list_camera",
+        data: this.qs.stringify({ page: this.currPage }),
+      }).then((res) => {
+        this.Idlist = res.data.data;
+        this.totalPage = Math.ceil(res.data.counts / 12);
+        this.initMonitor(); //进入页面默认1屏都显示视频
+      });
+    },
+    getJkList2() {
+      this.$axios({
+        method: "POST",
+        url: "/api/list_camera",
+        data: this.qs.stringify({ page: this.currPage }),
+      }).then((res) => {
+        this.Idlist = res.data.data;
+      });
+    },
+    //视频分页
+    splitPage(str) {
+      this.selected = "";
+      this.activeIndex = null;
+      if (str == "jian") {
+        if (this.currPage > 1) {
+          this.currPage--;
+          this.getJkList2();
+        }
+      } else {
+        if (this.currPage < this.totalPage) {
+          this.currPage++;
+          this.getJkList2();
+        }
+      }
+    },
+    //上下左右和拍照
+    configCamera(id, ctrl, movenum) {
+      if (id != "") {
+        if (ctrl == "takephoto") {
+          this.$axios({
+            method: "POST",
+            url: "camera_takephoto",
+            data: this.qs.stringify({
+              device_id: id,
+              ctrl: ctrl,
+            }),
+          }).then((res) => {
+            if (res.data.code == 200) {
+              let data = res.data.data;
+              this.picUrl = data.picUrl;
+              this.takePhotoDialogVisible = true;
+            } else {
+              this.$message.error("设备网络异常!");
+            }
+          });
+        } else {
+          //上下左右、放大、缩小
+          this.$axios({
+            method: "POST",
+            url: "ctrl_camera",
+            data: this.qs.stringify({
+              device_id: id,
+              ctrl: ctrl,
+              movenum: movenum,
+            }),
+          }).then((res) => {
+            if (res.data == 1) {
+              this.$message.success("操作成功");
+            } else {
+              this.$message.error("操作失败");
+            }
+          });
+        }
+      } else {
+        this.$message.error("请选中监控");
+      }
+    },
+    //关闭方向
+    stopConfigCamera(id) {
+      if (id != "") {
+        this.$axios({
+          method: "POST",
+          url: "ctrl_camera",
+          data: this.qs.stringify({
+            device_id: id,
+            ctrl: "stop",
+          }),
+        });
+      }
+    },
+    //分屏默认显示视频
+    initMonitor() {
+      this.selected = ""; //取消监控选中
+      this.activeIndex = null; //取消菜单选中
+      for (let item = 0; item < this.divNum; item++) {
+        if (this.Idlist[item]) {
+          //避免右侧监控数量少于divNum
+          this.$axios({
+            url: "addr_camera",
+            method: "POST",
+            data: this.qs.stringify({ device_id: this.Idlist[item].device_id }),
+          }).then((res) => {
+            var data = eval("(" + res.data + ")");
+            var hlsHdSrc = data.hlsHd;
+            var rtmpHdSrc = data.rtmp;
+            let index = "my-video" + this.divNum + (item + 1);
+            this.$nextTick(() => {
+              let playHtml = `<video id="videoitem${this.divNum}${item}"
+								 style='width: 100%;height: 100%;' src="${hlsHdSrc}" muted autoplay  poster='' controls playsInline  webkit-playsinline>
+								 </video>`;
+              document.getElementById(
+                "my-video" + this.divNum + (item + 1)
+              ).innerHTML = playHtml;
+              this.$nextTick(() => {
+                let player = new EZUIKit.EZUIPlayer(
+                  "videoitem" + this.divNum + item
+                );
+                player.play();
+              });
+            });
+          });
+        }
+      }
+    },
+    //选中右侧菜单设备
+    selectEquip(device_id, jktype, index) {
+      console.log(jktype);
+      if (this.selected !== "") {
+        //判断是否选中左侧监控
+        document
+          .getElementsByClassName("selected")[0]
+          .getElementsByClassName("current")[0].innerHTML = device_id; //更换current里的设备id值
+        console.log(device_id);
+        this.jktype = jktype;
+        this.activeIndex = index; //菜单选中状态
+        this.id = device_id; //保存选中的设备id
+        console.log(this.divName);
+        this.$axios({
+          url: "addr_camera",
+          method: "POST",
+          data: this.qs.stringify({ device_id: device_id }),
+        }).then((res) => {
+          // console.log(123);
+          var data = eval("(" + res.data + ")");
+          let hlsHdSrc = data.hlsHd;
+          let playHtml = `<video id="n${this.divName}"
+								 style='width: 100%;height: 100%;' src="${hlsHdSrc}" muted autoplay  poster='' controls playsInline  webkit-playsinline>
+								 </video>`;
+          let target = document.getElementById(this.divName);
+          target.removeChild(target.childNodes[0]);
+          target.innerHTML = playHtml;
+          this.$nextTick(() => {
+            new EZUIKit.EZUIPlayer(`n${this.divName}`);
+          });
+        });
+      }
+    },
+    //点击分屏
+    splitView(num) {
+      this.divNum = num;
+      this.$nextTick(() => {
+        this.initMonitor();
+      });
+    },
+    //点击视频
+    selectVideo(e, i, divName) {
+      console.log("外");
+      let current = e.currentTarget.getElementsByClassName("current")[0]
+        .innerHTML;
+      if (current.indexOf("device_id") == -1) {
+        this.id = current;
+      } else {
+        this.id = JSON.parse(current).device_id;
+      }
+      console.log(this.id);
+      this.divName = divName; //视频外面div的id
+      this.selected = i;
+    },
+    //复制拍照地址
+    copyPicUrl() {
+      document.getElementById("picUrl").select();
+      this.$message({
+        showClose: true,
+        message: "手动复制,在浏览器打开,另存为",
+      });
+    },
+    //添加设备
+    addEquip() {
+      this.$prompt("添加设备id", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+      })
+        .then(({ value }) => {
+          this.$axios({
+            method: "POST",
+            url: "add_camera",
+            data: this.qs.stringify({ device_id: value }),
+          }).then((res) => {
+            if (res.data == 1) {
+              this.getJkList();
+            } else {
+              this.$message.error(res.data);
+            }
+          });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "取消添加",
+          });
+        });
+    },
+    fScreenFun() {
+      this.fScreen = !this.fScreen;
+    },
+    oneFullFun(el, i) {
+      this.selected = i;
+      let par = el.currentTarget.parentNode;
+      let current = par.getElementsByClassName("current")[0].innerHTML;
+      if (current == "") {
+        return false;
+      } else if (current.indexOf("device_id") == -1) {
+        this.oneId = current;
+      } else {
+        this.oneId = JSON.parse(current).device_id;
+      }
+      this.$nextTick(() => {
+        par.classList.toggle("fullScreen");
+        this.oneFScreen = !this.oneFScreen; //点击菜单栏全屏按钮后,再点击单个监控全屏时,隐藏恢复按钮
+      });
+    },
+    playBackSubmit() {
+      let start = new Date(this.backForm.time[0]);
+      let end = new Date(this.backForm.time[1]);
+      let beginVal = "";
+      let endVal = "";
+      function checked(num) {
+        if (num < 10) {
+          num = "0" + num;
+        }
+        return num;
+      }
+      beginVal =
+        beginVal +
+        start.getFullYear() +
+        checked(start.getMonth() + 1) +
+        checked(start.getDate()) +
+        checked(start.getHours()) +
+        checked(start.getMinutes()) +
+        checked(start.getSeconds());
+      endVal =
+        endVal +
+        end.getFullYear() +
+        checked(end.getMonth() + 1) +
+        checked(end.getDate()) +
+        checked(end.getHours()) +
+        checked(end.getMinutes()) +
+        checked(end.getSeconds());
+      // console.log( beginVal, endVal);
+      this.$axios({
+        method: "POST",
+        url: "nvr_view",
+        data: this.qs.stringify({
+          e_id: this.id,
+        }),
+      }).then((res) => {
+        let accessToken = res.data.jk_token;
+        let url = `ezopen://open.ys7.com/${this.id}/${this.backForm.aisle}.local.rec?begin=${beginVal}&end=${endVal}`;
+        console.log(url);
+        document.getElementById(
+          "videoBack"
+        ).innerHTML = `<video id="videoBack" style="width: 600px; height: 400px;" src=""></video>`;
+        new EZUIKit.EZUIPlayer({
+          id: "videoBack",
+          autoplay: true,
+          url: url,
+          accessToken: accessToken,
+          decoderPath: "src/plugin/",
+          width: 750,
+          height: 500,
+        });
+      });
+    },
+  },
+};
+</script>
+
+<style lang='less' scoped>
+ul,
+li {
+  list-style-type: none;
+  margin: 0;
+  padding: 0;
+}
+.monitor-container {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  .monitor-wrap {
+    height: 100%;
+    display: flex;
+    justify-content: space-between;
+    background: #ddd;
+    flex: 1;
+    .video-box {
+      flex: 1;
+      padding: 10px;
+      .fScreen {
+        position: absolute;
+        z-index: 8;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100% !important;
+      }
+      .fbg {
+        position: fixed;
+        top: 0;
+        bottom: 0;
+        left: 0;
+        right: 0;
+        background: #000;
+        z-index: 5;
+      }
+      .fbgBtn {
+        position: fixed;
+        z-index: 9;
+        right: 20px;
+        bottom: 20px;
+        width: 100px;
+        height: 100px;
+        background: url(../assets/images/monitor/fS2.png);
+      }
+      .video-container {
+        width: 100%;
+        height: calc(100% - 45px);
+        background: #000;
+        display: flex;
+        flex-wrap: wrap;
+        .fullScreen {
+          position: fixed !important;
+          width: 100% !important;
+          height: 100% !important;
+          top: 0;
+          right: 0;
+          bottom: 0;
+          left: 0;
+          z-index: 10;
+          background: #000;
+          .vedio_btn_control {
+            display: block;
+          }
+        }
+        .videoItem {
+          position: relative;
+          border: 1px solid #000;
+          box-sizing: border-box;
+          .fSBtn {
+            position: absolute;
+            z-index: 2;
+            top: 10px;
+            right: 20px;
+            color: #fff;
+            font-size: 20px;
+            cursor: pointer;
+          }
+          .fSBtn:hover {
+            color: red;
+          }
+        }
+        .videoItem:hover {
+          border-color: aquamarine;
+        }
+        .selected {
+          border: 1px solid aquamarine;
+        }
+        .a1 {
+          width: 100%;
+          height: 100%;
+        }
+        .a2 {
+          width: 50%;
+          height: 100%;
+        }
+        .a9 {
+          width: 33.3%;
+          height: 33.3%;
+        }
+        .a12 {
+          width: 33.3%;
+          height: 25%;
+        }
+      }
+      .split-screen {
+        background: #f0f0f0;
+        display: flex;
+        justify-content: flex-start;
+        padding: 15px 10px;
+        .sp {
+          width: 17px;
+          height: 17px;
+          display: inline-block;
+          margin-right: 10px;
+          cursor: pointer;
+        }
+        .sp00 {
+          background: url(../assets/images/monitor/1.png);
+        }
+        .sp01 {
+          background: url(../assets/images/monitor/2.png);
+        }
+        .sp02 {
+          background: url(../assets/images/monitor/9.png);
+        }
+        .sp03 {
+          background: url(../assets/images/monitor/12.png);
+        }
+        .sp0 {
+          background: url(../assets/images/monitor/11.png);
+        }
+        .sp1 {
+          background: url(../assets/images/monitor/22.png);
+        }
+        .sp2 {
+          background: url(../assets/images/monitor/99.png);
+        }
+        .sp3 {
+          background: url(../assets/images/monitor/122.png);
+        }
+      }
+    }
+    .nav-box {
+      width: 240px;
+      background: #f0f0f0;
+      color: #000;
+      font-size: 14px;
+      .viewLists {
+        height: 50%;
+        overflow: auto;
+        li {
+          padding-left: 25px;
+          padding-right: 25px;
+          line-height: 34px;
+          cursor: pointer;
+          .viewPhoto {
+            color: #eba219;
+            float: right;
+            font-size: 12px;
+            cursor: pointer;
+          }
+          .viewPhoto:hover {
+            text-decoration: underline;
+          }
+          .dot {
+            display: inline-block;
+            width: 7px;
+            height: 7px;
+            border-radius: 100%;
+            margin-right: 15px;
+          }
+          .onLine {
+            background: #15bb88;
+          }
+          .outLine {
+            background: #c1c1c1;
+          }
+        }
+        li.active {
+          background: #5aae22;
+        }
+        li:hover {
+          background: #5aae22;
+        }
+      }
+      .splitPage {
+        height: 3%;
+        margin-top: 2%;
+        text-align: center;
+        color: #15bb88;
+        -webkit-user-select: none;
+        -moz-user-select: none;
+        -ms-user-select: none;
+        .arrow {
+          font-size: 20px;
+          cursor: pointer;
+        }
+      }
+      .direc {
+        position: relative;
+        z-index: 0;
+        text-align: center;
+        width: 160px;
+        height: 160px;
+        margin: 10px auto;
+        // position: relative;
+        background: url(../assets/images/monitor/direction-btn.png)
+					no-repeat center;
+        background-size: contain;
+        & > div {
+          position: absolute;
+          width: 53px;
+          height: 53px;
+          cursor: pointer;
+        }
+        .upCtr {
+          top: 0px;
+          transform: translateX(-50%);
+          margin-left: 50%;
+        }
+        .downCtr {
+          bottom: 0px;
+          transform: translateX(-50%);
+          margin-left: 50%;
+        }
+        .leftCtr {
+          transform: translateY(-50%);
+          left: 0;
+          margin-top: 50%;
+        }
+        .rightCtr {
+          transform: translateY(-50%);
+          right: 0;
+          margin-top: 50%;
+        }
+        .cameraCtr {
+          top: 0;
+          bottom: 0;
+          left: 0;
+          right: 0;
+          margin: auto;
+        }
+      }
+      .btnBox {
+        .zoom,
+        .playBack,
+        .playtype0,
+        .playtype1,
+        .addequip,
+        .fSBtn1,
+        .fSBtn2 {
+          width: 140px;
+          height: 32px;
+          margin: auto;
+          margin-bottom: 5px;
+          cursor: pointer;
+        }
+        .zoom {
+          background: no-repeat center / 100%
+            url(../assets/images/monitor/zoom-btn.png);
+          display: flex;
+          & > span {
+            flex: 1;
+            height: 32px;
+          }
+        }
+        .playBack {
+          background: url(../assets/images/monitor/playback-btn.png)
+						no-repeat center;
+        }
+        .playtype0 {
+          background: url(../assets/images/monitor/playtype0.png)
+						no-repeat center;
+        }
+        .playtype1 {
+          background: url(../assets/images/monitor/playtype1.png)
+						no-repeat center;
+        }
+        .addequip {
+          background: url(../assets/images/monitor/addequip.png) no-repeat
+						center;
+        }
+        .fSBtn1 {
+          background: url(../assets/images/monitor/fS.png) no-repeat
+						center;
+          position: relative;
+        }
+      }
+    }
+  }
+
+  .vedio_btn_control {
+    display: none;
+    position: absolute;
+    right: 10px;
+    bottom: 10px;
+    z-index: 20;
+    width: 140px;
+    height: 200px;
+    .direc {
+      position: relative;
+      text-align: center;
+      width: 100px;
+      height: 100px;
+      margin: 10px auto;
+      background: url(../assets/images/monitor/direction-btn.png)
+				no-repeat center;
+      background-size: contain;
+      & > div {
+        position: absolute;
+        width: 33px;
+        height: 33px;
+        cursor: pointer;
+      }
+      .upCtr {
+        top: 0px;
+        transform: translateX(-50%);
+        margin-left: 50%;
+      }
+      .downCtr {
+        bottom: 0px;
+        transform: translateX(-50%);
+        margin-left: 50%;
+      }
+      .leftCtr {
+        transform: translateY(-50%);
+        left: 0;
+        margin-top: 50%;
+      }
+      .rightCtr {
+        transform: translateY(-50%);
+        right: 0;
+        margin-top: 50%;
+      }
+      .cameraCtr {
+        top: 0;
+        bottom: 0;
+        left: 0;
+        right: 0;
+        margin: auto;
+      }
+    }
+    .zoom {
+      width: 140px;
+      height: 32px;
+      background: no-repeat center / 100%
+        url(../assets/images/monitor/zoom-btn.png);
+      display: flex;
+      & > span {
+        flex: 1;
+        height: 32px;
+      }
+    }
+  }
+}
+</style>

+ 115 - 0
src/plugin/elementUi.js

@@ -0,0 +1,115 @@
+import Vue from 'vue'
+// 导入自己需要的组件
+import { Container,Header,Aside,Main,Footer,Select, Dialog,Option, OptionGroup, Input, Tree, Row, Col,Button,
+  Menu,
+  Submenu,
+  MenuItem,
+  MenuItemGroup,
+  Tooltip,
+  Breadcrumb,
+  BreadcrumbItem,
+  Card,
+  Switch,
+  Table,
+  TableColumn,
+  DatePicker,
+  Pagination,
+  MessageBox,
+  Message,
+  Icon,
+  Dropdown,
+  DropdownMenu,
+  DropdownItem,
+  Badge,
+  Alert,
+  Form,
+  FormItem,
+  Radio,
+  RadioGroup,
+  Tabs,
+  TabPane,
+  Progress,
+  Slider,
+  Carousel,
+  CarouselItem, 
+  TimeSelect,
+  TimePicker,
+  Upload,
+  Cascader,
+  Popover,
+  Checkbox,
+  PageHeader,
+  CheckboxGroup,
+  Image,
+  Collapse,
+  Divider,
+  Loading,
+  CollapseItem} from 'element-ui'
+// const element = {
+  // install: function (Vue) {
+    
+    Vue.use(Container)
+    Vue.use(Header)
+    Vue.use(Aside)
+    Vue.use(Main)
+    Vue.use(Footer)
+    Vue.use(Select)
+    Vue.use(Option)
+    Vue.use(OptionGroup)
+    Vue.use(Input)
+    Vue.use(Tree)
+    Vue.use(Dialog)
+    Vue.use(Row)
+    Vue.use(Col)
+    Vue.use(Button)
+    Vue.use(Menu);
+    Vue.use(Submenu);
+    Vue.use(MenuItem);
+    Vue.use(MenuItemGroup);
+    Vue.use(Tooltip);
+    Vue.use(Breadcrumb);
+    Vue.use(BreadcrumbItem);
+    Vue.use(Card);
+    Vue.use(Switch);
+    Vue.use(Table);
+    Vue.use(TableColumn);
+    Vue.use(DatePicker);
+    Vue.use(Pagination);
+    Vue.use(Icon);
+    Vue.use(Dropdown);
+    Vue.use(DropdownMenu);
+    Vue.use(DropdownItem);
+    Vue.use(Badge);
+    Vue.use(Alert);
+    Vue.use(Dialog);
+    Vue.use(Form);
+    Vue.use(FormItem);
+    Vue.use(Radio);
+    Vue.use(RadioGroup);
+    Vue.use(Tabs);
+    Vue.use(TabPane);
+    Vue.use(Progress);
+    Vue.use(Slider);
+    Vue.use(Carousel);
+    Vue.use(CarouselItem);
+    Vue.use(TimeSelect);
+    Vue.use(TimePicker);
+    Vue.use(Upload);
+    Vue.use(Cascader);
+    Vue.use(Popover);
+    Vue.use(Checkbox);
+    Vue.use(PageHeader);
+    Vue.use(CheckboxGroup);
+    Vue.use(Image);
+    Vue.use(Collapse);
+    Vue.use(CollapseItem);
+    Vue.use(Divider);
+    Vue.use(Loading);
+    Vue.prototype.$msgbox = MessageBox;
+    Vue.prototype.$alert = MessageBox.alert;
+    Vue.prototype.$confirm = MessageBox.confirm;
+    Vue.prototype.$prompt = MessageBox.prompt;
+    Vue.prototype.$message = Message;
+  // }
+// }
+// export default element

Різницю між файлами не показано, бо вона завелика
+ 1614 - 0
src/plugin/ezuikit.js


+ 29 - 0
src/router/index.js

@@ -0,0 +1,29 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+// const Login = () => import('@/components/Login')
+const Index = () => import('@/components/Index')
+const Monitor = () => import('@/pages/Monitor')
+Vue.use(Router)
+
+export default new Router({
+  routes: [{
+      path: '',
+      redirect: '/index/monitor'
+    },
+    // {
+    //   path: '/login',
+    //   component: Login
+    // },
+    {
+      path: '/index',
+      component: Index,
+      children: [
+        {
+          path: 'monitor',
+          component: Monitor,
+        },
+      ]
+    },
+    
+  ]
+})

+ 0 - 0
static/.gitkeep