zhulizhen il y a 6 ans
commit
abf7b5ef9d
100 fichiers modifiés avec 53008 ajouts et 0 suppressions
  1. 18 0
      .babelrc
  2. 9 0
      .editorconfig
  3. 5 0
      .eslintignore
  4. 35 0
      .eslintrc.js
  5. 17 0
      .gitignore
  6. 10 0
      .postcssrc.js
  7. 4 0
      README.md
  8. 41 0
      build/build.js
  9. 54 0
      build/check-versions.js
  10. 101 0
      build/utils.js
  11. 22 0
      build/vue-loader.conf.js
  12. 109 0
      build/webpack.base.conf.js
  13. 95 0
      build/webpack.dev.conf.js
  14. 149 0
      build/webpack.prod.conf.js
  15. 7 0
      config/dev.env.js
  16. 119 0
      config/index.js
  17. 4 0
      config/prod.env.js
  18. 7 0
      config/test.env.js
  19. 26 0
      index.html
  20. 39001 0
      package-lock.json
  21. 100 0
      package.json
  22. 23 0
      src/App.vue
  23. 6 0
      src/assets/css/public.css
  24. 65 0
      src/assets/css/reset.css
  25. 165 0
      src/common/SgyRange.vue
  26. 187 0
      src/common/sagacloudMulSelect.vue
  27. 182 0
      src/common/sagacloudSelect.vue
  28. 216 0
      src/common/sagasloudTreeSelect.vue
  29. 99 0
      src/common/scrollList.vue
  30. 101 0
      src/common/swipe.vue
  31. 278 0
      src/common/tree.vue
  32. 89 0
      src/components/Head.vue
  33. 91 0
      src/components/Home.vue
  34. 203 0
      src/components/Login.vue
  35. 142 0
      src/components/Nav.vue
  36. 29 0
      src/main.js
  37. 68 0
      src/router/index.js
  38. 45 0
      src/store/index.js
  39. 2 0
      src/tools/bus.js
  40. 11 0
      src/tools/currentDate.js
  41. 24 0
      src/tools/dataPickerConfig.js
  42. 41 0
      src/tools/download.js
  43. 56 0
      src/tools/fastJson.js
  44. 17 0
      src/tools/formatData.js
  45. 47 0
      src/tools/formatTime.js
  46. 15 0
      src/tools/systemClass.js
  47. 126 0
      src/views/asset/AssetTable.vue
  48. 492 0
      src/views/asset/index.vue
  49. 573 0
      src/views/check/index.vue
  50. 316 0
      src/views/detail/EneryParams.vue
  51. 322 0
      src/views/detail/EnvirmentParams.vue
  52. 363 0
      src/views/detail/index.vue
  53. 312 0
      src/views/equipment/EqSelect.vue
  54. 214 0
      src/views/equipment/Handle.vue
  55. 388 0
      src/views/equipment/index.vue
  56. 127 0
      src/views/main/AlarmCharts.vue
  57. 392 0
      src/views/main/HistoryTable.vue
  58. 669 0
      src/views/main/PompBox.vue
  59. 402 0
      src/views/main/Select.vue
  60. 362 0
      src/views/main/StatusTable.vue
  61. 350 0
      src/views/main/TableAlarm.vue
  62. 407 0
      src/views/main/index.vue
  63. 157 0
      src/views/monitoring/index.vue
  64. 195 0
      src/views/rooms/RoomEq.vue
  65. 386 0
      src/views/rooms/index.vue
  66. 150 0
      src/views/spread/MessageModal.vue
  67. 124 0
      src/views/spread/PropertyTable.vue
  68. 618 0
      src/views/spread/index.vue
  69. 387 0
      src/views/system/index.vue
  70. 373 0
      src/views/vr/EqRight.vue
  71. 122 0
      src/views/vr/EqTable.vue
  72. 145 0
      src/views/vr/PicSwipe.vue
  73. 693 0
      src/views/vr/index.vue
  74. 127 0
      src/views/vr/serveTable.vue
  75. 0 0
      static/.gitkeep
  76. 77 0
      static/css/reset.css
  77. 9 0
      static/css/viewer.min.css
  78. 370 0
      static/font/demo.css
  79. 256 0
      static/font/demo_fontclass.html
  80. 351 0
      static/font/demo_symbol.html
  81. 294 0
      static/font/demo_unicode.html
  82. 89 0
      static/font/iconfont.css
  83. BIN
      static/font/iconfont.eot
  84. 1 0
      static/font/iconfont.js
  85. 134 0
      static/font/iconfont.svg
  86. BIN
      static/font/iconfont.ttf
  87. BIN
      static/font/iconfont.woff
  88. BIN
      static/img/QRcode.jpg
  89. BIN
      static/img/alarm.png
  90. BIN
      static/img/alarmAandS.png
  91. BIN
      static/img/auto.png
  92. BIN
      static/img/backIcon.jpg
  93. BIN
      static/img/bill.png
  94. BIN
      static/img/deal.png
  95. BIN
      static/img/down.png
  96. BIN
      static/img/eleCon.png
  97. BIN
      static/img/elePower.png
  98. BIN
      static/img/email.png
  99. BIN
      static/img/ernomal.png
  100. 0 0
      static/img/event.png

+ 18 - 0
.babelrc

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

+ 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

+ 5 - 0
.eslintignore

@@ -0,0 +1,5 @@
+/build/
+/config/
+/dist/
+/*.js
+/test/unit/coverage/

+ 35 - 0
.eslintrc.js

@@ -0,0 +1,35 @@
+// 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',
+    // allow ==
+    'eqeqeq': 'off',
+    // allow tab
+    'no-tabs': 'off',
+    // allow ""
+    'quotes': 'off'
+  }
+}

+ 17 - 0
.gitignore

@@ -0,0 +1,17 @@
+.DS_Store
+node_modules/
+/dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+/test/unit/coverage/
+/test/e2e/reports/
+selenium-debug.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": {}
+  }
+}

+ 4 - 0
README.md

@@ -0,0 +1,4 @@
+## alarm-system-web
+
+报警子系统
+

+ 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)
+  }
+}

+ 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'
+  }
+}

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

@@ -0,0 +1,109 @@
+'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: ['babel-polyfill', 'event-source-polyfill','./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]')
+        }
+      },
+      {
+        test: /\.less$/,
+        use: [
+          {loader: 'style-loader'},
+          {loader: 'css-loader'},
+          {
+            loader: 'px2rem-loader',
+            // options here
+            options: {
+              remUni: 75,
+              remPrecision: 8
+            }
+          },
+          {loader: 'less-loader'},
+        ]
+        
+      }
+    ]
+  },
+  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)
+    }
+  })
+})

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

@@ -0,0 +1,149 @@
+'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 = process.env.NODE_ENV === 'testing'
+  ? require('../config/test.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: process.env.NODE_ENV === 'testing'
+        ? 'index.html'
+        : 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"'
+})

+ 119 - 0
config/index.js

@@ -0,0 +1,119 @@
+'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.20.225:8080",//设置你调用的接口域名和端口号 别忘了加http
+          changeOrigin: true,
+          pathRewrite: {
+              '^/api': '/' // 这里理解成用‘/api’代替target里面的地址,后面组件中我们掉接口时直接用api代替 比如我要调用'http://40.00.100.100:3002/user/add',直接写‘/api/user/add’即可
+          }
+      },
+      '/data-platform-3':{
+        target:"http://101.200.32.13:28888",
+        changeOrigin:true, 
+        pathRewrite:{
+          '^/data-platform-3': '/'
+        }
+      },
+      '/alarm-system':{
+        target:"http://47.93.33.207:8889",
+        changeOrigin:true,
+        pathRewrite:{
+          '^/alarm-system': '/'
+        }
+      },
+      '/workorder':{
+        target:"http://47.94.89.44:8081",
+        changeOrigin:true,
+        pathRewrite:{
+          '^/workorder': '/'
+        }
+      },
+      '/info-mng-backend': {
+        target:"http://192.168.20.33:8080",//故障代理
+        changeOrigin: true,
+        pathRewrite: {
+          '^/info-mng-backend': '/' // 这里理解成用‘/api’代替target里面的地址,后面组件中我们掉接口时直接用api代替 比如我要调用'http://40.00.100.100:3002/user/add',直接写‘/api/user/add’即可
+        }
+      },
+      '/image-service': {
+        target:"http://service.sagacloud.cn:28888",
+        changeOrigin:true,
+        pathRewrite:{
+          '^/image-service': '/'
+        }
+      }
+  },
+
+    // Various Dev Server settings
+    host: 'localhost', // can be overwritten by process.env.HOST
+    disableHostCheck: true,
+    port: 8080, // 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: false,
+    // 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: true,
+    // 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"'
+}

+ 7 - 0
config/test.env.js

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

+ 26 - 0
index.html

@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <title>报警子系统</title>
+    <link rel="stylesheet" type="text/css" href="//at.alicdn.com/t/font_871500_dvtmcl3wjil.css">
+    <link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet">
+    <link href="https://cdn.bootcss.com/bootstrap-daterangepicker/2.1.25/daterangepicker.css" rel="stylesheet">
+
+    <link rel="stylesheet" href="./static/css/viewer.min.css">
+    <link rel="stylesheet" href="./static/css/reset.css">
+    <script src="./static/js/three.min.js"></script>
+    <script src="./static/js/viewer.min.js"></script>
+    <script src="./static/js/photo-sphere-viewer.min.js"></script>
+    <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
+    <script type="text/javascript" src="http://netdna.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
+    <script src="https://cdn.bootcss.com/bootstrap-daterangepicker/2.1.25/moment.js"></script>
+    <script src="https://cdn.bootcss.com/bootstrap-daterangepicker/2.1.25/daterangepicker.js"></script>
+  </head>
+  <body>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

Fichier diff supprimé car celui-ci est trop grand
+ 39001 - 0
package-lock.json


+ 100 - 0
package.json

@@ -0,0 +1,100 @@
+{
+  "name": "wanke-project",
+  "version": "1.0.0",
+  "description": "A Vue.js project",
+  "author": "zlz",
+  "private": true,
+  "scripts": {
+    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+    "start": "npm run dev",
+    "unit": "jest --config test/unit/jest.conf.js --coverage",
+    "e2e": "node test/e2e/runner.js",
+    "test": "npm run unit && npm run e2e",
+    "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
+    "build": "node build/build.js"
+  },
+  "dependencies": {
+    "axios": "^0.18.0",
+    "echarts": "^4.2.0-rc.1",
+    "iview": "^3.1.1-rc.1",
+    "jquery": "^3.3.1",
+    "svg-sprite-loader": "^4.1.2",
+    "vue": "^2.5.2",
+    "vue-router": "^3.0.1",
+    "vue-ydui": "^1.2.6",
+    "vuex": "^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-jest": "^21.0.2",
+    "babel-loader": "^7.1.1",
+    "babel-plugin-dynamic-import-node": "^1.2.0",
+    "babel-plugin-syntax-jsx": "^6.18.0",
+    "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
+    "babel-plugin-transform-runtime": "^6.22.0",
+    "babel-plugin-transform-vue-jsx": "^3.5.0",
+    "babel-polyfill": "^6.26.0",
+    "babel-preset-env": "^1.3.2",
+    "babel-preset-stage-2": "^6.22.0",
+    "babel-register": "^6.22.0",
+    "bootstrap-vue": "^2.0.0-rc.11",
+    "chalk": "^2.0.1",
+    "chromedriver": "^2.27.2",
+    "copy-webpack-plugin": "^4.0.1",
+    "cross-spawn": "^5.0.1",
+    "css-loader": "^0.28.0",
+    "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.14.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",
+    "event-source-polyfill": "^1.0.4",
+    "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",
+    "jest": "^22.0.4",
+    "jest-serializer-vue": "^0.3.0",
+    "less": "^3.8.1",
+    "less-loader": "^4.1.0",
+    "nightwatch": "^0.9.12",
+    "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",
+    "px2rem-loader": "^0.1.9",
+    "rimraf": "^2.6.0",
+    "selenium-server": "^3.0.1",
+    "semver": "^5.3.0",
+    "shelljs": "^0.7.6",
+    "uglifyjs-webpack-plugin": "^1.1.1",
+    "url-loader": "^0.5.8",
+    "vue-jest": "^1.0.2",
+    "vue-loader": "^13.3.0",
+    "vue-style-loader": "^3.0.1",
+    "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"
+  ]
+}

+ 23 - 0
src/App.vue

@@ -0,0 +1,23 @@
+<template>
+  <div id="app">
+
+      <router-view />
+
+  </div>
+</template>
+
+<script>
+
+export default {
+  name: 'App',
+  mounted () {
+    this.$store.dispatch('loadEquipmentAll')
+  }
+}
+</script>
+<style lang="less">
+#app {
+  position: relative;
+  margin: 0 auto;
+}
+</style>

+ 6 - 0
src/assets/css/public.css

@@ -0,0 +1,6 @@
+.remark-icon{
+    width:6px;
+    height: 20px;
+    display: inline-block;
+    background:#4A9EF9; 
+}

+ 65 - 0
src/assets/css/reset.css

@@ -0,0 +1,65 @@
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+  margin: 0;
+  padding: 0;
+  border: 0;
+  font: inherit;
+  vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+  display: block;
+}
+body {
+  background: #FFFFFF;
+  line-height: 1;
+  font-size: 16px;
+  /*使用简书的那一套字体
+    简书优先选择了lucida家族的系列字体作为英文字体,该系列字体在Mac和Win上都是预装的,并且有着不俗的表现;
+    中文字体方面将冬青黑体作为最优先使用的字体,同样考虑了Linux系统。
+  */
+  font-family: "MicrosoftYaHei", "lucida grande", "lucida sans unicode", lucida, helvetica, "Hiragino Sans GB", "WenQuanYi Micro Hei", sans-serif;
+  -webkit-font-smoothing: subpixel-antialiased;
+  -moz-osx-font-smoothing: auto;
+}
+ol, ul {
+  list-style: none;
+}
+blockquote, q {
+  quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+  content: '';
+  content: none;
+}
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+a {
+  text-decoration: none;
+  color: black;
+}
+html,body {
+  height: 100%;
+}
+/*消除window、mac系统差异,windows border-width:2px mac: border-width:1px*/
+button {
+  border-width: 0;
+}
+* {
+  box-sizing: border-box;
+}

+ 165 - 0
src/common/SgyRange.vue

@@ -0,0 +1,165 @@
+<template>
+  <div class="sgy-range">
+      <div class="my-mark" :style="`color:${colorStyle}`" v-if="alarmVal!='undefined'">
+           <!-- 减去文本自身 宽度的一半,因为三角指示箭头是居中的 -->
+          <span :style="`transform: translateX(${left(alarmVal) - 50 }px)`">报警触发值 {{this.alarmVal}} {{unit}}</span>
+      </div>
+      <div class="range">
+          <p class="bg-range"></p>
+          <p class="real-range" :style="`left:${left(min)}px;width:${normalWidth}px`"></p>
+      </div>
+       <div class="my-current-mark" :style="`color:${colorCurrentStyle}`" v-if="currentValue!='undefined'">
+           <!-- 减去文本自身 宽度的一半,因为三角指示箭头是居中的 -->
+            <span :style="`transform: translateX(${left(currentValue) - 38}px)`">当前值 {{this.currentValue}} {{unit}}</span>
+        </div>
+      <div class="normal-range" :style="`margin-left:${left(min)}px;width:${normalWidth}px`">
+          <i>{{min}}{{unit}}</i>
+          <i>正常范围</i>
+          <i>{{max}}{{unit}}</i>
+      </div>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: {
+    alarmVal: {
+    },
+    min: {},
+    max: {},
+    currentValue: {},
+    unit: ""
+  },
+
+  data () {
+    return {
+      space: 50 // 左右空白50px;
+    }
+  },
+
+  computed: {
+    arr () {
+      let arr = [this.alarmVal, this.min, this.max, this.currentValue]
+      let newArr = []
+      arr.forEach(el => {
+        if (el != 'undefined') {
+          newArr.push(el)
+        }
+      })
+      return newArr.sort(function (a, b) {
+        return a - b
+      })
+    },
+    // 系数, 每一个px表的值
+    pel () {
+      return (this.arr[this.arr.length - 1] - this.arr[0]) / (620 - this.space * 2)
+    },
+    normalWidth () {
+      return (this.max - this.min) / this.pel
+    },
+    myCurrentMarkWidth () {
+      return this.$nextTick(() => {
+        return document.querySelector('.my-current-mark span').scrollWidth
+      })
+    },
+    myMarkWidth () {
+      return this.$nextTick(() => {
+        return document.querySelector('.my-mark span').scrollWidth
+      })
+    },
+    colorStyle () {
+      if (this.alarmVal > this.min && this.alarmVal < this.max) {
+        return '#3BC6A1'
+      } else {
+        return '#F08378'
+      }
+    },
+    colorCurrentStyle () {
+      if (this.currentValue > this.min && this.currentValue < this.max) {
+        return '#3BC6A1'
+      } else {
+        return '#F08378'
+      }
+    }
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    left (val) {
+      return ((val - this.arr[0]) / this.pel) + this.space
+    }
+
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.sgy-range {
+    position: relative;
+    .my-mark {
+        color: #F08378 ;
+        span {
+            display: inline-block;
+            text-align: center;
+            &::after {
+                content: '▼';
+                display: block;
+            }
+        }
+    }
+    .my-current-mark {
+       color: #F08378 ;
+       position: absolute;
+       top: 48px;
+        span {
+            display: inline-block;
+            text-align: center;
+            &::before {
+                content: '▲';
+                display: block;
+
+            }
+        }
+    }
+    .range {
+        position: relative;
+        .bg-range {
+            position: absolute;
+            top:0;
+            width: 620px;
+            height: 8px;
+            background: #E5E5E5;
+            border-radius: 6px;
+        }
+        .real-range {
+            position: absolute;
+            box-sizing: border-box;
+            top:0;
+            //left: 120px;
+            //width: 280px;
+            height: 8px;
+            background: #3BC6A1;
+            border-left: 2px solid #FFFFFF;
+            border-right: 2px solid #FFFFFF;
+        }
+    }
+    .normal-range {
+        color: #3BC6A1;
+        //margin-left: 115px;
+        padding-top: 13px;
+        width: 295px;
+        display: flex;
+        justify-content: space-between;
+    }
+}
+</style>

+ 187 - 0
src/common/sagacloudMulSelect.vue

@@ -0,0 +1,187 @@
+<template>
+
+    <div class="sgy-select" tabindex="0" @blur="show = false">
+
+      <div class="fill" @click="show = !show">
+
+        <div class="tags">
+          <div>
+            <label>{{label}} :</label>
+            <span v-if="value.length == 0">全部</span>
+            <ul class="items" v-else>
+              <template v-for="item in value" >
+                {{getTextByValue(item)}}、
+              </template>
+            </ul>
+          </div>
+        </div>
+        <Icon type="ios-arrow-down" :class="{rotate: show}"/>
+      </div>
+
+      <div class="list" v-if="show">
+        <ul>
+          <li class="clear" @click="clearSelect">清空选项</li>
+          <li v-for="(item, index) in list" :class="{actived: active(item.value)}" :key="index" @click="onClick(item.value)">
+             <Icon type="ios-square-outline" class="check-tag" v-show="!active(item.value)"/><Icon type="ios-checkbox-outline"  v-show="active(item.value)"/> {{item.text}}
+          </li>
+        </ul>
+      </div>
+
+    </div>
+
+</template>
+
+<script>
+export default {
+  model: {
+    prop: 'value',
+    event: 'input'
+  },
+  components: {},
+  props: {
+    value: {},
+    list: {
+      type: Array,
+      default: () => []
+    },
+    label: ""
+  },
+  data () {
+    return {
+      show: false
+    }
+  },
+
+  computed: {},
+
+  mounted () {},
+
+  methods: {
+    active (val) {
+      return this.value.includes(val)
+    },
+    onClick (val) {
+      if (this.active(val)) {
+        // 取消选中
+        const index = this.value.indexOf(val)
+        this.value.splice(index, 1)
+      } else {
+        this.value.push(val)
+      }
+      this.$emit('input', this.value)
+    },
+    clearSelect () {
+      this.$emit('input', [])
+    },
+    getTextByValue (value) {
+      const item = this.list.find(i => i.value == value)
+      return item ? item.text : ''
+    }
+  }
+}
+</script>
+
+<style scoped lang="less" style="text/less">
+.rotate {
+  transform: rotate(180deg);
+}
+.sgy-select {
+  outline: none;
+  width:280px;
+  position: relative;
+  z-index: 5;
+  .fill {
+    vertical-align: middle;
+    width: 100%;
+    height:34px;
+    border-radius: 4px;
+    box-shadow: none;
+    border: 1px solid #ccc;
+    padding: 0 2px;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    background: #fff;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    &:hover,
+    &:active,
+    &:focus {
+      outline: none;
+      border-color: #2d8cf0;
+    }
+    i.rotate,.ivu-icon-ios-arrow-down {
+      margin-right: 10px;
+      transition: transform 0.3s ease-in-out;
+    }
+
+    .tags {
+      > div {
+         display: flex;
+         margin-top: 9px;
+        label{
+              font-size: 14px;
+              color: #212830;
+              padding-left: 3px;
+        }
+        span {
+            display: inline-block;
+            font-size: 14px;
+            padding-right: 5px;
+            padding-left: 5px;
+            border-radius: 2px;
+            color: #212830;
+        }
+        ul {
+           display: inline-block;
+           font-size: 14px;
+           color: #212830;
+           width: 144px;
+           white-space: nowrap;
+           overflow: hidden;
+           text-overflow: ellipsis;
+           padding-left: 5px;
+           margin-bottom:-3px;
+          li {
+             display: inline-block;
+             padding-right: 5px;
+          }
+        }
+      }
+    }
+  }
+  .list {
+        //margin-top: 5px;
+        z-index: 6;
+        ul {
+            border: 1px solid #E0E0E0;
+            box-shadow: 0 1px 6px 0 rgba(0,0,0,0.12);
+            border-radius: 4px;
+            background-color: #fff;
+            width: 95%;
+            position: absolute;
+            max-height: 400px;
+            overflow: auto;
+            .clear {
+              color: #728DEE;
+            }
+        li {
+                padding: 5px;
+                padding-left: 9px;
+                cursor: pointer;
+                &:hover {
+                background-color: #f5f7fa;
+            }
+            &.actived {
+                color:#2d8cf0;
+            }
+            i{
+                margin-right: 8px;
+            }
+        }
+    }
+  }
+}
+</style>

+ 182 - 0
src/common/sagacloudSelect.vue

@@ -0,0 +1,182 @@
+<template>
+
+    <div class="sgy-select" tabindex="0" @blur="show=false">
+
+      <div class="fill" @click="show = !show">
+
+        <div class="tags">
+          <div>
+            <label>{{label}} :</label>
+            <span  v-if="value===''">全部</span>
+            <ul class="items" v-else>
+              <template>
+                {{getTextByValue(value)}}
+              </template>
+            </ul>
+
+          </div>
+        </div>
+        <Icon type="ios-arrow-down" :class="{rotate: show}"/>
+      </div>
+
+      <div class="list" v-if="show">
+        <ul>
+          <li class="clear" @click="clearSelect">清空选项</li>
+          <li v-for="(item, index) in list" :class="{actived: active(item.value)}" :key="index" @click="onClick(item.value)">
+             {{item.text}}<Icon type="ios-checkmark" size='30' v-show="active(item.value)"/>
+          </li>
+        </ul>
+      </div>
+
+    </div>
+
+</template>
+
+<script>
+export default {
+  model: {
+    prop: 'value',
+    event: 'input'
+  },
+  components: {},
+  props: {
+    value: {},
+    list: {
+      type: Array,
+      default: () => []
+    },
+    label: ""
+  },
+  data () {
+    return {
+      show: false
+    }
+  },
+
+  computed: {},
+
+  mounted () {},
+
+  methods: {
+    active (val) {
+      return this.value == val
+    },
+    onClick (val) {
+      this.$emit('input', val)
+    },
+    clearSelect () {
+      this.$emit('input', '')
+    },
+    getTextByValue (value) {
+      const item = this.list.find(i => i.value == value)
+      return item ? item.text : ''
+    }
+  }
+}
+</script>
+
+<style scoped lang="less" style="text/less">
+.rotate {
+  transform: rotate(180deg);
+}
+.sgy-select {
+  outline: none;
+  width:280px;
+  position: relative;
+  z-index: 3;
+  .fill {
+    vertical-align: middle;
+    width: 100%;
+    height:34px;
+    border-radius: 4px;
+    box-shadow: none;
+    border: 1px solid #ccc;
+    padding: 0 2px;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    background: #fff;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    &:hover,
+    &:active,
+    &:focus {
+      outline: none;
+      border-color: #2d8cf0;
+    }
+    i.rotate,.ivu-icon-ios-arrow-down {
+      margin-right: 10px;
+      transition: transform 0.3s ease-in-out;
+    }
+
+    .tags {
+      > div {
+         display: flex;
+         margin-top: 9px;
+        label{
+              font-size: 14px;
+              color: #212830;
+              padding-left: 3px;
+        }
+        span {
+            display: inline-block;
+            font-size: 14px;
+            padding-right: 5px;
+            padding-left: 5px;
+            border-radius: 2px;
+            color: #212830;
+        }
+        ul {
+           display: inline-block;
+           font-size: 14px;
+           color: #212830;
+           width: 140px;
+           white-space: nowrap;
+           overflow: hidden;
+           text-overflow: ellipsis;
+           padding-left: 5px;
+           margin-bottom:-3px;
+          li {
+             display: inline-block;
+             padding-right: 5px;
+          }
+        }
+      }
+    }
+  }
+  .list {
+        //margin-top: 5px;
+        z-index: 4;
+        ul {
+            border: 1px solid #E0E0E0;
+            box-shadow: 0 1px 6px 0 rgba(0,0,0,0.12);
+            border-radius: 4px;
+            background-color: #fff;
+            width: 95%;
+            position: absolute;
+            max-height: 400px;
+            overflow: auto;
+            .clear {
+              color: #728DEE;
+            }
+        li {
+              padding: 5px;
+              padding-left: 9px;
+              cursor: pointer;
+              &:hover {
+              background-color: #f5f7fa;
+            }
+            &.actived {
+                color:#2d8cf0;
+            }
+            i{
+                float: right;
+                margin-right: 8px;
+            }
+        }
+    }
+  }
+}
+</style>

+ 216 - 0
src/common/sagasloudTreeSelect.vue

@@ -0,0 +1,216 @@
+<template>
+
+    <div class="sgy-select" tabindex="0" @blur="show = false">
+
+      <div class="fill" @click="show = !show">
+
+        <div class="tags">
+          <div>
+            <label>{{label}} :</label>
+            <span v-if="all">全部</span>
+            <ul class="items" v-else>
+              <template v-for="item in value.buildingId" >
+               {{getTextByValue(item)}}
+              </template>
+              <template v-for="item in value.floorId" >
+               {{getTextByValue(item)}}
+              </template>
+              <template v-for="item in value.spaceId" >
+               {{getTextByValue(item)}}
+              </template>
+            </ul>
+          </div>
+        </div>
+        <Icon type="ios-arrow-down" :class="{rotate: show}"/>
+      </div>
+
+      <div class="list" v-if="show">
+        <ul>
+          <li class="clear" @click="clearSelect">清空选项</li>
+           <sgy-tree ref="sgyTree" :treeList="list" @on-change="onChange"></sgy-tree>
+        </ul>
+      </div>
+
+    </div>
+
+</template>
+
+<script>
+import Tree from './tree.vue'
+// import { log } from 'util'
+export default {
+  model: {
+    prop: 'value',
+    event: 'input'
+  },
+  components: {
+    'sgy-tree': Tree
+  },
+  props: {
+    value: {},
+    list: {
+      type: Array,
+      default: () => []
+    },
+    label: ""
+  },
+  data () {
+    return {
+      show: false
+    }
+  },
+
+  computed: {
+    all () {
+      return this.value.buildingId.length == 0 && this.value.floorId.length == 0 && this.value.spaceId.length == 0
+    }
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    onChange (val) {
+      this.$emit('input', val)
+      this.$emit('onChange')
+    },
+    clearSelect () {
+      let obj = {
+        buildingId: [],
+        floorId: [],
+        spaceId: []
+      }
+      this.$emit('input', obj)
+      // 清空checked
+      this.$refs['sgyTree'].setTreeList(this.list)
+    },
+    getTextByValue (value) {
+      for (let i of this.list) {
+        if (i.value == value) {
+          return i.title
+        } else if (i.children && i.children.length > 0) {
+          for (let j of i.children) {
+            if (j.value == value) {
+              return j.title
+            } else if (j.children && j.children.length > 0) {
+              for (let k of j.children) {
+                if (k.value == value) {
+                  return k.title
+                }
+              }
+            }
+          }
+        }
+      }
+      return value
+    }
+  }
+}
+</script>
+
+<style scoped lang="less" style="text/less">
+.rotate {
+  transform: rotate(180deg);
+}
+.sgy-select {
+  outline: none;
+  width:280px;
+  position: relative;
+  z-index: 2;
+  .fill {
+    vertical-align: middle;
+    width: 100%;
+    height:34px;
+    border-radius: 4px;
+    box-shadow: none;
+    border: 1px solid #ccc;
+    padding: 0 2px;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    background: #fff;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    &:hover,
+    &:active,
+    &:focus {
+      outline: none;
+      border-color: #2d8cf0;
+    }
+    i.rotate,.ivu-icon-ios-arrow-down {
+      margin-right: 10px;
+      transition: transform 0.3s ease-in-out;
+    }
+
+    .tags {
+      > div {
+         display: flex;
+         margin-top: 9px;
+        label{
+          font-size: 14px;
+          color: #212830;
+          padding-left: 3px;
+        }
+        span {
+            display: inline-block;
+            font-size: 14px;
+            padding-right: 5px;
+            padding-left: 5px;
+            border-radius: 2px;
+            color: #212830;
+        }
+        ul {
+           display: inline-block;
+           font-size: 14px;
+           color: #212830;
+           width: 140px;
+           white-space: nowrap;
+           overflow: hidden;
+           text-overflow: ellipsis;
+           padding-left: 5px;
+           margin-bottom:-3px;
+          li {
+             display: inline-block;
+             padding-right: 5px;
+             padding-left: 9px;
+          }
+        }
+      }
+    }
+  }
+  .list {
+        //margin-top: 5px;
+        z-index: 3;
+        ul {
+            border: 1px solid #E0E0E0;
+            box-shadow: 0 1px 6px 0 rgba(0,0,0,0.12);
+            border-radius: 4px;
+            background-color: #fff;
+            width: 95%;
+            position: absolute;
+            max-height: 338px;
+            overflow: auto;
+            .clear {
+              color: #728DEE;
+              padding-left: 15px;
+            }
+        li {
+                padding: 5px;
+                cursor: pointer;
+                &:hover {
+                background-color: #f5f7fa;
+            }
+            &.actived {
+                color:#2d8cf0;
+            }
+            i{
+                margin-right: 8px;
+            }
+        }
+    }
+  }
+}
+</style>

+ 99 - 0
src/common/scrollList.vue

@@ -0,0 +1,99 @@
+<template>
+  <div class="scroll-list" :style="`height: ${height}px`" @scroll="onScroll">
+    <div class="content">
+      <slot></slot>
+    </div>
+    <div class="loading" v-if="loading && !finished">
+      <Icon type="ios-loading" />
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: {
+    height: {
+      type: Number,
+      default: 320
+    },
+    offset: {
+      type: Number,
+      default: 50
+    },
+    finished: {
+      type: Boolean,
+      default: false
+    },
+    loading: {
+      type: Boolean,
+      default: false
+    }
+  },
+
+  data () {
+    return {
+      l: ''
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    onScroll () {
+      if (this.finished && this.loading) {
+        return
+      }
+      clearTimeout(this.l)
+      this.l = setTimeout(() => {
+        let content = document.querySelector('.content')
+        let box = document.querySelector('.scroll-list')
+        let SH = content.scrollHeight
+        let ST = box.scrollTop
+        let CH = this.height // 可视区
+        if (SH - this.offset <= CH + ST) {
+          console.log('onloadd')
+          this.$emit('onLoad')
+        }
+      }, 1000)
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.scroll-list {
+  position: relative;
+  overflow-y: auto;
+  .loading {
+    text-align: center;
+    color: #2db7f5;
+    i {
+       animation: circle 1s ease-in-out infinite;
+    }
+  }
+}
+@keyframes circle {
+  0% {
+    transform: rotate(0)
+  }
+  50% {
+    transform: rotate(180deg)
+  }
+  100% {
+    transform: rotate(360deg)
+  }
+}
+</style>

+ 101 - 0
src/common/swipe.vue

@@ -0,0 +1,101 @@
+<template>
+  <div class="sgy-swipe">
+
+       <div v-if="list.length > 4" class="left-loop" :class="{disabled: !isCanClickLeft}" @click="moveLeft"> <Icon type="ios-arrow-back" size='24'/> </div>
+
+       <div class="loop-content">
+            <div class="contanier" :style="`transform: translateX(-${index * 104}px)`">
+                <img v-for="(item, index) in list" :key="index" :src="item.key?`/data-platform-3/image-service/common/image_get?systemId=dataPlatform&key=${item.key}&width=96&height=95`:``">
+            </div>
+        </div>
+
+        <div v-if="list.length > 4" class="right-loop" :class="{disabled: !isCanClickRight}" @click="moveRight"> <Icon type="ios-arrow-forward" size='24'/> </div>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: {
+    list: {
+      type: Array,
+      default: () => []
+
+    }
+  },
+
+  data () {
+    return {
+      index: 0
+    }
+  },
+
+  computed: {
+    isCanClickLeft () {
+      return this.index > 0
+    },
+    isCanClickRight () {
+      return this.index + 4 < this.list.length
+    }
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    moveLeft () {
+      if (this.isCanClickLeft) {
+        this.index--
+      }
+    },
+    moveRight () {
+      if (this.isCanClickRight) {
+        this.index++
+      }
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.sgy-swipe {
+    display: flex;
+    .left-loop {
+        color: #CACACA;
+        padding-top: 35px;
+        margin-right: 15px;
+        cursor: pointer;
+    }
+    .right-loop {
+        color: #CACACA;
+        padding-top: 35px;
+        cursor: pointer;
+    }
+    .disabled {
+        //cursor: not-allowed;
+       display: none;
+    }
+    .loop-content {
+        width:450px;
+        white-space: nowrap;
+        overflow: hidden;
+        .contanier {
+            transition: transform 0.3s ease-in-out;
+            img {
+                vertical-align: middle;
+                margin-right: 8px;
+                width: 96px;
+                height: 95px;
+            }
+        }
+
+    }
+}
+</style>

+ 278 - 0
src/common/tree.vue

@@ -0,0 +1,278 @@
+<template>
+
+   <div class="sgy-tree" v-if="myTreeList.length > 0">
+      <div class="level1" v-for="(level1, index1) in myTreeList" :key="level1.value">
+            <p class="level1-lable">
+              <i class="iconfont icon-start1"
+                :class="[{hasChildren: level1.children && level1.children.length >0},
+                       {expand: level1.expand}
+                ]"
+                @click="onClickExpand(index1)"
+              ></i>
+              <span @click="onClick(index1)">{{level1.title}}</span>
+              <i class="iconfont icon-duigou" v-if="level1.checked" @click="onClick(index1)"></i>
+            </p>
+
+          <div class="level2" v-show="level1.expand" v-for="(level2, index2) in level1.children" :key="level2.value">
+                <p class="level2-lable">
+                  <i class="iconfont icon-start1"
+                    :class="[{hasChildren: level2.children && level2.children.length >0},
+                            {expand: level2.expand}
+                    ]"
+                    @click="onClickExpand(index1, index2)"
+                  ></i>
+                  <span @click="onClick(index1, index2)">{{level2.title}}</span>
+                  <i class="iconfont icon-duigou" v-if="level2.checked"  @click="onClick(index1, index2)"></i>
+                </p>
+
+              <div class="level3" v-show="level2.expand" v-for="(level3, index3) in level2.children" :key="level3.value">
+                    <p class="level3-lable">
+                      <i class="iconfont icon-start1"
+                      :class="[{hasChildren: level3.children && level3.children.length >0},
+                               {expand: level3.expand}
+                      ]"
+                      @click="onClickExpand(index1, index2, index3)"
+                      ></i>
+                      <span @click="onClick(index1, index2, index3)">{{level3.title}}</span>
+                      <i class="iconfont icon-duigou" v-if="level3.checked"  @click="onClick(index1, index2, index3)"></i>
+                    </p>
+              </div>
+          </div>
+      </div>
+  </div>
+</template>
+
+<script>
+export default {
+
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: {
+    treeList: {
+      type: Array
+    },
+    // 默认单选
+    multiple: {
+      type: Boolean,
+      default: false
+    }
+  },
+
+  data () {
+    return {
+      myTreeList: []
+    }
+  },
+
+  computed: {
+  },
+  watch: {
+    // 并没有实际用处,方便调试使用
+    treeList (newVal, oldVal) {
+      this.setTreeList(newVal)
+    }
+  },
+  mounted () {
+    this.setTreeList(this.treeList)
+  },
+
+  methods: {
+    setTreeList (newVal) {
+      this.myTreeList = JSON.parse(JSON.stringify([...newVal]))
+    },
+    onClickExpand () {
+      switch (arguments.length) {
+        case 1:
+          this.myTreeList[arguments[0]].expand = !this.myTreeList[arguments[0]].expand
+          break
+        case 2:
+          this.myTreeList[arguments[0]].children[arguments[1]].expand = !this.myTreeList[arguments[0]].children[arguments[1]].expand
+          break
+        case 3:
+          this.myTreeList[arguments[0]].children[arguments[1]].children[arguments[2]].expand = !this.myTreeList[arguments[0]].children[arguments[1]].children[arguments[2]].expand
+          break
+      }
+    },
+
+    onClick () {
+      let tree = {}
+      let parentTree = {}
+      let grandParentTree = {}
+      // let value = ''
+      // let index = -1
+      // let arr = []
+      switch (arguments.length) {
+        case 1:
+          tree = this.myTreeList[arguments[0]]
+          break
+        case 2:
+          parentTree = this.myTreeList[arguments[0]]
+          tree = parentTree.children[arguments[1]]
+          break
+        case 3:
+          grandParentTree = this.myTreeList[arguments[0]]
+          parentTree = this.myTreeList[arguments[0]].children[arguments[1]]
+          tree = parentTree.children[arguments[2]]
+          break
+      }
+
+      // 单选时执行
+      if (!this.multiple) {
+        this.clearAllChecked()
+      }
+
+      // 若已选中,置为取消选中; 若未选中,置为选中
+      tree.children = this.setChildrenChecked(tree, !tree.checked)
+
+      // 通过parentTree检查兄弟,是否全部选中
+      if (parentTree.children && this.isEveryChilderChecked(parentTree.children)) {
+        parentTree.checked = true
+      } else {
+        parentTree.checked = false
+      }
+
+      // 同理
+      if (grandParentTree.children && this.isEveryChilderChecked(grandParentTree.children)) {
+        grandParentTree.checked = true
+      } else {
+        grandParentTree.checked = false
+      }
+
+      this.setSelectedValue()
+    },
+
+    setChildrenChecked (tree, checked) {
+      // 自己
+      tree.checked = checked
+      let arr = tree.children
+      if (arr && arr.length > 0) {
+        for (let i = 0; i < arr.length; i++) {
+          arr[i].checked = checked
+          if (arr[i].children && arr[i].children.length > 0) {
+            this.setChildrenChecked(arr[i], checked)
+          }
+        }
+      }
+      return arr
+    },
+
+    // 清空所有选中状态
+    clearAllChecked () {
+      this.myTreeList = this.myTreeList.map(i => {
+        i.checked = false
+        if (i.children && i.children.length > 0) {
+          i.children = this.setChildrenChecked(i, false)
+        }
+        return i
+      })
+    },
+
+    isEveryChilderChecked (children) {
+      let arr = children
+      if (arr && arr.length > 0) {
+        for (let i = 0; i < arr.length; i++) {
+          if (!arr[i].checked) {
+            return false
+          }
+          if (arr[i].children && arr[i].children.length > 0) {
+            this.isEveryChilderChecked(arr[i].children)
+          }
+        }
+      }
+      return true
+    },
+
+    setSelectedValue () {
+      let obj = {
+        buildingId: [],
+        floorId: [],
+        spaceId: []
+      }
+      for (let i of this.myTreeList) {
+        if (i.checked) {
+          if (i.type === 'building') {
+            obj.buildingId.push(i.value)
+          } else if (i.type === 'floor') {
+            obj.floorId.push(i.value)
+          } else {
+            obj.spaceId.push(i.value)
+          }
+        } else if (i.children && i.children.length > 0) {
+          for (let j of i.children) {
+            if (j.checked) {
+              if (j.type === 'floor') {
+                obj.floorId.push(j.value)
+              } else {
+                obj.spaceId.push(j.value)
+              }
+            } else if (j.children && j.children.length > 0) {
+              for (let k of j.children) {
+                if (k.checked) {
+                  obj.spaceId.push(k.value)
+                }
+              }
+            }
+          }
+        }
+      }
+      this.$emit('on-change', obj)
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.sgy-tree {
+    i {
+        display: inline-block;
+        font-size: 12px;
+        transform: scale(0.8);
+        color: #728DEE ;
+    }
+    i.icon-start1 {
+        transform: scale(0.8) rotate(270deg);
+        display: none;
+        position: absolute;
+    }
+    i.expand {
+        transform: scale(0.8) rotate(0deg);
+    }
+    i.icon-duigou {
+        position: absolute;
+        right: 12px;
+        top: 5px;
+    }
+    i.hasChildren {
+         display: inline-block;
+    }
+    p {
+        cursor: pointer;
+        padding: 3px 5px;
+        position: relative;
+        &:hover {
+            background-color: #F8F8F8;
+        }
+        span {
+            display: inline-block;
+            width: 100%;
+            padding-left: 20px;
+        }
+    }
+    .level1 {
+        position: relative;
+        padding-left: 10px;
+        .level2 {
+            padding-left: 15px;
+            .level3 {
+                padding-left: 15px;
+                color:#A7ADB6;
+            }
+        }
+    }
+}
+</style>

+ 89 - 0
src/components/Head.vue

@@ -0,0 +1,89 @@
+<template>
+  <div class="my-head">
+    <div class="my-menu" @click="setAsideMenu">
+      <Icon type="md-menu" size='28'/>
+    </div>
+    <div class="user-info">
+      <Icon  type="md-contact" size="28"/>
+        <Dropdown  trigger="click">
+          <a href="javascript:void(0)">
+              <span>登录名称</span>
+              <Icon type="ios-arrow-down" size='20'></Icon>
+          </a>
+          <DropdownMenu slot="list">
+              <DropdownItem>密码修改</DropdownItem>
+              <DropdownItem>退出</DropdownItem>
+          </DropdownMenu>
+      </Dropdown>
+      <!-- <span>登录名称</span>
+      <Icon type="ios-arrow-down" size='20'/> -->
+    </div>
+  </div>
+</template>
+
+<script>
+// import axios from 'axios'
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: {
+
+  },
+
+  data () {
+    return {
+      showAside: false
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+  },
+
+  methods: {
+    setAsideMenu () {
+      this.showAside = !this.showAside
+      this.$emit('setAsideMenu', this.showAside)
+    }
+
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.my-head{
+  display:flex;
+  justify-content: space-between;
+  align-items: center;
+  box-shadow: 0 1px 2px 0 rgba(11,13,17,0.05);
+  width: 100%;
+  font-size: 20px;
+  background: #393E47;
+  z-index:999999;
+  .my-menu{
+    width: 80px;
+    height: 60px;
+    line-height: 60px;
+    text-align: center;
+    background:#728DEE;
+    color:#fff;
+  }
+  .user-info{
+     color: #DFE0E1;
+     margin-right: 20px;
+     a, span{
+       font-size: 14px;
+       color: #DFE0E1;
+       text-decoration:none;
+     }
+  }
+}
+</style>

+ 91 - 0
src/components/Home.vue

@@ -0,0 +1,91 @@
+<template>
+  <div class="global-home" v-if="isShow">
+      <my-head class="my-head" @setAsideMenu="setAsideMenu"></my-head>
+      <!-- <my-nav class="aside" :class="{'spread': isSpread}" :isSpread="isSpread"></my-nav> -->
+
+      <div class="fp-content">
+        <router-view>
+        </router-view>
+      </div>
+  </div>
+</template>
+
+<script>
+import MyHead from './Head.vue'
+import MyNav from './Nav'
+export default {
+  components: {
+    MyHead,
+    MyNav
+  },
+
+  mixins: [],
+
+  props: {
+
+  },
+
+  data () {
+    return {
+      isSpread: false,
+      isShow: false
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+    const pid = this.$route.query.id || localStorage.getItem('projectId') || this.$store.state.projId
+    this.$store.commit('setProId', pid)
+    localStorage.setItem('projectId', pid)
+    this.isShow = true
+  },
+
+  methods: {
+    setAsideMenu (val) {
+      this.isSpread = val
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.global-home {
+  font-size: 15px;
+  font-family: "MicrosoftYaHei";
+  .my-head {
+    height: 60px;
+    position: fixed;
+    top: 0;
+  }
+  .aside {
+    position: fixed;
+    top: 60px;
+    left: 0;
+    bottom: 0;
+    width: 81px;
+    border-right: 1px solid #ebecf0;
+    transition: all 0.3s ease-in-out;
+    overflow-x: hidden;
+    overflow-y: auto;
+    background: #fff;
+  }
+  .fp-content {
+    // margin-left: 80px;
+    padding: 80px 20px 20px 20px;
+    transition: all 0.3s ease-in-out;
+    //background: #eeeff3;
+  }
+  // & > .aside:hover {
+  //   width: 300px;
+  //   background: #fff;
+  // }
+  .spread {
+    width: 260px;
+    background: #fff;
+  }
+}
+</style>

+ 203 - 0
src/components/Login.vue

@@ -0,0 +1,203 @@
+<template>
+  <div class="my-login">
+      <div class="bg"></div>
+        <div class="drag">
+            <img class="login-img" src="/static/img/loginbg.jpg" alt="">
+            <div class="my-form">
+                <p class="login-title">欢迎登录</p>
+                <div class="login-info">
+                    <input class="username" type="text" v-model="username" autocomplete="new-username" placeholder="请输入用户名">
+                    <i class="iconfont icon-zhanghao mark"></i>
+                    <i class="iconfont icon-close close"></i>
+                    </div>
+                <div class="login-info">
+                    <input class="password" type="password" v-model="password" autocomplete="new-password" placeholder="请输入密码">
+                    <i class="iconfont icon-mima mark"></i>
+                    <i class="iconfont icon-close close"></i>
+                    </div>
+                <p class="forget-password">忘记密码 <span class="msg">{{msg}}</span></p>
+                <button class="login-btn" @click="handleLogin">登陆</button>
+                <div class="login-bottom">@2018 Persagy.All right reserved.版权所有</div>
+            </div>
+        </div>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: {
+
+  },
+
+  data () {
+    return {
+      username: "",
+      password: "",
+      msg: ""
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    handleLogin () {
+      if (this.username == '') {
+        this.msg = '用户名或密码错误'
+      }
+      if (this.password == '') {
+        this.msg = '用户名或密码错误'
+      }
+      if (this.username != '' && this.password != '') {
+        this.$router.push({path: "/home"})
+      }
+    }
+
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.my-login{
+    width: 100%;
+    height:100%;
+    position:fixed;
+    .bg{
+        width:100%;
+        height:100%;
+        background: url("/static/img/bg.jpg") no-repeat;
+        padding:1px;
+        box-sizing:border-box;
+        z-index:1;
+        background-size:cover;
+        filter: blur(15px)
+    }
+    .drag{
+        margin:220px auto;
+        width:1120px;
+        height:640px;
+        background: #fff;
+        display: flex;
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        margin-left: -560px;
+        margin-top:-320px;
+        .login-img{
+            width: 688px;
+            height: 100%;
+        }
+        .my-form{
+            display: inline-block;
+            width: 432px;
+            text-align: center;
+            .login-title{
+                font-weight: bold;
+                font-size: 32px;
+                color: #3B4254;
+                letter-spacing: 1.71px;
+                padding:132px 0 98px 0;
+            }
+            .login-info{
+                width: 320px;
+                height: 22px;
+                margin:0 0  24px 58px;
+                position: relative;
+                >input{
+                    width: 100%;
+                    border: none;
+                    //font-size: 16px;
+                    outline: none;
+                    border-bottom:1px solid #DBDDE4;
+                    padding:5px 20px;
+                    &:-webkit-autofill {
+                        -webkit-box-shadow: inset 0 0 0px 9999px white;
+                    }
+                    &:focus{
+                        border-bottom-color: #4A9EF9;
+                    }
+                    &:focus ~ i.mark{
+                       color: #4A9EF9;
+                    }
+                    &:focus ~ i.close{
+                       opacity: 1;
+                    }
+                }
+                .mark {
+                    position: absolute;
+                    top: 3px;
+                    left: 0;
+                }
+                .close {
+                    position: absolute;
+                    top:0;
+                    right: 0;
+                    opacity: 0;
+                    cursor: pointer;
+                    &:hover {
+                        color: #000;
+                    }
+                }
+                .my-img{
+                    width: 20px;
+                    height: 20px;
+                    margin-right: 22px;
+                }
+                .my-close{
+                    width:20px;
+                    height: 20px;
+                    margin-left: 50px;
+                }
+            }
+            .forget-password{
+                float: left;
+                //margin:0 0 0 52px;
+                padding-left: 52px;
+                //font-size: 14px;
+                color: #4A9EF9;
+                letter-spacing: 0;
+                display: flex;
+                .msg{
+                    padding-left: 100px;
+                    color: #FF7B7B;
+                    letter-spacing: 0;
+                }
+            }
+            .login-btn{
+                width: 320px;
+                line-height: 44px;
+                text-align: center;
+                background: #4A9EF9;
+                box-shadow: 0 2px 4px 0 rgba(39,110,227,0.20);
+                border-radius: 3px;
+                font-size: 18px;
+                color: #FFFFFF;
+                letter-spacing: 0.75px;
+                font-weight: bold;
+                margin-top:16px;
+            }
+            .login-bottom{
+                margin-top:142px;
+                opacity: 0.8;
+                font-family: 'ArialMT';
+                color: #B5B9C3;
+                letter-spacing: 0.2px;
+            }
+        }
+
+    }
+
+}
+</style>

+ 142 - 0
src/components/Nav.vue

@@ -0,0 +1,142 @@
+<template>
+    <div class="aside-menu">
+      <ul class="floor1">
+        <li>
+          <router-link to="/main">
+           <i class="iconfont icon-home"></i>
+            <span >首页</span>
+          </router-link>
+          <!-- <ul class="floor2" :class="{left300: isSpread}" >
+            <li>11111</li>
+            <li>22222</li>
+            <li>11111</li>
+            <li>22222</li>
+          </ul> -->
+        </li>
+        <li>
+          <router-link to="/equipment">
+           <i class="iconfont icon-zonglan"></i>
+            <span >设备详情</span>
+          </router-link>
+           <!-- <ul class="floor2" :class="{left300: isSpread}" style="top:94px;">
+            <li>dsa</li>
+            <li>dasd</li>
+            <li>dasd</li>
+            <li>222dasd22</li>
+          </ul> -->
+        </li>
+
+        <li>
+          <router-link to="/rooms">
+           <i class="iconfont icon-anquancanshu"></i>
+            <span >空间详情</span>
+          </router-link>
+        </li>
+        <li>
+          <router-link to="/vr">
+           <i class="iconfont icon-qushi"></i>
+            <span >空间</span>
+          </router-link>
+        </li>
+         <!-- <li>
+          <router-link to="/spread">
+           <i class="iconfont icon-anquancanshu"></i>
+            <span >设备</span>
+          </router-link>
+        </li> -->
+         <li>
+          <router-link to="/asset">
+           <i class="iconfont icon-anquancanshu"></i>
+            <span >资产</span>
+          </router-link>
+        </li>
+         <li>
+          <router-link to="/system">
+           <i class="iconfont icon-qiangdianzhuanyexitong"></i>
+            <span >系统详情</span>
+          </router-link>
+        </li>
+      </ul>
+    </div>
+</template>
+
+<script>
+// import axios from 'axios'
+export default {
+  components: {},
+
+  mixins: [],
+
+  props: {
+    isSpread: {
+      type: Boolean,
+      default: false
+    }
+  },
+
+  data () {
+    return {
+
+    }
+  },
+
+  computed: {},
+
+  mounted () {
+
+  },
+
+  methods: {
+
+  }
+}
+</script>
+
+<style scoped lang="less" >
+.aside-menu {
+  z-index:99999;
+  box-shadow: 2px 0 4px 0 rgba(44,48,62,0.06);
+  ul.floor1 {
+    > li {
+      position: relative;
+      ul.floor2{
+        display: none;
+        position: fixed;
+        top: 50px;
+        left: 80px;
+        background: #fff;
+        transition: all 0.3s ease-in-out;
+        z-index: 2;
+      }
+      ul.left200 {
+        left: 200px;
+      }
+      &:hover {
+        background: #eee;
+        > ul.floor2 {
+          display: block;
+        }
+      }
+      > a {
+        display: inline-block;
+        white-space: nowrap;
+        padding: 10px 23px;
+        width: 100%;
+        color: #b6bccb;
+        span {
+          padding-left: 37px;
+          color: black;
+          font-size: 15px;
+        }
+      }
+      .router-link-active {
+        color: #57a4f7;
+      }
+      .iconfont{
+        padding-left: 4px;
+        font-size: 22px;
+      }
+    }
+  }
+}
+</style>

+ 29 - 0
src/main.js

@@ -0,0 +1,29 @@
+
+import './assets/css/reset.css'
+import 'jquery'
+import Vue from 'vue'
+import App from './App'
+import router from './router'
+import store from './store'
+import iView from 'iview'
+import 'iview/dist/styles/iview.css'
+import BootstrapVue from 'bootstrap-vue'
+import 'bootstrap/dist/css/bootstrap.css'
+import 'bootstrap-vue/dist/bootstrap-vue.css'
+import YDUI from 'vue-ydui' /* 相当于import YDUI from 'vue-ydui/ydui.rem.js' */
+import 'vue-ydui/dist/ydui.rem.css'
+/* 使用px:import 'vue-ydui/dist/ydui.px.css'; */
+
+Vue.use(YDUI)
+Vue.use(BootstrapVue)
+
+Vue.use(iView)
+Vue.config.productionTip = false
+/* eslint-disable no-new */
+new Vue({
+  el: '#app',
+  router,
+  store,
+  components: { App },
+  template: '<App/>'
+})

+ 68 - 0
src/router/index.js

@@ -0,0 +1,68 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+Vue.use(Router)
+
+const Home = () => import(/* webpackChunkName: 'home' */ '@/components/Home.vue')
+const Main = () => import(/* webpackChunkName: 'home' */ '@/views/main')
+const Equipment = () => import(/* webpackChunkName: 'equipment' */ '@/views/equipment')
+const Rooms = () => import(/* webpackChunkName: 'rooms' */ '@/views/rooms')
+const VR = () => import(/* webpackChunkName: 'vr' */ '@/views/VR')
+const Detail = () => import(/* webpackChunkName: 'detail' */ '@/views/detail')
+const Monitoring = () => import(/* webpackChunkName: 'monitoring' */ '@/views/monitoring')
+const Spread = () => import(/* webpackChunkName: 'spread' */ '@/views/spread')
+const Check = () => import(/* webpackChunkName: 'spread' */ '@/views/check')
+const Asset = () => import(/* webpackChunkName: 'spread' */ '@/views/asset')
+const System = () => import(/* webpackChunkName: 'system' */ '@/views/system')
+
+export default new Router({
+  mode: 'history',
+  routes: [
+    {
+      path: '/',
+      component: Home,
+      redirect: '/main',
+      children: [
+        {
+          path: 'main',
+          component: Main
+        },
+        {
+          path: 'equipment',
+          component: Equipment
+        },
+        {
+          path: 'rooms',
+          component: Rooms
+        },
+        {
+          path: 'vr',
+          component: VR
+        },
+        {
+          path: 'detail',
+          component: Detail
+        },
+        {
+          path: 'monitoring',
+          component: Monitoring
+        },
+        {
+          path: 'spread',
+          component: Spread
+        },
+        {
+          path: 'check',
+          component: Check
+        },
+        {
+          path: 'asset',
+          component: Asset
+        },
+        {
+          path: 'system',
+          component: System
+        }
+      ]
+    }
+  ]
+})

+ 45 - 0
src/store/index.js

@@ -0,0 +1,45 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import axios from 'axios'
+Vue.use(Vuex)
+
+const store = new Vuex.Store({
+  state: {
+    name: '这里是全局的',
+    equipmentAll: [],
+    // projectArr: [
+    //   { projId: 'Pj1101080001', secret: '123', projLocalName: '新华创新大厦' }
+    // { projId: 'Pj1101080001', secret: '123', projLocalName: '广联达二期' }
+    // { projId: 'Pj1101010001', secret: '123', projLocalName: '北京中海地产广场' }
+    // { projId: 'Pj1101020001', secret: 'saga123456', projLocalName: '广电国际酒店' }
+    // ],
+    projId: 'Pj4419000005',
+    baseUrl: "http://api.sagacloud.cn/dp-auxiliary"
+  },
+  getters: {
+    projectArr: state => state.projectArr
+  },
+  mutations: {
+    setProId (state, projectId) {
+      state.projId = projectId
+    },
+    setEquipmentAll (state, {equipmentAll}) {
+      state.equipmentAll = equipmentAll
+    }
+  },
+  actions: {
+    loadEquipmentAll (context) {
+      axios.get(`/data-platform-3/data-platform-3/dict/query/equipment_all`).then(res => {
+        let data = res.data
+        if (data.Result === 'success') {
+          // context.state.equipmentAll = data.Content
+          context.commit('setEquipmentAll', {equipmentAll: data.Content})
+        }
+      })
+    }
+  },
+  modules: {
+  }
+})
+
+export default store

+ 2 - 0
src/tools/bus.js

@@ -0,0 +1,2 @@
+import Vue from 'vue'
+export default new Vue()

+ 11 - 0
src/tools/currentDate.js

@@ -0,0 +1,11 @@
+function currentTime (date) {
+  const dateObj = {
+    year: date.getFullYear(),
+    month: date.getMonth() + 1 > 9 ? date.getMonth() + 1 : `0${date.getMonth() + 1}`,
+    day: date.getDate() > 9 ? date.getDate() : `0${date.getDate()}`
+  }
+  return dateObj.year + dateObj.month + dateObj.day + '000000'
+}
+module.exports = {
+  currentTime
+}

+ 24 - 0
src/tools/dataPickerConfig.js

@@ -0,0 +1,24 @@
+const date = new Date()
+const dateObj = {
+  year: date.getFullYear(),
+  month: date.getMonth() + 1 > 9 ? date.getMonth() + 1 : `0${date.getMonth() + 1}`,
+  day: date.getDate() > 9 ? date.getDate() : `0${date.getDate()}`
+}
+module.exports = {
+  all: {
+    view: '全部',
+    startDate: '', // 给datePicker用的
+    endDate: '',
+    dStart: '', // 给接口用的
+    dEnd: ''
+  },
+  oneMonth: {
+    view: dateObj.month == 1 ? `${dateObj.year - 1}-12-${dateObj.day + 1} - ${dateObj.year}-01-${dateObj.day}` : `${dateObj.year}-0${dateObj.month - 1}-${dateObj.day} - ${dateObj.year}-${dateObj.month}-${dateObj.day}`,
+    // eslint-disable-next-line
+    startDate: moment().subtract(30, 'days'),
+    // eslint-disable-next-line
+    endDate: moment().subtract(0, 'days'),
+    dStart: dateObj.month == 1 ? `${dateObj.year - 1}12${dateObj.day + 1}000000` : `${dateObj.year}0${dateObj.month - 1}${dateObj.day}000000`,
+    dEnd: `${dateObj.year}${dateObj.month}${dateObj.day}000000`
+  }
+}

+ 41 - 0
src/tools/download.js

@@ -0,0 +1,41 @@
+function getBlob (url, callback) {
+  var xhr = new XMLHttpRequest()
+  xhr.open('GET', url, true)
+  xhr.responseType = 'blob'
+  xhr.onload = () => {
+    if (xhr.status === 200) {
+      callback(xhr.response)
+    }
+  }
+  xhr.send()
+}
+function saveAs (blob, filename) {
+  if (window.navigator.msSaveOrOpenBlob) {
+    navigator.msSaveBlob(blob, filename)
+  } else {
+    const link = document.createElement('a')
+    const body = document.querySelector('body')
+
+    link.href = window.URL.createObjectURL(blob)
+    link.download = filename
+
+    // fix Firefox
+    link.style.display = 'none'
+    body.appendChild(link)
+
+    link.click()
+    body.removeChild(link)
+
+    window.URL.revokeObjectURL(link.href)
+  }
+}
+
+function download (url, filename) {
+  getBlob(url, function (blob) {
+    saveAs(blob, filename)
+  })
+}
+
+module.exports = {
+  download
+}

+ 56 - 0
src/tools/fastJson.js

@@ -0,0 +1,56 @@
+/* eslint-disable */
+var FastJson = {
+  isArray: function (a) {
+    return typeof a === 'object' && Object.prototype.toString.call(a).toLowerCase() === '[object array]'
+  },
+  isObject: function (a) {
+    return typeof a == 'object' && Object.prototype.toString.call(a).toLowerCase() == '[object object]'
+  },
+  format: function (a) {
+    if (a == null) { return null }
+    typeof a == 'string' && (a = eval('(' + a + ')'))
+    return this._format(a, a, null, null, null)
+  },
+  _randomId: function () {
+    return 'randomId_' + parseInt(1E9 * Math.random())
+  },
+  _getJsonValue: function (a, c) {
+    var d = this._randomId()
+    var b
+    b = '' + ('function' + d + '(root){') + ('return root.' + c + ';')
+    b += '}'
+    b += ''
+    var e = document.createElement('script')
+    e.id = d
+    e.text = b
+    document.body.appendChild(e)
+    d = window[d](a)
+    e.parentNode.removeChild(e)
+    return d
+  },
+
+  _format: function (a, c, d, b, e) {
+    d || (d = '')
+    if (this.isObject(c)) {
+      if (c.$ref) {
+        var g = c.$ref
+        g.indexOf('$.') == 0 &&
+              (b[e] = this._getJsonValue(a, g.substring(2)))
+        return
+      }
+      for (var f in c) {
+        b = d, b != '' && (b += '.'), g = c[f], b += f, this
+          ._format(a, g, b, c, f)
+      }
+    } else if (this.isArray(c)) {
+      for (f in c) {
+        b = d, g = c[f], b = b + '[' + f + ']', this._format(a, g,
+          b, c, f)
+      }
+    }
+    return a
+  }
+}
+module.exports = {
+  FastJson
+}

+ 17 - 0
src/tools/formatData.js

@@ -0,0 +1,17 @@
+const formatCodetoClass = (equipmentAll, str) => {
+  let code1 = str.slice(0, 2)
+  let code2 = str.slice(2, 4)
+  let code3 = str.slice(2, str.length)
+
+  let item1 = equipmentAll.find(i => i.code === code1)
+  if (item1) {
+    let item2 = item1.content.find(i => i.code === code2)
+    if (item2) {
+      let item3 = item2.content.find(i => i.code === code3)
+      return item3 ? item3.facility : ''
+    }
+  }
+}
+module.exports = {
+  formatCodetoClass
+}

+ 47 - 0
src/tools/formatTime.js

@@ -0,0 +1,47 @@
+const formatTime = (str) => {
+  return str.slice(0, 4) + '.' + str.slice(4, 6) + '.' + str.slice(6, 8) + ' ' + str.slice(8, 10) + ':' + str.slice(10, 12)
+}
+const toHourMinute = (minutes) => {
+  return (Math.floor(minutes / 60) >= 24 ? Math.floor(minutes / 60 / 24) + '天' + (Math.floor(minutes / 60 % 24)) : Math.floor(minutes / 60)) + '小时' + (minutes % 60) + '分'
+}
+const secondsToDay = (msd) => {
+  var time = msd
+  if (time > 60 && time < 60 * 60) {
+    time = parseInt(time / 60.0) + '分钟'
+  } else if (time >= 60 * 60 && time < 60 * 60 * 24) {
+    time = parseInt(time / 3600.0) + '小时' + parseInt((parseFloat(time / 3600.0) -
+              parseInt(time / 3600.0)) * 60) + '分钟'
+  } else if (time >= 60 * 60 * 24) {
+    time = parseInt(time / 3600 / 24) + '天' + parseInt((parseFloat(time / 3600 / 24) -
+              parseInt(time / 3600 / 24)) * 24) + '小时' + parseInt((parseFloat(time / 3600.0) -
+              parseInt(time / 3600.0)) * 60) + '分钟'
+  } else {
+    time = 1 + '分钟'
+  }
+  return time
+}
+// 转换成时间戳
+const amendTime = (hms) => {
+  let t = new Date(hms).getTime() / 1000
+  return t
+}
+// 时间戳转换为2019-01-22 12:10:00
+const date = (str) => {
+  let date = str * 1000
+  const dateObj = {
+    year: new Date(date).getFullYear(),
+    month: new Date(date).getMonth() + 1 > 9 ? new Date(date).getMonth() + 1 : `0${new Date(date).getMonth() + 1}`,
+    day: new Date(date).getDate() > 9 ? new Date(date).getDate() : `0${new Date(date).getDate()}`,
+    hour: new Date(date).getHours() > 9 ? new Date(date).getHours() : `0${new Date(date).getHours()}`,
+    minutes: new Date(date).getMinutes() > 9 ? new Date(date).getMinutes() : `0${new Date(date).getMinutes()}`,
+    seconds: new Date(date).getSeconds() > 9 ? new Date(date).getSeconds() : `0${new Date(date).getSeconds()}`
+  }
+  return dateObj.year + "" + dateObj.month + "" + dateObj.day + "" + dateObj.hour + "" + dateObj.minutes + "" + dateObj.seconds
+}
+module.exports = {
+  formatTime,
+  toHourMinute,
+  secondsToDay,
+  amendTime,
+  date
+}

+ 15 - 0
src/tools/systemClass.js

@@ -0,0 +1,15 @@
+const SystemCodetoClass = (equipmentAll, str) => {
+  let code1 = str.slice(0, 2)
+  let code2 = str.slice(2, 4)
+
+  let item1 = equipmentAll.find(i => i.code === code1)
+  if (item1) {
+    let item2 = item1.content.find(i => i.code === code2)
+    if (item2) {
+      return item2 ? item2.system : ''
+    }
+  }
+}
+module.exports = {
+  SystemCodetoClass
+}

+ 126 - 0
src/views/asset/AssetTable.vue

@@ -0,0 +1,126 @@
+<template>
+  <div class="my-table">
+      <div class="my-box">
+           <i-Table stripe  :columns="columns1" :data="tableData" size="large"></i-Table>
+      </div>
+  </div>
+</template>
+
+<script>
+
+// import { formatTime, toHourMinute} from '../../tools/formatTime.js'
+// import {mapActions, mapMutations, mapGetters, mapState} from 'vuex'
+// import axios from 'axios'
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: ['tableData'],
+
+  data () {
+    return {
+      itemsData: {},
+      messageName: [],
+      emailName: [],
+      columns1: [
+        {
+          title: "资产名称",
+          key: "level"
+        },
+        {
+          title: "资产编号",
+          key: "type"
+        },
+        {
+          title: "设备类",
+          key: "content",
+          sortable: true
+        },
+        {
+          title: "未恢复的报警",
+          key: "ctime"
+        },
+        {
+          title: "设备安装时间",
+          key: "duration",
+          className: "description-td"
+        },
+        {
+          title: "操作",
+          key: "deal",
+          render: (h, params) => {
+            return h('div', [
+              h('Button', {
+                props: {
+                  size: 'small'
+                },
+                style: {
+                  marginRight: '5px',
+                  color: '#728DEE',
+                  border: '1px solid #728DEE'
+                },
+                on: {
+                  click: () => {
+                    this.handleClick(params.row)
+                  }
+                }
+              }, '设备详情')
+            ])
+          }
+        }
+      ]
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    handleClick (row) {
+      this.$router.push('asset')
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.my-table {
+    .my-box{
+       background: #fff;
+    }
+}
+</style>
+<style lang="less">
+.my-table{
+    .ivu-table-wrapper {
+    border: none;
+  }
+  .ivu-table td,
+  .ivu-table th {
+    border: none;
+  }
+  .ivu-table:before{
+      height: 0;
+  }
+  .ivu-table:after{
+      width:0;
+  }
+  .ivu-table-row .description-td>.ivu-table-cell>span{
+        // overflow: hidden;
+        // text-overflow: ellipsis;
+        // white-space: nowrap;
+        max-height: 100px;
+        display: inline-block;
+    }
+}
+
+</style>

+ 492 - 0
src/views/asset/index.vue

@@ -0,0 +1,492 @@
+<template>
+  <div class="eq-asset">
+     <div class="vr-left">
+       <p class="left-title">{{Info.infos.EquipLocalName || Info.infos.EquipName}}-{{Info.infos.EquipLocalID || Info.infos.EquipID}}</p>
+       <div class="box-content">
+         <div class="box-left">
+           <table>
+              <tr class="RQ">
+                <td>资产二维码</td>
+                <td class="qr-code">
+                  <img :src="Info.infos.EquipQRCode?`/data-platform-3/image-service/common/file_get?systemId=dataPlatform&key=${Info.infos.EquipQRCode}`:'/static/img/noimg.png'">
+                   <p class="download" v-if="Info.infos.EquipQRCode"   @click="downloadFile(Info.infos.EquipQRCode)">下载</p>
+                </td>
+                <td><p v-if="Info.infos.InsuranceNum_his">保险保单 <span >{{Info.infos.InsuranceNum_his.length || 0 }}份</span></p><p v-if="Info.infos.InstallDrawing_his">资产图纸 <span>{{Info.infos.InstallDrawing_his.length || 0 }}份</span></p></td>
+                <td><p class="load" v-if="Info.infos.InsuranceNum" @click="downloadFile(2,Info.infos.InsuranceNum)">保险文件下载</p><p class="load" v-if="Info.infos.InstallDrawing"  @click="downloadFile(2,Info.infos.InstallDrawing)">图纸下载</p></td>
+              </tr>
+              <tr>
+                <td>品牌:</td>
+                <td>{{Info.infos.Brand || '--'}}</td>
+                <td>生产厂家:</td>
+                <td>{{Info.infos.Manufacturer || '--'}}</td>
+              </tr>
+              <tr>
+                <td>型号:</td>
+                <td>{{Info.infos.Specification || '--'}}</td>
+                <td>生产日期:</td>
+                <td>{{Info.infos.ProductDate || '--'}}</td>
+              </tr>
+              <tr>
+                <td>采购价格:</td>
+                <td>{{Info.infos.PurchasePrice || '--'}} 元</td>
+                <td>供应商单位名称:</td>
+                <td>{{Info.infos.Supplier || '--'}}</td>
+              </tr>
+              <tr>
+                <td>主体材质:</td>
+                <td>{{Info.infos.Material || '--'}}</td>
+                <td>供应商联系人:</td>
+                <td>{{Info.infos.SupplierContactor || '--'}}</td>
+              </tr>
+              <tr>
+                <td>所属部门:</td>
+                <td>{{Info.infos.Dept || '--'}}</td>
+                <td>供应商联系电话:</td>
+                <td>{{Info.infos.SupplierPhone || '--'}}</td>
+              </tr>
+              <tr>
+                <td>投产日期:</td>
+                <td>{{Info.infos.StartDate || '--'}}</td>
+                <td>保险单号:</td>
+                <td>{{Info.infos.InsuranceNum || '--'}}</td>
+              </tr>
+              <tr>
+                <td>使用寿命:</td>
+                <td>{{Info.infos.ServiceLife || '--'}}</td>
+                <td>保险公司:</td>
+                <td>{{Info.infos.Insurer || '--'}}</td>
+              </tr>
+              <tr>
+                <td>维修联系人:</td>
+                <td>{{Info.infos.MaintainerContactor || '--'}}</td>
+                <td>保险联系人:</td>
+                <td>{{Info.infos.InsurerContactor || '--'}}</td>
+              </tr>
+              <tr>
+                <td>维修联系电话:</td>
+                <td>{{Info.infos.MaintainerPhone || '--'}}</td>
+                <td>保险联系电话:</td>
+                <td>{{Info.infos.InsurerPhone || '--'}}</td>
+              </tr>
+          </table>
+
+          <p class="more" @click="getMoreInfo(Info)">查看更多<img src="/static/img/more.png"></p>
+         </div>
+           <div class="box-right" >
+           <div class="pic-con">
+             <div v-if="Info.infos.Pic && Info.infos.Pic[0] && Info.infos.Pic[0].type=='panorama'">
+               <div id="container" >
+              </div>
+             </div>
+             <div class="image-content" v-if="Info.infos.Pic && keySrc">
+               <img :src="`/data-platform-3/image-service/common/image_get?systemId=dataPlatform&key=${keySrc}`">
+             </div>
+
+               <div class="no-right" v-else>
+                  <img src="/static/img/no_pic.png" alt="">
+                  <br/><br/>
+                  <p>暂无图片</p>
+              </div>
+           </div>
+            <div class="swip-container" v-if="Info.infos.Pic && Info.infos.Pic.length>0" >
+              <pic-swipe :list='Info.infos.Pic' @onClick="isPanorama">
+              </pic-swipe>
+            </div>
+             <div class="swip-nocontainer" v-else>
+               <div class="none">
+                  <img src="/static/img/no_pic.png" alt="">
+                  <br/><br/>
+                  <p>暂无图片</p>
+               </div>
+            </div>
+          </div>
+       </div>
+       <div class="box-bottom">
+          <Collapse v-model="panelValue" accordion>
+              <Panel name="1">
+                  历史安装在此处的资产
+                  <p slot="content">
+                    <asset-table :tableData='tableData'></asset-table>
+                  </p>
+              </Panel>
+          </Collapse>`
+       </div>
+     </div>
+     <div class="vr-right">
+      <eq-right :linkEq='linkEq' :moniData='moniData'></eq-right>
+     </div>
+     <div class="mask-bg"></div>
+     <div class="mask">
+       <message-modal @close='close' :isQR='isQR'></message-modal>
+     </div>
+  </div>
+</template>
+
+<script>
+import PicSwipe from '../vr/PicSwipe'
+import assetTable from './AssetTable'
+import eqRight from '../vr/EqRight'
+import messageModal from '../spread/MessageModal'
+import axios from 'axios'
+export default {
+  components: {
+    PicSwipe,
+    assetTable,
+    eqRight,
+    messageModal
+  },
+
+  mixins: [],
+
+  props: {
+
+  },
+
+  data () {
+    return {
+      panelValue: '',
+      list: [],
+      tableData: [],
+      keySrc: "",
+      Info: {
+        infos: {
+          EquipLocalName: '--',
+          EquipLocalID: '--',
+          EquipQRCode: '',
+          Manufacturer: '--',
+          ProductDate: '--',
+          Specification: '--',
+          SerialNum: '--',
+          BIMID: '--',
+          Pic: [],
+          Supplier: '--',
+          PurchasePrice: '--',
+          InstallLocation: '--',
+          StartDate: '--',
+          SupplierContactor: '--',
+          InsuranceNum: '',
+          MaintainerPhone: '--',
+          Insurer: '--',
+          Maintainer: '--',
+          InsurerContactor: '--',
+          InsurerPhone: '--',
+          Principal: '--'
+        },
+        location: {
+          building: '--',
+          floor: '--'
+        }
+      },
+      bdObjName: '--',
+      flObjName: '--',
+      sysObjName: "--",
+      isQR: 1,
+      objctId: 'Pe00ce06da7b8c49f4b9e2012a59f1bf3d',
+      objArr: [],
+      linkEq: "", // 资产相关设备
+      moniData: 0 // 摄像头
+    }
+  },
+
+  computed: {
+  },
+
+  mounted () {
+    this.getAssetData()
+  },
+  watch: {
+
+  },
+
+  methods: {
+    // 摄像头
+    getMoniCount () {
+      let params = {
+        id: this.linkEq
+      }
+      axios.post(`/api/front-api/monitor/list?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.moniData = data.count
+        }
+      })
+    },
+    // 判断显示全景图还是大图
+    isPanorama (item) { // panorama
+      if (item.type == 'image') {
+        this.keySrc = item.key
+      }
+      if (item.type == 'panorama') {
+        this.draw(item.key)
+      }
+    },
+    // 获取去资产信息
+    getAssetData () {
+      let params = {
+        criterias: [
+          {id: this.objctId}
+        ],
+        'historyInfos': true
+      }
+      axios.post(`/data-platform-3/data-platform-3/property/id_query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result === 'success') {
+          this.Info = data.Content[0]
+          if (this.Info.infos.Pic && this.Info.infos.Pic.length > 0) {
+            if (this.Info.infos.Pic[0].type == 'image') {
+              this.keySrc = this.Info.infos.Pic[0].key
+            }
+            if (this.Info.infos.Pic[0].type == 'panorama') {
+              this.draw(this.Info.infos.Pic[0].key)
+            }
+          }
+          if (this.Info.relation && this.Info.relation.link) {
+            this.linkEq = this.Info.relation.link
+            this.getMoniCount()
+          }
+        }
+      })
+    },
+    // 查看更多的点击事件
+    getMoreInfo (Info) {
+      this.$router.push({path: 'check', query: {obj: JSON.stringify(Info)}})
+    },
+    // 查看全景图
+    draw (key) {
+      var photosphere = document.getElementById('container')
+      // eslint-disable-next-line
+      var PSV = new PhotoSphereViewer({
+        panorama: `/data-platform-3/image-service/common/image_get?systemId=dataPlatform&key=${key}`,
+        container: photosphere,
+        time_anim: false,
+        navbar: true,
+        size: {
+          width: '100%',
+          height: '440px'
+        }
+      })
+    },
+    // 下载文件的弹框
+    downloadFile (isQR, objArr) {
+      this.isQR = isQR
+      this.objArr = objArr
+      document.querySelector('body').style.overflow = 'hidden'
+      document.querySelector('.mask-bg').style.display = 'block'
+      document.querySelector('.mask').style.display = 'block'
+    },
+    close () {
+      document.querySelector('body').style.overflow = 'auto'
+      document.querySelector('.mask-bg').style.display = 'none'
+      document.querySelector('.mask').style.display = 'none'
+    }
+
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.eq-asset {
+        font-size: 16px;
+        margin: 0;
+        display: flex;
+        .vr-left {
+          width: 78%;
+          min-width: 1050px;
+          background: #fff;
+          box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+          border-radius: 2px;
+          margin-right: 20px;
+          padding:20px 20px 0 20px;
+          .left-title {
+            font-size: 18px;
+            font-weight: bold;
+            color: #212830;
+            >span {
+              font-size: 14px;
+              color: #6D747C;
+              margin-left: 34px;
+            }
+          }
+          .left-remark {
+            font-size: 14px;
+            color: #6D747C;
+          }
+          .box-content {
+            width: 100%;
+            display: flex;
+            justify-content:space-between;
+            .box-left {
+              width:50%;
+              min-width: 500px;
+              background: #F5F5F5;
+              border-radius: 2px;
+              margin-right: 20px;
+              display: inline-block;
+              padding-top: 20px;
+              position: relative;
+              .more {
+                position: absolute;
+                font-size: 16px;
+                color: #6682E6;
+                bottom: 13px;
+                right: 20px;
+                cursor: pointer;
+              }
+              tr {
+                td {
+                  padding-left:20px;
+                  padding-top: 8px;
+                  font-size: 14px;
+                  color: #6D747C;
+                  line-height: 24px;
+                  word-break: break-word;
+                  >img {
+                     width:90px;
+                     height: 90px;
+                  }
+                  .load {
+                    color: #6682E6;
+                    cursor: pointer;
+                  }
+                  p{
+                    >span {
+                        color:#212830;
+                    }
+                  }
+                  .download {
+                    font-size: 14px;
+                    color: #6682E6;
+                    cursor: pointer;
+                    padding-left:12px;
+                  }
+                }
+              }
+              .RQ {
+                >td {
+                  vertical-align: top;
+                }
+                .qr-code {
+                  position: relative;
+                  >img:hover + .download {
+                    opacity: 1;
+                  }
+                  .download {
+                    position: absolute;
+                    bottom: 0;
+                    background: rgba(255, 255, 255, .9);
+                    width: 80px;
+                    height: 30px;
+                    line-height: 30px;
+                    z-index: 10;
+                    text-align: center;
+                    color: #6682E6;
+                    font-size: 14px;
+                    cursor: pointer;
+                    opacity: 0;
+                  }
+                }
+              }
+            }
+            .no-right {
+                width: 100%;
+                background: #F5F5F5;
+                border-radius: 2px;
+                height: 440px;
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                flex-direction: column;
+            }
+            .box-right {
+              display: inline-block;
+              width: 50%;
+              background: #fff;
+              border-radius: 2px;
+              .pic-con {
+                background: #F5F5F5;
+                color:#6D747C;
+                #container {
+                  width: 100%;
+                  height: 440px;
+                  display: flex;
+                  justify-content: center;
+                  align-items: center;
+                  cursor: pointer;
+                }
+                .image-content{
+                  >img{
+                    width: 100%;
+                    height: 440px;
+                  }
+                }
+              }
+              .swip-container{
+                margin-top: 20px;
+                height: 152px;
+                color:#6D747C;
+              }
+              .swip-nocontainer{
+                margin-top: 20px;
+                height: 152px;
+
+                color:#6D747C;
+               .none{
+                 width:180px;
+                 height: 152px;
+                 background: #F5F5F5;
+                 border-radius: 2px;
+                 text-align: center;
+                 padding-top: 35px;
+                 color: #6D747C;
+               }
+              }
+            }
+          }
+          .box-bottom{
+            margin:40px 0;
+          }
+        }
+        .vr-right{
+          width: 21%;
+          border-radius: 2px;
+          display: inline-block;
+        }
+        .mask-bg{
+          position: fixed;
+          top: 0;
+          bottom: 0;
+          left: 0;
+          right: 0;
+          z-index: 99;
+          background:rgba(0, 0, 0, .6);
+          display: none;
+        }
+        .mask {
+          width: 860px;
+          height: 458px;
+          background: #fff;
+          position: fixed;
+          z-index: 999;
+          top: 120px;
+          left: 30%;
+          display: none;
+        }
+    }
+
+</style>
+<style lang="less">
+ .eq-asset {
+   .box-bottom{
+     .ivu-icon-ios-arrow-forward {
+        float: right;
+        margin-top: 10px;
+        transform: rotate(-90deg);
+    }
+    .ivu-collapse>.ivu-collapse-item>.ivu-collapse-header{
+        background: #F4F5F8;
+        border-radius: 2px;
+      }
+   }
+ }
+</style>

+ 573 - 0
src/views/check/index.vue

@@ -0,0 +1,573 @@
+<template>
+  <div class="detail-info">
+      <div class="eq-top">
+           <img src="/static/img/backIcon.jpg" alt="" @click="back">
+           <span>返回 </span>
+      </div>
+      <div class="detail-content">
+          <div class="content-top">
+              <p>{{eqMaterial.infos.EquipLocalName || '--'}}详情</p>
+              <div><Checkbox v-model="isData" label="只显示有数据的信息" name="type" @on-change="onChange"></Checkbox>只显示有数据的信息</div>
+          </div>
+          <hr>
+          <div class="content-bottom">
+              <div class="content-left">
+                  <div>
+                       <ul v-for="(list,index1) in mainInfo" :key='index1' :class="{changeStyle:changeColor == index1}"
+                      @click="change(index1)"><a :href="`#${list.href}`">{{list.name}}</a>
+                        <template  v-if="list.list">
+                            <li v-for="(item,index2) in list.list" :key="index2" :class="{color:changeColor == index1 && liIndex == index2}"  @click="changeLi(index2)"><a :href="`#${item.href}`">{{item.name}}</a></li>
+                        </template>
+                      </ul>
+                  </div>
+              </div>
+              <div class="content-right" @scroll="handleScroll">
+                  <section>
+                    <p id="baseInfo" class="group1"><span></span>基本信息</p>
+                    <ul>
+                        <li><span>设备ID</span>{{eqMaterial.infos.EquipID || '--'}}</li>
+                        <li><span>设备二维码图片</span><i v-if="eqMaterial.infos.EquipQRCode" @click="lookAt">查看</i></li>
+                        <li><span>设备名称</span>{{eqMaterial.infos.EquipName || '--'}}</li>
+                        <li><span>BIM模型中编码</span>{{eqMaterial.infos.BIMID || '--'}}</li>
+                        <li><span>设备本地编码</span>{{eqMaterial.infos.EquipLocalID || '--'}}</li>
+                        <li><span>BIM模型中坐标</span>{{eqMaterial.infos.BIMLocation || '--'}}</li>
+                        <li><span>设备本地名称</span>{{eqMaterial.infos.EquipLocalName || '--'}}</li>
+                    </ul>
+                  </section>
+
+                  <section>
+                    <p id="standInfo" class="group1"><span></span>台账信息</p>
+                    <p id="001" class="p-title">设备厂家</p>
+                    <ul >
+                        <li><span>生产厂家</span>{{eqMaterial.infos.Manufacturer || '--'}}</li>
+                        <li><span>品牌</span>{{eqMaterial.infos.Brand || '--'}}</li>
+                        <li><span>生产日期</span>{{eqMaterial.infos.ProductDate || '--'}}</li>
+                        <li><span>设备型号</span>{{eqMaterial.infos.Specification || '--'}}</li>
+                        <li><span>出厂编号</span>{{eqMaterial.infos.SerialNum || '--'}}</li>
+                    </ul>
+                    <p id="002" class="p-title">供应&购买</p>
+                    <ul>
+                        <li><span>供应商单位名称</span>{{eqMaterial.infos.Supplier || '--'}}</li>
+                        <li><span>供应商联系人</span>{{eqMaterial.infos.SupplierContactor || '--'}}</li>
+                        <li><span>供应商联系电话</span>{{eqMaterial.infos.SupplierPhone || '--'}}</li>
+                        <li><span>供应商电子邮件</span>{{eqMaterial.infos.SupplierEmail || '--'}}</li>
+                        <li><span>供应商网址</span>{{eqMaterial.infos.SupplierWeb || '--'}}</li>
+                        <li><span>供应商传真</span>{{eqMaterial.infos.SupplierFax || '--'}}</li>
+                        <li><span>供应合同编号</span>{{eqMaterial.infos.SupplierContractID || '--'}}</li>
+                        <li><span>资产编号</span>{{eqMaterial.infos.AssetID || '--'}}</li>
+                        <li><span>采购价格</span>{{eqMaterial.infos.PurchasePrice || '--'}}</li>
+                    </ul>
+                    <p id="003" class="p-title"> 现场&安装</p>
+                    <ul >
+                        <li><span>长</span>{{eqMaterial.infos.Length || '--'}} m</li>
+                        <li><span>宽</span>{{eqMaterial.infos.Width || '--'}} m</li>
+                        <li><span>高</span>{{eqMaterial.infos.Height || '--'}} m</li>
+                        <li><span>净重</span>{{eqMaterial.infos.NetWeight || '--'}} kg</li>
+                        <li><span>主体材质</span>{{eqMaterial.infos.Material || '--'}}</li>
+                        <li><span>所属部门</span>{{eqMaterial.infos.InstallLocation || '--'}}</li>
+                        <li><span>安装位置</span>{{eqMaterial.infos.Width || '--'}}</li>
+                    </ul>
+                    <p id="004" class="p-title"> 运行&维保</p>
+                    <ul >
+                        <li><span>维保负责人</span>{{eqMaterial.infos.Principal || '--'}}</li>
+                        <li><span>投产日期</span>{{eqMaterial.infos.StartDate || '--'}}</li>
+                        <li><span>保修期</span>{{eqMaterial.infos.Warranty || '--'}}</li>
+                        <li><span>维保合同截止日期</span>{{eqMaterial.infos.MaintainDeadline || '--'}}</li>
+                        <li><span>使用寿命</span>{{eqMaterial.infos.ServiceLife || '--'}}</li>
+                        <li><span>预计报废日期</span>{{eqMaterial.infos.ExpectScrapDate || '--'}}</li>
+                        <li><span>保养周期</span>{{eqMaterial.infos.MaintainPeriod || '--'}}</li>
+                        <li><span>维修商单位名称</span>{{eqMaterial.infos.Maintainer || '--'}}</li>
+                        <li><span>维修商联系人</span>{{eqMaterial.infos.MaintainerContactor || '--'}}</li>
+                        <li><span>维修商联系电话</span>{{eqMaterial.infos.MaintainerPhone || '--'}}</li>
+                        <li><span>维修商电子邮件</span>{{eqMaterial.infos.MaintainerEmai || '--'}}</li>
+                        <li><span>维修商网址</span>{{eqMaterial.infos.MaintainerWeb || '--'}}</li>
+                        <li><span>维修商传真</span>{{eqMaterial.infos.MaintainerFax || '--'}}</li>
+                    </ul>
+                    <p id="005" class="p-title"> 保险</p>
+                    <ul >
+                        <li><span>保险公司名称</span>{{eqMaterial.infos.Insurer || '--'}}</li>
+                        <li><span>保险公司联系人</span>{{eqMaterial.infos.InsurerContactor || '--'}}</li>
+                        <li><span>保险公司联系电话</span>{{eqMaterial.infos.InsurerPhone || '--'}}</li>
+                        <li><span>保险公司电子邮件</span>{{eqMaterial.infos.InsurerEmail || '--'}}</li>
+                        <li><span>保险公司网址</span>{{eqMaterial.infos.InsurerWeb || '--'}}</li>
+                        <li><span>保险公司传真</span>{{eqMaterial.infos.InsurerFax || '--'}}</li>
+                        <li><span>保险单号</span>{{eqMaterial.infos.InsuranceNum || '--'}}</li>
+                        <li><span>保险文件</span>{{eqMaterial.infos.InsuranceFile || '--'}}</li>
+                    </ul>
+                    <p id="006" class="p-title">照片&文档</p>
+                    <ul>
+                        <li v-if="eqMaterial.infos.Nameplate"><span>设备铭牌照片</span>{{eqMaterial.infos.Nameplate[0].key?eqMaterial.infos.Nameplate[0].key:'--'}}</li>
+                    </ul>
+                  </section>
+
+                 <section>
+                    <p id="controlInfo"><span></span>控制参数</p>
+                    <ul>
+                        <li><span>控制模式</span>{{eqMaterial.infos.CtrlMode || '--'}}</li>
+                    </ul>
+                 </section>
+
+                 <section>
+                    <p id="setInfo"><span></span>设定参数</p>
+                    <ul>
+                        <li><span>设备开关设定</span>{{eqMaterial.infos.EquipSwitchSet || '--'}}</li>
+                        <li><span>设备开设定</span>{{eqMaterial.infos.EquipOnSet || '--'}}</li>
+                        <li><span>设备关设定</span>{{eqMaterial.infos.EquipOffSet || '--'}}</li>
+                        <li><span>设备频率设定</span>{{eqMaterial.infos.EquipFreqSet || '--'}}</li>
+                        <li><span>设备开度设定</span>{{eqMaterial.infos.EquipOpeningSet || '--'}}</li>
+                    </ul>
+                 </section>
+
+                  <section>
+                    <p id="technologyInfo"><span></span>技术参数</p>
+                    <ul>
+                        <li><span>额定电压</span>{{eqMaterial.infos.RatedU || '--'}} V</li>
+                        <li><span>额定电流</span>{{eqMaterial.infos.RatedI || '--'}} A</li>
+                        <li><span>额定功率</span>{{eqMaterial.infos.RatedP || '--'}} kW</li>
+                        <li><span>额定频率</span>{{eqMaterial.infos.RatedFreq || '--'}} Hz</li>
+                        <li><span>累计运行时间</span>{{eqMaterial.infos.AccRunTime || '--'}} h</li>
+                        <li><span>水泵类型</span>{{eqMaterial.infos.PumpType || '--'}}</li>
+                        <li><span>泵体安装类型</span>{{eqMaterial.infos.InstallType || '--'}}</li>
+                        <li><span>输配介质</span>{{eqMaterial.infos.MediumType || '--'}}</li>
+                        <li><span>调节类型</span>{{eqMaterial.infos.AdjustType || '--'}}</li>
+                        <li><span>管网使用类型</span>{{eqMaterial.infos.NetUseType || '--'}}</li>
+                        <li><span>是否为备用泵</span>{{eqMaterial.infos.isBackup || '--'}}</li>
+                        <li><span>额定扬程</span>{{eqMaterial.infos.RatedHead || '--'}} m</li>
+                        <li><span>额定驱动压力</span>{{eqMaterial.infos.RatedDrivePress || '--'}} MPa</li>
+                        <li><span>额定增压比</span>{{eqMaterial.infos.RatedPressRatio || '--'}}</li>
+                        <li><span>额定转速</span>{{eqMaterial.infos.RatedRPM || '--'}} rpm</li>
+                    </ul>
+                  </section>
+
+                  <section>
+                    <p id="operationInfo"><span></span>运行参数</p>
+                    <p id="101" class="p-title">运行状态</p>
+                    <ul>
+                        <li><span>运行状态</span>{{eqMaterial.infos.RunStatus || '--'}}</li>
+                        <li><span>本地远程状态</span>{{eqMaterial.infos.RemoteStatus || '--'}}</li>
+                        <li><span>A相电压</span>{{eqMaterial.infos.APhaseU || '--'}} V</li>
+                        <li><span>B相电压</span>{{eqMaterial.infos.BPhaseU || '--'}} V</li>
+                        <li><span>C相电压</span>{{eqMaterial.infos.CPhaseU || '--'}} V</li>
+                        <li><span>A相电流</span>{{eqMaterial.infos.APhaseI || '--'}} A</li>
+                        <li><span>B相电流</span>{{eqMaterial.infos.BPhaseI || '--'}} A</li>
+                        <li><span>C相电流</span>{{eqMaterial.infos.CPhaseI || '--'}} A</li>
+                        <li><span>耗电功率</span>{{eqMaterial.infos.ElecConsumP || '--'}} kW</li>
+                        <li><span>水泵进口压力</span>{{eqMaterial.infos.InPress || '--'}} MPa</li>
+                        <li><span>水泵出口压力</span>{{eqMaterial.infos.OutPress || '--'}} MPa</li>
+                        <li><span>电机效率</span>{{eqMaterial.infos.MotorEff || '--'}} %</li>
+                        <li><span>瞬时增压比</span>{{eqMaterial.infos.PressRatio || '--'}}</li>
+                        <li><span>整体效率</span>{{eqMaterial.infos.OverallEff || '--'}} %</li>
+                    </ul>
+                    <p id="102" class="p-title">累计参数</p>
+                    <ul>
+                        <li><span>累计流量</span>{{eqMaterial.infos.AccFlow || '--'}} m³</li>
+                        <li><span>累计耗电量</span>{{eqMaterial.infos.AccElecConsum || '--'}} kWh</li>
+                        <li><span>累计运行时间</span>{{eqMaterial.infos.AccRunTime || '--'}} h</li>
+                        <li><span>开启时间计时</span>{{eqMaterial.infos.OpenTimeCount || '--'}} h</li>
+                        <li><span>关闭时间计时</span>{{eqMaterial.infos.CloseTimeCount || '--'}} h</li>
+                    </ul>
+                  </section>
+
+                  <section style="min-height: 590px">
+                    <p id="eneryInfo"><span></span>能耗信息</p>
+                    <enery-params v-show="eqMaterial" :roomInfo='eqMaterial' :isShowChange='isShowChange'></enery-params>
+                  </section>
+              </div>
+          </div>
+      </div>
+      <div class="mask-bg"></div>
+     <div class="mask">
+       <message-modal @close='close' :isQR='isQR'></message-modal>
+     </div>
+  </div>
+</template>
+
+<script>
+import eneryParams from '../detail/EneryParams'
+import messageModal from '../spread/MessageModal.vue'
+import axios from 'axios'
+export default {
+  components: {
+    eneryParams,
+    messageModal
+  },
+
+  mixins: [],
+
+  props: {
+
+  },
+
+  data () {
+    return {
+      isData: false,
+      isShowChange: false,
+      eqMaterial: {
+        infos: {
+          EquipLocalName: "--",
+          EquipName: "--",
+          EquipID: "--",
+          EquipLocalID: "--",
+          EquipQRCode: "--",
+          Manufacturer: "--",
+          ProductDate: "--",
+          Specification: "--",
+          SerialNum: "--",
+          BIMID: "--",
+          Supplier: "--",
+          PurchasePrice: "--",
+          InstallLocation: "--",
+          StartDate: "--",
+          SupplierContactor: "--",
+          InsuranceNum: "--",
+          MaintainerPhone: "--",
+          Insurer: "--",
+          Maintainer: "--",
+          InsurerContactor: "--",
+          InsurerPhone: "--",
+          Principal: "--",
+          Nameplate: [{key: "--"}]
+        },
+        location: {
+          building: "--",
+          floor: "--"
+        }
+      },
+      isQR: "",
+      changeColor: 0,
+      liIndex: -1,
+      mainInfo: [
+        {name: "基本信息", href: "baseInfo"},
+        {
+          name: "台账信息",
+          href: "standInfo",
+          list: [
+            {name: "设备厂家", href: "001"},
+            {name: "供应&购买", href: "002"},
+            {name: "现场&安装", href: "003"},
+            {name: "运行&维保", href: "004"},
+            {name: "保险", href: "005"},
+            {name: "照片&文档", href: "006"}
+          ]},
+        {name: "控制参数", href: "controlInfo"},
+        {name: "设定参数", href: "setInfo"},
+        {name: "技术参数", href: "technologyInfo"},
+        {
+          name: "运行参数",
+          href: "operationInfo",
+          list: [
+            {name: "运行状态", href: "101"},
+            {name: "累计参数", href: "102"}
+          ]
+        },
+        {name: "能耗信息", href: "eneryInfo"}
+      ],
+      groups: [],
+      box: null
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+    this.getObjInfo()
+    this.$nextTick(() => {
+      this.box = document.querySelector(".content-right")
+      this.groups = document.querySelectorAll(".content-right>section")
+    })
+  },
+
+  methods: {
+    getCurrentData () {
+      let params = {
+        criterias: [
+          {
+            id: this.eqMaterial.id,
+            code: "ElecConsumP"
+          },
+          {
+            id: this.eqMaterial.id,
+            code: "AccElecConsum"
+          }
+        ]
+      }
+      axios.post(`/data-platform-3/data-platform-3/parameter/batch_query_param?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          let content = data.Content
+          content.forEach(el => {
+            if (el.code == 'ElecConsumP') {
+              this.ElecConsumPData = el.data
+            }
+            if (el.code == 'AccElecConsum') {
+              this.AccElecConsumData = el.data
+            }
+          })
+        }
+      })
+    },
+    change (index) {
+      this.changeColor = index
+    },
+    changeLi (index2) {
+      this.liIndex = index2
+    },
+    // 路由传参得到Info
+    getObjInfo () {
+      this.eqMaterial = JSON.parse(this.$route.query.obj)
+      this.getCurrentData()
+    },
+    back () {
+      history.go(-1)
+    },
+    // 下载弹框
+    lookAt () {
+      this.isQR = this.eqMaterial.infos.EquipQRCode
+      document.querySelector('body').style.overflow = 'hidden'
+      document.querySelector('.mask-bg').style.display = 'block'
+      document.querySelector('.mask').style.display = 'block'
+    },
+    close () {
+      document.querySelector('body').style.overflow = 'auto'
+      document.querySelector('.mask-bg').style.display = 'none'
+      document.querySelector('.mask').style.display = 'none'
+    },
+    onChange (val) {
+      if (val) {
+        this.hiddenNoData()
+      } else {
+        this.showAllData()
+      }
+    },
+    hiddenNoData () {
+      this.isShowChange = true
+      let arr = document.querySelectorAll('.content-right li')
+      arr.forEach(i => {
+        if (i.innerHTML.includes('--')) {
+          i.style.display = 'none'
+        }
+      })
+    },
+    // 只显示有数据的
+    showAllData () {
+      this.isShowChange = false
+      let arr = document.querySelectorAll('.content-right li')
+      arr.forEach(i => {
+        i.style.display = 'block'
+      })
+    },
+    // 滚动触发事件
+    handleScroll () {
+      let top = this.box.scrollTop
+      let i = this.groups.length - 1
+      for (; i >= 0; i--) {
+        if (this.groups[i].offsetTop <= top) {
+          this.changeColor = i
+          let pTitles = this.groups[i].querySelectorAll('.p-title')
+          let j = pTitles ? pTitles.length - 1 : 0
+          for (; j >= 0; j--) {
+            if (pTitles[j].offsetTop <= top) {
+              this.liIndex = j
+              break
+            }
+          }
+          break
+        }
+      }
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.detail-info {
+    .eq-top {
+        margin-bottom: 20px;
+        margin-left: 20px;
+        font-size: 7px;
+        color: #212830;
+        >img {
+            //vertical-align: middle;
+            cursor: pointer;
+            border: 1px solid #CACACA;
+            border-radius: 2px;
+        }
+        >span {
+            font-size: 16px;
+            color: #212830;
+        }
+    }
+    .detail-content {
+        box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+        border-radius: 2px;
+        background: #fff;
+        padding-left:20px;
+        .content-top {
+            width: 100%;
+            padding-top: 10px;
+            p {
+                font-size: 18px;
+                color: #212830;
+                font-weight: bold;
+                padding: 24px 0 20px 0;
+            }
+        }
+        hr {
+            margin-bottom: 0;
+        }
+        .content-bottom {
+            display: flex;
+            .content-left {
+                width: 264px;
+                border-radius: 2px;
+                padding-top: 10px;
+                margin-right: 60px;
+                margin-bottom: 20px;
+                background: #FAFAFA;
+                div {
+                    .p-title{
+                        margin-left: 24px ;
+                        margin-bottom: 12px;
+                        border-bottom:1px dashed #cecece;
+                    }
+                    .p-title{
+                        padding: 20px;
+                    }
+                    .group1{
+                      margin-bottom:20px;
+                    }
+                    ul{
+                        font-size: 16px;
+                        padding:5px 0 5px 40px;
+                        font-weight: bold;
+                        cursor: pointer;
+                        a {
+                             color: #212830;
+                            &:hover,&:active {
+                                color:#6682E6;
+                            }
+                        }
+                    li {
+                        font-size: 16px;
+                        padding:18px 0 0 40px;
+                        font-weight: bold;
+                        cursor: pointer;
+                        a{
+                             color: #6D747C;
+                        }
+                         &:first-child {
+                            padding-top: 15px;
+                        }
+                        &:last-child {
+                            padding-bottom: 0;
+                        }
+                    }
+                }
+                }
+            }
+            .content-right {
+                width: 1450px;
+                height: 700px;
+                overflow-y:scroll;
+                padding: 10px;
+                position: relative;
+               section{
+                    p {
+                        height: 40px;
+                        span {
+                            display: inline-block;
+                            width: 4px;
+                            height: 16px;
+                            background: #728DEE;
+                            margin-right: 10px;
+                            vertical-align: middle;
+                        }
+                    }
+                    ul {
+                        display: flex;
+                        flex-wrap: wrap;
+                        margin-left: 10px;
+                        li {
+                            width: 50%;
+                            padding-bottom: 15px;
+                            overflow: hidden;
+                            text-overflow: ellipsis;
+                            white-space: nowrap;
+                            span {
+                                font-size: 14px;
+                                color: #6D747C;
+                                display: inline-block;
+                                width: 98px;
+                                margin-right: 20px;
+                            }
+                            i{
+                                color:#6682E6;
+                                cursor: pointer;
+                            }
+                        }
+                    }
+               }
+            }
+        }
+    }
+    .mask-bg{
+        position: fixed;
+        top: 0;
+        bottom: 0;
+        left: 0;
+        right: 0;
+        z-index: 99;
+        background:rgba(0, 0, 0, .6);
+        display: none;
+    }
+    .mask {
+        width: 860px;
+        height: 458px;
+        background: #fff;
+        position: fixed;
+        z-index: 999;
+        top: 120px;
+        left: 30%;
+        display: none;
+    }
+     .changeStyle{
+        color: #6682E6!important;
+        background: #fff;
+        >a{
+            color: #6682E6!important;
+        }
+    }
+    .color{
+         >a{
+            color: #6682E6!important;
+        }
+    }
+}
+</style>
+<style lang="less">
+.detail-info {
+    .ivu-table-wrapper {
+        border: none;
+    }
+    .ivu-table td,
+    .ivu-table th {
+        border: none;
+    }
+    .ivu-table:before{
+        height: 0;
+    }
+    .ivu-table:after{
+        width:0;
+    }
+    .ivu-table-row .description-td>.ivu-table-cell>span{
+            // overflow: hidden;
+            // text-overflow: ellipsis;
+            // white-space: nowrap;
+            max-height: 100px;
+            display: inline-block;
+    }
+}
+</style>

+ 316 - 0
src/views/detail/EneryParams.vue

@@ -0,0 +1,316 @@
+<template>
+  <div class="en-table">
+        <table class="ivu-table-wrapper stripe ivu-table ivu-table-border ivu-table-stripe" style="position:relative">
+              <div class="">
+                <table class="">
+                  <colgroup></colgroup>
+                  <tr class="ivu-table-row">
+                    <td class="ivu-table-cell " >信息点</td>
+                    <td class="ivu-table-cell" >表号功能号</td>
+                    <td class="ivu-table-cell" >实时数据</td>
+                    <td class="ivu-table-cell" >曲线变化</td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell fixed-td">逐时用电功率</td>
+                    <td class="ivu-table-cell test">{{roomInfo.infos.ElecConsumP || '--'}} </td>
+                    <td class="ivu-table-cell" >{{ ElecConsumPData || '--'}} kW</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.ElecConsumP)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell fixed-td" >逐时用燃气量</td>
+                    <td class="ivu-table-cell test">{{roomInfo.infos.GasConsumP || '--'}}</td>
+                    <td class="ivu-table-cell" >{{GasConsumPData || '--'}} m³/h</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.GasConsumP)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell fixed-td">燃气压力</td>
+                    <td class="ivu-table-cell test">{{roomInfo.infos.GasPress || '--'}}</td>
+                    <td class="ivu-table-cell" >{{GasPressData || '--'}} Pa</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.GasPress)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell fixed-td" >逐时用燃油量</td>
+                    <td class="ivu-table-cell test">{{roomInfo.infos.FuelConsumP || '--'}} </td>
+                    <td class="ivu-table-cell" >{{FuelConsumPData || '--'}} L/h</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.FuelConsumP)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell ">燃油压力</td>
+                    <td class="ivu-table-cell test">{{roomInfo.infos.FuelPress || '--'}}</td>
+                    <td class="ivu-table-cell" >{{FuelPressData || '--'}} MPa</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.FuelPress)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell ">逐时用水量</td>
+                    <td class="ivu-table-cell test">{{roomInfo.infos.WaterConsumP || '--'}}</td>
+                    <td class="ivu-table-cell" >{{WaterConsumPData || '--'}} m³/h</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.WaterConsumP)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell">自来水压力</td>
+                    <td class="ivu-table-cell test">{{roomInfo.infos.WaterPress || '--'}}</td>
+                    <td class="ivu-table-cell" >{{WaterPressData || '--'}} MPa</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.WaterPress)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell " >逐时用热量</td>
+                    <td class="ivu-table-cell test">{{roomInfo.infos.HeatConsumP || '--'}}</td>
+                    <td class="ivu-table-cell" >{{HeatConsumPData || '--'}} kW</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.HeatConsumP)">查看</button></td>
+                  </tr>
+                </table>
+               </div>
+          </table>
+          <div class="mask-bg"></div>
+          <div class="mask-layout">
+            <p class="box-title">详细信息<Icon type="md-close" class='close-btn' @click="closeMask"/></p>
+            <alarm-charts v-if="charts" :charts='charts'></alarm-charts>
+          </div>
+  </div>
+</template>
+
+<script>
+import axios from 'axios'
+import {formatTime} from '../../tools/formatTime.js'
+// import {currentTime} from '../../tools/currentDate.js'
+import alarmCharts from '../main/AlarmCharts'
+export default {
+  components: {
+    alarmCharts
+  },
+
+  mixins: [],
+
+  props: {
+    roomInfo: {
+      type: Object
+    },
+    isShowChange: {
+      type: Boolean
+    }
+  },
+
+  data () {
+    return {
+      ElecConsumPData: "--",
+      GasConsumPData: "--",
+      GasPressData: "--",
+      FuelConsumPData: "--",
+      FuelPressData: "--",
+      WaterConsumPData: "--",
+      WaterPressData: "--",
+      HeatConsumPData: "--",
+      charts: []
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+    this.$nextTick(function () {
+      this.getCurrentData()
+    })
+  },
+  watch: {
+    isShowChange (newv, oldv) {
+      if (newv) {
+        this.changeDisplayNone()
+      } else {
+        this.changeDisplayBlock()
+      }
+    }
+  },
+  methods: {
+    getCurrentData () {
+      let params = {
+        criterias: [
+          {
+            id: this.roomInfo.id,
+            code: "ElecConsumP"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "GasConsumP"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "GasPress"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "FuelConsumP"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "FuelPress"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "WaterConsumP"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "WaterPress"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "HeatConsumP"
+          }
+        ]
+      }
+      axios.post(`/data-platform-3/data-platform-3/parameter/batch_query_param?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          let content = data.Content
+          content.forEach(el => {
+            if (el.code == 'ElecConsumP') {
+              this.ElecConsumPData = el.data
+            }
+            if (el.code == 'GasConsumP') {
+              this.GasConsumPData = el.data
+            }
+            if (el.code == 'GasPress') {
+              this.GasPressData = el.data
+            }
+            if (el.code == 'FuelConsumP') {
+              this.FuelConsumPData = el.data
+            }
+            if (el.code == 'FuelPress') {
+              this.FuelPressData = el.data
+            }
+            if (el.code == 'WaterConsumP') {
+              this.WaterConsumPData = el.data
+            }
+            if (el.code == 'WaterPress') {
+              this.WaterPressData = el.data
+            }
+            if (el.code == 'HeatConsumP') {
+              this.HeatConsumPData = el.data
+            }
+          })
+        }
+      })
+    },
+    changeDisplayNone () {
+      let arr = document.querySelectorAll('.en-table .test')
+      arr.forEach(i => {
+        if (i.innerHTML.includes('--')) {
+          i.parentNode.style.display = 'none'
+        }
+      })
+    },
+    changeDisplayBlock () {
+      let arr = document.querySelectorAll('.en-table .test')
+      arr.forEach(i => {
+        if (i.innerHTML.includes('--')) {
+          i.parentNode.style.display = 'table-row'
+        }
+      })
+    },
+    closeMask () {
+      document.querySelector(".mask-bg").style.display = 'none'
+      document.querySelector(".mask-layout").style.display = 'none'
+    },
+    // 得到图的数据
+    getBoundData (code) {
+      document.querySelector(".mask-bg").style.display = 'block'
+      document.querySelector(".mask-layout").style.display = 'block'
+      let params = {
+        criteria: {
+          // id: this.roomInfo.id,
+          id: "Sp1101080001001004013",
+          // code:code,
+          code: "CO2", // 信息点编码
+          // period: period,
+          period: "5min",
+          // receivetime:receivetime,
+          receivetime: {
+            $gte: "20190110000000",
+            $lt: "20190111000000"
+          }
+        }
+      }
+      axios.post(`/data-platform-3/data-platform-3/hisdata/query_period_data?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.charts = data.Content
+          this.charts.forEach(el => {
+            el.time = formatTime(el.data_time)
+            el.value = parseInt(el.data_value)
+          })
+        }
+      })
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.en-table {
+    width:95%;
+    margin-bottom: 38px;
+    table{
+      width: 100%;
+      font-size: 14px;
+    }
+    tr:nth-child(2n)>td{
+        background: #f5f5f5;
+    }
+    td {
+        width:30%;
+        .look-btn{
+            color:#6682E6;
+            background:none;
+        }
+    }
+    .mask-bg {
+      position: fixed;
+      top: 0;
+      bottom: 0;
+      left: 0;
+      right: 0;
+      z-index: 99;
+      background:rgba(0, 0, 0, .6);
+      display: none;
+    }
+   .mask-layout{
+      width: 680px;
+      height: 480px;
+      background: #fff;
+      box-shadow: 0 2px 8px 0 rgba(0,0,0,0.12);
+      border-radius: 4px;
+      z-index: 999;
+      position: fixed;
+      top: 230px;
+      left: 50%;
+      margin-left: -360px;
+      display: none;
+      .box-title {
+        line-height: 60px;
+        height: 60px;
+        font-size: 16px;
+        color: #FFFFFF;
+        background: #728DEE;
+        padding-left: 40px;
+        margin-bottom: 0;
+        // .box-header{
+        //     display: inline-block;
+        //     width: 503px;
+        //     height: 60px;
+        //     overflow: hidden;
+        //     text-overflow: ellipsis;
+        //     white-space: nowrap;
+        // }
+        .close-btn{
+            float: right;
+            margin-top: 20px;
+            margin-right: 14px;
+            cursor: pointer;
+        }
+    }
+    }
+}
+</style>

+ 322 - 0
src/views/detail/EnvirmentParams.vue

@@ -0,0 +1,322 @@
+<template>
+  <div class="en-table">
+       <!-- <i-Table stripe  :columns="columns1" :data="tableData" size="large" :no-data-text="noData"></i-Table> -->
+        <table class="ivu-table-wrapper ivu-table ivu-table-border ivu-table-stripe" style="position:relative">
+              <div class="ov-div">
+                <table class="fixed-table">
+                  <colgroup></colgroup>
+                  <tr class="ivu-table-row">
+                    <td class="ivu-table-cell fixed-td" >信息点</td>
+                    <td class="ivu-table-cell" >表号功能号</td>
+                    <td class="ivu-table-cell" >实时数据</td>
+                    <td class="ivu-table-cell" >曲线变化</td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell fixed-td">空气(干球)温度</td>
+                   <td class="ivu-table-cell test" >{{roomInfo.infos.Tdb || '--'}}</td>
+                    <td class="ivu-table-cell" >{{TdbData || '--'}} ℃</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.Tdb)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell fixed-td" >空气相对湿度</td>
+                    <td class="ivu-table-cell test" >{{roomInfo.infos.RH || '--'}}</td>
+                    <td class="ivu-table-cell" >{{ RHData || '--'}} %RH</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.RH)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row">
+                    <td class="ivu-table-cell fixed-td" >空气密度</td>
+                    <td class="ivu-table-cell test" >{{roomInfo.infos.Rou || '--'}}</td>
+                    <td class="ivu-table-cell" >{{ RouData || '--'}} kg/m³</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.Rou)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell fixed-td" >空气湿球温度</td>
+                    <td class="ivu-table-cell test" >{{roomInfo.infos.Twb || '--'}}</td>
+                    <td class="ivu-table-cell" >{{TwbData || '--'}} ℃</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.Twb)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell fixed-td" >空气CO2浓度</td>
+                    <td class="ivu-table-cell test" >{{roomInfo.infos.CO2 || '--'}}</td>
+                    <td class="ivu-table-cell" >{{COData || '--'}} ppm</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.CO2)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row" >
+                    <td class="ivu-table-cell fixed-td" >空气PM2.5浓度</td>
+                    <td class="ivu-table-cell test">{{roomInfo.infos['PM2.5'] || '--'}}</td>
+                    <td class="ivu-table-cell" >{{PM25Data || '--'}}</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos['PM2.5'])">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row">
+                    <td class="ivu-table-cell fixed-td" >空气PM10浓度</td>
+                    <td class="ivu-table-cell test">{{roomInfo.infos.PM10 || '--'}}</td>
+                    <td class="ivu-table-cell" >{{PM10Data || '--'}} mg/m³</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.PM10)">查看</button></td>
+                  </tr>
+                  <tr class="ivu-table-row">
+                    <td class="ivu-table-cell fixed-td" >空气甲烷浓度</td>
+                    <td class="ivu-table-cell test">{{roomInfo.infos.CH4 || '--'}}</td>
+                    <td class="ivu-table-cell" >{{ CHData || '--'}} ppm</td>
+                    <td class="ivu-table-cell" ><button class="look-btn" @click="getBoundData(roomInfo.infos.CH4)">查看</button></td>
+                  </tr>
+                </table>
+               </div>
+          </table>
+          <div class="mask-bg"></div>
+          <div class="mask-layout">
+            <p class="box-title">详细信息<Icon type="md-close" class='close-btn' @click="closeMask"/></p>
+            <alarm-charts v-if="charts" :charts='charts'></alarm-charts>
+          </div>
+  </div>
+</template>
+
+<script>
+import axios from 'axios'
+import {formatTime} from '../../tools/formatTime.js'
+// import {currentTime} from '../../tools/currentDate.js'
+import alarmCharts from '../main/AlarmCharts'
+export default {
+  components: {
+    alarmCharts
+  },
+
+  mixins: [],
+
+  props: {
+    roomInfo: {
+      type: Object
+    },
+    isShowChange: {
+      type: Boolean
+    }
+  },
+
+  data () {
+    return {
+      TdbData: "--",
+      RHData: "--",
+      COData: "--",
+      CHData: "--",
+      PM25Data: "--",
+      PM10Data: "--",
+      TwbData: "--",
+      RouData: "--",
+      charts: []
+    }
+  },
+
+  computed: {
+  },
+
+  mounted () {
+    this.$nextTick(function () {
+      this.getCurrentData()
+    })
+    if (this.isShowChange) {
+      this.changeDisplayNone()
+    } else {
+      this.changeDisplayBlock()
+    }
+  },
+  watch: {
+    isShowChange (newv, oldv) {
+      if (newv) {
+        this.changeDisplayNone()
+      } else {
+        this.changeDisplayBlock()
+      }
+    }
+  },
+
+  methods: {
+    getCurrentData () {
+      let params = {
+        criterias: [
+          {
+            id: this.roomInfo.id,
+            code: "Tdb"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "RH"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "Rou"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "Twb"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "CO2"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "PM2.5"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "PM10"
+          },
+          {
+            id: this.roomInfo.id,
+            code: "CH4"
+          }
+        ]
+      }
+      axios.post(`/data-platform-3/data-platform-3/parameter/batch_query_param?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          let content = data.Content
+          content.forEach(el => {
+            if (el.code == 'Tdb') {
+              this.TdbData = el.data
+            }
+            if (el.code == 'RH') {
+              this.RHData = el.data
+            }
+            if (el.code == 'Rou') {
+              this.RouData = el.data
+            }
+            if (el.code == 'Twb') {
+              this.TwbData = el.data
+            }
+            if (el.code == 'CO2') {
+              this.COData = el.data
+            }
+            if (el.code == 'PM2.5') {
+              this.PM25Data = el.data
+            }
+            if (el.code == 'PM10') {
+              this.PM10Data = el.data
+            }
+            if (el.code == 'CH4') {
+              this.CHData = el.data
+            }
+          })
+        }
+      })
+    },
+    changeDisplayNone () {
+      let arr = document.querySelectorAll('.en-table .test')
+      arr.forEach(i => {
+        if (i.innerHTML.includes('--')) {
+          i.parentNode.style.display = 'none'
+        }
+      })
+    },
+    changeDisplayBlock () {
+      let arr = document.querySelectorAll('.en-table .test')
+      arr.forEach(i => {
+        if (i.innerHTML.includes('--')) {
+          i.parentNode.style.display = 'table-row'
+        }
+      })
+    },
+    closeMask () {
+      document.querySelector(".mask-bg").style.display = 'none'
+      document.querySelector(".mask-layout").style.display = 'none'
+    },
+    // 得到图的数据
+    getBoundData (code) {
+      document.querySelector(".mask-bg").style.display = 'block'
+      document.querySelector(".mask-layout").style.display = 'block'
+      let params = {
+        criteria: {
+          // id: this.roomInfo.id,
+          id: "Sp1101080001001004013",
+          // code:code,
+          code: "CO2", // 信息点编码
+          // period: period,
+          period: "5min",
+          // receivetime:receivetime,
+          receivetime: {
+            $gte: "20190110000000",
+            $lt: "20190111000000"
+          }
+        }
+      }
+      axios.post(`/data-platform-3/data-platform-3/hisdata/query_period_data?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.charts = data.Content
+          this.charts.forEach(el => {
+            el.time = formatTime(el.data_time)
+            el.value = parseInt(el.data_value)
+          })
+        }
+      })
+    }
+
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.en-table {
+    width:95%;
+    margin-bottom: 38px;
+    table{
+      width: 100%;
+      font-size: 14px;
+    }
+    tr:nth-child(2n)>td{
+        background: #f5f5f5;
+    }
+    td {
+        width:30%;
+        .look-btn{
+            color:#6682E6;
+            background: none;
+        }
+    }
+    .mask-bg {
+      position: fixed;
+      top: 0;
+      bottom: 0;
+      left: 0;
+      right: 0;
+      z-index: 99;
+      background:rgba(0, 0, 0, .6);
+      display: none;
+    }
+   .mask-layout{
+      width: 680px;
+      height: 480px;
+      background: #fff;
+      box-shadow: 0 2px 8px 0 rgba(0,0,0,0.12);
+      border-radius: 4px;
+      z-index: 999;
+      position: fixed;
+      top: 230px;
+      left: 50%;
+      margin-left: -360px;
+      display: none;
+      .box-title {
+        line-height: 60px;
+        height: 60px;
+        font-size: 16px;
+        color: #FFFFFF;
+        background: #728DEE;
+        padding-left: 40px;
+        margin-bottom: 0;
+        // .box-header{
+        //     display: inline-block;
+        //     width: 503px;
+        //     height: 60px;
+        //     overflow: hidden;
+        //     text-overflow: ellipsis;
+        //     white-space: nowrap;
+        // }
+        .close-btn{
+            float: right;
+            margin-top: 20px;
+            margin-right: 14px;
+        }
+      }
+    }
+}
+</style>

+ 363 - 0
src/views/detail/index.vue

@@ -0,0 +1,363 @@
+<template>
+  <div class="detail-info">
+      <div class="eq-top">
+           <img src="/static/img/backIcon.jpg" alt="" @click="back">
+           <span>返回 </span>
+      </div>
+      <div class="detail-content">
+          <div class="content-top">
+              <p>{{roomInfo.infos.RoomLocalName}}的详情</p>
+              <div><Checkbox v-model="isData" label="只显示有数据的信息" name="type" @on-change="onChange"></Checkbox>只显示有数据的信息</div>
+          </div>
+          <hr>
+          <div class="content-bottom">
+              <div class="content-left">
+                  <div>
+                      <ul>
+                          <li v-for="(list,index) in mainInfo" :key='index' :class="{changeStyle:changeColor == index}"
+                          @click="change(index)"><a :href="`#${list.href}`">{{list.name}}</a></li>
+                      </ul>
+                  </div>
+              </div>
+              <div class="content-right"  @scroll="handleScroll">
+                  <p id="baseInfo" class="group"><span></span>基本信息</p>
+                  <ul>
+                      <li><span>空间ID</span>{{roomInfo.infos.RoomID}}</li>
+                      <li><span>空间名称</span>{{roomInfo.infos.RoomName || '--'}}</li>
+                      <li><span>空间本地编码</span>{{roomInfo.infos.RoomLocalID || '--'}}</li>
+                      <li><span>空间本地名称</span>{{roomInfo.infos.RoomLocalName || '--'}}</li>
+                      <li><span>空间二维码图片</span><i v-if="roomInfo.infos.RoomQRCode" @click="lookAt">查看</i></li>
+                      <li><span>BIM模型中编码</span>{{roomInfo.infos.BIMID || '--'}}</li>
+                      <li><span>空间功能区类型</span>{{roomInfo.infos.RoomFuncType || '--'}}</li>
+                      <li><span>进深</span>{{roomInfo.infos.Depth || '--'}} m</li>
+                      <li><span>面宽</span>{{roomInfo.infos.Width || '--'}} m</li>
+                      <li><span>建筑面积</span>{{roomInfo.infos.BuildArea || '--'}} m²</li>
+                      <li><span>使用面积</span>{{roomInfo.infos.NetArea || '--'}} m²</li>
+                      <li><span>高度</span>{{roomInfo.infos.Height || '--'}} m</li>
+                      <li><span>配电容量</span>{{roomInfo.infos.ElecCap || '--'}} A</li>
+                      <li><span>备注文字</span>{{roomInfo.infos.Intro || '--'}}</li>
+                  </ul>
+                  <p id="lesseeInfo" class="group"><span></span>租户信息</p>
+                  <ul>
+                      <li><span>租赁业态类型</span>{{roomInfo.infos.TenantType || '--'}}</li>
+                      <li><span>所属租户</span>{{roomInfo.infos.Tenant || '--'}}</li>
+                  </ul>
+                  <p id="peoplesInfo" class="group"><span></span>人员信息</p>
+                  <ul>
+                      <li><span>空间常驻人数</span>{{roomInfo.infos.PermanentPeopleNum || '--'}}</li>
+                      <li><span>逐时流出人数</span>{{roomInfo.infos.OutPeopleFlow || '--'}}</li>
+                  </ul>
+                  <p id="enviromentInfo" class="group"><span></span>环境参数</p>
+                   <ul>
+                        <enviroment-params v-show="roomInfo" :roomInfo='roomInfo' :isShowChange='isShowChange'></enviroment-params>
+                   </ul>
+                  <p id="eneryInfo" class="group"><span></span>能耗信息</p>
+                   <ul style="min-height: 590px">
+                        <enery-params v-show="roomInfo" :roomInfo='roomInfo' :isShowChange='isShowChange'></enery-params>
+                   </ul>
+              </div>
+          </div>
+      </div>
+       <div class="mask-bg"></div>
+     <div class="mask">
+       <message-modal @close='close' :isQR="isQR"></message-modal>
+     </div>
+  </div>
+</template>
+
+<script>
+import enviromentParams from './EnvirmentParams'
+import eneryParams from './EneryParams'
+import messageModal from '../spread/MessageModal'
+// import { log } from 'util'
+export default {
+  components: {
+    enviromentParams,
+    eneryParams,
+    messageModal
+  },
+
+  mixins: [],
+
+  props: {
+  },
+
+  data () {
+    return {
+      isData: false,
+      changeColor: 0,
+      isShowChange: false, // 控制表格是否显示没数据的那一行
+      roomInfo: {
+        infos: {
+          RoomLocalName: '--',
+          RoomLocalID: '--',
+          RoomQRCode: '--',
+          BIMID: '--',
+          RoomFuncType: '--',
+          BIMLocation: '--',
+          Depth: '--',
+          Width: '--',
+          Height: '--',
+          BuildArea: '--',
+          NetArea: '--',
+          ElecCap: '--',
+          TenantType: '--',
+          Tenant: '--'
+        },
+        location: {
+          building: '--',
+          floor: '--'
+        }
+      },
+      isQR: "",
+      mainInfo: [
+        {name: "基本信息", href: "baseInfo"},
+        {name: "租户信息", href: "lesseeInfo"},
+        {name: "人员信息", href: "peoplesInfo"},
+        {name: "环境参数", href: "enviromentInfo"},
+        {name: "能耗信息", href: 'eneryInfo'}
+      ],
+      groups: [],
+      box: null // 滚动盒子
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+    this.getRouteParams()
+    this.$nextTick(() => {
+      this.box = document.querySelector(".content-right")
+      this.groups = document.querySelectorAll(".content-right .group")
+    })
+  },
+
+  methods: {
+    // 滚动触发事件
+    handleScroll () {
+      let top = this.box.scrollTop
+      let i = this.groups.length - 1
+      for (; i >= 0; i--) {
+        if (this.groups[i].offsetTop <= top) {
+          this.changeColor = i
+          break
+        }
+      }
+    },
+    change (index) {
+      this.changeColor = index
+    },
+    back () {
+      this.$router.push('/vr')
+    },
+    // 接受来自父组件路由传过来的参数
+    getRouteParams () {
+      this.roomInfo = JSON.parse(this.$route.query.obj)
+    },
+    // 下载弹框
+    lookAt () {
+      this.isQR = this.roomInfo.infos.RoomQRCode
+      document.querySelector('body').style.overflow = 'hidden'
+      document.querySelector('.mask-bg').style.display = 'block'
+      document.querySelector('.mask').style.display = 'block'
+    },
+    close () {
+      document.querySelector('body').style.overflow = 'auto'
+      document.querySelector('.mask-bg').style.display = 'none'
+      document.querySelector('.mask').style.display = 'none'
+    },
+    onChange (val) {
+      if (val) {
+        this.hiddenNoData()
+      } else {
+        this.showAllData()
+      }
+    },
+    hiddenNoData () {
+      this.isShowChange = true
+      let arr = document.querySelectorAll('.content-right li')
+      arr.forEach(i => {
+        if (i.innerHTML.includes('--')) {
+          i.style.display = 'none'
+        }
+      })
+    },
+    // 只显示有数据的
+    showAllData () {
+      this.isShowChange = false
+      let arr = document.querySelectorAll('.content-right li')
+      arr.forEach(i => {
+        i.style.display = 'block'
+      })
+    }
+  }
+}
+</script>
+
+<style scoped lang="less" >
+.detail-info {
+    .eq-top {
+        margin-bottom: 20px;
+        margin-left: 20px;
+        font-size: 7px;
+        color: #212830;
+        >img {
+            //vertical-align: middle;
+            cursor: pointer;
+            border: 1px solid #CACACA;
+            border-radius: 2px;
+        }
+        >span {
+            font-size: 16px;
+            color: #212830;
+        }
+    }
+    .detail-content {
+        box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+        border-radius: 2px;
+        background: #fff;
+        padding-left:20px;
+        .content-top {
+            p {
+                font-size: 18px;
+                color: #212830;
+                font-weight: bold;
+                padding: 24px 0 20px 0;
+            }
+        }
+        hr {
+            margin-bottom: 0;
+        }
+        .content-bottom {
+            padding-left: 10px;
+            display: flex;
+            margin-bottom: 20px;
+            .content-left {
+                width: 264px;
+                border-radius: 2px;
+                margin-right: 70px;
+                padding-top: 10px;
+                background: #FAFAFA;
+                margin-bottom: 20px;
+                div {
+                    li{
+                        font-size: 16px;
+                        padding:8px 0 8px 40px;
+                        font-weight: bold;
+                        cursor: pointer;
+                        &:hover {
+                            color:#6682E6;
+                            background: #fff;
+                        }
+                        a {
+                             color: #212830;
+                             &:hover {
+                                color:#6682E6;
+                                background: #fff;
+                            }
+                           }
+                       }
+                   }
+                .active{
+                    color:#6682E6;
+                    background: #fff;
+                    }
+            }
+            .content-right {
+                width: 1450px;
+                height: 700px;
+                overflow-y:auto;
+                padding-top: 10px;
+                position: relative;
+                p {
+                    span {
+                        display: inline-block;
+                        width: 4px;
+                        height: 16px;
+                        background: #728DEE;
+                        margin-right: 10px;
+                        margin-bottom: -3px;
+                    }
+                }
+                ul {
+                    display: flex;
+                    flex-wrap: wrap;
+                    margin-left: 10px;
+                    margin-top: 20px;
+                    li {
+                        width: 50%;
+                        padding-bottom: 15px;
+                        overflow: hidden;
+                        text-overflow: ellipsis;
+                        white-space: nowrap;
+                        span {
+                            font-size: 14px;
+                            color: #6D747C;
+                            display: inline-block;
+                            width: 98px;
+                            margin-right: 20px;
+                        }
+                        i{
+                            color:#6682E6;
+                            cursor: pointer;
+                        }
+                    }
+                }
+            }
+        }
+    }
+     .mask-bg{
+        position: fixed;
+        top: 0;
+        bottom: 0;
+        left: 0;
+        right: 0;
+        z-index: 99;
+        background:rgba(0, 0, 0, .6);
+        display: none;
+    }
+    .mask {
+        width: 860px;
+        height: 458px;
+        background: #fff;
+        position: fixed;
+        z-index: 999;
+        top: 120px;
+        left: 30%;
+        display: none;
+    }
+    .changeStyle{
+        color: #6682E6!important;
+        background: #fff;
+        >a{
+            color: #6682E6!important;
+        }
+    }
+}
+</style>
+<style lang="less">
+.detail-info {
+    .ivu-table-wrapper {
+        border: none;
+    }
+    .ivu-table td,
+    .ivu-table th {
+        border: none;
+    }
+    .ivu-table:before{
+        height: 0;
+    }
+    .ivu-table:after{
+        width:0;
+    }
+    .ivu-table-row .description-td>.ivu-table-cell>span{
+            // overflow: hidden;
+            // text-overflow: ellipsis;
+            // white-space: nowrap;
+            max-height: 100px;
+            display: inline-block;
+    }
+}
+</style>

+ 312 - 0
src/views/equipment/EqSelect.vue

@@ -0,0 +1,312 @@
+<template>
+  <div class="my-all-select">
+    <!-- 重要级别 -->
+    <sg-mul-select class="my-select" v-model="selectParams.selectedLevel" :list="levelList" :label="label1"></sg-mul-select>
+    <!-- 报警条目 -->
+    <sg-mul-select class="my-select" v-model="selectParams.alarmName" :label="label" :list="alarmNameList"></sg-mul-select>
+    <!-- <sg-mul-select class="my-select" v-model="selectParams.selectedType" :list="typeList" :label="label2"></sg-mul-select> -->
+    <!-- 报警开始时间 -->
+    <div class="my-select">
+      <div class="date-input" >
+        <label>报警开始时间:</label>
+        <input type="text" name="daterange" id="config-demo" class="form-control">
+        <i class="glyphicon glyphicon-calendar fa fa-calendar"></i>
+      </div>
+    </div>
+    <!-- 报警持续时间 -->
+    <sg-select class="my-select" v-model="selectParams.selectedDurationTime" :list="startTimeList" :label="label4"></sg-select>
+
+  </div>
+</template>
+
+<script>
+import sgMulSelect from "../../common/sagacloudMulSelect.vue"
+import sgSelect from "../../common/sagacloudSelect.vue"
+import dataPickerConfig from '../../tools/dataPickerConfig.js'
+// import {mapActions,mapMutations,mapGetters,mapState} from 'vuex'
+// import axios from 'axios'
+// import { setTimeout } from 'timers'
+export default {
+  components: {
+    sgMulSelect,
+    sgSelect
+  },
+
+  mixins: [],
+
+  props: {
+    datePickerKey: {
+      type: String,
+      default: 'all'
+    },
+    dateLimitDays: {
+      type: Number,
+      default: Number.MAX_SAFE_INTEGER // js里的最大安全整数 9007199254740991
+    },
+    alarmNameList: {
+      type: Array,
+      default: () => []
+    }
+  },
+
+  data () {
+    return {
+      label1: "重要级别",
+      label4: "报警持续时间",
+      selectParams: {
+        selectedLevel: [], // 全部
+        selectedCode: [], // 报警条目
+        selectedDurationTime: "",
+        selectedStartTime: {
+          dStart: "", // 20181208
+          dEnd: "" // 20181209
+        },
+        alarmName: []
+      },
+      levelList: [
+        {
+          value: "S",
+          text: "S级"
+        },
+        {
+          value: "A",
+          text: "A级"
+        },
+        {
+          value: "B",
+          text: "B级"
+        },
+        {
+          value: "C",
+          text: "C级"
+        },
+        {
+          value: "D",
+          text: "D级"
+        }
+      ],
+      startTimeList: [
+        {
+          value: "5m",
+          text: "不超过5分钟"
+        },
+        {
+          text: "5分钟-2小时",
+          value: "2h"
+        },
+        {
+          text: "2-24小时",
+          value: "24h"
+        },
+        {
+          text: "超过24小时",
+          value: "1d"
+        }
+      ],
+      durationTimeList: [
+        {
+          value: "24h",
+          text: "近24小时"
+        },
+        {
+          value: "3d",
+          text: "近3天"
+        },
+        {
+          value: "7d",
+          text: "近7天"
+        },
+        {
+          value: "1m",
+          text: "近一个月"
+        },
+        {
+          value: "auto",
+          text: "自定义"
+        }
+      ],
+      label: '筛选报警条目',
+      changeAlarm: 0
+    }
+  },
+
+  computed: {
+
+  },
+  watch: {
+    'selectParams.selectedLevel': function (newVal, oldVal) {
+      this.$emit('setSelectParams', this.selectParams)
+    },
+    'selectParams.alarmName': function (newVal, oldVal) {
+      this.$emit('setSelectParams', this.selectParams)
+    },
+    'selectParams.selectedDurationTime': function (newVal, oldVal) {
+      this.$emit('setSelectParams', this.selectParams)
+    },
+    datePickerKey () {
+      this.daterangepicker()
+    },
+    dateLimitDays () {
+      this.daterangepicker()
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.daterangepicker()
+    })
+  },
+
+  methods: {
+    // 绑定控制开始时间的函数
+    /* eslint-disable */
+    daterangepicker () {
+      $("#config-demo").val(dataPickerConfig[this.datePickerKey].view)
+      let vm = this
+      $("#config-demo").daterangepicker(
+        {
+          startDate: dataPickerConfig[this.datePickerKey].startDate,
+          endDate: dataPickerConfig[this.datePickerKey].endDate,
+          timePicker: false,
+          timePicker24Hour: false,
+          linkedCalendars: false,
+          autoUpdateInput: false,
+          showDropdowns: true,
+          autoApply: true,
+          dateLimit: {
+            days: this.dateLimitDays
+          },
+          ranges: {
+            "清空选择": [moment().subtract(30, "days"), moment().subtract(0, "days")],
+            "近 24 小时": [ moment().subtract(0, "days"), moment().subtract(0, "days")],
+            "近 3 天": [
+              moment().subtract(3, "days"),
+              moment().subtract(0, "days")
+            ],
+            "近 7 天": [moment().subtract(7, "days"), moment()],
+            "近 1 个月": [
+              moment().subtract(30, "days"),
+              moment().subtract(0, "days")
+            ]
+          },
+          opens: "right",
+          separator: "-",
+          locale: {
+            format: "YYYY-MM-DD",
+            applyLabel: "应用",
+            cancelLabel: "取消",
+            resetLabel: "重置",
+            customRangeLabel: "自定义",
+            daysOfWeek: ["日", "一", "二", "三", "四", "五", "六"],
+            monthNames: [
+              "一月",
+              "二月",
+              "三月",
+              "四月",
+              "五月",
+              "六月",
+              "七月",
+              "八月",
+              "九月",
+              "十月",
+              "十一月",
+              "十二月"
+            ]
+          }
+        },
+        function (start, end, label) {
+          let _start = this.startDate.format(this.locale.format)
+          let _end = this.endDate.format(this.locale.format)
+          if (!this.startDate) {
+            this.element.val("")
+          } else {
+            if (_start == '1970-01-01' && _end == '1970-01-01') {
+              this.element.val("全部")
+              vm.selectParams.selectedStartTime.dStart = ''
+              vm.selectParams.selectedStartTime.dEnd = ''
+            } else {
+              this.element.val(_start + this.locale.separator + _end)
+              vm.selectParams.selectedStartTime.dStart = _start.split('-').join('') + '000000'
+              vm.selectParams.selectedStartTime.dEnd = _start == _end ? _end.split('-').join('') + '595959' : _end.split('-').join('') + '000000'
+            }
+            vm.changeAlarm = 1
+            vm.$emit('setSelectParams', vm.selectParams)
+            vm.$emit('setChangeAlarm', vm.changeAlarm)
+          }
+        }
+      )
+    }
+  }
+}
+</script>
+
+<style scoped lang="less" >
+.my-all-select {
+  padding: 18px 0 20px 12px;
+  background: #f4f5f8;
+  display: flex;
+  .my-select {
+    padding: 4px 8px;
+    display: inline-block;
+    .date-input {
+      width: 362px;
+      height: 34px;
+      display: flex;
+      background: #fff;
+      border: 1px solid #ccc;
+      position: relative;
+      border-radius: 4px;
+      &:hover,
+      &:active,
+      &:focus {
+        outline: none;
+        border-color: #2d8cf0;
+      }
+      > input {
+        height: 30px;
+        border: none;
+        outline: none;
+        font-size: 14px;
+        &:focus {
+          box-shadow: none;
+        }
+      }
+      > label {
+        width: 148px;
+        height: 34px;
+        padding-top: 4px;
+        padding-left: 5px;
+      }
+      > i {
+        position: absolute;
+        bottom: 6px;
+        right: 24px;
+        top: auto;
+        cursor: pointer;
+      }
+
+      .daterangepicker .ranges li.active {
+        background: #728dee;
+        border: 1px solid #728dee;
+      }
+      .daterangepicker td.active,
+      .daterangepicker td.active:hover {
+        background: #728dee;
+      }
+    }
+  }
+}
+</style>
+<style lang="less">
+.my-all-select {
+  .ivu-input {
+    height: 34px;
+    border: 1px solid #ccc;
+    &:hover,
+    &:active,
+    &:focus {
+      outline: none;
+      border-color: #2d8cf0;
+    }
+  }
+}
+</style>

+ 214 - 0
src/views/equipment/Handle.vue

@@ -0,0 +1,214 @@
+<template>
+  <div class="my-handle" v-if="this.lists">
+      <div class="handle-select">
+          <sgy-mul-select v-model="selected" :label="label" :list="alarmLists"></sgy-mul-select>
+      </div>
+      <div class="handle">
+            <scroll-list @onLoad="onLoad" :loading="loading" :finished="finished">
+                <Timeline pending v-for="(item, index) in appendLists" :key="index">
+                      <p class="time">{{formatTime(item.rtime || item.ctime )}}</p>
+                        <TimelineItem>
+                            <p class="content"> <span>{{item.alarmName}}</span>持续 {{secondsToDay(item.duration)}}</p>
+                            <p class="content">{{item.staffName}}<i>{{item.note}}</i></p>
+                            <div class="attachment" v-for='(item2, index2) in item.attachment' :key='index2'>
+                              <p  class="attach" v-if="item2.type=='file'">
+                                <a :href="$store.state.baseUrl + item2.url">非图片附件</a></p>
+                              <div class="pic" v-if="item2.type=='image'">
+                                <img :src="$store.state.baseUrl + item2.url"></div>
+                            </div>
+                        </TimelineItem>
+                </Timeline>
+            </scroll-list>
+      </div>
+  </div>
+</template>
+
+<script>
+import sgyMulSelect from '../../common/sagacloudMulSelect'
+import axios from 'axios'
+import ScrollList from '../../common/scrollList'
+import { setTimeout } from 'timers'
+import {formatTime, secondsToDay} from '../../tools/formatTime.js'
+export default {
+  components: {
+    sgyMulSelect,
+    ScrollList
+  },
+
+  mixins: [],
+
+  props: {
+    objectId: {
+      default: String
+    }
+  },
+
+  data () {
+    return {
+      formatTime,
+      secondsToDay,
+      SIZE: 3,
+      index: 0,
+      label: '筛选报警条目',
+      selected: [],
+      everyLists: [],
+      lists: [
+      ],
+      appendLists: [], // 显示的list
+      loading: false,
+      finished: false,
+      alarmLists: []
+    }
+  },
+
+  computed: {
+  },
+  watch: {
+    selected (newVal, oldVal) {
+      this.filterList(newVal)
+    }
+  },
+  mounted () {
+    this.manualData()
+  },
+
+  methods: {
+    init () {
+      if (this.lists.length && this.lists.length > this.SIZE) {
+        this.everyLists = this.lists.slice(0, this.SIZE)
+      } else {
+        this.everyLists = this.lists
+      }
+      this.setAlarmLists()
+      this.filterList(this.selected)
+    },
+    setAlarmLists () {
+      for (let el in this.everyLists) {
+        if (!this.alarmLists.includes(this.everyLists[el].alarmName)) {
+          this.alarmLists.push(this.everyLists[el].alarmName)
+        }
+      }
+      this.alarmLists = this.alarmLists.map(el => {
+        return {value: el, text: el}
+      })
+    },
+    manualData () {
+      let params = {
+        objectId: this.objectId
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/manualHandle/query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.lists = Array.from(data.Content)
+          this.init()
+        }
+      })
+    },
+    onLoad () {
+      this.loading = true
+      setTimeout(() => {
+        this.loading = false
+        if (this.everyLists.length >= this.lists.length) {
+          this.finished = true
+        }
+        this.index += 1
+        const data = this.lists.slice(this.index * this.SIZE, (this.index + 1) * this.SIZE) || this.lists
+        this.everyLists = [...this.everyLists, ...data]
+        this.alarmLists = []
+        this.setAlarmLists()
+        this.filterList(this.selected)
+      }, 3000)
+    },
+    filterList (arr) {
+      if (arr && arr.length > 0) {
+        this.appendLists = this.everyLists.filter(i => {
+          return arr.includes(i.alarmName)
+        })
+      } else {
+        this.appendLists = this.everyLists
+      }
+    }
+
+  }
+
+}
+</script>
+<style scoped lang="less" >
+.my-handle{
+    .handle-select {
+        padding: 18px 0 18px 20px;
+        height: 70px;
+        background: #F4F5F8;
+    }
+    .handle {
+        padding-top: 46px;
+        padding-bottom:40px;
+        .time {
+            font-size: 14px;
+            position: absolute;
+            transform: translateY(-5px)
+        }
+        .ivu-timeline-item-content{
+          .attachment{
+            padding-bottom: 20px;
+            font-size: 14px;
+            color: #6D747C;
+            word-break: break-all;
+            display: inline-block;
+        }
+        .content {
+            padding-bottom: 20px;
+            font-size: 14px;
+            color: #6D747C;
+            word-break: break-all;
+            width: 500px;
+            >span {
+                color: #212830;
+                font-size: 16px;
+                font-weight: bold;
+                padding-right: 40px;
+            }
+            >i {
+                color: #232831;
+                padding-left: 14px;
+            }
+        }
+        .attach{
+            color:#728DEE;
+            padding:14px 0;
+            cursor: pointer;
+        }
+        .pic{
+            display: inline-block;
+            width: 108px;
+            height: 108px;
+            background: #E9E9E9;
+            border-radius: 2px;
+            margin-right: 16px;
+            >img {
+              width: 108px;
+              height: 108px;
+            }
+        }
+
+        }
+    }
+}
+</style>
+<style lang="less">
+.my-handle{
+  .ivu-timeline-item:last-child .ivu-timeline-item-tail{
+    display: inline-block;
+  }
+  .ivu-timeline {
+    padding-left: 30%;
+  }
+  .ivu-timeline-item {
+    left: 140px;
+    display: inline-block;
+  }
+  .ivu-timeline-item-content{
+    padding-left:74px;
+  }
+}
+</style>

+ 388 - 0
src/views/equipment/index.vue

@@ -0,0 +1,388 @@
+<template>
+  <div class="equipment">
+      <div class="eq-top">
+           <img src="/static/img/backIcon.jpg" alt="" @click="back">
+           <span>设备详情 / </span>
+            <strong>{{eqName}}-{{objectId}}报警详情</strong>
+      </div>
+      <div class="eq-head" v-if="false">
+        <div class="f-left"></div>
+        <div class="f-right">
+			<p class="f-salarm">近期多次出现以下报警:“电流谐波畸变率过高”、“室温温度传感器出错”、“电压过压”。可能存在设备或零件老化,请多加关注!</p>
+			<Icon type="md-close" class="close-btn" @click="closeBox"/>
+        </div>
+    </div>
+      <div class="eq-bottom">
+          <div class="alarm-top">
+            <span @click="onClickTab(0)" :class="{active: activeIndex== 0}">当前未恢复报警</span>
+            <span @click="onClickTab(1)" :class="{active: activeIndex== 1}">历史报警记录</span>
+            <span @click="onClickTab(2)" :class="{active: activeIndex== 2}">手动处理备注</span>
+          </div>
+          <div v-if="activeIndex==0">
+              <table-alarm :tableData='tableData' @setSort='setSort'></table-alarm>
+          </div>
+          <div v-if="activeIndex==1">
+               <div class="my-select-type">
+                    <my-select  @setSelectParams="setSelectParams" @setChangeAlarm='setChangeAlarm' :datePickerKey='datePickerKey'
+                    :dateLimitDays='dateLimitDays' :alarmNameList='alarmNameList'></my-select>
+               </div>
+               <history-table v-if="show" :historyTableData='historyTableData' :total='total' :Current='pageCurrent'
+		:pageSize='pageSize' @changeCurrentPage='changeCurrentPage'  @setSort='setSort'></history-table>
+          </div>
+          <div v-if="activeIndex==2">
+              <my-handle v-show="show" :objectId='objectId'></my-handle>
+          </div>
+      </div>
+  </div>
+</template>
+
+<script>
+import tableAlarm from '../main/TableAlarm.vue'
+import historyTable from '../main/HistoryTable'
+import mySelect from './EqSelect.vue'
+import myHandle from './Handle.vue'
+import {formatTime, secondsToDay} from '../../tools/formatTime.js'
+import dataPickerConfig from '../../tools/dataPickerConfig.js'
+// import {mapActions, mapMutations, mapGetters, mapState} from 'vuex'
+import axios from 'axios'
+// import { setTimeout } from 'timers'
+export default {
+  components: {
+    tableAlarm,
+    mySelect,
+    myHandle,
+    historyTable
+  },
+
+  mixins: [],
+
+  props: {
+
+  },
+
+  data () {
+    return {
+      show: false,
+      datePickerKey: 'oneMonth',
+      dateLimitDays: Number.MAX_SAFE_INTEGER,
+      activeIndex: 0,
+      pageSize: 15,
+      historyTableData: [],
+      tableData: [],
+      total: null,
+      pageCurrent: 1,
+      order: { // 选填,没有order字段时按照默认顺序排序
+        column: "", // 要排序的列名,只支持level,duration,ctime
+        asc: true // true升序,false降序
+      },
+      status: 'alarm', // 区分3个tab的状态
+      autoHandle: null, // 区分3个tab的手动自动
+      selectParams: { // 所有下拉框的默认值
+        selectedLevel: [], // 级别
+        selectedDurationTime: "", // 持续时间
+        selectedStartTime: { // 开始时间
+          dStart: "",
+          dEnd: ""
+        },
+        alarmName: []
+      },
+      alarmNameList: [],
+      objectId: "Eq1101080002001ACATFC031",
+      eqName: ""
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+    this.getEqNameAndId()
+  },
+
+  methods: {
+    // 监控到如果时间改变,重新触发请求报警条目的函数
+    setChangeAlarm () {
+      this.saveAlarmName()
+    },
+    // 根据路由得到设备名称和id
+    getEqNameAndId () {
+      let hostUrl = location.search
+      let pid = hostUrl.split('&')[1].toString().split('=')[1]
+      this.$store.commit('setProId', pid)
+      this.eqName = decodeURI(location.hash)
+      this.objectId = hostUrl.split("&")[2]
+      this.getDataList()
+      this.saveAlarmName()
+      this.show = true
+    },
+    // 存储条目数
+    saveAlarmName () {
+      let ctime = {}
+      if (Object.values(this.selectParams.selectedStartTime).some(i => i.length)) {
+        ctime = {
+          $gte: this.selectParams.selectedStartTime.dStart,
+          $lte: this.selectParams.selectedStartTime.dEnd
+        }
+      } else {
+        ctime = null
+      }
+      let params = {
+        objectId: this.objectId,
+        ctime: ctime
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/alarmName/list?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.alarmNameList = data.Content
+          this.alarmNameList = Array.from(new Set(this.alarmNameList)).map(el => {
+            return {value: el, text: el}
+          })
+        }
+      })
+    },
+    back () {
+      history.go(-1)
+    },
+    closeBox () {
+      document.querySelector('.eq-head').style.display = 'none'
+    },
+    // 请求得到报警条目列表,传给后台 objectId ctime
+
+    // 每个下拉框值变化触发表格数据的返回值
+    setSelectParams (obj) {
+      this.selectParams = obj
+      if (this.activeIndex == 0) {
+        this.status = 'alarm'
+        this.autoHandle = null
+      } else if (this.activeIndex == 2) {
+        this.status = 'alarm'
+        this.autoHandle = false
+      } else {
+        this.status = null
+        this.autoHandle = null
+      }
+      this.getDataList()
+    },
+    // 触发排序函数
+    setSort (col) {
+      this.order.column = col.key
+      this.order.asc = col.order == 'asc'
+      this.getDataList()
+    },
+    // 3个按钮的点击传参数
+    onClickTab (status) {
+      this.activeIndex = status
+      if (status == 0) {
+        this.status = 'alarm'
+        this.autoHandle = null
+        this.getDataList()
+        this.dateLimitDays = Number.MAX_SAFE_INTEGER
+      } else if (status == 2) {
+        this.status = 'alarm'
+        this.autoHandle = false
+        this.dateLimitDays = Number.MAX_SAFE_INTEGER
+      } else {
+        this.status = null
+        this.autoHandle = null
+        this.selectParams.selectedStartTime.dStart = dataPickerConfig[this.datePickerKey].dStart // 20181215000000
+        this.selectParams.selectedStartTime.dEnd = dataPickerConfig[this.datePickerKey].dEnd
+        this.dateLimitDays = 30
+        this.getDataList()
+        this.saveAlarmName()
+      }
+    },
+    // 默认未恢复的请求函数
+    getDataList () {
+      // 得到项目id和secret
+      let params
+      // 排序
+      let order = null
+      if (Object.values(this.order).some(i => i.length)) {
+        order = this.order
+      }
+
+      // 持续时间的转换
+      let duration = {}
+      if (Object.values(this.selectParams.selectedDurationTime).some(i => i.length)) {
+        if (this.selectParams.selectedDurationTime == '5m') {
+          duration.$lt = 5 * 60
+        } else if (this.selectParams.selectedDurationTime == '2h') {
+          duration.$gte = 300
+          duration.$lte = 2 * 60 * 60
+        } else if (this.selectParams.selectedDurationTime == '24h') {
+          duration.$gte = 2 * 60 * 60
+          duration.$lte = 24 * 60 * 60
+        } else if (this.selectParams.selectedDurationTime == '1d') {
+          duration.$gt = 24 * 60 * 60
+        }
+      } else {
+        duration = null
+      }
+      // 开始时间的转换
+      let ctime = {}
+
+      if (Object.values(this.selectParams.selectedStartTime).some(i => i.length)) {
+        ctime = {
+          $gte: this.selectParams.selectedStartTime.dStart,
+          $lte: this.selectParams.selectedStartTime.dEnd
+        }
+      } else {
+        ctime = null
+      }
+      // 参数的添加
+      if (this.activeIndex == 0) {
+        params = {
+          criteria: {
+            objectId: this.objectId,
+            status: this.status
+          },
+          order: order
+        }
+      } if (this.activeIndex == 1) {
+        params = {
+          criteria: {
+            levels: this.selectParams.selectedLevel.length > 0 ? this.selectParams.selectedLevel : null, // 选填,报警等级
+            objectId: this.objectId,
+            ctime: ctime,
+            duration: duration,
+            status: this.status,
+            autoHandle: this.autoHandle,
+            alarmName: this.selectParams.alarmName.length > 0 ? this.selectParams.alarmName : null // 报警条目
+          },
+          order: order
+        }
+      }
+      // 请求表格数据
+      axios.post(`/alarm-system/alarm-system/alarm/list?projectId=${this.$store.state.projId}&secret=`, params)
+        .then(res => {
+          let data = res.data
+          //   let vm = this
+          if (data.Result == 'success') {
+            this.tableData = data.Content
+            this.total = data.Count
+            console.log(this.tableData)
+            this.tableData.forEach(el => {
+              el.cTime = formatTime(el.ctime)
+              el.durationT = secondsToDay(el.duration)
+              el.alarmName = el.alarmName || ""
+              el.location = el.source ? el.source : ""
+              el.content = el.alarmName + "/" + el.location
+              if (!el.autoHandle) {
+                el.deal = 0
+              } else {
+                if (el.event.type == 1) {
+                  el.deal = 1
+                } else if (el.event.type == 2) {
+                  el.deal = 2
+                } else {
+                  el.deal = 3
+                }
+              }
+            })
+            // 自己分页
+            if (this.activeIndex == 1) {
+              this.changeCurrentPage(this.pageCurrent)
+            }
+          }
+        })
+    },
+    // 分页 点击的是哪页
+    changeCurrentPage (index) {
+      this.historyTableData = []
+      // 需要显示开始数据的index,(因为数据是从0开始的,页码是从1开始的,需要-1)
+      let _start = (index - 1) * this.pageSize
+      // 需要显示结束数据的index
+      let _end = index * this.pageSize
+      // 截取需要显示的数据
+      this.historyTableData = this.tableData.slice(_start, _end)
+      this.pageCurrent = index
+    }
+  }
+}
+</script>
+
+<style scoped lang="less" >
+.equipment {
+    .eq-top {
+        margin-bottom: 20px;
+        >img {
+            //vertical-align: middle;
+            cursor: pointer;
+            border: 1px solid #CACACA;
+            border-radius: 2px;
+        }
+        >span {
+            font-size: 16px;
+            color: #728DEE;
+        }
+    }
+    .eq-head {
+        width: 100%;
+        background: #FFF6F5;
+        border-radius: 2px;
+        font-size: 14px;
+        display: flex;
+        margin:10px 0 20px 0;
+        //height: 60px;
+        position: relative;
+        .f-left {
+          width: 8px;
+          background: #F08378;
+          display: inline-block;
+        }
+        .f-right {
+          padding: 20px 0 20px 38px;
+          display: inline-block;
+          .close-btn {
+            position: absolute;
+            right: 12px;
+            top: 22px;
+          }
+          .f-salarm {
+            font-size: 16px;
+            color: #F08378;
+            font-weight: bold;
+          }
+        }
+    }
+    .eq-bottom {
+        background: #FFFFFF;
+        box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+        border-radius: 2px;
+        padding-top:30px;
+        .alarm-top {
+            margin-bottom: 40px;
+            display: flex;
+            justify-content: center;
+            span {
+            text-align: center;
+            padding: 6px 20px;
+            color: #62697b;
+            cursor: pointer;
+            border: 1px solid #cacaca;
+            border-right: none;
+            &:last-child {
+                border-right: 1px solid #cacaca;
+                border-top-right-radius: 3px;
+                border-bottom-right-radius: 3px;
+            }
+            &:first-child {
+                border-top-left-radius: 3px;
+                border-bottom-left-radius: 3px;
+            }
+            &:hover,
+            &.active {
+                background: #728DEE;
+                color: #fff;
+            }
+            }
+        }
+        .my-select-type {
+            padding-left: 30px;
+            padding-right: 20px;
+        }
+    }
+}
+
+</style>

+ 127 - 0
src/views/main/AlarmCharts.vue

@@ -0,0 +1,127 @@
+<template>
+  <div class="my-echarts">
+      <p style="padding-top:10px;padding-left:20px;">单位:{{detailData.unit}}</p>
+      <div id="alarmCharts" style="width:634px;height:400px;"></div>
+  </div>
+</template>
+
+<script>
+var echarts = require("echarts")
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: ['charts', 'detailData'],
+
+  data () {
+    return {
+
+    }
+  },
+
+  computed: {
+
+  },
+  mounted () {
+    let vm = this
+    this.$nextTick(function () {
+      vm.getAlarmCharts()
+    })
+  },
+
+  methods: {
+    getAlarmCharts () {
+      let _this = this
+      let timeX = []
+      let valueY = []
+      this.charts.map(el => {
+        timeX.push(el.time)
+        valueY.push(el.value)
+        return (timeX, valueY)
+      })
+
+      let alarmCharts = echarts.init(document.getElementById('alarmCharts'))
+
+      alarmCharts.setOption({
+        tooltip: {
+          trigger: 'axis',
+          position: function (pt) {
+            return [pt[0], '10%']
+          },
+          formatter: function (params, ticket, callback) {
+            return params[0].axisValue + "<br/>" + params[0].data + _this.detailData.unit
+          }
+        },
+        title: {
+          left: 'center',
+          text: ''
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: timeX.reverse()
+        },
+        yAxis: {
+          type: 'value',
+          boundaryGap: [0, '100%']
+        },
+        dataZoom: [{
+          type: 'inside',
+          start: 0,
+          end: 100
+        }, {
+          start: 0,
+          end: 10,
+          handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
+          handleSize: '80%',
+          handleStyle: {
+            color: '#fff',
+            shadowBlur: 3,
+            shadowColor: 'rgba(0, 0, 0, 0.6)',
+            shadowOffsetX: 2,
+            shadowOffsetY: 2
+          }
+        }
+        ],
+        series: [
+          {
+            name: '数据',
+            type: 'line',
+            smooth: true,
+            symbol: 'none',
+            sampling: 'average',
+            itemStyle: {
+              color: 'rgb(255, 70, 131)'
+            },
+            areaStyle: {
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
+                offset: 0,
+                color: 'rgb(255, 158, 68)'
+              }, {
+                offset: 1,
+                color: 'rgb(255, 70, 131)'
+              }])
+            },
+            data: valueY.reverse()
+          }
+        ]
+      })
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.my-echarts {
+  position: relative;
+  #alarmCharts {
+    position: absolute;
+    top: -20px;
+  }
+}
+
+</style>

+ 392 - 0
src/views/main/HistoryTable.vue

@@ -0,0 +1,392 @@
+<template>
+  <div class="history-table">
+      <div class="my-box">
+            <i-Table stripe  :columns="columns1" :data="historyTableData" size="large" @on-sort-change="onSortChange"></i-Table>
+            <div style="margin: 10px;overflow: hidden" v-if="historyTableData.length>0">
+                <div style="float: right;margin-right:100px;">
+                    <Page :total="total" :current="current" :pageSize='pageSize' @on-page-size-change="_nowPageSize"
+                     @on-change="changePage">
+                    </Page>
+                </div>
+            </div>
+      </div>
+      <div class="mask-bg"></div>
+     <div id="messageBox" v-if="itemsData">
+        <pomp-box :itemsData="itemsData" :detailData='detailData' :emailName='emailName' :messageName='messageName' @onClose="close"></pomp-box>
+    </div>
+  </div>
+</template>
+
+<script>
+import pompBox from './PompBox'
+// import { formatTime, toHourMinute} from '../../tools/formatTime.js'
+import axios from 'axios'
+export default {
+  components: {
+    pompBox
+  },
+
+  mixins: [],
+
+  props: ['historyTableData', 'total', 'current', 'pageSize'],
+
+  data () {
+    return {
+      itemsData: {},
+      emailName: [],
+      messageName: [],
+      detailData: {},
+      columns1: [
+        {
+          title: "重要级别",
+          key: "level",
+          sortable: 'custom',
+          render: (h, params) => {
+            const text = params.row.level + '级'
+            if (params.row.level == 'S') {
+              return h('div', [
+                h('img', {
+                  attrs: {
+                    src: '/static/img/ernomal.png'
+                  },
+                  style: {
+                    marginRight: '5px',
+                    verticalAlign: 'middle',
+                    marginTop: '-3px'
+                  }
+                }),
+                h('span', {
+                  style: {
+                    color: '#F08378'
+                  }
+                }, '' + text)
+              ])
+            } else if (params.row.level == 'A') {
+              return h('div', [
+                h('span', {
+                  style: {
+                    color: '#F08378',
+                    marginLeft: '10px'
+                  }
+                }, '' + text)
+              ])
+            } else if (params.row.level == 'B') {
+              return h('div', [
+                h('span', {
+                  style: {
+                    color: '#F3B767',
+                    marginLeft: '10px'
+                  }
+                }, '' + text)
+              ])
+            } else {
+              return h('div', [
+                h('span', {
+                  style: {
+                    marginLeft: '10px'
+                  }
+                }, '' + text)
+              ])
+            }
+          }
+        },
+        {
+          title: "报警类型",
+          key: "type"
+
+        },
+        {
+          title: "报警内容",
+          key: "content",
+          width: 400,
+          className: "description-td",
+          render: (h, params) => {
+            const content = params.row.content ? params.row.content : ""
+            if (content) {
+              const text1 = content.split("/")[0]
+              const text2 = content.split("/")[1]
+              return h('div', [
+                h('span', {
+                  style: {
+                    marginRight: '18px'
+                  }
+                }, text1),
+                h('span', {
+                  style: {
+                    color: "#A6ADB5"
+                  }
+                }, text2)
+              ])
+            }
+          }
+        },
+        {
+          title: "报警开始时间",
+          key: "cTime",
+          sortable: 'custom'
+
+        },
+        {
+          title: "报警持续时间",
+          key: "durationT",
+          sortable: 'custom',
+          align: 'right'
+        },
+        {
+          title: "报警状态",
+          key: "status",
+          align: 'center',
+          render: (h, params) => {
+            const status = params.row.status
+            if (status == 'alarm') {
+              return h('div', [
+                h('Button', {
+                  props: {
+                    type: 'text',
+                    size: 'small'
+                  },
+                  style: {
+                    color: '#F08378'
+                  }
+                }, '未恢复')
+              ])
+            } else {
+              return h('div', [
+                h('Button', {
+                  props: {
+                    type: 'text',
+                    size: 'small'
+                  },
+                  style: {
+                    color: '#3BC6A1'
+                  }
+                }, '已恢复')
+              ])
+            }
+          }
+        },
+        {
+          title: "处理情况",
+          key: "deal",
+          align: 'center',
+          render: (h, params) => {
+            const deal = params.row.deal
+            const status = params.row.event ? params.row.event.status : ""
+            const id = params.row.event ? params.row.event.id : ""
+            if (deal == 0) {
+              return h('div', [
+                h('Button', {
+                  props: {
+                    size: 'small'
+                  },
+                  style: {
+                    marginRight: '5px',
+                    color: '#728DEE',
+                    border: '1px solid #728DEE'
+                  },
+                  on: {
+                    click: () => {
+                      this.handleClick(params.row)
+                    }
+                  }
+                }, '需手动处理')
+              ])
+            }
+            if (deal == 1) {
+              const text = '工单状态:' + status + '工单编号:' + id
+              return h('div', [
+                h('img', {
+                  attrs: {
+                    src: '/static/img/bill.png'
+                  },
+                  style: {
+                    marginRight: '5px',
+                    verticalAlign: 'middle'
+                  }
+                }),
+                h('span', {
+                  style: {
+                    marginRight: '5px',
+                    color: '#6D747C',
+                    cursor: 'pointer'
+                  },
+                  on: {
+                    click: () => {
+                      this.handleClick(params.row)
+                    }
+                  }
+                }, text)
+              ])
+            }
+            if (deal == 2) {
+              const text = '事件状态:' + status + '事件编号:' + id
+              return h('div', [
+                h('img', {
+                  attrs: {
+                    src: '/static/img/event.png'
+                  },
+                  style: {
+                    marginRight: '5px',
+                    verticalAlign: 'middle'
+                  }
+                }),
+                h('span', {
+                  style: {
+                    marginRight: '5px',
+                    color: '#6D747C',
+                    cursor: 'pointer'
+                  },
+                  on: {
+                    click: () => {
+                      this.handleClick(params.row)
+                    }
+                  }
+                }, text)
+              ])
+            }
+            if (deal == 3) {
+              const text = '上级线路已断,此条自动隐藏'
+              return h('div', [
+                h('span', {
+                  style: {
+                    marginRight: '5px',
+                    color: '#6D747C',
+                    cursor: 'pointer'
+                  },
+                  on: {
+                    click: () => {
+                      this.handleClick(params.row)
+                    }
+                  }
+                }, text)
+              ])
+            }
+          }
+        }
+      ]
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    // iview的排序
+    onSortChange (col) {
+      this.$emit('setSort', col)
+    },
+    // 每页显示的数据条数
+    _nowPageSize (index) {
+      // 实时获取当前需要显示的条数
+      this.pageSize = index
+    },
+    changePage (index) {
+      this.$emit('changeCurrentPage', index)
+    },
+    handleClick (row) {
+      document.querySelector('.mask-bg').style.display = 'block'
+      document.querySelector('#messageBox').style.display = 'block'
+      this.itemsData = row
+      this.getEamilInfo(row)
+    },
+    getEamilInfo (row) {
+      let params = {
+        id: row.id
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/detail/query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.detailData = data.Content
+          if (data.Content && data.Content.notification) {
+            let emailName = data.Content.notification.mail ? data.Content.notification.mail : []
+            let messageName = data.Content.notification.message ? data.Content.notification.message : []
+            this.emailName = []
+            if (emailName.length > 0) {
+              emailName.forEach(el => {
+                this.emailName.push(el.name)
+              })
+            }
+
+            this.messageName = []
+            if (messageName.length > 0) {
+              messageName.forEach(el => {
+                this.messageName.push(el.name)
+              })
+            } else {
+              this.messageName = []
+              this.emailName = []
+            }
+          }
+        }
+      })
+    },
+    close () {
+      document.querySelector('.mask-bg').style.display = 'none'
+      document.querySelector('#messageBox').style.display = 'none'
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.history-table {
+    .my-box{
+       padding: 0 20px 20px 24px;
+       background: #fff;
+    }
+    .mask-bg {
+      position: fixed;
+      top: 0;
+      bottom: 0;
+      left: 0;
+      right: 0;
+      z-index: 99;
+      background:rgba(0, 0, 0, .6);
+      display: none;
+    }
+    #messageBox{
+      width: 747px;
+      height: 630px;
+      background: #fff;
+      box-shadow: 0 2px 8px 0 rgba(0,0,0,0.12);
+      border-radius: 4px;
+      z-index: 999;
+      position: fixed;
+      top: 70px;
+      left: 50%;
+      margin-left: -360px;
+      display: none;
+    }
+}
+</style>
+<style lang="less">
+.history-table{
+    .ivu-table-wrapper {
+    border: none;
+  }
+  .ivu-table td,
+  .ivu-table th {
+    border: none;
+  }
+  .ivu-table:before{
+      height: 0;
+  }
+  .ivu-table:after{
+      width:0;
+  }
+  .ivu-table-row .description-td>.ivu-table-cell>span{
+        // overflow: hidden;
+        // text-overflow: ellipsis;
+        // white-space: nowrap;
+        max-height: 100px;
+        display: inline-block;
+    }
+}
+
+</style>

+ 669 - 0
src/views/main/PompBox.vue

@@ -0,0 +1,669 @@
+<template>
+  <div class="pomp-box">
+      <p class="box-title"><i class="box-header" v-if='itemsData.content'>报警详情:{{itemsData.content.split('/')[0]}}<span>{{itemsData.content.split('/')[1]}}</span></i><Icon type="md-close" class='close-btn' @click="closeMask"/></p>
+      <div class="box-content">
+          <p :class="`${classStyle}`">{{itemsData.status=='alarm'?(itemsData.deal==0?"待手动处理":"未恢复"):"已恢复"}}</p>
+          <p class="notification"><i v-if="messageName.length>0"><img src="/static/img/message.png" alt="">已短信通知 {{messageName.join("、")}}</i>
+          <span v-if="emailName.length>0"><img src="/static/img/email.png" alt="">已邮件通知 {{emailName.join("、")}}</span></p>
+          <p class="my-time">报警开始时间<span v-if="itemsData.ctime">{{formatTime(itemsData.ctime)}}</span></p>
+          <p class="my-time">报警持续时间<span>{{secondsToDay(itemsData.duration)}}
+              <!-- <img src="/static/img/video.png" alt="">
+              <i class="my-video">报警时间内有视频监控</i> -->
+              </span>
+          </p>
+          <div class="alarm-deal-info">
+              <p class="deal-title"><span class="sign-icon"></span>报警处理信息</p>
+              <div v-if="itemsData.deal==1">
+                  <p class="my-time">处理详情<span>已自动转工单</span></p>
+                  <p class="my-time">工单状态<span>{{itemsData.event.status}}</span></p>
+                  <p class="my-time">工单编号<span>{{itemsData.event.id}}</span></p>
+              </div>
+              <div v-if="itemsData.deal==2">
+                  <p class="my-time">处理详情<span>已自动转事件</span></p>
+                  <p class="my-time">工单状态<span>{{itemsData.event.status}}</span></p>
+                  <p class="my-time">工单编号<span>{{itemsData.event.id}}</span></p>
+              </div>
+              <div v-if="itemsData.deal==3">
+                  <p class="my-time">处理详情<span>上级线路已断,此条自动隐藏</span></p>
+              </div>
+              <div v-if="itemsData.deal==0 && itemsData.status=='recovered' && detailData.history && detailData.history.length>0">
+                   <table class="deal-detail" v-for="(item,index) in detailData.history" :key='index'>
+                       <tr>
+                           <td class="name">处理详情</td>
+                           <td class="describ"> {{item.staffName}}手动处理-报警已解决</td>
+                       </tr>
+                        <tr>
+                            <td class="name">处理备注</td>
+                            <td class="describ">
+                                <p >{{item.note}}</p>
+                                <template v-if="item.attachment">
+                                    <div style="display:inline-block" v-for="(item2,index2) in item.attachment" :key='index2'>
+                                        <p class="attach" v-if="item2.type=='file'"><a :href="$store.state.baseUrl + item2.url">非图片附件名称</a></p>
+                                        <div class="pic" v-if="item2.type=='image'">
+                                            <img :src="$store.state.baseUrl + item2.url" alt="">
+                                        </div>
+                                    </div>
+                                </template>
+                            </td>
+                        </tr>
+                    </table>
+              </div>
+             <div v-if="itemsData.deal==0 && itemsData.status=='alarm' ">
+                   <div  class="collspan-box"  v-if="detailData.history && detailData.history.length>0">
+                       <p class="deal-remind">此设备历史上出现过同样的报警,相关备注供您参考:</p>
+                        <table class="deal-detail"  v-for="(item,index) in detailData.history" :key="index">
+                            <tr>
+                                <td>{{formatTime(item.rtime)}}</td>
+                                <td class="name">{{item.staffName}}</td>
+                                <td class="describ">
+                                    <p>{{item.note}}</p>
+                                    <template v-if="item.attachment">
+                                        <div style="display:inline-block" v-for="(item2,index2) in item.attachment" :key='index2'>
+                                            <p class="attach" v-if="item2.type=='file'"><a :href="$store.state.baseUrl + item2.url">非图片附件名称</a></p>
+                                            <div class="pic" v-if="item2.type=='image'">
+                                                <img :src="$store.state.baseUrl + item2.url" alt="">
+                                            </div>
+                                        </div>
+                                    </template>
+                                </td>
+                            </tr>
+                        </table>
+                   </div>
+                     <Button class="check-line" v-if="detailData.history.length>3 && showHeight" @click="getMoreDetail">查看更多</Button>
+                     <Button class="check-line" v-if="detailData.history.length>3 && !showHeight" @click="closeMoreDetail">收起</Button>
+                    <p class="remarks" v-if='!recentNote && detailData' @click="showRecentAlarmNote" ><img src="/static/img/warn.png"> 查看近期其他设备的此类报警备注</p>
+                   <div class="recent-detail" v-if='recentNote'>
+                         <Button class="check-line"  @click="closeRecentAlarmNote">收起</Button>
+                        <div v-for="(el,ind) in RecentAlarm" :key="ind">
+                             <p class="deal-remind">{{locationT(el)}} {{el.object?el.object.name:""}} {{el.object?el.object.id : ''}}</p>
+                         <table class="deal-detail" v-for="(item, index1) in el.alarmList"  :key="index1">
+                            <tr>
+                                <td>{{formatTime(item.rtime)}}</td>
+                                <td class="name">{{item.staffName}}</td>
+                                <td class="describ">
+                                    <p>{{item.alarmName}}</p>
+                                    <template v-if="item.attachment">
+                                        <div style="display:inline-block" v-for="(item2,index2) in item.attachment" :key="index2">
+                                            <p class="attach" v-if="item2.type=='file'"><a :href="$store.state.baseUrl + item2.url">非图片附件名称</a></p>
+                                            <div class="pic" v-if="item2.type=='image'">
+                                                <img :src="$store.state.baseUrl + item2.url" alt="">
+                                            </div>
+                                        </div>
+                                    </template>
+                                </td>
+                            </tr>
+                        </table>
+                        </div>
+                   </div>
+                    <div class="manual">
+                        <p class="manual-alarm-title">请手动处理报警</p>
+                        <div class="manual-alarm-radio">
+                            <span>处理方式<i>*</i></span>
+                            <RadioGroup v-model="radio">
+                                <Radio label="此条报警是误报"></Radio>
+                                <Radio label="报警已解决"></Radio>
+                            </RadioGroup>
+                            <span v-if="false"><i>请选择处理方式</i></span>
+                        </div>
+                        <div class="manual-alarm-mode">
+                            <span>填写备注</span>
+                            <div>
+                                <Input v-model="note" type="textarea" :rows="4" :maxlength="100"/>
+                            </div> <span> ({{note.length}}/100)</span>
+                        </div>
+                        <div class="manual-upload">
+                            <span>上传附件</span>
+                            <Button class="my-btn"><label class="my-label">点击上传</label>
+                            <input multiple name="file" type="file" id="file" @change="getFile($event)"/></Button> <span> ({{attachment.length}}/3)</span>
+                        </div>
+                         <div class="upload-filename">
+                             <p v-for="(item, index) in attachment" :key="index"><span>{{item.fileName}}</span><Icon type="ios-close-circle" @click="deleteFile(index)" /></p>
+                             <span v-if="loading">uploading...</span>
+                             <span v-if="fileMsg">上传文件不能超过3个</span>
+                        </div>
+                        <div class="deal-button"><Button type="primary" size='large' @click="upload(itemsData.id)">确认处理</Button>
+                        <span v-if="sucMsg" class="success-message">报警处理成功!</span><span v-if="errMsg" class="error-message">报警处理失败!</span></div>
+                    </div>
+             </div>
+          </div>
+          <div class="alarm-deal-info" v-if="detailData.algorithmType || detailData.algorithmType=='sump'">
+            <p class="deal-title"><span class="sign-icon"></span>报警触发详情</p>
+            <div class="my-range" v-if="detailData.algorithmType=='threshold'">
+                <sgy-range :alarmVal="`${detailData.algorithmInfo.triggerValue}`" :min="`${detailData.algorithmInfo.threshold.lower}`"
+                :max="`${detailData.algorithmInfo.threshold.upper}`" :currentValue='`${detailData.algorithmInfo.currentValue}`' :unit='detailData.unit'></sgy-range>
+            </div>
+            <div style="margin-top:20px">
+                <Button class="check-line" v-if="startBtn" @click="showEcharts">查看报警时间段内数值曲线</Button>
+                <Button class="check-line" v-else  @click="closeEcharts">收起</Button>
+            </div>
+            <alarm-charts v-if="tag && charts.length>0" :charts="charts" :detailData='detailData'></alarm-charts>
+          </div>
+      </div>
+  </div>
+</template>
+
+<script>
+import SgyRange from '../../common/SgyRange'
+import alarmCharts from './alarmCharts.vue'
+import axios from 'axios'
+import {formatTime, secondsToDay, amendTime, date} from '../../tools/formatTime.js' // amendTime, date
+import { setTimeout } from 'timers'
+import Bus from '../../tools/bus.js'
+export default {
+  components: {
+    SgyRange,
+    alarmCharts
+  },
+
+  mixins: [],
+
+  props: ['itemsData', 'messageName', 'emailName', 'detailData'],
+
+  data () {
+    return {
+      formatTime,
+      secondsToDay,
+      radio: '此条报警是误报',
+      tag: false,
+      startBtn: true,
+      recentNote: false,
+      staffName: "王晓丽",
+      note: "",
+      sucMsg: false,
+      errMsg: false,
+      charts: [],
+      fileList: [],
+      loading: false,
+      fileMsg: false,
+      showHeight: true,
+      RecentAlarm: [],
+      attachment: []
+    }
+  },
+
+  computed: {
+    classStyle () {
+      if (this.itemsData.status == 'alarm') {
+        if (this.itemsData.deal == 0) {
+          return 'handleAuto'
+        } else {
+          return 'state'
+        }
+      } else {
+        return 'nostate'
+      }
+    }
+  },
+
+  mounted () {
+  },
+
+  methods: {
+    locationT (RecentAlarm) {
+      if (RecentAlarm.object && RecentAlarm.object.location) {
+        return (RecentAlarm.object.location.buildingName ? RecentAlarm.object.location.buildingName : "") + (RecentAlarm.object.location.floorName ? RecentAlarm.object.location.floorName : "") +
+        (RecentAlarm.object.location.spaceName ? RecentAlarm.object.location.spaceName : "") + RecentAlarm.object.location.equipmentName ? RecentAlarm.object.location.equipmentName : ""
+      }
+    },
+    // 查看更多
+    getMoreDetail () {
+      this.showHeight = false
+      let box = document.querySelector(".collspan-box")
+      box.style.overflow = "visible"
+      box.style.height = 'auto'
+    },
+    // 收起更多的信息
+    closeMoreDetail () {
+      this.showHeight = true
+      let box = document.querySelector(".collspan-box")
+      box.style.overflow = "hidden"
+      box.style.height = '200px'
+    },
+    // 上传图片或文件
+    getFile (event) {
+      let baseUrl = this.$store.state.baseUrl
+      const files = event.target.files
+      let vm = this
+      this.fileList = [...files]
+      if (this.attachment.length + files.length > 3) {
+        this.fileMsg = true
+        setTimeout(function () {
+          vm.fileMsg = false
+        }, 3000)
+        return
+      }
+      this.fileList.forEach((i) => {
+        let fileName = new Date().getTime() + i.name
+        let url
+        let type = ""
+        let url1 = ""
+        if (i.type.toString().split("/")[0] == 'image') {
+          type = 'image'
+          url = `${baseUrl}/image-service/common/image_upload?systemId=dataPlatform&secret=9e0891a7a8c8e885&key=${fileName}`
+          url1 = `/image-service/common/image_get?systemId=dataPlatform&key=${fileName}`
+        } else {
+          type = "file"
+          url = `${baseUrl}/image-service/common/file_upload?systemId=dataPlatform&secret=9e0891a7a8c8e885&key=${fileName}`
+          url1 = `/image-service/common/file_get?systemId=dataPlatform&key=${fileName}`
+        }
+        let obj = {
+          fileName: fileName,
+          type: type,
+          url: url1
+        }
+        this.loading = true
+        let _this = this
+        let reader = new FileReader()
+        reader.readAsArrayBuffer(i)
+        reader.onload = function (e) {
+          var xhr = new XMLHttpRequest()
+          xhr.open('POST', url)
+          xhr.send(reader.result)
+          xhr.onreadystatechange = function () {
+            if (xhr.readyState == 4) {
+              _this.loading = false
+              if (xhr.status == 200) {
+                _this.attachment.push(obj)
+                console.log("图片上传成功!")
+              }
+            }
+          }
+        }
+      })
+    },
+    deleteFile (index) {
+      this.attachment.splice(index, 1)
+    },
+    // 修改或增加报警信息
+    upload (mes) {
+      let handleType = "1"
+      if (this.radio == '此条报警是误报') {
+        handleType = "1"
+      } else {
+        handleType = "2"
+      }
+      let params = {
+        id: mes, // 报警id,必填
+        staffName: this.staffName, // 处理人员姓名,必填
+        handleType: handleType, // 处理方式,1此条报警是误报,2报警已经解决,必填
+        note: this.note, // 备注,选填
+        attachment: this.attachment
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/manualHandle/create?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        let vm = this
+        if (data.Result == 'success') {
+          this.sucMsg = true
+          setTimeout(function () {
+            vm.sucMsg = false
+          }, 3000)
+          this.note = ""
+          this.attachment = []
+          this.closeMask()
+          Bus.$emit('main-init')
+        } else {
+          this.errMsg = true
+          setTimeout(function () {
+            vm.errMsg = false
+          }, 3000)
+        }
+      })
+    },
+    // 查看近期报警备注
+    showRecentAlarmNote () {
+      this.recentNote = true
+      let params = {
+        objectId: this.detailData.objectId,
+        typeCode: this.detailData.typeCode
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/manualHandle/recentSameQuery/query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.RecentAlarm = data.Content
+        }
+      })
+    },
+    closeRecentAlarmNote () {
+      this.recentNote = false
+    },
+    showEcharts () {
+      if (this.itemsData && this.detailData) {
+        this.tag = true
+        this.startBtn = false
+        let period1 = ""
+        let receivetime = {
+          $gte: "",
+          $lt: ""
+        }
+        //  formatTime 将20190116174200 转换成2019-01-16 17:42:00  amendTime转换时间戳 然后减去10分钟,然后把时间戳转成时间再转成原来的格式
+        if (this.itemsData.duration < 60) {
+          period1 = "5min"
+          receivetime.$gte = receivetime.$gte = date(amendTime(this.itemsData.cTime) - 10 * 60)
+          if (this.itemsData.rime) {
+            receivetime.$lt = date(amendTime(formatTime(this.itemsData.rtime)) + 10 * 60)
+          } else {
+            receivetime.$lt = date(amendTime(Date.parse(new Date())))
+          }
+        } else if (this.itemsData.duration < 60 * 60 * 24) {
+          period1 = "15min"
+          receivetime.$gte = receivetime.$gte = date(amendTime(this.itemsData.cTime) - 30 * 60)
+          if (this.itemsData.rime) {
+            receivetime.$lt = date(amendTime(formatTime(this.itemsData.rtime)) + 30 * 60)
+          } else {
+            receivetime.$lt = date(amendTime(Date.parse(new Date())))
+          }
+        } else if (this.itemsData.duration < 60 * 60 * 24 * 7) {
+          period1 = "1h"
+          receivetime.$gte = receivetime.$gte = date(amendTime(this.itemsData.cTime) - 3 * 60 * 60)
+          if (this.itemsData.rime) {
+            receivetime.$lt = date(amendTime(formatTime(this.itemsData.rtime)) + 3 * 60 * 60)
+          } else {
+            receivetime.$lt = date(amendTime(Date.parse(new Date())))
+          }
+        } else {
+          period1 = "1d"
+          receivetime.$gte = receivetime.$gte = date(amendTime(this.itemsData.cTime) - (3 * 24 * 60 * 60))
+          if (this.itemsData.rime) {
+            receivetime.$lt = date(amendTime(formatTime(this.itemsData.rtime)) + (3 * 24 * 60 * 60))
+          } else {
+            receivetime.$lt = date(amendTime(Date.parse(new Date())))
+          }
+        }
+
+        let params = {
+          criteria: {
+            id: this.detailData.objectId,
+            code: this.detailData.infoCode, // 信息点编码
+            period: period1,
+            receivetime: receivetime
+          }
+        }
+        axios.post(`/data-platform-3/data-platform-3/hisdata/query_period_data?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+          let data = res.data
+          if (data.Result == 'success') {
+            this.charts = data.Content
+            this.charts.forEach(el => {
+              el.time = formatTime(el.data_time)
+              el.value = parseInt(el.data_value)
+            })
+          } else {
+            this.charts = []
+          }
+        })
+      }
+    },
+    closeEcharts () {
+      this.tag = false
+      this.startBtn = true
+    },
+    closeMask () {
+      this.recentNote = false
+      this.tag = false
+      this.startBtn = true
+      this.$emit('onClose')
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.pomp-box {
+    font-size: 14px;
+    color: #6D747C;
+    .box-title {
+        line-height: 60px;
+        height: 60px;
+        font-size: 16px;
+        color: #FFFFFF;
+        background: #728DEE;
+        padding-left: 40px;
+        margin-bottom: 0;
+        .box-header{
+            display: inline-block;
+            width: 503px;
+            height: 60px;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+        }
+        .close-btn{
+            float: right;
+            margin-top: 20px;
+            margin-right: 14px;
+            cursor: pointer;
+        }
+        >span {
+            opacity: 0.7;
+            font-size: 7px;
+            padding-left: 14px;
+        }
+    }
+    .box-content {
+        padding: 20px 0 0 40px;
+        height: 520px;
+        overflow-y: auto;
+        .state {
+          font-size: 16px;
+          color: #F08378;
+          font-weight: bold;
+        }
+        .handleAuto{
+            font-size: 16px;
+            color: #F3B767;
+            font-weight: bold;
+        }
+        .nostate{
+          font-size: 16px;
+          color: #3BC6A1;
+          font-weight: bold;
+        }
+        .notification{
+            color: #6D747C;
+            font-size: 12px;
+            padding-top: 10px;
+            img{
+                //vertical-align: middle;
+                margin-right: 8px;
+            }
+            >i{
+                padding-right:180px;
+            }
+        }
+        .my-time {
+            font-size: 14px;
+            padding-top: 14px;
+            >span {
+                padding-left: 14px;
+                color:#212830;
+            }
+            img {
+                vertical-align: middle;
+                margin-left: 45px;
+            }
+            .my-video {
+                color: #728DEE;
+                padding-left: 8px;
+            }
+        }
+        .alarm-deal-info {
+            margin:20px 0 54px 0;
+            .deal-title {
+                font-size: 16px;
+                color:#212830;
+                .sign-icon {
+                    display: inline-block;
+                    width: 8px;
+                    height: 16px;
+                    background:#728DEE;
+                    margin-right: 8px;
+                    vertical-align: middle;
+                }
+            }
+            .collspan-box{
+                height: 200px;
+                overflow: hidden;
+            }
+            .deal-remind {
+                color: #6D747C;
+                font-size: 14px;
+                padding-top: 20px;
+            }
+            .deal-detail {
+                margin-top: 20px;
+               tr {
+                   height: 38px;
+                   vertical-align: top;
+                   .name {
+                       width: 72px;
+                       text-align: center;
+                   }
+                   .describ{
+                       color: #212830;
+                       >p {
+                           word-break: break-all;
+                       }
+                   }
+                   .attach{
+                       color:#728DEE;
+                       padding:14px 0;
+                       cursor: pointer;
+                       display: block;
+                   }
+                   .pic{
+                       display: inline-block;
+                       width: 108px;
+                       height: 108px;
+                       background: #E9E9E9;
+                       border-radius: 2px;
+                       margin-right: 16px;
+                       >img {
+                           width: 107px;
+                           height: 108px;
+                       }
+                   }
+               }
+            }
+            .remarks {
+                padding:30px 0 20px 0;
+                color: #728DEE;
+                cursor: pointer;
+                img {
+                    vertical-align: middle;
+                    margin-right: 2px;
+                    width: 16px;
+                    height: 16px;
+                }
+
+            }
+            .recent-detail{
+                width: 640px;
+                padding: 20px;
+                border-radius: 2px;
+                background:#F7F7F7;
+                margin: 20px 0;
+            }
+            .manual {
+                width: 640px;
+                background: #F4F6FE;
+                border-radius: 2px;
+                padding: 0 20px 20px 20px;
+                .manual-alarm-title {
+                    text-align: center;
+                    color: #212830;
+                    padding: 20px 0 10px 0;
+                }
+                .manual-alarm-radio{
+                    margin-bottom:20px;
+                        span {
+                        padding-right: 30px;
+                        >i {
+                            color: #F08378;
+                            margin-left: 4px;
+                        }
+                    }
+                }
+                .manual-alarm-mode {
+                    display: flex;
+                    span {
+                        padding-right: 45px;
+                    }
+                    >div {
+                        width: 454px;
+                        background: #FFFFFF;
+                        border-radius: 2px;
+                    }
+                }
+                .manual-upload {
+                    //display: flex;
+                    margin-top: 20px;
+                    span {
+                        padding-right: 30px;
+                    }
+                    .my-btn {
+                      width: 440px;
+                      height: 30px;
+                      line-height: 13px;
+                      text-align: center;
+                      color: #728DEE;
+                      border: 1px solid #728DEE;
+                      border-radius: 2px;
+                      position: relative;
+                      cursor: pointer;
+                      &:hover {
+                            background-color:#efefef;
+                          }
+                      .my-label{
+                          position: absolute;
+                          left: 196px;
+                          font-size: 14px;
+                      }
+                      input[type='file']{
+                           cursor: pointer;
+                           width: 454px;
+                           display: inline;
+                           opacity: 0;
+                      }
+                    }
+                }
+                .upload-filename{
+                    margin-left: 100px;
+                    margin-bottom: 20px;
+                    background: #F4F6FE;
+                    width: 454px;
+                    line-height: 30px;
+                    > p {
+                        i {
+                            font-size: 16px;
+                            float: right;
+                            margin: 6px 25px 0 0;
+                            cursor: pointer;
+                            &:hover {
+                                color: red;
+                                transform: scale(1.1)
+                            }
+                        }
+                    }
+                }
+                .deal-button {
+                    text-align: center;
+                }
+                .success-message{
+                    padding-left: 20px;
+                    color:#3BC6A1;
+                }
+                .error-message {
+                    padding-left: 20px;
+                    color:#F08378;
+                }
+            }
+            .my-range {
+                margin:30px 20px;
+            }
+            .check-line {
+                color:#728DEE;
+            }
+        }
+    }
+}
+</style>

+ 402 - 0
src/views/main/Select.vue

@@ -0,0 +1,402 @@
+<template>
+  <div class="my-all-select">
+    <!-- 重要级别 -->
+    <sg-mul-select class="my-select" v-model="selectParams.selectedLevel" :list="levelList" :label="label1"></sg-mul-select>
+    <!-- 报警类型 -->
+    <sg-mul-select class="my-select" v-model="selectParams.selectedType" :list="typeList" :label="label2"></sg-mul-select>
+    <!-- 报警持续时间 -->
+    <sg-select class="my-select" v-model="selectParams.selectedDurationTime" :list="startTimeList" :label="label4"></sg-select>
+     <!-- 报警开始时间 -->
+     <!-- <div class="my-select" v-if="clear==2">
+       <history-date-picker></history-date-picker>
+     </div> -->
+    <div class="my-select">
+      <div class="date-input" >
+        <label>报警开始时间:</label>
+        <input type="text" name="daterange" id="config-demo" class="form-control">
+        <i class="glyphicon glyphicon-calendar fa fa-calendar"></i>
+      </div>
+    </div>
+    <!-- 报警所在位置 -->
+    <sg-tree-select class="my-select" v-model="selectParams.selectedPosition" :list="positionList" :label="label3" ></sg-tree-select>
+    <!-- 搜索 -->
+    <div class="my-select">
+      <i-Input placeholder="输入设备/空间名称关键字查找" v-model="selectParams.keyword" clearable style="width:230px" @on-enter="onkeyup">
+        <Icon type="ios-search" slot="suffix"/>
+      </i-Input>
+    </div>
+  </div>
+</template>
+
+<script>
+import sgMulSelect from "../../common/sagacloudMulSelect.vue"
+import sgSelect from "../../common/sagacloudSelect.vue"
+import sgTreeSelect from "../../common/sagasloudTreeSelect.vue"
+
+// import {mapActions, mapMutations, mapGetters} from 'vuex'
+import axios from 'axios'
+import dataPickerConfig from '../../tools/dataPickerConfig.js'
+// import { log } from 'util'
+export default {
+  components: {
+    sgMulSelect,
+    sgSelect,
+    sgTreeSelect
+  },
+
+  mixins: [],
+
+  props: {
+    datePickerKey: {
+      type: String,
+      default: 'all'
+    },
+    dateLimitDays: {
+      type: Number,
+      default: Number.MAX_SAFE_INTEGER // js里的最大安全整数 9007199254740991
+    }
+  },
+
+  data () {
+    return {
+      label1: "重要级别",
+      label2: "报警类型",
+      label3: "报警所在位置",
+      label4: "报警持续时间",
+      // 下拉框的默认值
+      selectParams: {
+        selectedLevel: [], // 全部
+        selectedType: [],
+        selectedPosition: {
+          buildingId: [],
+          floorId: [],
+          spaceId: []
+        },
+        selectedDurationTime: "",
+        selectedStartTime: {
+          dStart: "", // 20181208
+          dEnd: "" // 20181209
+        },
+        keyword: null
+      },
+      levelList: [
+        {
+          value: "S",
+          text: "S级"
+        },
+        {
+          value: "A",
+          text: "A级"
+        },
+        {
+          value: "B",
+          text: "B级"
+        },
+        {
+          value: "C",
+          text: "C级"
+        },
+        {
+          value: "D",
+          text: "D级"
+        }
+      ],
+      typeList: [
+        {
+          value: "1",
+          text: "类型1"
+        },
+        {
+          value: "2",
+          text: "类型2"
+        },
+        {
+          value: "3",
+          text: "类型3"
+        },
+        {
+          value: "4",
+          text: "类型4"
+        },
+        {
+          value: "5",
+          text: "类型5"
+        }
+      ],
+      positionList: [
+      ],
+      startTimeList: [
+        {
+          value: "5m",
+          text: "不超过5分钟"
+        },
+        {
+          text: "5分钟-2小时",
+          value: "2h"
+        },
+        {
+          text: "2-24小时",
+          value: "24h"
+        },
+        {
+          text: "超过24小时",
+          value: "1d"
+        }
+      ],
+      durationTimeList: [
+        {
+          value: "24h",
+          text: "近24小时"
+        },
+        {
+          value: "3d",
+          text: "近3天"
+        },
+        {
+          value: "7d",
+          text: "近7天"
+        },
+        {
+          value: "1m",
+          text: "近一个月"
+        },
+        {
+          value: "auto",
+          text: "自定义"
+        }
+      ]
+    }
+  },
+
+  computed: {
+
+  },
+  watch: {
+    'selectParams.selectedLevel': function (newVal, oldVal) {
+      this.$emit('setSelectParams', this.selectParams)
+    },
+    'selectParams.selectedPosition': function (newVal, oldVal) {
+      this.$emit('setSelectParams', this.selectParams)
+    },
+    'selectParams.selectedType': function (newVal, oldVal) {
+      this.$emit('setSelectParams', this.selectParams)
+    },
+    'selectParams.selectedDurationTime': function (newVal, oldVal) {
+      this.$emit('setSelectParams', this.selectParams)
+    },
+    datePickerKey () {
+      this.daterangepicker()
+    },
+    dateLimitDays () {
+      this.daterangepicker()
+    }
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.daterangepicker()
+    })
+    this.getRoomLists()
+  },
+
+  methods: {
+    // 得到空间列表
+    getRoomLists () {
+      axios.get(`/alarm-system/alarm-system/alarm/buildingHierarchy?projectId=${this.$store.state.projId}&secret=`).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.positionList = data.Content
+          this.positionList.forEach(i => {
+            i.title = i.buildingName || i.spaceName || i.floorName
+            i.value = i.buildingId || i.spaceId || i.floorId
+            i.checked = false // 默认不选中
+            i.expand = false // 默认不展开
+            i.type = i.buildingId ? 'building' : i.floorId ? 'floor' : 'space'
+            if (i.content) {
+              i.children = []
+              i.content.forEach(j => {
+                j.title = j.spaceName || j.floorName
+                j.value = j.spaceId || j.floorId
+                j.checked = false // 默认不选中
+                j.expand = false // 默认不展开
+                j.type = j.floorId ? 'floor' : 'space'
+                i.children.push(j)
+                if (j.content) {
+                  j.children = []
+                  j.content.forEach(k => {
+                    k.title = k.spaceName
+                    k.value = k.spaceId
+                    k.checked = false // 默认不选中
+                    k.expand = false // 默认不展开
+                    k.type = 'space'
+                    j.children.push(k)
+                  })
+                } else {
+                  i.children = []
+                }
+              })
+            } else {
+              i.children = []
+            }
+          })
+        }
+      })
+    },
+    // 回车搜索
+    onkeyup () {
+      this.$emit('setSelectParams', this.selectParams)
+    },
+    // 绑定控制开始时间的函数
+    /* eslint-disable */
+    daterangepicker () {
+      $("#config-demo").val(dataPickerConfig[this.datePickerKey].view)
+      console.log(dataPickerConfig[this.datePickerKey].view)
+      let vm = this
+      $("#config-demo").daterangepicker(
+        {
+          startDate: moment().startOf('hour'),
+          endDate: moment().startOf('hour').add(32, 'hour'),
+          timePicker: false,
+          timePicker24Hour: false,
+          linkedCalendars: false,
+          autoUpdateInput: false,
+          showDropdowns: true,
+          autoApply: true,
+          dateLimit: {
+            days: this.dateLimitDays
+          },
+          ranges: {
+            "清空选择": [moment().subtract(30, "days"), moment().subtract(0, "days")],
+            "近 24 小时": [ moment().subtract(0, "days"), moment().subtract(0, "days")],
+            "近 3 天": [
+              moment().subtract(3, "days"),
+              moment().subtract(0, "days")
+            ],
+            "近 7 天": [moment().subtract(7, "days"), moment()],
+            "近 1 个月": [
+              moment().subtract(30, "days"),
+              moment().subtract(0, "days")
+            ]
+          },
+          opens: "right",
+          separator: "-",
+          locale: {
+            format: "YYYY-MM-DD",
+            applyLabel: "应用",
+            cancelLabel: "取消",
+            resetLabel: "重置",
+            customRangeLabel: "自定义",
+            daysOfWeek: ["日", "一", "二", "三", "四", "五", "六"],
+            monthNames: [
+              "一月",
+              "二月",
+              "三月",
+              "四月",
+              "五月",
+              "六月",
+              "七月",
+              "八月",
+              "九月",
+              "十月",
+              "十一月",
+              "十二月"
+            ]
+          }
+        },
+        function (start, end, label) {
+          let _start = this.startDate.format(this.locale.format)
+          let _end = this.endDate.format(this.locale.format)
+          if (!this.startDate) {
+            this.element.val("")
+          } else {
+            if (_start == '1970-01-01' && _end == '1970-01-01') {
+              this.element.val("全部")
+              vm.selectParams.selectedStartTime.dStart = ''
+              vm.selectParams.selectedStartTime.dEnd = ''
+            } else {
+              this.element.val(_start + this.locale.separator + _end)
+              vm.selectParams.selectedStartTime.dStart = _start.split('-').join('') + '000000'
+              vm.selectParams.selectedStartTime.dEnd = _start == _end ? _end.split('-').join('') + '595959' : _end.split('-').join('') + '000000'
+            }
+            console.log( vm.selectParams.selectedStartTime)
+            vm.$emit('setSelectParams', vm.selectParams)
+          }
+        }
+      )
+    }
+  }
+}
+</script>
+
+<style scoped lang="less" >
+.my-all-select {
+  padding: 18px 0 20px 12px;
+  background: #f4f5f8;
+  display: flex;
+  // justify-content: space-between;
+  flex-wrap: wrap;
+  .my-select {
+    padding: 4px 8px;
+    display: inline-block;
+    .date-input {
+      width: 362px;
+      height: 34px;
+      display: flex;
+      background: #fff;
+      border: 1px solid #ccc;
+      position: relative;
+      border-radius: 4px;
+      &:hover,
+      &:active,
+      &:focus {
+        outline: none;
+        border-color: #2d8cf0;
+      }
+      > input {
+        height: 30px;
+        border: none;
+        outline: none;
+        font-size: 14px;
+        &:focus {
+          box-shadow: none;
+        }
+      }
+      > label {
+        width: 148px;
+        height: 34px;
+        padding-top: 4px;
+        padding-left: 5px;
+      }
+      > i {
+        position: absolute;
+        bottom: 6px;
+        right: 24px;
+        top: auto;
+        cursor: pointer;
+      }
+
+      .daterangepicker .ranges li.active {
+        background: #728dee;
+        border: 1px solid #728dee;
+      }
+      .daterangepicker td.active,
+      .daterangepicker td.active:hover {
+        background: #728dee;
+      }
+    }
+  }
+}
+</style>
+<style lang="less">
+.my-all-select {
+  .ivu-input {
+    height: 34px;
+    border: 1px solid #ccc;
+    &:hover,
+    &:active,
+    &:focus {
+      outline: none;
+      border-color: #2d8cf0;
+    }
+  }
+}
+</style>

+ 362 - 0
src/views/main/StatusTable.vue

@@ -0,0 +1,362 @@
+<template>
+  <div class="status-table">
+      <div class="my-box">
+           <i-Table stripe  :columns="columns1" :data="tableData" size="large" :no-data-text="noData"  @on-sort-change="onSortChange"></i-Table>
+      </div>
+      <div class="mask-bg"></div>
+     <div id="messageBox" v-if="itemsData">
+        <pomp-box :itemsData="itemsData" :detailData='detailData' :messageName='messageName' :emailName='emailName' @onClose="close"></pomp-box>
+    </div>
+  </div>
+</template>
+
+<script>
+import pompBox from './PompBox'
+// import { formatTime, toHourMinute} from '../../tools/formatTime.js'
+import axios from 'axios'
+export default {
+  components: {
+    pompBox
+  },
+
+  mixins: [],
+
+  props: ['tableData'],
+
+  data () {
+    return {
+      itemsData: {},
+      messageName: [],
+      detailData: {},
+      emailName: [],
+      noData:
+        '<div style="padding-top:204px;height:868px;"><img src="/static/img/handleicon.png">' +
+        '<p style="font-size: 16px;margin-top:48px;color: #6D747C;">报警已全部帮您自动处理</p> <p style="font-size:16px;color:#6D747C">您可前往<button style="width:101px;height:30px;margin-left:10px;border: 1px solid #728DEE;border-radius: 2px;color:#728DEE;background: #fff;">查找历史报警</button></p></div>',
+      columns1: [
+        {
+          title: "重要级别",
+          key: "level",
+          sortable: 'custom',
+          render: (h, params) => {
+            const text = params.row.level + '级'
+            if (params.row.level == 'S') {
+              return h('div', [
+                h('img', {
+                  attrs: {
+                    src: '/static/img/ernomal.png'
+                  },
+                  style: {
+                    marginRight: '5px',
+                    verticalAlign: 'middle',
+                    marginTop: '-3px'
+                  }
+                }),
+                h('span', {
+                  style: {
+                    color: '#F08378'
+                  }
+                }, '' + text)
+              ])
+            } else if (params.row.level == 'A') {
+              return h('div', [
+                h('span', {
+                  style: {
+                    color: '#F08378',
+                    marginLeft: '10px'
+                  }
+                }, '' + text)
+              ])
+            } else if (params.row.level == 'B') {
+              return h('div', [
+                h('span', {
+                  style: {
+                    color: '#F3B767',
+                    marginLeft: '10px'
+                  }
+                }, '' + text)
+              ])
+            } else {
+              return h('div', [
+                h('span', {
+                  style: {
+                    marginLeft: '10px'
+                  }
+                }, '' + text)
+              ])
+            }
+          }
+        },
+        {
+          title: "报警类型",
+          key: "type"
+        },
+        {
+          title: "报警内容",
+          key: "content",
+          width: 400,
+          className: "description-td",
+          render: (h, params) => {
+            const content = params.row.content ? params.row.content : ""
+            if (content) {
+              const text1 = content.split("/")[0]
+              const text2 = content.split("/")[1]
+              return h('div', [
+                h('span', {
+                  style: {
+                    marginRight: '18px'
+
+                  }
+                }, text1),
+                h('span', {
+                  style: {
+                    color: "#A6ADB5"
+                  }
+                }, text2)
+              ])
+            }
+          }
+        },
+        {
+          title: "报警开始时间",
+          key: "cTime",
+          sortable: 'custom'
+        },
+        {
+          title: "报警持续时间",
+          key: "durationT",
+          sortable: 'custom',
+          align: 'right'
+        },
+        {
+          title: "报警状态",
+          key: "status",
+          align: 'center',
+          render: (h, params) => {
+            const status = params.row.status
+            if (status == 'alarm') {
+              return h('div', [
+                h('Button', {
+                  props: {
+                    type: 'text',
+                    size: 'small'
+                  },
+                  style: {
+                    color: '#F08378'
+                  }
+                }, '未恢复')
+              ])
+            } else {
+              return h('div', [
+                h('Button', {
+                  props: {
+                    type: 'text',
+                    size: 'small'
+                  },
+                  style: {
+                    color: '#3BC6A1'
+                  }
+                }, '已恢复')
+              ])
+            }
+          }
+        },
+        {
+          title: "处理情况",
+          key: "deal",
+          align: 'center',
+          render: (h, params) => {
+            const deal = params.row.deal
+            const status = params.row.event ? params.row.event.status : ""
+            const id = params.row.event ? params.row.event.id : ""
+            if (deal == 0) {
+              return h('div', [
+                h('Button', {
+                  props: {
+                    size: 'small'
+                  },
+                  style: {
+                    marginRight: '5px',
+                    color: '#728DEE',
+                    border: '1px solid #728DEE'
+                  },
+                  on: {
+                    click: () => {
+                      this.handleClick(params.row)
+                    }
+                  }
+                }, '需手动处理')
+              ])
+            }
+            if (deal == 1) {
+              const text = '工单状态:' + status + '工单编号:DGFJKALJNLPPPK782200' + id
+              return h('div', [
+                h('img', {
+                  attrs: {
+                    src: '/static/img/bill.png'
+                  },
+                  style: {
+                    marginRight: '5px',
+                    verticalAlign: 'middle'
+                  }
+                }),
+                h('span', {
+                  style: {
+                    marginRight: '5px',
+                    color: '#6D747C',
+                    cursor: 'pointer'
+                  },
+                  on: {
+                    click: () => {
+                      this.handleClick(params.row)
+                    }
+                  }
+                }, text)
+              ])
+            }
+            if (deal == 2) {
+              const text = '事件状态:' + status + '事件编号:' + id
+              return h('div', [
+                h('img', {
+                  attrs: {
+                    src: '/static/img/event.png'
+                  },
+                  style: {
+                    marginRight: '5px',
+                    verticalAlign: 'middle'
+                  }
+                }),
+                h('span', {
+                  style: {
+                    marginRight: '5px',
+                    color: '#6D747C',
+                    cursor: 'pointer'
+                  },
+                  on: {
+                    click: () => {
+                      this.handleClick(params.row)
+                    }
+                  }
+                }, text)
+              ])
+            }
+          }
+        }
+      ]
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    // iview的排序
+    onSortChange (col) {
+      this.$emit('setSort', col)
+    },
+    handleClick (row) {
+      document.querySelector('.mask-bg').style.display = 'block'
+      document.querySelector('#messageBox').style.display = 'block'
+      this.itemsData = row
+      this.getEamilInfo(row)
+    },
+    getEamilInfo (row) {
+      let params = {
+        id: row.id
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/detail/query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.detailData = data.Content
+          if (data.Content && data.Content.notification) {
+            let emailName = data.Content.notification.mail ? data.Content.notification.mail : []
+            let messageName = data.Content.notification.message ? data.Content.notification.message : []
+            this.emailName = []
+            if (emailName.length > 0) {
+              emailName.forEach(el => {
+                this.emailName.push(el.name)
+              })
+            }
+
+            this.messageName = []
+            if (messageName.length > 0) {
+              messageName.forEach(el => {
+                this.messageName.push(el.name)
+              })
+            }
+          } else {
+            this.messageName = []
+            this.emailName = []
+          }
+        }
+      })
+    },
+    close () {
+      document.querySelector('.mask-bg').style.display = 'none'
+      document.querySelector('#messageBox').style.display = 'none'
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.status-table {
+    .my-box{
+       padding: 0 20px 20px 24px;
+       background: #fff;
+    }
+    .mask-bg {
+      position: fixed;
+      top: 0;
+      bottom: 0;
+      left: 0;
+      right: 0;
+      z-index: 99;
+      background:rgba(0, 0, 0, .6);
+      display: none;
+    }
+    #messageBox{
+      width: 747px;
+      height: 630px;
+      background: #fff;
+      box-shadow: 0 2px 8px 0 rgba(0,0,0,0.12);
+      border-radius: 4px;
+      z-index: 999;
+      position: fixed;
+      top: 70px;
+      left: 50%;
+      margin-left: -360px;
+      display: none;
+    }
+}
+</style>
+<style lang="less">
+.status-table{
+    .ivu-table-wrapper {
+    border: none;
+  }
+  .ivu-table td,
+  .ivu-table th {
+    border: none;
+  }
+  .ivu-table:before{
+      height: 0;
+  }
+  .ivu-table:after{
+      width:0;
+  }
+  .ivu-table-row .description-td>.ivu-table-cell>span{
+        // overflow: hidden;
+        // text-overflow: ellipsis;
+        // white-space: nowrap;
+        max-height: 100px;
+        display: inline-block;
+    }
+}
+
+</style>

+ 350 - 0
src/views/main/TableAlarm.vue

@@ -0,0 +1,350 @@
+<template>
+  <div class="my-table">
+      <div class="my-box">
+           <i-Table stripe  :columns="columns1" :data="tableData" size="large" :no-data-text="noData"  @on-sort-change="onSortChange"></i-Table>
+      </div>
+      <div class="mask-bg"></div>
+     <div id="messageBox" v-if="itemsData">
+        <pomp-box :itemsData="itemsData" :detailData='detailData' :messageName='messageName' :emailName='emailName' @onClose="close"></pomp-box>
+    </div>
+  </div>
+</template>
+
+<script>
+import pompBox from './PompBox'
+// import { formatTime, toHourMinute} from '../../tools/formatTime.js'
+import axios from 'axios'
+export default {
+  components: {
+    pompBox
+  },
+
+  mixins: [],
+
+  props: ['tableData'],
+
+  data () {
+    return {
+      itemsData: {},
+      messageName: [],
+      emailName: [],
+      detailData: {},
+      noData:
+        '<div style="padding-top:204px;height:868px;"><i class="iconfont icon-kongzhuangtaiicon" style="font-size:98px;"></i>' +
+        '<p style="font-size: 16px;color: #6D747C;">当前状态良好,没有未恢复的报警</p> <p style="font-size:16px;color:#6D747C">您可前往<button style="width:101px;height:30px;margin-left:10px;border: 1px solid #728DEE;border-radius: 2px;color:#728DEE;background: #fff;">查找历史报警</button></p></div>',
+      columns1: [
+        {
+          title: "重要级别",
+          key: "level",
+          sortable: 'custom',
+          render: (h, params) => {
+            const text = params.row.level + '级'
+            if (params.row.level == 'S') {
+              return h('div', [
+                h('img', {
+                  attrs: {
+                    src: '/static/img/ernomal.png'
+
+                  },
+                  style: {
+                    marginRight: '5px',
+                    verticalAlign: 'middle',
+                    marginTop: '-3px'
+                  }
+                }),
+                h('span', {
+                  style: {
+                    color: '#F08378'
+                  }
+                }, '' + text)
+              ])
+            }
+            if (params.row.level == 'A') {
+              return h('div', [
+                h('span', {
+                  style: {
+                    color: '#F08378',
+                    marginLeft: '10px'
+                  }
+                }, '' + text)
+              ])
+            }
+            if (params.row.level == 'B') {
+              return h('div', [
+                h('span', {
+                  style: {
+                    color: '#F3B767',
+                    marginLeft: '10px'
+                  }
+                }, '' + text)
+              ])
+            } else {
+              return h('div', [
+                h('span', {
+                  style: {
+                    marginLeft: '10px'
+                  }
+                }, '' + text)
+              ])
+            }
+          }
+        },
+        {
+          title: "报警类型",
+          key: "type"
+
+        },
+        {
+          title: "报警内容",
+          key: "content",
+          width: 400,
+          className: "description-td",
+          render: (h, params) => {
+            const content = params.row.content ? params.row.content : ""
+            if (content) {
+              const text1 = content.split("/")[0]
+              const text2 = content.split("/")[1]
+              return h('div', [
+                h('span', {
+                  style: {
+                    marginRight: '18px'
+                  }
+                }, text1),
+                h('span', {
+                  style: {
+                    color: "#A6ADB5"
+                  }
+                }, text2)
+              ])
+            }
+          }
+        },
+        {
+          title: "报警开始时间",
+          key: "cTime",
+          sortable: 'custom'
+        },
+        {
+          title: "报警持续时间",
+          key: "durationT",
+          sortable: 'custom',
+          align: 'right'
+        },
+        {
+          title: "处理情况",
+          key: "deal",
+          align: 'center',
+          render: (h, params) => {
+            const deal = params.row.deal
+            const status = params.row.event ? params.row.event.status : ""
+            const id = params.row.event ? params.row.event.id : ""
+            if (deal == 0) {
+              return h('div', [
+                h('Button', {
+                  props: {
+                    size: 'small'
+                  },
+                  style: {
+                    marginRight: '5px',
+                    color: '#728DEE',
+                    border: '1px solid #728DEE'
+                  },
+                  on: {
+                    click: () => {
+                      this.handleClick(params.row)
+                    }
+                  }
+                }, '需手动处理')
+              ])
+            }
+            if (deal == 1) {
+              const text = '工单状态:' + status + '工单编号:' + id
+              return h('div', [
+                h('img', {
+                  attrs: {
+                    src: '/static/img/bill.png'
+                  },
+                  style: {
+                    marginRight: '5px',
+                    verticalAlign: 'middle'
+                  }
+                }),
+                h('span', {
+                  style: {
+                    marginRight: '5px',
+                    color: '#6D747C',
+                    cursor: 'pointer'
+                  },
+                  on: {
+                    click: () => {
+                      this.handleClick(params.row)
+                    }
+                  }
+                }, text)
+              ])
+            }
+            if (deal == 2) {
+              const text = '事件状态:' + status + '事件编号:' + id
+              return h('div', [
+                h('img', {
+                  attrs: {
+                    src: '/static/img/event.png'
+                  },
+                  style: {
+                    marginRight: '5px',
+                    verticalAlign: 'middle'
+                  }
+                }),
+                h('span', {
+                  style: {
+                    marginRight: '5px',
+                    color: '#6D747C',
+                    cursor: 'pointer'
+                  },
+                  on: {
+                    click: () => {
+                      this.handleClick(params.row)
+                    }
+                  }
+                }, text)
+              ])
+            }
+            if (deal == 3) {
+              const text = '上级线路已断,此条自动隐藏'
+              return h('div', [
+                h('span', {
+                  style: {
+                    marginRight: '5px',
+                    color: '#6D747C',
+                    cursor: 'pointer'
+                  },
+                  on: {
+                    click: () => {
+                      this.handleClick(params.row)
+                    }
+                  }
+                }, text)
+              ])
+            }
+          }
+        }
+      ]
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+  },
+
+  methods: {
+    // iview的排序
+    onSortChange (col) {
+      this.$emit('setSort', col)
+    },
+    handleClick (row) {
+      document.querySelector("body").style.overflow = "hidden"
+      document.querySelector('.mask-bg').style.display = 'block'
+      document.querySelector('#messageBox').style.display = 'block'
+      this.itemsData = row
+      this.getEamilInfo(row)
+    },
+    getEamilInfo (row) {
+      let params = {
+        id: row.id
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/detail/query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.detailData = data.Content
+          if (data.Content && data.Content.notification) {
+            let emailName = data.Content.notification.mail ? data.Content.notification.mail : []
+            let messageName = data.Content.notification.message ? data.Content.notification.message : []
+            this.emailName = []
+            if (emailName.length > 0) {
+              emailName.forEach(el => {
+                this.emailName.push(el.name)
+              })
+            }
+
+            this.messageName = []
+            if (messageName.length > 0) {
+              messageName.forEach(el => {
+                this.messageName.push(el.name)
+              })
+            }
+          } else {
+            this.messageName = []
+            this.emailName = []
+          }
+        }
+      })
+    },
+    close () {
+      document.querySelector("body").style.overflow = "auto"
+      document.querySelector('.mask-bg').style.display = 'none'
+      document.querySelector('#messageBox').style.display = 'none'
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.my-table {
+    .my-box{
+       padding: 0 20px 20px 24px;
+       background: #fff;
+    }
+    .mask-bg {
+      position: fixed;
+      top: 0;
+      bottom: 0;
+      left: 0;
+      right: 0;
+      z-index: 99;
+      background:rgba(0, 0, 0, .6);
+      display: none;
+    }
+    #messageBox{
+      width: 747px;
+      height: 630px;
+      background: #fff;
+      box-shadow: 0 2px 8px 0 rgba(0,0,0,0.12);
+      border-radius: 4px;
+      z-index: 999;
+      position: fixed;
+      top: 70px;
+      left: 50%;
+      margin-left: -360px;
+      display: none;
+    }
+}
+</style>
+<style lang="less">
+.my-table{
+    .ivu-table-wrapper {
+    border: none;
+  }
+  .ivu-table td,
+  .ivu-table th {
+    border: none;
+  }
+  .ivu-table:before{
+      height: 0;
+  }
+  .ivu-table:after{
+      width:0;
+  }
+  .ivu-table-row .description-td>.ivu-table-cell>span{
+        // overflow: hidden;
+        // text-overflow: ellipsis;
+        // white-space: nowrap;
+        max-height: 100px;
+        display: inline-block;
+    }
+}
+
+</style>

+ 407 - 0
src/views/main/index.vue

@@ -0,0 +1,407 @@
+<template>
+  <div class="first-pages">
+    <div class="myfirst-head" v-if="false">
+      <div class="f-left"></div>
+      <div class="f-right">
+        <p class="f-salarm">近期以下设备或空间状态异常,请多加关注!</p>
+        <p class="f-sroom"><span>风机盘管0001号-二层空调机房、风机盘管0001号-工作大厅、制冷机房-01号 </span>连续多次出现报警</p>
+        <p class="f-longalarm"><span>新风机19号-一楼新风机房</span>出现超长时间报警</p>
+        <Icon type="md-close" class="close-btn" @click="closeBox"/>
+      </div>
+    </div>
+	<div class="f-tab">
+    <div class="s-tab" :class="{clearness: clear == 0}" @click="onClickTab(0)" v-if="unrecoveredCount!=0">
+			<img src="/static/img/alarm.png" alt="">当前未恢复<strong>{{unrecoveredCount}}</strong><span class="s-info">其中严重报警<strong>{{urgencyCount}}</strong></span>
+    </div>
+    <div class="s-tab" :class="{clearness: clear == 0}" @click="onClickTab(0)" v-if="unrecoveredCount==0">
+			<img src="/static/img/alarm.png" alt="">全部报警已恢复
+    </div>
+    <div class="deal-tab" :class="{clearness: clear == 1}" @click="onClickTab(1)" v-if="manualCount!=0">
+      <img src="/static/img/deal.png" alt="">需手动处理<strong>{{manualCount}}</strong>
+    </div>
+    <div class="deal-tab" :class="{clearness: clear == 1}" @click="onClickTab(1)" v-if="manualCount==0">
+      <img src="/static/img/deal.png" alt="">报警全部自动处理
+    </div>
+    <div class="detect-tab" :class="{clearness: clear == 2}" @click="onClickTab(2)">
+      <img src="/static/img/auto.png" alt="">累计为您监测报警数<strong>{{totalCount}}</strong><span v-if="totalCount">其中已帮您自动处理<strong class="deal-info">{{(autoHandledCount/totalCount*100).toFixed(1)}}%</strong></span>
+			<button class="history-alarm">查找历史报警</button>
+    </div>
+  </div>
+  <div class="f-select-table">
+		<my-select ref="mySelect" @setSelectParams="setSelectParams" :datePickerKey='datePickerKey' :dateLimitDays="dateLimitDays"></my-select>
+		<p class="my-alarm">
+			<span>您在报警消息功能中设定过报警通知内容</span>
+			<Checkbox v-model="isAlarm" label="只看通知给我的报警" name="type" @on-change="getDataList"></Checkbox>
+		</p>
+		<table-alarm v-if="clear==0" :tableData='tableData'  @setSort='setSort'></table-alarm>
+		<status-table v-if="clear==1" :tableData='tableData'  @setSort='setSort'></status-table>
+		<history-table v-if="clear==2" :historyTableData='historyTableData' :total='total' :Current='pageCurrent'
+		:pageSize='pageSize' @changeCurrentPage='changeCurrentPage' @setSort='setSort'></history-table>
+  </div>
+  </div>
+</template>
+
+<script>
+import tableAlarm from './TableAlarm'
+import statusTable from './StatusTable.vue'
+import historyTable from './HistoryTable'
+import mySelect from './Select.vue'
+import axios from 'axios'
+import {formatTime, secondsToDay} from '../../tools/formatTime.js'
+import dataPickerConfig from '../../tools/dataPickerConfig.js'
+import Bus from '../../tools/bus.js'
+export default {
+  components: {
+    tableAlarm,
+    mySelect,
+    statusTable,
+    historyTable
+  },
+
+  mixins: [],
+
+  props: [],
+
+  data () {
+    return {
+      datePickerKey: 'all',
+      dateLimitDays: Number.MAX_SAFE_INTEGER,
+      isAlarm: false, // 您在报警消息功能中设定过报警通知内容 复选框的默认值
+      unrecoveredCount: 0,
+      urgencyCount: 0,
+      manualCount: 0,
+      totalCount: 0,
+      autoHandledCount: 0,
+      phoneNum: "13546321876",
+      tableData: [
+      ],
+      selectParams: { // 所有下拉框的默认值
+        selectedLevel: [], // 级别
+        selectedType: [], // 类型
+        selectedPosition: {
+          buildingId: [],
+          floorId: [],
+          spaceId: []
+        }, // 位置
+        selectedDurationTime: "", // 持续时间
+        selectedStartTime: { // 开始时间
+          dStart: "", // 20181115000000
+          dEnd: "" // 20181215000000
+        }
+      },
+      order: { // 选填,没有order字段时按照默认顺序排序
+        column: "", // 要排序的列名,只支持level,duration,ctime
+        asc: true // true升序,false降序
+      },
+      status: 'alarm', // 区分3个tab的状态
+      autoHandle: null, // 区分3个tab的手动自动
+      clear: 0, // 自定义3个tab的样式区分 opcity
+      total: 20, // 分页显示多少条数据
+      pageSize: 10, // 每页显示多少条数据
+      pageCurrent: 1, // 当前页
+      historyTableData: [], // 历史报警的表格数据
+      AlarmList: [] // 报警条目列表
+    }
+  },
+
+  computed: {
+
+  },
+  mounted () {
+    Bus.$on('main-init', this.init)
+    this.init()
+  },
+  methods: {
+    // 初始化调用
+    init () {
+      this.query_statistics()
+      this.getDataList()
+    },
+    // 触发排序函数
+    setSort (col) {
+      this.order.column = col.key
+      this.order.asc = col.order == 'asc'
+      this.getDataList()
+    },
+    // 每个下拉框值变化触发表格数据的返回值
+    setSelectParams (obj) {
+      this.selectParams = obj
+      if (this.clear == 0) {
+        this.status = 'alarm'
+        this.autoHandle = null
+      } else if (this.clear == 1) {
+        this.status = 'alarm'
+        this.autoHandle = false
+      } else {
+        this.status = null
+        this.autoHandle = null
+      }
+      this.getDataList()
+    },
+    // 区分点击的tab,并且传不同的参数的函数
+    onClickTab (status) {
+      if (status == 0) {
+        this.clear = 0
+        this.status = 'alarm'
+        this.autoHandle = null
+        this.datePickerKey = 'all'
+        this.dateLimitDays = Number.MAX_SAFE_INTEGER
+      } else if (status == 1) {
+        this.clear = 1
+        this.status = 'alarm'
+        this.autoHandle = false
+        this.datePickerKey = 'all'
+        this.dateLimitDays = Number.MAX_SAFE_INTEGER
+      } else {
+        this.clear = 2
+        this.status = null
+        this.autoHandle = null
+        this.datePickerKey = 'oneMonth'
+        this.dateLimitDays = 30
+      }
+      this.selectParams.selectedStartTime.dStart = dataPickerConfig[this.datePickerKey].dStart // 20181215000000
+      this.selectParams.selectedStartTime.dEnd = dataPickerConfig[this.datePickerKey].dEnd
+      console.log(this.selectParams.selectedStartTime)
+      this.getDataList()
+    },
+    // 查询3个tab中涉及到的数据
+    query_statistics () {
+      axios.get(`/alarm-system/alarm-system/alarm/statistics/query?projectId=${this.$store.state.projId}&secret=`)
+        .then(res => {
+          let data = res.data
+          if (data.Result == 'success') {
+            this.unrecoveredCount = data.unrecoveredCount
+            this.urgencyCount = data.urgencyCount
+            this.manualCount = data.manualCount
+            this.totalCount = data.totalCount
+            this.autoHandledCount = data.autoHandledCount
+          }
+        })
+    },
+    // 默认未恢复的请求函数
+    getDataList () {
+      // 持续时间的转换
+      let duration = {}
+      if (Object.values(this.selectParams.selectedDurationTime).some(i => i.length)) {
+        if (this.selectParams.selectedDurationTime == '5m') {
+          duration.$lt = 5 * 60
+        } else if (this.selectParams.selectedDurationTime == '2h') {
+          duration.$gte = 300
+          duration.$lte = 2 * 60 * 60
+        } else if (this.selectParams.selectedDurationTime == '24h') {
+          duration.$gte = 2 * 60 * 60
+          duration.$lte = 24 * 60 * 60
+        } else if (this.selectParams.selectedDurationTime == '1d') {
+          duration.$gt = 24 * 60 * 60
+        }
+      } else {
+        duration = null
+      }
+      // 开始时间的转换
+      let ctime = null
+      if (Object.values(this.selectParams.selectedStartTime).some(i => i.length)) {
+        ctime = {
+          $gte: this.selectParams.selectedStartTime.dStart,
+          $lte: this.selectParams.selectedStartTime.dEnd
+        }
+      }
+      let objectId = null
+      if (Object.values(this.selectParams.selectedPosition).some(i => i.length > 0)) {
+        objectId = [...this.selectParams.selectedPosition.buildingId, ...this.selectParams.selectedPosition.floorId, ...this.selectParams.selectedPosition.spaceId].join(',')
+      }
+
+      let order = null
+      if (Object.values(this.order).some(i => i.length)) {
+        order = this.order
+      }
+      let phoneNum = null
+      if (this.isAlarm == false) {
+        phoneNum = null
+      } else {
+        phoneNum = this.phoneNum
+      }
+      // 参数的添加
+      let params = {
+        criteria: {
+          levels: this.selectParams.selectedLevel.length > 0 ? this.selectParams.selectedLevel : null, // 选填,报警等级
+          labels: this.selectParams.selectedType.length > 0 ? this.selectParams.selectedType : null, // 选填,报警类型
+          objectId: objectId,
+          objectName: this.selectParams.keyword == '' ? null : this.selectParams.keyword, // 选填,设备名称,模糊匹配
+          ctime: ctime,
+          duration: duration,
+          status: this.status,
+          autoHandle: this.autoHandle,
+          phoneNum: phoneNum
+        },
+        order: order
+      }
+      // 请求表格数据
+      axios.post(`/alarm-system/alarm-system/alarm/list?projectId=${this.$store.state.projId}&secret=`, params)
+        .then(res => {
+          let data = res.data
+          if (data.Result == 'success') {
+            this.tableData = []
+            this.tableData = data.Content
+            this.total = data.Count
+            this.tableData.forEach(el => {
+              el.cTime = formatTime(el.ctime)
+              el.durationT = secondsToDay(el.duration)
+              el.alarmName = el.alarmName ? el.alarmName : ""
+              el.location = el.source ? el.source : ""
+              el.content = el.alarmName + "/" + el.location
+              if (!el.autoHandle) {
+                el.deal = 0
+              } else {
+                if (el.event.type == 1) {
+                  el.deal = 1
+                } else if (el.event.type == 2) {
+                  el.deal = 2
+                } else {
+                  el.deal = 3
+                }
+              }
+            })
+            // 自己分页
+            if (this.clear == 2) {
+              this.changeCurrentPage(this.pageCurrent)
+            }
+          }
+        })
+    },
+    // 分页 点击的是哪页
+    changeCurrentPage (index) {
+      this.historyTableData = []
+      // 需要显示开始数据的index,(因为数据是从0开始的,页码是从1开始的,需要-1)
+      let _start = (index - 1) * this.pageSize
+      // 需要显示结束数据的index
+      let _end = index * this.pageSize
+      // 截取需要显示的数据
+      this.historyTableData = this.tableData.slice(_start, _end)
+      this.pageCurrent = index
+    },
+    closeBox () {
+      document.querySelector('.myfirst-head').style.display = 'none'
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.first-pages {
+	width: 100%;
+	.myfirst-head {
+		width: 100%;
+		background: #FFF6F5;
+		border-radius: 2px;
+		font-size: 14px;
+		display: flex;
+		margin-bottom:20px;
+		position: relative;
+		.f-left{
+			width: 8px;
+			background: #F08378;
+			display: inline-block;
+		}
+		.f-right{
+			padding: 20px 0 20px 38px;
+			display: inline-block;
+			>p{
+				margin-bottom:0;
+			}
+			.close-btn{
+				position: absolute;
+				right: 12px;
+				top: 12px;
+			}
+			.f-salarm {
+				font-size: 16px;
+				color: #F08378;
+				font-weight: bold;
+			}
+			.f-sroom {
+				padding: 20px 0;
+				&>span {
+					color: #728DEE;
+				}
+			}
+			.f-longalarm >span {
+				color: #728DEE;
+			}
+		}
+	}
+	.f-tab {
+		font-size: 14px;
+		color: #6D747C;
+		display: flex;
+		justify-content:space-between;
+		img{
+			width: 50px;
+			height: 50px;
+			margin-right: 40px;
+			//vertical-align: middle;
+		}
+		strong{
+			font-family: DIN-Medium;
+			font-size: 24px;
+			padding: 0 30px 0 20px;
+		}
+		div{
+			padding: 30px 0 30px 30px;
+			background: #fff;
+			cursor: pointer;
+			border-radius: 2px;
+			display: inline-block;
+			margin-bottom: 20px;
+		}
+		.s-tab {
+			width: 572px;
+			margin-right: 20px;
+			.s-info{
+				color: #E98576;
+			}
+		}
+		.deal-tab{
+			width: 360px;
+			margin-right: 20px;
+		}
+		.detect-tab{
+			width: 730px;
+			position: relative;
+			.deal-info{
+				color: #4EC59E;
+			}
+			.history-alarm{
+				font-size: 14px;
+        color: #728DEE;
+        background: #fff;
+				position: absolute;
+				top: 20px;
+				right: 18px;
+				cursor: pointer;
+			}
+		}
+		.clearness {
+			box-shadow: 0 2px 10px 0 rgba(44,48,62,0.16);
+		}
+	}
+	.f-select-table{
+		background: #FFFFFF;
+		box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+		border-radius: 2px;
+		.my-alarm {
+			padding: 20px 0 20px 24px;
+			font-size: 14px;
+			background: #FFFFFF;
+			display: flex;
+        >span{
+           color: #6D747C;
+           margin-right: 30px;
+        }
+    }
+	}
+}
+</style>
+<style lang='less'>
+
+</style>

+ 157 - 0
src/views/monitoring/index.vue

@@ -0,0 +1,157 @@
+<template>
+  <div class="monitor">
+      <div class="eq-top">
+           <img src="/static/img/backIcon.jpg" alt="" @click="back">
+           <span>返回 </span>
+      </div>
+      <div class="monitor-content">
+          <div class="monitor-video" v-for="(item,index) in 8" :key="index" @click="popMask">
+              <div class="my-video"></div>
+              <p>F001-23</p>
+          </div>
+      </div>
+      <div class="mask-bg"></div>
+      <div class="big-mask">
+          <p>F001-23视频监控<Icon type="md-close" class='close-btn' @click="closeMask"/></p>
+          <div class="mask-container">
+              <div class="video"></div>
+          </div>
+      </div>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: {
+
+  },
+
+  data () {
+    return {
+
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    back () {
+      history.go(-1)
+    },
+
+    popMask () {
+      document.querySelector('body').style.overflow = 'hidden'
+      document.querySelector('.mask-bg').style.display = 'block'
+      document.querySelector('.big-mask').style.display = 'block'
+    },
+    closeMask () {
+      document.querySelector('body').style.overflow = 'auto'
+      document.querySelector('.mask-bg').style.display = 'none'
+      document.querySelector('.big-mask').style.display = 'none'
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.monitor {
+   position: relative;
+    .eq-top {
+        margin-bottom: 20px;
+        margin-left: 20px;
+        >img {
+            vertical-align: middle;
+            cursor: pointer;
+            border: 1px solid #cacaca;
+        }
+        >span {
+            font-size: 16px;
+            color: #212830;
+        }
+    }
+    .monitor-content {
+        margin:20px;
+        padding:40px;
+        background: #FFFFFF;
+        box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+        border-radius: 2px;
+        .monitor-video{
+            background: #F5F5F5;
+            border-radius: 2px;
+            width: 400px;
+            height: 268px;
+            text-align: center;
+            padding:10px;
+            display: inline-block;
+            margin:0 40px 40px 0;
+            .my-video{
+                width: 380px;
+                height: 212px;
+                border-radius: 2px;
+                background: rgba(0,0,0,0.30);
+                cursor: pointer;
+            }
+            p {
+                font-size: 14px;
+                color: #212830;
+                padding-top: 14px;
+            }
+        }
+
+    }
+    .mask-bg {
+      position: fixed;
+      top: 0;
+      bottom: 0;
+      left: 0;
+      right: 0;
+      z-index: 99;
+      background:rgba(0, 0, 0, .6);
+      display: none;
+    }
+    .big-mask {
+      width: 980px;
+      height: 620px;
+      background: #fff;
+      z-index: 999;
+      position: fixed;
+      top: 150px;
+      left: 15%;
+      display: none;
+      p {
+          height: 60px;
+          line-height:60px;
+          padding-left: 40px;
+          color:#fff;
+          background: #728DEE;
+          .close-btn{
+              float: right;
+              margin-right: 15px;
+              margin-top: 20px;
+          }
+      }
+      .mask-container{
+          padding:15px 40px;
+          .video{
+              width: 900px;
+              height: 500px;
+              border-radius: 2px;
+              background: rgba(0,0,0,0.30);
+          }
+      }
+    }
+}
+</style>

+ 195 - 0
src/views/rooms/RoomEq.vue

@@ -0,0 +1,195 @@
+<template>
+  <div class="room-eq">
+      <div v-if="content.length!=0">
+       <div class="eq-box" v-for="(item,index) in content" :key='index'>
+          <div class="box-left">
+              <p class="eq-name">{{item.equipLocalName}}-{{item.equipLocalID}}</p>
+              <p class="eq-type">设备类型: <span v-if="$store.state.equipmentAll.length > 0">{{formatCodetoClass($store.state.equipmentAll, item.category)}}{{facility}}</span></p>
+              <p class="eq-type">设备型号: <span>{{item.specification}}</span></p>
+          </div>
+          <div class="box-right">
+              <img :src="`/data-platform-3/image-service/common/file_get?systemId=dataPlatform&key=${item.equipQRCode}`">
+          </div>
+
+          <div class="box-bottom">
+               <p class="eq-type"  >设备图片: </p>
+               <div class="pic-box" v-if="item.pic">
+                   <ex-swipe :list="item.pic"></ex-swipe>
+              </div>
+              <div class="no-box" v-else>
+                  <img src="/static/img/noimg.png" alt="">
+              </div>
+              <p v-if="item.alarmList"><img src="/static/img/prompt.png" alt=""> 当前 {{item.alarmList.length}} 条报警未恢复:
+                 <span v-for="(ele,index) in item.alarmList" :key="index">{{ele.alarmName}} </span>
+              </p>
+          </div>
+      </div>
+      <p class="other-alarm">另有 {{count}} 个设备未报警</p>
+      </div>
+      <div class="noEq" v-else>
+          空间内设备未发生报警,请继续保持!
+      </div>
+  </div>
+</template>
+
+<script>
+import {formatCodetoClass} from '../../tools/formatData.js'
+import Swipe from '../../common/swipe'
+// import {mapActions, mapMutations, mapGetters, mapState} from 'vuex'
+import axios from 'axios'
+export default {
+  components: {
+    'ex-swipe': Swipe
+  },
+
+  mixins: [],
+
+  props: {
+
+  },
+
+  data () {
+    return {
+
+      formatCodetoClass,
+
+      content: [
+        //    {
+        //        equipLocalName :"" ,   //设备本地名称
+        //        equipLocalID:""    ,     //设备本地编码
+        //        specification:" ",        //设备型号
+        //        equipQRCode:"",         //设备二维码
+        //        category:""            //设备类型编码
+        //    }
+
+      ],
+      equipmentAll: [],
+      facility: '',
+      count: ''
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+    this.queryEquipmentInSpace()
+  },
+
+  methods: {
+    // 查询设备中空间报警
+    queryEquipmentInSpace () {
+      let params = {
+        spaceId: 'Sp1101080001dbba0f04aa8b11e8bd139b854ebc9e7b' // 空间id
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/equipInSpace/query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.content = data.Content
+          this.count = data.EquipCount - data.Count
+        }
+      })
+    }
+
+    // 所有的设备类型编码和对应的设备类型
+    // getEquipmentAll(){
+    //     axios.get(`/data-platform-3/data-platform-3/dict/query/equipment_all`).then(res=>{
+    //       let data = res.data;
+    //       if(data.Result=='success'){
+    //           this.equipmentAll = data.Content;
+    //           this.queryEquipmentInSpace();
+    //       }
+    //     })
+    // },
+    // 将设备类型编码转换成对应的设备类型
+    // formatCodetoClass(this, str){
+    //     let code = str.slice(2,str.length)
+    //     this.equipmentAll.forEach(i=>{
+    //         if(i.code == str.slice(0,2)){
+    //              i.content.forEach(j=>{
+    //             let item = j.content.find(k=>k.code == code)
+    //             if(item){
+    //               this.facility = item.facility
+    //             }
+    //         })
+    //         }
+
+    //     })
+    // }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.room-eq {
+    margin:0 20px 0 20px;
+    .noEq{
+        padding-bottom: 40px;
+    }
+    .eq-box {
+        background: #FAFAFA;
+        border: 1px solid #E0E0E0;
+        border-radius: 2px;
+        display: inline-block;
+        margin-right: 18px;
+        //min-width: 380px;
+        width: 560px;
+        padding: 20px 20px 20px 20px;
+        margin-bottom: 30px;
+        .box-left {
+            float: left;
+            .eq-name {
+              font-size: 18px;
+              color: #728DEE;
+              font-weight: bold;
+           }
+           .eq-type{
+                font-size: 14px;
+                color: #6D747C;
+                line-height: 16px;
+                padding:9px 0;
+               >span{
+                   color: #212830;
+                   padding-left: 14px;
+               }
+           }
+        }
+        .box-right{
+            float: right;
+            margin-right: 45px;
+            >img{
+                width:91px;
+                height: 90px;
+            }
+        }
+        .box-bottom {
+            clear: both;
+            color: #F08378;
+            font-weight: bold;
+            .pic-box {
+               height: 100px;
+               //width: 500px;
+               margin: 20px 0 20px 20px;
+           }
+           .no-box{
+               height: 100px;
+               //width: 500px;
+               margin: 20px 0 20px 20px;
+               img {
+                   width:96px;
+                   height: 95px;
+               }
+           }
+
+        }
+    }
+    .other-alarm {
+        padding-bottom: 40px;
+    }
+    .removeClass{
+        transform: translateX(-100px);
+    }
+}
+</style>

+ 386 - 0
src/views/rooms/index.vue

@@ -0,0 +1,386 @@
+<template>
+  <div class="rooms">
+      <div class="eq-top">
+           <img src="/static/img/backIcon.jpg" alt="" @click="back">
+           <span>空间详情 / </span>
+            <strong>空间名称-空间编号报警详情</strong>
+      </div>
+      <div class="eq-head" v-if="false">
+		<div class="f-left"></div>
+		<div class="f-right">
+			<p class="f-salarm">近期多次出现以下报警:“电流谐波畸变率过高”、“室温温度传感器出错”、“电压过压”。可能存在设备或零件老化,请多加关注!</p>
+			<Icon type="md-close" class="close-btn" @click="closeBox"/>
+		</div>
+	</div>
+      <div class="eq-bottom">
+          <div class="alarm-top">
+            <span @click="onClickTab(0)" :class="{active: activeIndex== 0}">当前未恢复</span>
+            <span @click="onClickTab(1)" :class="{active: activeIndex== 1}">近期报警记录</span>
+            <span @click="onClickTab(2)" :class="{active: activeIndex== 2}">手动处理备注</span>
+            <span @click="onClickTab(3)" :class="{active: activeIndex== 3}">空间内报警的设备</span>
+          </div>
+          <div v-if="activeIndex==0">
+               <table-alarm :tableData="tableData" @setSort='setSort'></table-alarm>
+          </div>
+          <div v-if="activeIndex==1">
+                <div class="my-select-type">
+                    <my-select :dateLimitDays='dateLimitDays' @setSelectParams="setSelectParams" @setChangeAlarm='setChangeAlarm' :datePickerKey='datePickerKey' :changeAlarm='changeAlarm' :alarmNameList='alarmNameList'></my-select>
+               </div>
+               <history-table :historyTableData='historyTableData' :total='total' :Current='pageCurrent'
+		:pageSize='pageSize' @changeCurrentPage='changeCurrentPage'  @setSort='setSort'></history-table>
+          </div>
+          <div  v-if="activeIndex==2">
+              <my-handle :objectId='objectId'></my-handle>
+          </div>
+          <div v-if="activeIndex==3">
+            <room-eq></room-eq>
+          </div>
+      </div>
+  </div>
+</template>
+
+<script>
+import tableAlarm from '../main/TableAlarm.vue'
+import mySelect from '../equipment/EqSelect.vue'
+import myHandle from '../equipment/Handle.vue'
+import historyTable from '../main/HistoryTable'
+import roomEq from './RoomEq.vue'
+import {formatTime, secondsToDay} from '../../tools/formatTime.js'
+import dataPickerConfig from '../../tools/dataPickerConfig.js'
+// import {mapActions, mapMutations, mapGetters, mapState} from 'vuex'
+import axios from 'axios'
+export default {
+  components: {
+    tableAlarm,
+    mySelect,
+    myHandle,
+    roomEq,
+    historyTable
+  },
+
+  mixins: [],
+
+  props: {
+
+  },
+
+  data () {
+    return {
+      datePickerKey: 'oneMonth',
+      dateLimitDays: Number.MAX_SAFE_INTEGER,
+      activeIndex: 0,
+      pageSize: 15,
+      historyTableData: [],
+      tableData: [],
+      total: null,
+      pageCurrent: 1,
+      status: 'alarm', // 区分3个tab的状态
+      autoHandle: null, // 区分3个tab的手动自动
+      order: { // 选填,没有order字段时按照默认顺序排序
+        column: '', // 要排序的列名,只支持level,duration,ctime
+        asc: true // true升序,false降序
+      },
+      selectParams: { // 所有下拉框的默认值
+        selectedLevel: [], // 级别
+        selectedType: [], // 类型
+        selectedCode: [],
+        selectedPosition: {
+          buildingId: [],
+          floorId: [],
+          spaceId: []
+        }, // 位置
+        selectedDurationTime: '', // 持续时间
+        selectedStartTime: { // 开始时间
+
+          dStart: '',
+          dEnd: ''
+        },
+        alarmName: []
+      },
+      alarmNameList: [],
+      objectId: 'Sp1101080002001000007',
+      changeAlarm: 0
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+    this.getDataList()
+    this.saveAlarmName()
+  },
+
+  methods: {
+    // 监控到如果时间改变,重新触发请求报警条目的函数
+    setChangeAlarm () {
+      this.saveAlarmName()
+    },
+    // 存储条目数
+    saveAlarmName () {
+      let ctime = {}
+      if (Object.values(this.selectParams.selectedStartTime).some(i => i.length)) {
+        ctime = {
+          $gte: this.selectParams.selectedStartTime.dStart,
+          $lte: this.selectParams.selectedStartTime.dEnd
+        }
+      } else {
+        ctime = null
+      }
+      let params = {
+        objectId: this.objectId,
+        ctime: ctime
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/alarmName/list?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.alarmNameList = data.Content
+          this.alarmNameList = this.alarmNameList.map(el => {
+            return {value: el, text: el}
+          })
+        }
+      })
+    },
+    back () {
+
+    },
+    closeBox () {
+      document.querySelector('.eq-head').style.display = 'none'
+    },
+    // 触发排序函数
+    setSort (col) {
+      this.order.column = col.key
+      this.order.asc = col.order == 'asc'
+      this.getDataList()
+    },
+    // 每个下拉框值变化触发表格数据的返回值
+    setSelectParams (obj) {
+      this.selectParams = obj
+      if (this.change == 1) {
+        this.saveAlarmName()
+      }
+      if (this.activeIndex == 0) {
+        this.status = 'alarm'
+        this.autoHandle = null
+      } else if (this.activeIndex == 2) {
+        this.status = 'alarm'
+        this.autoHandle = false
+      } else {
+        this.status = null
+        this.autoHandle = null
+      }
+      this.getDataList()
+    },
+    // 3个按钮的点击传参数
+    onClickTab (status) {
+      this.activeIndex = status
+      if (status == 0) {
+        this.status = 'alarm'
+        this.autoHandle = null
+        this.dateLimitDays = Number.MAX_SAFE_INTEGER
+        this.getDataList()
+      } else if (status == 2) {
+        this.status = 'alarm'
+        this.autoHandle = false
+        this.dateLimitDays = Number.MAX_SAFE_INTEGER
+      } else if (status == 1) {
+        this.status = null
+        this.autoHandle = null
+        this.dateLimitDays = 30
+        this.selectParams.selectedStartTime.dStart = dataPickerConfig[this.datePickerKey].dStart // 20181215000000
+        this.selectParams.selectedStartTime.dEnd = dataPickerConfig[this.datePickerKey].dEnd
+        this.getDataList()
+        this.saveAlarmName()
+      }
+    },
+    // 默认未恢复的请求函数
+    getDataList () {
+      // 得到项目id和secret
+      let params
+      // 持续时间的转换
+      let duration = {}
+      if (Object.values(this.selectParams.selectedDurationTime).some(i => i.length)) {
+        if (this.selectParams.selectedDurationTime == '5m') {
+          duration.$lt = 5 * 60
+        } else if (this.selectParams.selectedDurationTime == '2h') {
+          duration.$gte = 300
+          duration.$lte = 2 * 60 * 60
+        } else if (this.selectParams.selectedDurationTime == '24h') {
+          duration.$gte = 2 * 60 * 60
+          duration.$lte = 24 * 60 * 60
+        } else if (this.selectParams.selectedDurationTime == '1d') {
+          duration.$gt = 24 * 60 * 60
+        }
+      } else {
+        duration = null
+      }
+      // 开始时间的转换
+      let ctime = {}
+      if (Object.values(this.selectParams.selectedStartTime).some(i => i.length)) {
+        ctime = {
+          $gte: this.selectParams.selectedStartTime.dStart,
+          $lte: this.selectParams.selectedStartTime.dEnd
+        }
+      } else {
+        ctime = null
+      }
+      let order = null
+      if (Object.values(this.order).some(i => i.length)) {
+        order = this.order
+      }
+      // 参数的添加
+      if (this.activeIndex == 0) {
+        params = {
+          criteria: {
+            objectId: this.objectId,
+            status: this.status
+          },
+          order: order
+        }
+      } if (this.activeIndex == 1) {
+        params = {
+          criteria: {
+            levels: this.selectParams.selectedLevel.length > 0 ? this.selectParams.selectedLevel : null, // 选填,报警等级
+            objectId: this.objectId,
+            ctime: ctime,
+            duration: duration,
+            alarmName: this.selectParams.alarmName.length > 0 ? this.selectParams.alarmName : null, // 报警条目
+            status: this.status,
+            autoHandle: this.autoHandle
+          },
+          order: order
+        }
+      }
+      // 请求表格数据
+      axios.post(`/alarm-system/alarm-system/alarm/list?projectId=${this.$store.state.projId}&secret=`, params)
+        .then(res => {
+          let data = res.data
+          if (data.Result == 'success') {
+            this.tableData = data.Content
+            this.total = data.Count
+            this.tableData.forEach(el => {
+              el.cTime = formatTime(el.ctime)
+              el.durationT = secondsToDay(el.duration)
+              el.alarmName = el.alarmName ? el.alarmName : ''
+              el.location = el.source ? el.source : ''
+              el.content = el.alarmName + '/' + el.location
+              if (!el.autoHandle) {
+                el.deal = 0
+              } else {
+                if (el.event.type == 1) {
+                  el.deal = 1
+                } else if (el.event.type == 2) {
+                  el.deal = 2
+                } else {
+                  el.deal = 3
+                }
+              }
+            })
+            // 自己分页
+            if (this.activeIndex == 1) {
+              this.changeCurrentPage(this.pageCurrent)
+            }
+          }
+        })
+    },
+    // 分页 点击的是哪页
+    changeCurrentPage (index) {
+      this.historyTableData = []
+      // 需要显示开始数据的index,(因为数据是从0开始的,页码是从1开始的,需要-1)
+      let _start = (index - 1) * this.pageSize
+      // 需要显示结束数据的index
+      let _end = index * this.pageSize
+      // 截取需要显示的数据
+      this.historyTableData = this.tableData.slice(_start, _end)
+      this.pageCurrent = index
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.rooms {
+    .eq-top {
+         margin-bottom: 20px;
+        >img {
+            vertical-align: middle;
+            cursor: pointer;
+            border: 1px solid #CACACA;
+            border-radius: 2px;
+        }
+        >span {
+            font-size: 16px;
+            color: #728DEE;
+        }
+    }
+    .eq-head {
+        width: 100%;
+		background: #FFF6F5;
+		border-radius: 2px;
+		font-size: 14px;
+		display: flex;
+        margin:10px 0 20px 0;
+        //height: 60px;
+        position: relative;
+		.f-left {
+			width: 8px;
+			background: #F08378;
+			display: inline-block;
+		}
+		.f-right {
+			padding: 20px 0 20px 38px;
+			display: inline-block;
+			.close-btn {
+				position: absolute;
+				right: 12px;
+				top: 22px;
+			}
+			.f-salarm {
+				font-size: 16px;
+				color: #F08378;
+				font-weight: bold;
+			}
+		}
+    }
+    .eq-bottom {
+        background: #FFFFFF;
+        box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+        border-radius: 2px;
+        padding-top:30px;
+        .alarm-top {
+            margin-bottom: 40px;
+            display: flex;
+            justify-content: center;
+            span {
+            text-align: center;
+            padding: 6px 20px;
+            color: #62697b;
+            cursor: pointer;
+            border: 1px solid #cacaca;
+            border-right: none;
+            &:last-child {
+                border-right: 1px solid #cacaca;
+                border-top-right-radius: 3px;
+                border-bottom-right-radius: 3px;
+            }
+            &:first-child {
+                border-top-left-radius: 3px;
+                border-bottom-left-radius: 3px;
+            }
+            &:hover,
+            &.active {
+                background: #728DEE;
+                color: #fff;
+            }
+            }
+        }
+        .my-select-type {
+            padding-left: 30px;
+            padding-right: 20px;
+        }
+    }
+}
+
+</style>

+ 150 - 0
src/views/spread/MessageModal.vue

@@ -0,0 +1,150 @@
+<template>
+  <div class="modal-message">
+      <p>下载<Icon type="md-close" class='close-btn' @click="closeMask"/></p>
+      <div class="mod-content" v-if="flag">
+          <i-Table stripe ref="selection" :columns="columns1" :data="objArr" size="large" :no-data-text="noData"></i-Table>
+          <button class="my-btn" @click="exportData">下载</button>
+      </div>
+       <div class="mod-content" v-else>
+            <img v-if="isQR" :src="`/data-platform-3/image-service/common/file_get?systemId=dataPlatform&key=${isQR}`" alt="">
+            <button class="my-btn" @click="downQR">下载</button>
+     </div>
+  </div>
+</template>
+
+<script>
+import { download } from '../../tools/download.js'
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: ['isQR', 'objArr'],
+
+  data () {
+    return {
+      noData:
+        '<div style="padding-top:204px;height:868px;"><i class="iconfont icon-kongzhuangtaiicon" style="font-size:98px;"></i>' +
+        '<p style="font-size: 16px;color: #6D747C;">当前状态良好,没有未恢复的报警</p> <p style="font-size:16px;color:#6D747C">您可前往<button style="width:101px;height:30px;margin-left:10px;border: 1px solid #728DEE;border-radius: 2px;color:#728DEE;background: #fff;">查找历史报警</button></p></div>',
+      columns1: [
+        {
+          type: 'selection',
+          width: 60,
+          align: 'center'
+        },
+        {
+          title: '文件名称',
+          key: 'name'
+        },
+        {
+          title: '文件编号',
+          key: 'key'
+        },
+        {
+          title: '上传时间',
+          key: 'time',
+          sortable: true
+        }
+      ]
+
+    }
+  },
+
+  computed: {
+    flag () {
+      if (this.isQR === 2) {
+        return true
+      } else {
+        return false
+      }
+    }
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    closeMask () {
+      this.$emit('close')
+    },
+    downQR () {
+      const url = `/data-platform-3/image-service/common/file_get?systemId=dataPlatform&key=${this.isQR}`
+      download(url, 'qr.png')
+    },
+    exportData () {
+      this.$refs.table.exportCsv({
+        filename: '下载表格'
+      })
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.modal-message {
+    p {
+        height: 60px;
+        line-height: 60px;
+        padding-left: 20px;
+        background: #728DEE;
+        color:#fff;
+        font-size: 16px;
+        .close-btn{
+            float: right;
+            padding-top: 20px;
+            padding-right:20px;
+        }
+    }
+    .mod-content{
+        padding:20px;
+        text-align: center;
+        >img{
+            width: 200px;
+            height: 200px;
+        }
+       .my-btn{
+            width:180px;
+            height: 34px;
+            line-height: 34px;
+            color: #fff;
+            font-size: 14px;
+            background: #728DEE;
+            border-radius: 2px;
+            position: absolute;
+            bottom: 0;
+            left: 50%;
+            margin-bottom: 30px;
+            margin-left: -90px;
+        }
+    }
+}
+</style>
+<style lang="less">
+.modal-message {
+    .ivu-table-wrapper {
+    border: none;
+  }
+  .ivu-table td,
+  .ivu-table th {
+    border: none;
+  }
+  .ivu-table:before{
+      height: 0;
+  }
+  .ivu-table:after{
+      width:0;
+  }
+  .ivu-table-row .description-td>.ivu-table-cell>span{
+        // overflow: hidden;
+        // text-overflow: ellipsis;
+        // white-space: nowrap;
+        max-height: 100px;
+        display: inline-block;
+    }
+}
+
+</style>

+ 124 - 0
src/views/spread/PropertyTable.vue

@@ -0,0 +1,124 @@
+<template>
+  <div class="my-table">
+      <div class="my-box">
+           <i-Table stripe  :columns="columns1" :data="tableData" size="large"></i-Table>
+      </div>
+  </div>
+</template>
+
+<script>
+
+// import { formatTime, toHourMinute} from '../../tools/formatTime.js'
+// import {mapActions, mapMutations, mapGetters, mapState} from 'vuex'
+// import axios from 'axios'
+export default {
+  components: {
+  },
+
+  mixins: [],
+
+  props: ['tableData'],
+
+  data () {
+    return {
+      itemsData: {},
+      messageName: [],
+      emailName: [],
+      columns1: [
+        {
+          title: '资产名称',
+          key: 'level'
+        },
+        {
+          title: '资产编号',
+          key: 'type'
+        },
+        {
+          title: '设备类',
+          key: 'content',
+          sortable: true
+        },
+        {
+          title: '未恢复的报警',
+          key: 'ctime'
+        },
+        {
+          title: '设备安装时间',
+          key: 'duration',
+          className: 'description-td'
+        },
+        {
+          title: '操作',
+          key: 'deal',
+          render: (h, params) => {
+            return h('div', [
+              h('Button', {
+                props: {
+                  size: 'small'
+                },
+                style: {
+                  marginRight: '5px',
+                  color: '#728DEE',
+                  border: '1px solid #728DEE'
+                },
+                on: {
+                  click: () => {
+                    this.handleClick(params.row)
+                  }
+                }
+              }, '资产详情')
+            ])
+          }
+        }
+      ]
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+  },
+
+  methods: {
+    handleClick (row) {
+      this.$router.push('asset')
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.my-table {
+    .my-box{
+       background: #fff;
+    }
+}
+</style>
+<style lang="less">
+.my-table{
+    .ivu-table-wrapper {
+    border: none;
+  }
+  .ivu-table td,
+  .ivu-table th {
+    border: none;
+  }
+  .ivu-table:before{
+      height: 0;
+  }
+  .ivu-table:after{
+      width:0;
+  }
+  .ivu-table-row .description-td>.ivu-table-cell>span{
+        // overflow: hidden;
+        // text-overflow: ellipsis;
+        // white-space: nowrap;
+        max-height: 100px;
+        display: inline-block;
+    }
+}
+
+</style>

+ 618 - 0
src/views/spread/index.vue

@@ -0,0 +1,618 @@
+<template>
+  <div class="eq-spread">
+     <div class="vr-left">
+       <p class="left-title">{{Info.infos.EquipLocalName || Info.infos.EquipName}}-{{Info.infos.EquipLocalID || Info.infos.EquipID}}</p>
+       <p class="left-remark">所在位置:<span>{{location}} </span></p>
+       <div class="box-content">
+         <div class="box-left">
+           <table>
+              <tr class="RQ">
+                <td>设备二维码</td>
+                <td class="qr-code">
+                  <img :src="Info.infos.EquipQRCode?`/data-platform-3/image-service/common/file_get?systemId=dataPlatform&key=${Info.infos.EquipQRCode}`:'/static/img/noimg.png'">
+                  <p class="download" v-if="Info.infos.EquipQRCode" @click="downloadFile(Info.infos.EquipQRCode)">下载</p>
+                </td>
+                <td><p v-if="Info.infos.InsuranceNum_his">保险保单 <span>{{Info.infos.InsuranceNum_his.length || 0 }}份</span></p><p v-if="Info.infos.InstallDrawing_his">安装图纸 <span>{{Info.infos.InstallDrawing_his.length || 0 }}份</span></p><p v-if="Info.infos.Drawing_his">设备图纸 <span>{{Info.infos.Drawing_his.length || 0 }}份</span></p></td>
+                <td><p v-if="Info.infos.InsuranceNum_his&Info.infos.InsuranceNum" class="load" @click="downloadFile(2,Info.infos.InsuranceNum)">保险文件下载</p><p class="load" v-if="Info.infos.InstallDrawing_his" @click="downloadFile(2,Info.infos.InstallDrawing)">图纸下载</p><p class="load" v-if="Info.infos.Drawing_his" @click="downloadFile(2,Info.infos.Drawing)">图纸下载</p></td>
+              </tr>
+              <tr>
+                <td>所属系统:</td>
+                <td>--</td>
+                <td>生产厂家:</td>
+                <td>{{Info.infos.Manufacturer || '--'}}</td>
+              </tr>
+              <tr>
+                <td>所属空间:</td>
+                <td>--</td>
+                <td>生产日期:</td>
+                <td>{{Info.infos.ProductDate || '--'}}</td>
+              </tr>
+              <tr>
+                <td>设备型号:</td>
+                <td>{{Info.infos.Specification || '--'}}</td>
+                <td>出厂编号:</td>
+                <td>{{Info.infos.SerialNum || '--'}}</td>
+              </tr>
+              <tr>
+                <td>BIM模型中编码:</td>
+                <td>{{Info.infos.BIMID || '--'}}</td>
+                <td>供应商单位名称:</td>
+                <td>{{Info.infos.Supplier || '--'}}</td>
+              </tr>
+              <tr>
+                <td>采购价格:</td>
+                <td>{{Info.infos.PurchasePrice || '--'}} 元</td>
+                <td>供应商联系人:</td>
+                <td>{{Info.infos.SupplierContactor || '--'}}</td>
+              </tr>
+              <tr>
+                <td>安装位置:</td>
+                <td>{{Info.infos.InstallLocation || '--'}}</td>
+                 <td>供应商联系电话:</td>
+                <td>{{Info.infos.SupplierPhone || '--'}}</td>
+              </tr>
+              <tr>
+                <td>投产日期:</td>
+                <td>{{Info.infos.StartDate || '--'}}</td>
+                <td>保险单号:</td>
+                <td>{{Info.infos.InsuranceNum || '--'}}</td>
+              </tr>
+              <tr>
+                <td>维修商联系电话:</td>
+                <td>{{Info.infos.MaintainerPhone || '--'}}</td>
+                <td>保险公司名称:</td>
+                <td>{{Info.infos.Insurer || '--'}}</td>
+              </tr>
+              <tr>
+                <td>维修商单位名称:</td>
+                <td>{{Info.infos.Maintainer || '--'}}</td>
+                <td>保险公司联系人:</td>
+                <td>{{Info.infos.InsurerContactor || '--'}}</td>
+              </tr>
+              <tr>
+                <td>维修公司联系人:</td>
+                <td>{{Info.infos.InsurerContactor || '--'}}</td>
+                <td>保险公司联系电话:</td>
+                <td>{{Info.infos.InsurerPhone || '--'}}</td>
+              </tr>
+              <tr>
+                <td>维保负责人:</td>
+                <td>{{Info.infos.Principal || '--'}}</td>
+              </tr>
+          </table>
+
+          <p class="more" @click="getMoreInfo(Info)">查看更多<img src="/static/img/more.png"></p>
+         </div>
+           <div class="box-right" >
+           <div class="pic-con">
+              <div id="container"  v-if="Info.infos.Pic">
+              </div>
+               <div class="no-right" v-else>
+                  <img src="/static/img/no_pic.png" alt="">
+                  <p>暂无图片</p>
+              </div>
+           </div>
+            <div class="swip-container" v-if="Info.infos.Pic && Info.infos.Pic.length>0" >
+              <pic-swipe :list='Info.infos.Pic' @onClick="draw">
+              </pic-swipe>
+            </div>
+            <div class="swip-container" v-else>
+               <div>
+                  <img src="/static/img/no_pic.png" alt="">
+                  <br/><br/>
+                  <p>暂无图片</p>
+               </div>
+            </div>
+          </div>
+       </div>
+       <div class="box-bottom">
+          <Collapse v-model="panelValue" accordion @on-change='getTableData'>
+              <Panel name="1">
+                  历史安装在此处的资产
+                  <p slot="content">
+                    <property-table :tableData='tableData'></property-table>
+                  </p>
+              </Panel>
+          </Collapse>
+       </div>
+     </div>
+     <div class="vr-right">
+      <eq-right :Info='Info' :ElecConsumPData='ElecConsumPData' :subsetCount='subsetCount' :repairRadio='repairRadio'
+      :AccElecConsumData="AccElecConsumData" :orderCount='orderCount' :RunStatusData='RunStatusData' :moniData='moniData'></eq-right>
+     </div>
+     <div class="mask-bg"></div>
+     <div class="mask">
+       <message-modal @close='close' :isQR='isQR' :objArr='objArr'></message-modal>
+     </div>
+  </div>
+</template>
+
+<script>
+import PicSwipe from '../vr/PicSwipe'
+import propertyTable from './PropertyTable'
+import eqRight from '../vr/EqRight'
+import messageModal from './MessageModal'
+import {currentTime} from '../../tools/currentDate.js'
+import axios from 'axios'
+export default {
+  components: {
+    PicSwipe,
+    propertyTable,
+    eqRight,
+    messageModal
+  },
+
+  mixins: [],
+
+  props: {
+
+  },
+
+  data () {
+    return {
+      panelValue: '',
+      Info: {
+        infos: {
+          EquipLocalName: '--',
+          EquipLocalID: '--',
+          EquipQRCode: '',
+          Manufacturer: '--',
+          ProductDate: '--',
+          Specification: '--',
+          SerialNum: '--',
+          BIMID: '--',
+          Pic: [],
+          Supplier: '--',
+          PurchasePrice: '--',
+          InstallLocation: '--',
+          StartDate: '--',
+          SupplierContactor: '--',
+          InsuranceNum: '--',
+          MaintainerPhone: '--',
+          Insurer: '--',
+          Maintainer: '--',
+          InsurerContactor: '--',
+          InsurerPhone: '--',
+          Principal: '--'
+        },
+        location: {
+          building: '--',
+          floor: '--'
+        }
+      },
+      bdObjName: '',
+      flObjName: '',
+      sysObjName: "",
+      tableData: [],
+      isQR: 1,
+      objectId: 'Eq1101080001001ACCCOP014',
+      ElecConsumPData: "", // 耗电
+      AccElecConsumData: "", // 累计
+      orderCount: 0, // 工单
+      RunStatusData: "", // 运行状态
+      subsetCount: 0, // 同类设备数量
+      repairRadio: 0, // 故障率
+      moniData: 0, // 摄像头
+      objArr: []
+    }
+  },
+
+  computed: {
+    location () {
+      if (this.bdObjName || this.flObjName || this.sysObjName) {
+        return `${this.bdObjName}-${this.flObjName}-${this.sysObjName}`
+      }
+      return '未知'
+    }
+  },
+
+  mounted () {
+    // this.getId()
+    this.getEqNameAndId()
+    // this.initData(this.objectId)
+    // this.getEqRepair()
+  },
+
+  methods: {
+    getId () {
+      // this.objectId = this.$route.query.id
+      this.initData(this.objectId)
+      this.searchBuildingName(this.objectId)
+      this.getCurrentData(this.objectId)
+      this.underwayOrder(this.objectId)
+      this.getMoniCount(this.objectId)
+    },
+    getEqNameAndId () {
+      let hostUrl = location.search
+      this.objectId = hostUrl.split("&")[1].toString().split("=")[1]
+      let pid = hostUrl.split("&")[0].toString().split("=")[1]
+      console.log(pid, this.$store.state.projId)
+      this.$store.commit('setProId', pid)
+      this.initData(this.objectId)
+      this.searchBuildingName(this.objectId)
+      this.getCurrentData(this.objectId)
+      this.underwayOrder(this.objectId)
+      this.getMoniCount(this.objectId)
+    },
+    // 右侧进行中的工单
+    underwayOrder (objectId) {
+      let params = {
+        order_state: "5",
+        equip_ids: [objectId],
+        user_id: "systemId",
+        project_id: this.$store.state.projId,
+        start_time: "20180101000000",
+        end_time: currentTime(new Date())
+      }
+      axios.post(`/workorder/workorder/restWorkOrderService/queryWorkOrderList`, params).then(res => {
+        let data = res.data
+        this.orderCount = data.Count
+      })
+    },
+    // 同类设备数量
+    getSubset (type) {
+      let params = {
+        noInfo: true,
+        criteria: {
+          type: [type]
+        }
+      }
+      axios.post(`/data-platform-3/data-platform-3/object/subset_query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.subsetCount = data.Count
+        }
+      })
+    },
+    // 故障率
+    getEqRepair () {
+      axios.get(`/info-mng-backend/info-mng-backend/saas/getEqRepairCount?projectId=${this.$store.state.projId}`).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.repairRadio = (data.repairCount / data.eqCount) * 100
+        }
+      })
+    },
+    // 耗电量
+    getCurrentData (objectId) {
+      let params = {
+        criterias: [
+          {
+            id: objectId,
+            code: "ElecConsumP"
+          },
+          {
+            id: objectId,
+            code: "AccElecConsum"
+          },
+          {
+            id: objectId,
+            code: "RunStatus"
+          }
+        ]
+      }
+      axios.post(`/data-platform-3/data-platform-3/parameter/batch_query_param?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          let content = data.Content
+          content.forEach(el => {
+            if (el.code == 'ElecConsumP') {
+              this.ElecConsumPData = el.data
+            }
+            if (el.code == 'AccElecConsum') {
+              this.AccElecConsumData = el.data
+            }
+            if (el.code == 'RunStatus') {
+              this.RunStatusData = el.data
+            }
+          })
+        }
+      })
+    },
+    // 摄像头
+    getMoniCount (objectId) {
+      let params = {
+        id: objectId
+      }
+      axios.post(`/api/front-api/monitor/list?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.moniData = data.count
+        }
+      })
+    },
+    // 建筑的名称查询
+    searchBuildingName (objectId) {
+      let params = {
+        keywords: [],
+        category: ['EqObj'],
+        limit: 1,
+        ids: [objectId]
+      }
+      axios.post(`/data-platform-3/data-platform-3/object/search?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+
+        if (data.Result == 'success') {
+          if (data.Content.length > 0) {
+            this.bdObjName = data.Content[0].bdObjName ? data.Content[0].bdObjName : ""
+            this.flObjName = data.Content[0].flObjName ? data.Content[0].flObjName : ""
+            this.sysObjName = data.Content[0].sysObjName ? data.Content[0].sysObjName : ""
+          }
+        }
+      })
+    },
+    // 资产
+    getTableData (key) {
+      let params = {
+        criteria: {
+          graphType: 'EquipinSpace',
+          relType: '1',
+          toId: this.objctId, // 空间id
+          side: 'fromId'
+        }
+      }
+      axios.post(`/data-platform-3/data-platform-3/property/id_query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.tableData = data.Content
+          this.tableData.forEach(el => {
+            el.eqName = el.infos.EquipLocalName || '--'
+            el.eqId = el.infos.EquipLocalID || '--'
+            el.category = el.category // 记得翻译
+            el.location = el.location ? el.location.building : '--' // 拼接
+          })
+        }
+      })
+    },
+    initData (objectId) {
+      let params = {
+        criterias: [
+          {id: objectId}],
+        'historyInfos': true
+      }
+      axios.post(`/data-platform-3/data-platform-3/object/batch_query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.Info = data.Content[0]
+          if (this.Info.infos.Pic) {
+            this.draw(this.Info.infos.Pic[0].key)
+          }
+          if (this.Info.category) {
+            this.getSubset(this.Info.category.slice(2, 6))
+          }
+        }
+      })
+    },
+    // 查看更多的点击事件
+    getMoreInfo (Info) {
+      this.$router.push({path: 'check', query: {obj: JSON.stringify(Info)}})
+    },
+    // 查看全景图
+    draw (key) {
+      var div = document.getElementById('container')
+      // eslint-disable-next-line
+      var PSV = new PhotoSphereViewer({
+        panorama: `/data-platform-3/image-service/common/image_get?systemId=dataPlatform&key=${key}`,
+        container: div,
+        time_anim: false,
+        navbar: true,
+        size: {
+          width: '100%',
+          height: '440px'
+        }
+      })
+    },
+
+    // 下载文件的弹框
+    downloadFile (isQR, objArr) {
+      this.isQR = isQR
+      this.objArr = objArr
+      document.querySelector('body').style.overflow = 'hidden'
+      document.querySelector('.mask-bg').style.display = 'block'
+      document.querySelector('.mask').style.display = 'block'
+    },
+    close () {
+      document.querySelector('body').style.overflow = 'auto'
+      document.querySelector('.mask-bg').style.display = 'none'
+      document.querySelector('.mask').style.display = 'none'
+    }
+
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.eq-spread {
+        font-size: 16px;
+        margin: 0;
+        display: flex;
+        .vr-left {
+          width: 78%;
+          min-width: 1010px;
+          background: #fff;
+          box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+          border-radius: 2px;
+          margin-right: 20px;
+          padding:20px 20px 0 20px;
+          .left-title {
+            font-size: 18px;
+            font-weight: bold;
+            color: #212830;
+          }
+          .left-remark {
+            font-size: 14px;
+            display: inline-block;
+            color: #6D747C;
+            background: #F4F6FE;
+            height: 28px;
+            line-height: 28px;
+            padding-left: 20px;
+            margin: 10px 0;
+          }
+          .box-content {
+            width: 100%;
+            display: flex;
+            justify-content:space-between;
+            .box-left {
+              width:50%;
+              min-width: 500px;
+              background: #F5F5F5;
+              border-radius: 2px;
+              margin-right: 20px;
+              padding-top: 20px;
+              display: inline-block;
+              height: 740px;
+              position: relative;
+
+              .more {
+                position: absolute;
+                font-size: 16px;
+                color: #6682E6;
+                bottom: 13px;
+                right: 20px;
+                cursor: pointer;
+              }
+              tr {
+                td {
+                  padding-left:20px;
+                  padding-top: 8px;
+                  font-size: 14px;
+                  color: #6D747C;
+                  line-height: 24px;
+                  word-break: break-word;
+                  >img{
+                     width:90px;
+                     height: 90px;
+                  }
+                  .load {
+                    color: #6682E6;
+                    cursor: pointer;
+                  }
+                  p{
+                    >span {
+                        color:#212830;
+                    }
+                  }
+                  .download {
+                    font-size: 14px;
+                    color: #6682E6;
+                    cursor: pointer;
+                    padding-left:10px;
+                  }
+                }
+              }
+              .RQ {
+                >td {
+                  vertical-align: top;
+                }
+                .qr-code {
+                  position: relative;
+                  >img:hover + .download {
+                    opacity: 1;
+                  }
+                  .download {
+                    position: absolute;
+                    bottom: 0;
+                    background: rgba(255, 255, 255, .9);
+                    width: 80px;
+                    height: 30px;
+                    line-height: 30px;
+                    z-index: 10;
+                    text-align: center;
+                    color: #6682E6;
+                    font-size: 14px;
+                    cursor: pointer;
+                    opacity: 0;
+                  }
+                }
+              }
+            }
+            .no-right{
+              width: 100%;
+              background: #F5F5F5;
+              border-radius: 2px;
+              height: 440px;
+              display: flex;
+              justify-content: center;
+              align-items: center;
+              flex-direction: column;
+            }
+            .box-right {
+              display: inline-block;
+              width: 50%;
+              background: #fff;
+              border-radius: 2px;
+              .pic-con {
+                background: #F5F5F5;
+                color:#6D747C;
+                #container {
+                  width: 100%;
+                  height: 500px;
+                  display: flex;
+                  justify-content: center;
+                  align-items: center;
+                  cursor: pointer;
+                }
+              }
+              .swip-container{
+                margin-top: 20px;
+               >div{
+                 width:180px;
+                 height: 152px;
+                 background: #F5F5F5;
+                 border-radius: 2px;
+                 text-align: center;
+                 padding-top: 35px;
+                 color: #6D747C;
+               }
+              }
+            }
+          }
+          .box-bottom{
+            margin:40px 0;
+          }
+        }
+        .vr-right{
+          width: 21%;
+          border-radius: 2px;
+          display: inline-block;
+        }
+        .mask-bg{
+          position: fixed;
+          top: 0;
+          bottom: 0;
+          left: 0;
+          right: 0;
+          z-index: 99;
+          background:rgba(0, 0, 0, .6);
+          display: none;
+        }
+        .mask {
+          width: 860px;
+          height: 458px;
+          background: #fff;
+          position: fixed;
+          z-index: 999;
+          top: 120px;
+          left: 30%;
+          display: none;
+        }
+    }
+
+</style>
+<style lang="less">
+ .eq-spread {
+    .box-bottom{
+        .ivu-icon-ios-arrow-forward {
+            float: right;
+            margin-top: 10px;
+            transform: rotate(-90deg);
+        }
+        .ivu-collapse>.ivu-collapse-item>.ivu-collapse-header{
+          background: #F4F5F8;
+          border-radius: 2px;
+      }
+      }
+ }
+</style>

+ 387 - 0
src/views/system/index.vue

@@ -0,0 +1,387 @@
+<template>
+  <div class="system-spread">
+     <div class="vr-left">
+       <p class="left-title">{{Info.infos.SysLocalName || Info.infos.SysName}}-{{Info.infos.SysLocalID || Info.infos.SysID}}</p>
+       <p class="left-remark" v-if="Info.category">{{bdObjName}}-{{SystemCodetoClass(this.$store.state.equipmentAll,Info.category)}}</p>
+       <div class="box-content">
+          <p id="baseInfo"><span></span>技术基本参数</p>
+          <ul>
+              <li><span>系统ID</span>{{Info.infos.SysID || '--'}}</li>
+              <li><span>系统名称</span>{{Info.infos.SysName || '--'}}</li>
+              <li><span>BIM模型中编码</span>{{Info.infos.BIMID || '--'}}</li>
+          </ul>
+          <p id="baseInfo"><span></span>运行基本参数</p>
+          <ul>
+              <li><span>运行状态</span>{{Info.infos.RunStatus || '--'}}</li>
+              <li><span>本地远程状态</span>{{Info.infos.RemoteStatus || '--'}}</li>
+              <li><span>总供冷量</span>{{Info.infos.TotCool || '--'}}</li>
+              <li><span>总供热量</span>{{Info.infos.TotHeat || '--'}}</li>
+              <li><span>总除湿量</span><i>{{Info.infos.TotDeD}}</i></li>
+              <li><span>总加湿量</span>{{Info.infos.TotD || '--'}}</li>
+              <li><span>总耗电功率</span>{{Info.infos.TotElecConsumP || '--'}}</li>
+              <li><span>平均送风温度</span>{{Info.infos.AveSupplyAirV || '--'}} </li>
+              <li><span>平均回风温度</span>{{Info.infos.AveReturnAirV || '--'}} </li>
+              <li><span>总送风量</span>{{Info.infos.TotAirFlow || '--'}}</li>
+              <li><span>末端开启百分比</span>{{Info.infos.TerminalRunPct || '--'}}</li>
+              <li><span>末端负载率</span>{{Info.infos.TerminalPLR || '--'}} </li>
+              <li><span>末端系统COP</span>{{Info.infos.SysCOP || '--'}}</li>
+              <li><span>系统输配系数</span>{{Info.infos.WTFac || '--'}}</li>
+            </ul>
+            <p id="baseInfo"><span></span>技术基本参数</p>
+            <ul>
+                <li><span>末端设备</span>{{Info.infos.TerminalType || '--'}}</li>
+                <li><span>气流组织</span>{{Info.infos.AirDistributionType || '--'}}</li>
+                <li><span>总额定加湿量</span>{{Info.infos.RatedTotD || '--'}}</li>
+                <li><span>总额定除湿量</span>{{Info.infos.RatedTotDeD || '--'}}</li>
+                <li><span>总额定供冷量</span><i>{{Info.infos.RatedTotCool || '--'}}</i></li>
+                <li><span>总额定供热量</span>{{Info.infos.RatedTotHeat || '--'}}</li>
+                <li><span>总额定空气处理量</span>{{Info.infos.RatedTotAirFlow || '--'}}</li>
+              </ul>
+              <div class="sys-tab" v-for="(item,index) in sysEqArr" :key='index' @click="getEq(item.infos.EquipID)">
+                <p class="sys-name">{{item.infos.EquipLocalName || '--'}}-{{item.infos.EquipLocalID || '--'}}</p>
+                <div class="sys-type">
+                  <p>设备类型:{{item.category?formatCodetoClass($store.state.equipmentAll,item.category):'--'}}</p>
+                  <p>设备型号:{{item.infos.Specification || '--'}}</p>
+                </div>
+                <p class="sys-date">{{item.location || '--'}}</p>
+                <p class="sys-date">投产日期:{{item.infos.StartDate?formatTime(item.infos.StartDate) :'--'}} <span>保养周期:{{item.infos.MaintainPeriod || '--'}}</span></p>
+              </div>
+       </div>
+     </div>
+     <div class="vr-right">
+      <eq-right :Info='Info' :noAlarmNum='noAlarmNum' :ElecConsumPData='ElecConsumPData'
+      :AccElecConsumData="AccElecConsumData" :orderCount='orderCount' :moniData='moniData'></eq-right>
+     </div>
+
+  </div>
+</template>
+
+<script>
+
+import eqRight from '../vr/EqRight'
+import {SystemCodetoClass} from '../../tools/systemClass.js'
+import {formatCodetoClass} from '../../tools/formatData.js'
+import {formatTime} from '../../tools/formatTime.js'
+import {currentTime} from '../../tools/currentDate.js'
+import axios from 'axios'
+export default {
+  components: {
+    eqRight
+  },
+
+  mixins: [],
+
+  props: {
+
+  },
+
+  data () {
+    return {
+      formatTime,
+      formatCodetoClass,
+      SystemCodetoClass,
+      objectId: 'Sy1101080001001ACAT599',
+      orderCount: 0, // 进行中的工单数量
+      ElecConsumPData: "", // 耗电功率
+      AccElecConsumData: "", // 累计用电量
+      moniData: 0, // 摄像头
+      noAlarmNum: 0,
+      Info: {
+        infos: {
+          SysLocalName: '--',
+          category: "--"
+        }
+      },
+      bdObjName: '--',
+      sysEqArr: []
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+    this.getSystem()
+    this.initData()
+    this.noRecoverAlarm()
+    this.getCurrentData()
+    this.searchBuildingName()
+    this.underwayOrder()
+    this.getMoniCount()
+  },
+
+  methods: {
+    // 右侧耗电功率和累计用电量的统计
+    getCurrentData () {
+      let params = {
+        criterias: [
+          {
+            id: this.objectId,
+            code: "ElecConsumP"
+          },
+          {
+            id: this.objectId,
+            code: "AccElecConsum"
+          }
+        ]
+      }
+      axios.post(`/data-platform-3/data-platform-3/parameter/batch_query_param?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          let content = data.Content
+          content.forEach(el => {
+            if (el.code == 'ElecConsumP') {
+              this.ElecConsumPData = el.data
+            }
+            if (el.code == 'AccElecConsum') {
+              this.AccElecConsumData = el.data
+            }
+          })
+        }
+      })
+    },
+    // 未恢复的报警条数
+    noRecoverAlarm () {
+      let params = {
+        criteria: {
+          objectId: this.objctId,
+          status: 'alalrm'
+        }
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/list?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.noAlarmNum = data.Count
+        }
+      })
+    },
+    // 右侧进行中的工单
+    underwayOrder () {
+      let params = {
+        order_state: "5",
+        system_ids: [this.objectId],
+        user_id: "systemId",
+        project_id: this.$store.state.projId,
+        start_time: "20180101000000",
+        end_time: currentTime(new Date())
+      }
+      axios.post(`/workorder/workorder/restWorkOrderService/queryWorkOrderList`, params).then(res => {
+        let data = res.data
+        this.orderCount = data.Count
+      })
+    },
+    // 摄像头
+    getMoniCount () {
+      let params = {
+        id: this.objectId
+      }
+      axios.post(`/api/front-api/monitor/list?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.moniData = data.count
+        }
+      })
+    },
+    // 获取数据信息
+    initData () {
+      let params = {
+        criterias: [
+          {id: this.objectId}
+        ]
+      }
+      axios.post(`/data-platform-3/data-platform-3/object/batch_query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.Info = data.Content[0]
+        }
+      })
+    },
+    // 设备建筑查询
+    searchEqBuild (idArr) {
+      let params = {
+        keywords: [],
+        category: ['EqObj'],
+        limit: idArr.length,
+        ids: idArr
+      }
+      axios.post(`/data-platform-3/data-platform-3/object/search?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          let bdObjName, flObjName
+          if (data.Content.length > 0) {
+            bdObjName = data.Content[0].bdObjName ? data.Content[0].bdObjName : "--"
+            flObjName = data.Content[0].flObjName ? data.Content[0].flObjName : "--"
+          } else {
+            bdObjName = '--'
+            flObjName = '--'
+          }
+          this.sysEqArr.forEach(el => {
+            el.location = bdObjName + flObjName
+          })
+        }
+      })
+    },
+
+    // 建筑的名称查询
+    searchBuildingName () {
+      let params = {
+        keywords: [],
+        category: ['SyObj'],
+        limit: 1,
+        ids: [this.objectId]
+      }
+      axios.post(`/data-platform-3/data-platform-3/object/search?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          if (data.Content.length > 0) {
+            this.bdObjName = data.Content[0].bdObjName ? data.Content[0].bdObjName : "--"
+          } else {
+            this.bdObjName = '--'
+          }
+        }
+      })
+    },
+    getSystem () {
+      let params = {
+        criteria: {
+          graphType: 'SystemEquip',
+          relType: '1',
+          fromId: this.objctId, // 空间id
+          side: 'toId'
+        }
+      }
+      axios.post(`/data-platform-3/data-platform-3/object/rel_query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.sysEqArr = data.Content
+          if (this.sysEqArr.length > 0) {
+            let idArr = []
+            this.sysEqArr.forEach(el => {
+              idArr.push(el.id)
+            })
+            this.searchEqBuild(idArr)
+          }
+        }
+      })
+    },
+    getEq (id) {
+      this.$router.push({path: 'spread', query: {id: id}})
+    }
+
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.system-spread {
+        font-size: 16px;
+        margin: 0;
+        display: flex;
+        .vr-left {
+          width: 79%;
+          background: #fff;
+          box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+          border-radius: 2px;
+          margin-right: 20px;
+          padding:20px 20px 0 20px;
+          .left-title {
+            font-size: 18px;
+            font-weight: bold;
+            color: #212830;
+            >span {
+              font-size: 14px;
+              color: #6D747C;
+              margin-left: 34px;
+            }
+          }
+          .left-remark {
+            font-size: 14px;
+            color: #6D747C;
+            background: #F4F6FE;
+            height: 28px;
+            line-height: 28px;
+            padding-left: 20px;
+            margin-top: 10px;
+            display:inline-block;
+          }
+          .box-content {
+            padding-top: 20px;
+               >p {
+                    span {
+                        display: inline-block;
+                        width: 4px;
+                        height: 16px;
+                        background: #728DEE;
+                        margin-right: 10px;
+                        vertical-align: middle;
+                    }
+                }
+                ul {
+                    display: flex;
+                    //justify-content:space-between;
+                    flex-wrap: wrap;
+                    margin-left: 10px;
+                    li {
+                        width: 50%;
+                        padding-bottom: 15px;
+                        overflow: hidden;
+                        text-overflow: ellipsis;
+                        white-space: nowrap;
+                        span {
+                            font-size: 14px;
+                            color: #6D747C;
+                            display: inline-block;
+                            width: 98px;
+                            margin-right: 20px;
+                        }
+                        i{
+                            color:#6682E6;
+                            cursor: pointer;
+                        }
+                    }
+                }
+                .sys-tab{
+                  border-radius: 2px;
+                  background: #FAFAFA;
+                  border: 1px solid #E0E0E0;
+                  margin: 20px 0;
+                  padding: 20px;
+                  .sys-name {
+                    font-size: 16px;
+                    color: #212830;
+                    font-weight: bold;
+                  }
+                  .sys-date{
+                    font-size: 14px;
+                    color: #6D747C;
+                    padding-left: 20px;
+                    >span{
+                      margin-left: 60px;
+                    }
+                  }
+                  .sys-type{
+                    float:right;
+                  }
+                }
+
+          }
+
+        }
+        .vr-right{
+          width: 21%;
+          border-radius: 2px;
+          display: inline-block;
+        }
+
+    }
+</style>
+<style lang="less">
+ .eq-spread {
+    .ivu-icon-ios-arrow-forward {
+      float: right;
+      margin-top: 10px;
+   }
+ }
+</style>

+ 373 - 0
src/views/vr/EqRight.vue

@@ -0,0 +1,373 @@
+<template>
+  <div class="eqS-right">
+       <div class="atten-content">
+         <p>重点关注的内容</p>
+         <div><span></span><li>此区域暂时没有数据!</li></div>
+       </div>
+       <div class="info-center">
+         <div class="i-top" v-if="flag==3">
+           <div class="top-left">
+             <div class="i-box">优</div>
+             <p>环境健康指数</p>
+           </div>
+           <div class="top-right">
+             <p>空气温度: <span>{{envData.Tdb}}℃</span></p>
+             <p>空气湿度: <span>{{envData.RH }}%</span></p>
+             <p>CO2浓度: <span>{{envData.CO }} ppm</span></p>
+             <p>PM2.5: <span>{{envData.PM}} μg/m³</span></p>
+           </div>
+         </div>
+          <div class="i-top2" v-if="flag==1">
+              <p><img src="/static/img/yongxing.png" alt=""> 设备运行状态 <span class="grade">{{RunStatusData || '--'}}</span></p>
+          </div>
+          <div class="i-top2" v-if="flag==4">
+              <p><img src="/static/img/yongxing.png" alt=""> 系统运行状态 <span class="grade">{{RunStatusData || '--'}}</span></p>
+          </div>
+          <div class="i-top2" v-if="flag==2">
+              <p><img src="/static/img/yongxing.png" alt=""> 使用状态 <span class="grade" v-if="linkEq">使用中</span><span v-else>暂无使用</span></p>
+          </div>
+         <div class="i-bottom"  v-if="flag==1 || flag==3 || flag==4">
+           <div class="bottom-left">
+            <p><img src="/static/img/elePower.png"> <strong>{{ElecConsumPData || '--'}}</strong> kW</p>
+            <p class="readmine">耗电功率</p>
+           </div>
+           <div class="bottom-right">
+             <p><img src="/static/img/eleCon.png" alt=""> <strong>{{AccElecConsumData|| '--'}}</strong> kW/h</p>
+             <p class="readmine">累计用电量</p>
+           </div>
+         </div>
+       </div>
+       <div v-if="flag==1" class="fault-rate">
+           <div>
+               <p class="rate-num">{{subsetCount}}</p>
+               <p class="rate-name">同类设备数量</p>
+           </div>
+           <!-- <div>
+               <p class="rate-num">2<span style="font-size:14px">%</span>    </p>
+               <p class="rate-name">平均故障率</p>
+           </div> -->
+           <div>
+               <p class="rate-num">{{repairRadio}}<span style="font-size:14px">%</span> </p>
+               <p class="rate-name">同类设备故障率</p>
+           </div>
+       </div>
+       <div class="detail-info" >
+         <ul>
+           <a :href="`http://47.94.89.44:8058/equipment?pid=${this.$store.state.projId}&${Info.infos.EquipID}&${Info.infos.EquipLocalName}`" target="_black">
+             <li v-if="flag!=2">
+             <a><img src="/static/img/alarmAandS.png" alt="">未恢复的报警 </a>
+             <span class="type-number">{{noAlarmNum}}<img src="/static/img/left.png" alt=""></span>
+           </li>
+           </a>
+           <li v-if="flag!=2">
+             <a><img src="/static/img/order.png" alt="">进行中的工单 </a>
+             <span class="type-number">{{orderCount}}<img src="/static/img/left.png" alt=""></span>
+           </li>
+           <li @click="getMoreMonitor" v-if="flag==3">
+             <a><img src="/static/img/video.png" alt="">查看空间监控</a>
+             <span class="type-number" style="font-size:14px">{{moniData}}个机位<img src="/static/img/left.png" alt=""></span>
+           </li>
+           <li @click="getMoreMonitor" v-if="flag==2 || flag==1">
+             <a><img src="/static/img/video.png" alt="">查看设备相关视频</a>
+              <span class="type-number" style="font-size:14px">{{moniData}}个机位<img src="/static/img/left.png" alt=""></span>
+           </li>
+           <li @click="getMoreMonitor" v-if="flag==4">
+             <a><img src="/static/img/video.png" alt="">系统内相关视频</a>
+             <span class="type-number" style="font-size:14px">{{moniData}}个机位<img src="/static/img/left.png" alt=""></span>
+           </li>
+         </ul>
+         <!-- <div class="video-box">
+           <video class="my-video" ></video>
+           <p><button class="my-button" v-for="(item ,index ) in btn" :key="index" :class="{btnClass:type==item.type}" @click="changeVideo(item)">{{item.name}}</button></p>
+         </div> -->
+       </div>
+  </div>
+</template>
+
+<script>
+
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: {
+    envData: {
+      type: Object,
+      default: () => {}
+    },
+    Info: {
+      type: Object,
+      default: () => {}
+    },
+    noAlarmNum: {
+      type: Number,
+      default: 0
+    },
+    AccElecConsumData: {
+      type: String
+    },
+    ElecConsumPData: {
+      type: String
+    },
+    orderCount: {
+      type: Number
+    },
+    linkEq: {
+      type: String
+    },
+    RunStatusData: {
+      type: String
+    },
+    subsetCount: {
+      type: Number
+    },
+    repairRadio: {
+      type: Number
+    },
+    moniData: {
+      type: Number
+    }
+  },
+
+  data () {
+    return {
+      btn: [{type: 1, name: 'f001'}, {type: 2, name: 'f002'}, {type: 3, name: 'f003'}, {type: 4, name: 'f004'}],
+      type: 1
+
+    }
+  },
+
+  computed: {
+    flag () {
+      if (location.pathname === '/spread') {
+        return 1
+      } else if (location.pathname === '/asset') {
+        return 2
+      } else if (location.pathname === '/vr') {
+        return 3
+      } else if (location.pathname === '/system') {
+        return 4
+      }
+    },
+    RunStatus () {
+      if (this.Info.infos.RunStatus) {
+        return this.Info.infos.RunStatus
+      } else {
+        return '--'
+      }
+    }
+
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    getMoreMonitor () {
+      this.$router.push('monitoring')
+    },
+    changeVideo (item) {
+      this.type = item.type
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.eqS-right {
+    min-width: 300px;
+   .atten-content {
+        background: #FFFFFF;
+        box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+        border-radius: 2px;
+        padding: 20px;
+        >p {
+            font-size: 18px;
+            color: #212830;
+        }
+        div {
+             span {
+                background: #728DEE;
+                width: 8px;
+                height: 8px;
+                border-radius: 50%;
+                //margin-top: 8px;
+                display: inline-block;
+            }
+            li {
+                font-size: 14px;
+                color: #6D747C;
+                list-style: none;
+                padding-left: 14px;
+                display: inline;
+            }
+       }
+    }
+    .info-center{
+        margin: 20px 0;
+        background: #FFFFFF;
+        box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+        border-radius: 2px;
+        .i-top {
+            display: flex;
+            padding: 20px;
+            justify-content: space-evenly;
+            .top-left {
+                .i-box {
+                    background: #3BC6A1;
+                    border-radius: 6px;
+                    width: 80px;
+                    height: 80px;
+                    text-align: center;
+                    line-height: 80px;
+                    font-size: 20px;
+                    color: #FFFFFF;
+                }
+                >p{
+                    margin-top: 14px;
+                    font-size: 14px;
+                    color: #6D747C;
+                }
+            }
+            .top-right {
+                font-size: 14px;
+                color: #6D747C;
+                >p {
+                    margin-bottom: 10px;
+                }
+            }
+       }
+       .i-top2 {
+           padding: 10px 0 15px 20px;
+          p{
+               >img {
+               padding-right: 8px;
+           }
+          }
+           .grade {
+               font-size: 32px;
+               color: #3BC6A1;
+               margin-left: 10%;
+           }
+       }
+        .i-bottom {
+            display: flex;
+            padding: 0 20px 20px 20px;
+            justify-content:space-between;
+            img {
+                //margin-left: -42px;
+               margin-top: -5px;
+            }
+            strong {
+                font-family: 'DIN-Medium';
+                font-size: 18px;
+                color: #212830;
+            }
+            .readmine {
+                font-size: 14px;
+                color: #6D747C;
+            }
+        }
+    }
+    .fault-rate{
+        display: flex;
+        justify-content:space-between;
+        background: #FFFFFF;
+        box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+        border-radius: 2px;
+        padding:20px 20px;
+        margin-bottom:20px;
+        >div{
+            .rate-num {
+                font-size: 36px;
+                color: #212830;
+                text-align: center;
+            }
+            .rate-name {
+                font-size: 14px;
+                color: #6D747C;
+            }
+        }
+    }
+    .detail-info {
+        background: #FFFFFF;
+        box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+        border-radius: 2px;
+        ul {
+            margin-bottom: 0;
+            li {
+                padding-left: 24px;
+                height: 65px;
+                line-height: 65px;
+                font-size: 14px;
+                color: #6D747C;
+                display: flex;
+                align-items:center;
+                justify-content:space-between;
+                cursor: pointer;
+                &:hover {
+                    background: #f5f5f5;
+                }
+                .type-number {
+                    color: #212830;
+                    font-size: 32px;
+                    cursor: pointer;
+                    >img {
+                        margin-left: 14px;
+                    }
+                }
+            img {
+                //vertical-align: middle;
+                margin-right:20px;
+                margin-top: -2px;
+            }
+            }
+        }
+        .video-box{
+            width: 93%;
+            margin: 0 10px;
+            //height: 240px;
+            background: #F5F5F5;
+            border-radius: 2px;
+            .my-video {
+                margin: 10px;
+                width: 95%;
+                //height: 180px;
+                background: rgba(0,0,0,0.30);
+                border-radius: 2px;
+            }
+            >p {
+                padding-left: 10px;
+                .my-button {
+                    width: 52px;
+                    height: 28px;
+                    background: #FFFFFF;
+                    border: 1px solid #728DEE;
+                    border-radius: 2px;
+                    font-size: 14px;
+                    color: #728DEE;
+                    display: inline-block;
+                    margin-right: 10px;
+                    text-align: center;
+                    border-radius: 2px;
+                    margin-bottom: 10px;
+                     &:hover {
+                        background: #728DEE;
+                        color: #fff;
+                    }
+                }
+                 .btnClass{
+                    background: #728DEE;
+                    color: #fff;
+                }
+
+            }
+        }
+   }
+}
+</style>

+ 122 - 0
src/views/vr/EqTable.vue

@@ -0,0 +1,122 @@
+<template>
+  <div class="my-table">
+      <div class="my-box">
+           <i-Table stripe  :columns="columns1" :data="tableData" size="large" ></i-Table>
+      </div>
+  </div>
+</template>
+
+<script>
+
+// import { formatTime, toHourMinute} from '../../tools/formatTime.js'
+// import {mapActions, mapMutations, mapGetters, mapState} from 'vuex'
+// import axios from 'axios'
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: ['tableData'],
+
+  data () {
+    return {
+      itemsData: {},
+      messageName: [],
+      emailName: [],
+      columns1: [
+        {
+          title: '设备名称',
+          key: 'eqName',
+          width: 300
+        },
+        {
+          title: '设备编号',
+          key: 'eqId'
+        },
+        {
+          title: '设备类',
+          key: 'category',
+          sortable: true
+        },
+        {
+          title: '未恢复的报警',
+          key: 'alarmLength'
+        },
+        {
+          title: '操作',
+          key: 'deal',
+          render: (h, params) => {
+            return h('div', [
+              h('Button', {
+                props: {
+                  size: 'small'
+                },
+                style: {
+                  marginRight: '5px',
+                  color: '#728DEE',
+                  border: '1px solid #728DEE'
+                },
+                on: {
+                  click: () => {
+                    this.handleClick(params.row)
+                  }
+                }
+              }, '设备详情')
+            ])
+          }
+        }
+      ]
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    handleClick (row) {
+      this.$router.push({path: 'spread', query: {id: row.id}})
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.my-table {
+    .my-box{
+       background: #fff;
+    }
+}
+</style>
+<style lang="less">
+.my-table{
+    .ivu-table-wrapper {
+    border: none;
+  }
+  .ivu-table td,
+  .ivu-table th {
+    border: none;
+  }
+  .ivu-table:before{
+      height: 0;
+  }
+  .ivu-table:after{
+      width:0;
+  }
+  .ivu-table-row .description-td>.ivu-table-cell>span{
+        // overflow: hidden;
+        // text-overflow: ellipsis;
+        // white-space: nowrap;
+        max-height: 100px;
+        display: inline-block;
+    }
+}
+
+</style>

+ 145 - 0
src/views/vr/PicSwipe.vue

@@ -0,0 +1,145 @@
+<template>
+  <div class="pic-swipe">
+
+       <div v-if="isShowArrow" class="left-loop" :class="{disabled: !isCanClickLeft}"  @click="moveLeft"> <Icon type="ios-arrow-back" size='24'/> </div>
+
+       <div class="loop-content">
+            <div class="contanier" :style="`transform: translateX(-${index * 180}px)`">
+                <span  v-for="(item, index) in list" :key="index">
+                    <img :src="item.key?`/data-platform-3/image-service/common/image_get?systemId=dataPlatform&key=${item.key}&width=96&height=95`:``" @click="onClick(item)">
+                    <span class="alt-name">{{item.name}}</span>
+                </span>
+
+            </div>
+        </div>
+
+        <div v-if="isShowArrow" class="right-loop" :class="{disabled: !isCanClickRight}"  @click="moveRight"> <Icon type="ios-arrow-forward" size='24'/> </div>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: {
+
+    list: {
+      type: Array,
+      default: () => []
+    }
+  },
+
+  data () {
+    return {
+      index: 0,
+      isShowArrow: false,
+      SC: 0,
+      BY: 0
+    }
+  },
+
+  computed: {
+    isCanClickLeft () {
+      return this.index > 0
+    },
+    isCanClickRight () {
+      return (this.index * 180) + this.BD < this.SC
+    }
+  },
+  watch: {
+    list () {
+      this.checkArrow()
+    }
+  },
+  mounted () {
+    this.checkArrow()
+  },
+
+  methods: {
+    checkArrow () {
+      this.$nextTick(() => {
+        this.SC = document.querySelector('.pic-swipe .contanier').scrollWidth
+        this.BD = document.querySelector('.pic-swipe').clientWidth
+        this.isShowArrow = this.SC > this.BD
+      })
+    },
+    moveLeft () {
+      if (this.isCanClickLeft) {
+        this.index--
+      }
+    },
+    moveRight () {
+      if (this.isCanClickRight) {
+        this.index++
+      }
+    },
+    onClick (key) {
+      this.$emit('onClick', key)
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.pic-swipe {
+    display: flex;
+    .left-loop, .right-loop {
+        color: #999DA1;
+        padding-top: 68px;
+        //margin-right: 15px;
+        cursor: pointer;
+        background-color: #EEEEEE;
+        &:hover {
+          background-color: #DDDDDD;
+        }
+    }
+    .left-loop {
+      border-top-left-radius: 4px;
+      border-bottom-left-radius: 4px;
+    }
+    .right-loop {
+      border-top-right-radius: 4px;
+      border-bottom-right-radius: 4px;
+    }
+    .disabled {
+        //cursor: not-allowed;
+       display: none;
+    }
+    .loop-content {
+        white-space: nowrap;
+        overflow: hidden;
+        margin: 0 5px;
+        .contanier {
+            transition: transform 0.3s ease-in-out;
+            >span {
+                position: relative;
+                cursor: pointer;
+                img {
+                    vertical-align: middle;
+                    margin-right: 14px;
+                    width: 180px;
+                    max-height: 152px;
+                }
+                .alt-name{
+                    position: absolute;
+                    left: 3px;
+                    background:#fff;
+                    z-index: 3;
+                    font-size: 14px;
+                    color: #212830;
+                    padding: 4px 10px;
+                    margin: 4px 0 0 4px;
+                    box-shadow: 0 2px 8px 0 rgba(44,48,62,0.10);
+                    border-radius: 2px;
+                }
+            }
+        }
+
+    }
+}
+</style>

+ 693 - 0
src/views/vr/index.vue

@@ -0,0 +1,693 @@
+<template>
+  <div class="my-vr">
+     <div class="vr-left">
+       <p class="left-title">{{Info.infos.RoomLocalName || Info.infos.RoomName}}-{{Info.infos.RoomLocalID || Info.infos.RoomID}}<span> 业务空间类型:{{Info.business_type || '--'}}</span></p>
+       <p class="left-remark">所在位置:{{bdObjName}}-{{flObjName}}</p>
+       <div class="box-content">
+         <div class="box-left">
+           <table>
+              <tr class="RQ">
+                <td>空间二维码</td>
+                <td class="qr-code">
+                  <img :src="Info.infos.RoomQRCode?`/data-platform-3/image-service/common/file_get?systemId=dataPlatform&key=${Info.infos.RoomQRCode}`:'/static/img/noimg.png'">
+                  <p class="download" v-if="Info.infos.RoomQRCode"  @click="downloadFile(Info.infos.RoomQRCode)">下载</p>
+                </td>
+              </tr>
+              <tr>
+                <td>BIM模型中编码:</td>
+                <td>{{Info.infos.BIMID || '--'}}</td>
+              </tr>
+              <tr>
+                <td>空间功能区类型:</td>
+                <td>{{Info.infos.RoomFuncType || '--'}}</td>
+              </tr>
+              <tr>
+                <td>空间本地编码:</td>
+                <td>{{Info.infos.RoomLocalID || '--'}}</td>
+              </tr>
+              <tr>
+                <td>BIM模型中坐标:</td>
+                <td>{{Info.infos.BIMLocation || '--'}}</td>
+              </tr>
+              <tr>
+                <td>进深:</td>
+                <td>{{Info.infos.Depth || '--'}} m</td>
+              </tr>
+              <tr>
+                <td>面宽:</td>
+                <td>{{Info.infos.Width || '--'}} m</td>
+              </tr>
+              <tr>
+                <td>高度:</td>
+                <td>{{Info.infos.Height || '--'}} m</td>
+              </tr>
+              <tr>
+                <td>建筑面积:</td>
+                <td>{{Info.infos.BuildArea || '--'}} m²</td>
+              </tr>
+              <tr>
+                <td>使用面积</td>
+                <td>{{Info.infos.NetArea || '--'}} m²</td>
+              </tr>
+              <tr>
+                <td>配电容量:</td>
+                <td>{{Info.infos.ElecCap || '--'}} A</td>
+              </tr>
+              <tr>
+                <td>租赁业态类型:</td>
+                <td>{{Info.infos.TenantType || '--'}}</td>
+              </tr>
+              <tr>
+                <td>所属租户:</td>
+                <td>{{Info.infos.Tenant || '--'}}</td>
+              </tr>
+          </table>
+          <p class="more" @click="getMoreInfo(Info)">查看更多<img src="/static/img/more.png"></p>
+         </div>
+          <div class="box-right" >
+           <div class="pic-con">
+              <div id="container"  v-if="Info.infos.Pic">
+              </div>
+               <div class="no-right" v-else>
+                  <img src="/static/img/no_pic.png" alt="">
+                  <p>暂无图片</p>
+              </div>
+           </div>
+            <div class="swip-container" v-if="Info.infos.Pic && Info.infos.Pic.length>0" >
+              <pic-swipe :list='Info.infos.Pic' @onClick="draw">
+              </pic-swipe>
+            </div>
+            <div class="swip-container" v-else>
+               <div>
+                  <img src="/static/img/no_pic.png" alt="">
+                  <br/><br/>
+                  <p>暂无图片</p>
+               </div>
+            </div>
+          </div>
+
+       </div>
+       <div class="box-bottom">
+          <Collapse v-model="panelValue" accordion @on-change='getTableData'>
+              <Panel name="1" >
+                  空间内设备
+                  <p slot="content" v-if="tableData">
+                    <eq-table :tableData='tableData'></eq-table>
+                  </p>
+              </Panel>
+              <Panel name="2">
+                  服务于空间设备
+                  <p slot="content" v-if="serveData">
+                    <serve-table :serveData='serveData'></serve-table>
+                  </p>
+              </Panel>
+          </Collapse>`
+       </div>
+     </div>
+     <div class="vr-right">
+      <eq-right :envData='envData' :Info='Info' :noAlarmNum='noAlarmNum' :ElecConsumPData='ElecConsumPData'
+      :AccElecConsumData="AccElecConsumData" :orderCount='orderCount' :moniData='moniData'></eq-right>
+     </div>
+     <div class="mask-bg"></div>
+     <div class="mask">
+       <message-modal @close='close' :isQR='isQR'></message-modal>
+     </div>
+  </div>
+</template>
+
+<script>
+import PicSwipe from './PicSwipe'
+import eqTable from './EqTable'
+import eqRight from './EqRight'
+import messageModal from '../spread/MessageModal'
+import {formatCodetoClass} from '../../tools/formatData.js'
+import {currentTime} from '../../tools/currentDate.js'
+import serveTable from './serveTable'
+import axios from 'axios'
+export default {
+  components: {
+    PicSwipe,
+    eqTable,
+    eqRight,
+    messageModal,
+    serveTable
+  },
+
+  mixins: [],
+
+  props: {
+
+  },
+
+  data () {
+    return {
+      panelValue: '',
+      tableData: [],
+      serveData: [],
+      Info: {
+        business_type: "--",
+        infos: {
+          RoomLocalName: '--',
+          RoomLocalID: '--',
+          RoomQRCode: '',
+          BIMID: '--',
+          RoomFuncType: '--',
+          BIMLocation: '--',
+          Depth: '--',
+          Width: '--',
+          Height: '--',
+          BuildArea: '--',
+          NetArea: '--',
+          ElecCap: '--',
+          TenantType: '--',
+          Tenant: '--',
+          Pic: []
+        },
+        location: {
+          building: '--',
+          floor: '--'
+        }
+      },
+      bdObjName: "--",
+      flObjName: "--",
+      isQR: '',
+      objctId: 'Sp1101080001001003001',
+      ElecConsumPData: "", // 耗电功率
+      AccElecConsumData: "", // 累计用电量
+      orderCount: 0, // 工单
+      moniData: 0, // 摄像头的数量
+      envData: {
+        Tdb: "--",
+        RH: "--",
+        CO: "--",
+        PM: "--"
+      },
+      noAlarmNum: 0
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+    this.initData()
+    this.searchBuildingName()
+    this.noRecoverAlarm()
+    this.envInfo()
+    this.getCurrentData()
+    this.underwayOrder()
+    this.getMoniCount()
+  },
+
+  methods: {
+    // 右侧耗电功率和累计用电量的统计
+    getCurrentData () {
+      let params = {
+        criterias: [
+          {
+            id: this.objctId,
+            code: "ElecConsumP"
+          },
+          {
+            id: this.objctId,
+            code: "AccElecConsum"
+          }
+        ]
+      }
+      axios.post(`/data-platform-3/data-platform-3/parameter/batch_query_param?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          let content = data.Content
+          content.forEach(el => {
+            if (el.code == 'ElecConsumP') {
+              this.ElecConsumPData = el.data
+            }
+            if (el.code == 'AccElecConsum') {
+              this.AccElecConsumData = el.data
+            }
+          })
+        }
+      })
+    },
+    // 右侧进行中的工单
+    underwayOrder () {
+      let params = {
+        order_state: "5",
+        space_ids: [this.objctId],
+        user_id: "systemId",
+        project_id: this.$store.state.projId,
+        start_time: "20180101000000",
+        end_time: currentTime(new Date())
+      }
+      axios.post(`/workorder/workorder/restWorkOrderService/queryWorkOrderList`, params).then(res => {
+        let data = res.data
+        this.orderCount = data.Count
+      })
+    },
+    // 摄像头数量
+    getMoniCount () {
+      let params = {
+        id: this.objctId
+      }
+      axios.post(`/api/front-api/monitor/list?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.moniData = data.count
+        }
+      })
+    },
+    // 空间建筑的名称查询
+    searchBuildingName () {
+      let params = {
+        keywords: [],
+        category: ['SpObj'],
+        limit: 1,
+        ids: [this.objctId]
+      }
+      axios.post(`/data-platform-3/data-platform-3/object/search?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          if (data.Content.length > 0) {
+            this.bdObjName = data.Content[0].bdObjName ? data.Content[0].bdObjName : "--"
+            this.flObjName = data.Content[0].flObjName ? data.Content[0].flObjName : "--"
+          } else {
+            this.bdObjName = '--'
+            this.this.flObjName = '--'
+          }
+        }
+      })
+    },
+    // 未恢复的报警条数
+    noRecoverAlarm () {
+      let params = {
+        criteria: {
+          objectId: this.objctId,
+          status: 'alalrm'
+        }
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/list?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.noAlarmNum = data.Count
+        }
+      })
+    },
+    // c02等信息
+    envInfo () {
+      let params = {
+        criterias: [
+          { id: this.objctId, code: 'Tdb' },
+          { id: this.objctId, code: 'RH' },
+          { id: this.objctId, code: 'CO2' },
+          { id: this.objctId, code: 'PM2.5' }
+        ]
+      }
+      axios.post(`/data-platform-3/data-platform-3/parameter/batch_query_param?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          let info = data.Content
+          info.forEach(el => {
+            if (el.code == 'Tdb') {
+              this.envData.Tdb = el.data ? el.data.toFixed(2) : '--'
+            }
+            if (el.code == 'RH') {
+              this.envData.RH = el.data ? el.data.toFixed(2) : '--'
+            }
+            if (el.code == 'CO2') {
+              this.envData.CO = el.data ? el.data.toFixed(2) : '--'
+            }
+            if (el.code == 'PM2.5') {
+              this.envData.PM = el.data ? el.data.toFixed(2) : '--'
+            }
+          })
+        }
+      })
+    },
+    // 获取数据信息
+    initData () {
+      let params = {
+        criterias: [
+          {id: this.objctId}
+        ]
+      }
+      axios.post(`/data-platform-3/data-platform-3/object/batch_query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          this.Info = data.Content[0]
+          if (this.Info.infos.Pic) {
+            this.draw(this.Info.infos.Pic[0].key)
+          }
+        }
+      })
+    },
+    // 设备建筑查询
+    searchEqBuild (idArr) {
+      let params = {
+        keywords: [],
+        category: ['EqObj'],
+        limit: idArr.length,
+        ids: idArr
+      }
+      axios.post(`/data-platform-3/data-platform-3/object/search?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          let bdObjName, flObjName
+          if (data.Content.length > 0) {
+            bdObjName = data.Content[0].bdObjName ? data.Content[0].bdObjName : "--"
+            flObjName = data.Content[0].flObjName ? data.Content[0].flObjName : "--"
+          } else {
+            bdObjName = '--'
+            flObjName = '--'
+          }
+          this.serveData.forEach(el => {
+            el.eqName = el.infos.EquipLocalName || '--'
+            el.eqId = el.infos.EquipLocalID || '--'
+            // el.category = (el.category) // youwenti
+            el.category = formatCodetoClass(this.$store.state.equipmentAll, el.category) // youwenti
+            el.location = bdObjName + flObjName
+            el.alarmLength = el.alarmLength ? el.alarmLength : 0
+          })
+        }
+      })
+    },
+
+    // 空间内设备
+    getTableData (key) {
+      let params = {
+        criteria: {
+          graphType: 'EquipinSpace',
+          relType: '1',
+          toId: this.objctId, // 空间id
+          side: 'fromId'
+        }
+      }
+      if (key[0] == 1) {
+        params.criteria.graphType = 'EquipinSpace'
+        axios.post(`/data-platform-3/data-platform-3/object/rel_query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+          let data = res.data
+          if (data.Result == 'success') {
+            this.tableData = data.Content
+            this.equipInSpace()
+          }
+        })
+      } else {
+        params.criteria.graphType = 'EquipforSpace'
+        axios.post(`/data-platform-3/data-platform-3/object/rel_query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+          let data = res.data
+          if (data.Result == 'success') {
+            this.serveData = data.Content
+            if (this.serveData.length > 0) {
+              let idArr = []
+              this.serveData.forEach(el => {
+                idArr.push(el.id)
+              })
+              this.equipForSpace()
+              this.searchEqBuild(idArr)
+            }
+          }
+        })
+      }
+    },
+    // 服务于空间设备未恢复的报警条数
+    equipInSpace () {
+      let params = {
+        spaceId: this.objctId // 空间id
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/equipInSpace/query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          let alarm = data.Content
+          if (alarm.length > 0) {
+            alarm.map(j => {
+              this.tableData.map(i => {
+                if (i.infos.EquipID == j.equipmentId) {
+                  i.alarmLength = j.alarmList ? j.alarmList.length : 0
+                }
+              })
+            })
+          }
+          this.tableData.forEach(el => {
+            el.eqName = el.infos.EquipLocalName || '--'
+            el.eqId = el.infos.EquipLocalID || '--'
+            // el.category = (el.category) // youwenti
+            el.category = formatCodetoClass(this.$store.state.equipmentAll, el.category) // youwenti
+            el.location = el.location ? el.location.building : '--' // youwenti
+            el.alarmLength = el.alarmLength ? el.alarmLength : 0
+          })
+        }
+      })
+    },
+    //
+    equipForSpace () {
+      let params = {
+        spaceId: this.objctId // 空间id
+      }
+      axios.post(`/alarm-system/alarm-system/alarm/equipForSpace/query?projectId=${this.$store.state.projId}&secret=`, params).then(res => {
+        let data = res.data
+        if (data.Result == 'success') {
+          let alarm = data.Content
+          if (alarm.length > 0) {
+            this.serveData = this.serveData.map(i => {
+              alarm.map(j => {
+                if (i.infos.EquipID == j.equipmentId) {
+                  i.alarmLength = j.alarmList ? j.alarmList.length : 0
+                }
+              })
+            })
+          }
+        }
+      })
+    },
+    // 查看更多的点击事件
+    getMoreInfo (Info) {
+      this.$router.push({path: 'detail', query: {obj: JSON.stringify(Info)}})
+    },
+    // 查看全景图
+    draw (key) {
+      var div = document.getElementById('container')
+      // let baseUrl = this.$store.state.baseUrl
+      // eslint-disable-next-line
+      var PSV = new PhotoSphereViewer({
+        panorama: `/data-platform-3/image-service/common/image_get?systemId=dataPlatform&key=${key}`,
+        container: div,
+        time_anim: false,
+        navbar: true,
+        size: {
+          width: '100%',
+          height: '440px'
+        }
+      })
+    },
+    // 下载弹框
+    downloadFile (isQR) {
+      this.isQR = isQR
+      document.querySelector('body').style.overflow = 'hidden'
+      document.querySelector('.mask-bg').style.display = 'block'
+      document.querySelector('.mask').style.display = 'block'
+    },
+    close () {
+      document.querySelector('body').style.overflow = 'auto'
+      document.querySelector('.mask-bg').style.display = 'none'
+      document.querySelector('.mask').style.display = 'none'
+    }
+
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.my-vr {
+        font-size: 16px;
+        margin: 0;
+        display: flex;
+        .vr-left {
+          width: 78%;
+          min-width: 900px;
+          background: #fff;
+          box-shadow: 0 2px 10px 0 rgba(44,48,62,0.06);
+          border-radius: 2px;
+          margin-right: 20px;
+          padding:20px 20px 0 20px;
+          .left-title {
+            font-size: 18px;
+            font-weight: bold;
+            color: #212830;
+            >span {
+              font-size: 14px;
+              display: inline-block;
+              color: #6D747C;
+              width: 248px;
+              height: 28px;
+              line-height: 28px;
+              padding-left: 20px;
+              margin-left: 34px;
+            }
+          }
+          .left-remark {
+            font-size: 14px;
+            display: inline-block;
+            color: #6D747C;
+            background: #F4F6FE;
+            height: 28px;
+            line-height: 28px;
+            padding-left: 20px;
+            margin: 10px 0;
+          }
+          .box-content {
+            width: 100%;
+            display: flex;
+            .box-left {
+              width:30%;
+              min-width: 250px;
+              background: #F5F5F5;
+              border-radius: 2px;
+              margin-right: 20px;
+              display: inline-block;
+              position: relative;
+              .more {
+                position: absolute;
+                font-size: 16px;
+                color: #6682E6;
+                bottom: 13px;
+                right: 20px;
+                cursor: pointer;
+              }
+              tr {
+                td {
+                  padding-left:20px;
+                  padding-top: 8px;
+                  font-size: 14px;
+                  color: #6D747C;
+                  line-height: 24px;
+                  word-break: break-word;
+                  >img{
+                     width:90px;
+                     height: 90px;
+                  }
+                  .download {
+                    font-size: 14px;
+                    color: #6682E6;
+                    cursor: pointer;
+                    padding-left:10px;
+                  }
+                }
+              }
+              .RQ {
+                >td {
+                  vertical-align: top;
+                }
+                .qr-code {
+                  position: relative;
+                  >img:hover + .download {
+                    opacity: 1;
+                  }
+                  .download {
+                    position: absolute;
+                    bottom: 0;
+                    background: rgba(255, 255, 255, .9);
+                    width: 80px;
+                    height: 30px;
+                    line-height: 30px;
+                    z-index: 10;
+                    text-align: center;
+                    color: #6682E6;
+                    font-size: 14px;
+                    cursor: pointer;
+                    opacity: 0;
+                  }
+                }
+              }
+            }
+            .no-right{
+              width: 100%;
+              background: #F5F5F5;
+              border-radius: 2px;
+              height: 440px;
+              display: flex;
+              justify-content: center;
+              align-items: center;
+              flex-direction: column;
+            }
+            .box-right {
+              display: inline-block;
+              width: 70%;
+              background: #fff;
+              border-radius: 2px;
+              .pic-con {
+                background: #F5F5F5;
+                color:#6D747C;
+                #container {
+                  width: 100%;
+                  height: 500px;
+                  display: flex;
+                  justify-content: center;
+                  align-items: center;
+                  cursor: pointer;
+                }
+              }
+              .swip-container{
+                margin-top: 20px;
+                >div{
+                  width:180px;
+                  height: 152px;
+                  background: #F5F5F5;
+                  border-radius: 2px;
+                  text-align: center;
+                  padding-top: 35px;
+                  color: #6D747C;
+                }
+              }
+            }
+          }
+          .box-bottom{
+            margin:40px 0;
+          }
+        }
+        .vr-right{
+          width:21%;
+          border-radius: 2px;
+          display: inline-block;
+        }
+        .mask-bg{
+          position: fixed;
+          top: 0;
+          bottom: 0;
+          left: 0;
+          right: 0;
+          z-index: 99;
+          background:rgba(0, 0, 0, .6);
+          display: none;
+        }
+        .mask {
+          width: 860px;
+          height: 458px;
+          background: #fff;
+          position: fixed;
+          z-index: 999;
+          top: 120px;
+          left: 30%;
+          display: none;
+        }
+    }
+
+</style>
+<style lang="less">
+ .my-vr {
+    .box-bottom{
+      // .ivu-collapse-content{
+      //   padding:0;
+      // }
+      .ivu-icon-ios-arrow-forward {
+          float: right;
+          margin-top: 10px;
+          transform: rotate(-90deg);
+      }
+      .ivu-collapse>.ivu-collapse-item>.ivu-collapse-header{
+        background: #F4F5F8;
+        border-radius: 2px;
+      }
+    }
+ }
+</style>

+ 127 - 0
src/views/vr/serveTable.vue

@@ -0,0 +1,127 @@
+<template>
+  <div class="my-table">
+      <div class="my-box">
+           <i-Table stripe  :columns="columns1" :data="serveData" size="large"></i-Table>
+      </div>
+  </div>
+</template>
+
+<script>
+
+// import { formatTime, toHourMinute} from '../../tools/formatTime.js'
+// import {mapActions, mapMutations, mapGetters, mapState} from 'vuex'
+// import axios from 'axios'
+export default {
+  components: {
+
+  },
+
+  mixins: [],
+
+  props: ['serveData'],
+
+  data () {
+    return {
+      itemsData: {},
+      messageName: [],
+      emailName: [],
+      columns1: [
+        {
+          title: '设备名称',
+          key: 'eqName',
+          width: 300
+        },
+        {
+          title: '设备编号',
+          key: 'eqId'
+        },
+        {
+          title: '设备类',
+          key: 'category',
+          sortable: true
+        },
+        {
+          title: '未恢复的报警',
+          key: 'alarmLength'
+        },
+        {
+          title: '安装位置',
+          key: 'location',
+          className: 'description-td'
+        },
+        {
+          title: '操作',
+          key: 'deal',
+          render: (h, params) => {
+            return h('div', [
+              h('Button', {
+                props: {
+                  size: 'small'
+                },
+                style: {
+                  marginRight: '5px',
+                  color: '#728DEE',
+                  border: '1px solid #728DEE'
+                },
+                on: {
+                  click: () => {
+                    this.handleClick(params.row)
+                  }
+                }
+              }, '设备详情')
+            ])
+          }
+        }
+      ]
+    }
+  },
+
+  computed: {
+
+  },
+
+  mounted () {
+
+  },
+
+  methods: {
+    handleClick (row) {
+      this.$router.push({path: 'spread', query: {id: row.id}})
+    }
+  }
+
+}
+</script>
+
+<style scoped lang="less" >
+.my-table {
+    .my-box{
+       background: #fff;
+    }
+}
+</style>
+<style lang="less">
+.my-table{
+    .ivu-table-wrapper {
+    border: none;
+  }
+  .ivu-table td,
+  .ivu-table th {
+    border: none;
+  }
+  .ivu-table:before{
+      height: 0;
+  }
+  .ivu-table:after{
+      width:0;
+  }
+  .ivu-table-row .description-td>.ivu-table-cell>span{
+        // overflow: hidden;
+        // text-overflow: ellipsis;
+        // white-space: nowrap;
+        max-height: 100px;
+        display: inline-block;
+    }
+}
+
+</style>

+ 0 - 0
static/.gitkeep


+ 77 - 0
static/css/reset.css

@@ -0,0 +1,77 @@
+html,
+body,
+div,
+span,
+object,
+iframe,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+blockquote,
+pre,
+abbr,
+address,
+cite,
+code,
+del,
+dfn,
+em,
+img,
+ins,
+kbd,
+q,
+samp,
+small,
+strong,
+sub,
+sup,
+var,
+b,
+i,
+dl,
+dt,
+dd,
+ol,
+ul,
+li,
+fieldset,
+form,
+label,
+legend,
+table,
+caption,
+tbody,
+tfoot,
+thead,
+tr,
+th,
+td,
+article,
+aside,
+canvas,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+menu,
+nav,
+section,
+summary,
+time,
+mark,
+audio,
+video {
+    margin: 0;
+    padding: 0;
+    border: 0;
+    outline: 0;
+    font-size: 100%;
+    vertical-align: baseline;
+    background: transparent;
+}

Fichier diff supprimé car celui-ci est trop grand
+ 9 - 0
static/css/viewer.min.css


+ 370 - 0
static/font/demo.css

@@ -0,0 +1,370 @@
+*{margin: 0;padding: 0;list-style: none;}
+/*
+KISSY CSS Reset
+理念:1. reset 的目的不是清除浏览器的默认样式,这仅是部分工作。清除和重置是紧密不可分的。
+2. reset 的目的不是让默认样式在所有浏览器下一致,而是减少默认样式有可能带来的问题。
+3. reset 期望提供一套普适通用的基础样式。但没有银弹,推荐根据具体需求,裁剪和修改后再使用。
+特色:1. 适应中文;2. 基于最新主流浏览器。
+维护:玉伯<lifesinger@gmail.com>, 正淳<ragecarrier@gmail.com>
+ */
+
+/** 清除内外边距 **/
+body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */
+dl, dt, dd, ul, ol, li, /* list elements 列表元素 */
+pre, /* text formatting elements 文本格式元素 */
+form, fieldset, legend, button, input, textarea, /* form elements 表单元素 */
+th, td /* table elements 表格元素 */ {
+  margin: 0;
+  padding: 0;
+}
+
+/** 设置默认字体 **/
+body,
+button, input, select, textarea /* for ie */ {
+  font: 12px/1.5 tahoma, arial, \5b8b\4f53, sans-serif;
+}
+h1, h2, h3, h4, h5, h6 { font-size: 100%; }
+address, cite, dfn, em, var { font-style: normal; } /* 将斜体扶正 */
+code, kbd, pre, samp { font-family: courier new, courier, monospace; } /* 统一等宽字体 */
+small { font-size: 12px; } /* 小于 12px 的中文很难阅读,让 small 正常化 */
+
+/** 重置列表元素 **/
+ul, ol { list-style: none; }
+
+/** 重置文本格式元素 **/
+a { text-decoration: none; }
+a:hover { text-decoration: underline; }
+
+
+/** 重置表单元素 **/
+legend { color: #000; } /* for ie6 */
+fieldset, img { border: 0; } /* img 搭车:让链接里的 img 无边框 */
+button, input, select, textarea { font-size: 100%; } /* 使得表单元素在 ie 下能继承字体大小 */
+/* 注:optgroup 无法扶正 */
+
+/** 重置表格元素 **/
+table { border-collapse: collapse; border-spacing: 0; }
+
+/* 清除浮动 */
+.ks-clear:after, .clear:after {
+  content: '\20';
+  display: block;
+  height: 0;
+  clear: both;
+}
+.ks-clear, .clear {
+  *zoom: 1;
+}
+
+.main {
+  padding: 30px 100px;
+width: 960px;
+margin: 0 auto;
+}
+.main h1{font-size:36px; color:#333; text-align:left;margin-bottom:30px; border-bottom: 1px solid #eee;}
+
+.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;
+
+}
+
+.icon_lists li{
+  float:left;
+  width: 100px;
+  height:180px;
+  text-align: center;
+  list-style: none !important;
+}
+.icon_lists .icon{
+  font-size: 42px;
+  line-height: 100px;
+  margin: 10px 0;
+  color:#333;
+  -webkit-transition: font-size 0.25s ease-out 0s;
+  -moz-transition: font-size 0.25s ease-out 0s;
+  transition: font-size 0.25s ease-out 0s;
+
+}
+.icon_lists .icon:hover{
+  font-size: 100px;
+}
+
+
+
+.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,
+.markdown pre {
+  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 pre {
+  border-radius: 6px;
+  background: #f7f7f7;
+  padding: 20px;
+}
+
+.markdown pre code {
+  border: none;
+  background: #f7f7f7;
+  margin: 0;
+}
+
+.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;
+  font-style: italic;
+}
+
+.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;
+}
+
+pre{
+  background: #fff;
+}
+
+
+
+
+

+ 256 - 0
static/font/demo_fontclass.html

@@ -0,0 +1,256 @@
+
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8"/>
+    <title>IconFont</title>
+    <link rel="stylesheet" href="demo.css">
+    <link rel="stylesheet" href="iconfont.css">
+</head>
+<body>
+    <div class="main markdown">
+        <h1>IconFont 图标</h1>
+        <ul class="icon_lists clear">
+            
+                <li>
+                <i class="icon iconfont icon-add"></i>
+                    <div class="name">add</div>
+                    <div class="fontclass">.icon-add</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-gongdan"></i>
+                    <div class="name">gongdan2</div>
+                    <div class="fontclass">.icon-gongdan</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-gongdan1"></i>
+                    <div class="name">gongdan</div>
+                    <div class="fontclass">.icon-gongdan1</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-home"></i>
+                    <div class="name">home</div>
+                    <div class="fontclass">.icon-home</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-more"></i>
+                    <div class="name">more</div>
+                    <div class="fontclass">.icon-more</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-message"></i>
+                    <div class="name">message</div>
+                    <div class="fontclass">.icon-message</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-peo"></i>
+                    <div class="name">peo2</div>
+                    <div class="fontclass">.icon-peo</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-people"></i>
+                    <div class="name">people</div>
+                    <div class="fontclass">.icon-people</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-peo1"></i>
+                    <div class="name">peo3</div>
+                    <div class="fontclass">.icon-peo1</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-search"></i>
+                    <div class="name">search</div>
+                    <div class="fontclass">.icon-search</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-sort"></i>
+                    <div class="name">sort1</div>
+                    <div class="fontclass">.icon-sort</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-start"></i>
+                    <div class="name">start</div>
+                    <div class="fontclass">.icon-start</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-start1"></i>
+                    <div class="name">start 2</div>
+                    <div class="fontclass">.icon-start1</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-anquancanshu"></i>
+                    <div class="name">安全参数</div>
+                    <div class="fontclass">.icon-anquancanshu</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-dangqianbaojing"></i>
+                    <div class="name">当前报警</div>
+                    <div class="fontclass">.icon-dangqianbaojing</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-huanjing"></i>
+                    <div class="name">环境</div>
+                    <div class="fontclass">.icon-huanjing</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-huanjinglogo"></i>
+                    <div class="name">环境logo</div>
+                    <div class="fontclass">.icon-huanjinglogo</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-huiyuanmanyidu"></i>
+                    <div class="name">会员满意度</div>
+                    <div class="fontclass">.icon-huiyuanmanyidu</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-jiancedian"></i>
+                    <div class="name">监测点</div>
+                    <div class="fontclass">.icon-jiancedian</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-lengzhanlogo"></i>
+                    <div class="name">冷站logo</div>
+                    <div class="fontclass">.icon-lengzhanlogo</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-nengyuanlogo"></i>
+                    <div class="name">能源logo</div>
+                    <div class="fontclass">.icon-nengyuanlogo</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-pingfen"></i>
+                    <div class="name">评分</div>
+                    <div class="fontclass">.icon-pingfen</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-peidianlogo"></i>
+                    <div class="name">配电logo</div>
+                    <div class="fontclass">.icon-peidianlogo</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-qushi"></i>
+                    <div class="name">趋势</div>
+                    <div class="fontclass">.icon-qushi</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-qiangdianzhuanyexitong"></i>
+                    <div class="name">强电专业系统</div>
+                    <div class="fontclass">.icon-qiangdianzhuanyexitong</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-shenghuoreshui"></i>
+                    <div class="name">生活热水</div>
+                    <div class="fontclass">.icon-shenghuoreshui</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-xiangmudafenbiao"></i>
+                    <div class="name">项目打分表</div>
+                    <div class="fontclass">.icon-xiangmudafenbiao</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-kongzhuangtaiicon"></i>
+                    <div class="name">空状态icon</div>
+                    <div class="fontclass">.icon-kongzhuangtaiicon</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-tongjifenxiblue"></i>
+                    <div class="name">统计分析blue</div>
+                    <div class="fontclass">.icon-tongjifenxiblue</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-yujing"></i>
+                    <div class="name">预警</div>
+                    <div class="fontclass">.icon-yujing</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-zonglan"></i>
+                    <div class="name">总览</div>
+                    <div class="fontclass">.icon-zonglan</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-zulinlogo"></i>
+                    <div class="name">租赁logo</div>
+                    <div class="fontclass">.icon-zulinlogo</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-zhanghao"></i>
+                    <div class="name">账号</div>
+                    <div class="fontclass">.icon-zhanghao</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-close"></i>
+                    <div class="name">close</div>
+                    <div class="fontclass">.icon-close</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-mima"></i>
+                    <div class="name">密码</div>
+                    <div class="fontclass">.icon-mima</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont icon-meos"></i>
+                    <div class="name">meos</div>
+                    <div class="fontclass">.icon-meos</div>
+                </li>
+            
+        </ul>
+
+        <h2 id="font-class-">font-class引用</h2>
+        <hr>
+
+        <p>font-class是unicode使用方式的一种变种,主要是解决unicode书写不直观,语意不明确的问题。</p>
+        <p>与unicode使用方式相比,具有如下特点:</p>
+        <ul>
+        <li>兼容性良好,支持ie8+,及所有现代浏览器。</li>
+        <li>相比于unicode语意明确,书写更直观。可以很容易分辨这个icon是什么。</li>
+        <li>因为使用class来定义图标,所以当要替换图标时,只需要修改class里面的unicode引用。</li>
+        <li>不过因为本质上还是使用的字体,所以多色图标还是不支持的。</li>
+        </ul>
+        <p>使用步骤如下:</p>
+        <h3 id="-fontclass-">第一步:引入项目下面生成的fontclass代码:</h3>
+
+
+        <pre><code class="lang-js hljs javascript"><span class="hljs-comment">&lt;link rel="stylesheet" type="text/css" href="./iconfont.css"&gt;</span></code></pre>
+        <h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
+        <pre><code class="lang-css hljs">&lt;<span class="hljs-selector-tag">i</span> <span class="hljs-selector-tag">class</span>="<span class="hljs-selector-tag">iconfont</span> <span class="hljs-selector-tag">icon-xxx</span>"&gt;&lt;/<span class="hljs-selector-tag">i</span>&gt;</code></pre>
+        <blockquote>
+        <p>"iconfont"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。</p>
+        </blockquote>
+    </div>
+</body>
+</html>

+ 351 - 0
static/font/demo_symbol.html

@@ -0,0 +1,351 @@
+
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8"/>
+    <title>IconFont</title>
+    <link rel="stylesheet" href="demo.css">
+    <script src="iconfont.js"></script>
+
+    <style type="text/css">
+        .icon {
+          /* 通过设置 font-size 来改变图标大小 */
+          width: 1em; height: 1em;
+          /* 图标和文字相邻时,垂直对齐 */
+          vertical-align: -0.15em;
+          /* 通过设置 color 来改变 SVG 的颜色/fill */
+          fill: currentColor;
+          /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
+             normalize.css 中也包含这行 */
+          overflow: hidden;
+        }
+
+    </style>
+</head>
+<body>
+    <div class="main markdown">
+        <h1>IconFont 图标</h1>
+        <ul class="icon_lists clear">
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-add"></use>
+                    </svg>
+                    <div class="name">add</div>
+                    <div class="fontclass">#icon-add</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-gongdan"></use>
+                    </svg>
+                    <div class="name">gongdan2</div>
+                    <div class="fontclass">#icon-gongdan</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-gongdan1"></use>
+                    </svg>
+                    <div class="name">gongdan</div>
+                    <div class="fontclass">#icon-gongdan1</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-home"></use>
+                    </svg>
+                    <div class="name">home</div>
+                    <div class="fontclass">#icon-home</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-more"></use>
+                    </svg>
+                    <div class="name">more</div>
+                    <div class="fontclass">#icon-more</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-message"></use>
+                    </svg>
+                    <div class="name">message</div>
+                    <div class="fontclass">#icon-message</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-peo"></use>
+                    </svg>
+                    <div class="name">peo2</div>
+                    <div class="fontclass">#icon-peo</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-people"></use>
+                    </svg>
+                    <div class="name">people</div>
+                    <div class="fontclass">#icon-people</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-peo1"></use>
+                    </svg>
+                    <div class="name">peo3</div>
+                    <div class="fontclass">#icon-peo1</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-search"></use>
+                    </svg>
+                    <div class="name">search</div>
+                    <div class="fontclass">#icon-search</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-sort"></use>
+                    </svg>
+                    <div class="name">sort1</div>
+                    <div class="fontclass">#icon-sort</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-start"></use>
+                    </svg>
+                    <div class="name">start</div>
+                    <div class="fontclass">#icon-start</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-start1"></use>
+                    </svg>
+                    <div class="name">start 2</div>
+                    <div class="fontclass">#icon-start1</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-anquancanshu"></use>
+                    </svg>
+                    <div class="name">安全参数</div>
+                    <div class="fontclass">#icon-anquancanshu</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-dangqianbaojing"></use>
+                    </svg>
+                    <div class="name">当前报警</div>
+                    <div class="fontclass">#icon-dangqianbaojing</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-huanjing"></use>
+                    </svg>
+                    <div class="name">环境</div>
+                    <div class="fontclass">#icon-huanjing</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-huanjinglogo"></use>
+                    </svg>
+                    <div class="name">环境logo</div>
+                    <div class="fontclass">#icon-huanjinglogo</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-huiyuanmanyidu"></use>
+                    </svg>
+                    <div class="name">会员满意度</div>
+                    <div class="fontclass">#icon-huiyuanmanyidu</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-jiancedian"></use>
+                    </svg>
+                    <div class="name">监测点</div>
+                    <div class="fontclass">#icon-jiancedian</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-lengzhanlogo"></use>
+                    </svg>
+                    <div class="name">冷站logo</div>
+                    <div class="fontclass">#icon-lengzhanlogo</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-nengyuanlogo"></use>
+                    </svg>
+                    <div class="name">能源logo</div>
+                    <div class="fontclass">#icon-nengyuanlogo</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-pingfen"></use>
+                    </svg>
+                    <div class="name">评分</div>
+                    <div class="fontclass">#icon-pingfen</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-peidianlogo"></use>
+                    </svg>
+                    <div class="name">配电logo</div>
+                    <div class="fontclass">#icon-peidianlogo</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-qushi"></use>
+                    </svg>
+                    <div class="name">趋势</div>
+                    <div class="fontclass">#icon-qushi</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-qiangdianzhuanyexitong"></use>
+                    </svg>
+                    <div class="name">强电专业系统</div>
+                    <div class="fontclass">#icon-qiangdianzhuanyexitong</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-shenghuoreshui"></use>
+                    </svg>
+                    <div class="name">生活热水</div>
+                    <div class="fontclass">#icon-shenghuoreshui</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-xiangmudafenbiao"></use>
+                    </svg>
+                    <div class="name">项目打分表</div>
+                    <div class="fontclass">#icon-xiangmudafenbiao</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-kongzhuangtaiicon"></use>
+                    </svg>
+                    <div class="name">空状态icon</div>
+                    <div class="fontclass">#icon-kongzhuangtaiicon</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-tongjifenxiblue"></use>
+                    </svg>
+                    <div class="name">统计分析blue</div>
+                    <div class="fontclass">#icon-tongjifenxiblue</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-yujing"></use>
+                    </svg>
+                    <div class="name">预警</div>
+                    <div class="fontclass">#icon-yujing</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-zonglan"></use>
+                    </svg>
+                    <div class="name">总览</div>
+                    <div class="fontclass">#icon-zonglan</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-zulinlogo"></use>
+                    </svg>
+                    <div class="name">租赁logo</div>
+                    <div class="fontclass">#icon-zulinlogo</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-zhanghao"></use>
+                    </svg>
+                    <div class="name">账号</div>
+                    <div class="fontclass">#icon-zhanghao</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-close"></use>
+                    </svg>
+                    <div class="name">close</div>
+                    <div class="fontclass">#icon-close</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-mima"></use>
+                    </svg>
+                    <div class="name">密码</div>
+                    <div class="fontclass">#icon-mima</div>
+                </li>
+            
+                <li>
+                    <svg class="icon" aria-hidden="true">
+                        <use xlink:href="#icon-meos"></use>
+                    </svg>
+                    <div class="name">meos</div>
+                    <div class="fontclass">#icon-meos</div>
+                </li>
+            
+        </ul>
+
+
+        <h2 id="symbol-">symbol引用</h2>
+        <hr>
+
+        <p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
+        这种用法其实是做了一个svg的集合,与另外两种相比具有如下特点:</p>
+        <ul>
+          <li>支持多色图标了,不再受单色限制。</li>
+          <li>通过一些技巧,支持像字体那样,通过<code>font-size</code>,<code>color</code>来调整样式。</li>
+          <li>兼容性较差,支持 ie9+,及现代浏览器。</li>
+          <li>浏览器渲染svg的性能一般,还不如png。</li>
+        </ul>
+        <p>使用步骤如下:</p>
+        <h3 id="-symbol-">第一步:引入项目下面生成的symbol代码:</h3>
+        <pre><code class="lang-js hljs javascript"><span class="hljs-comment">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;</span></code></pre>
+        <h3 id="-css-">第二步:加入通用css代码(引入一次就行):</h3>
+        <pre><code class="lang-js hljs javascript">&lt;style type=<span class="hljs-string">"text/css"</span>&gt;
+.icon {
+   width: <span class="hljs-number">1</span>em; height: <span class="hljs-number">1</span>em;
+   vertical-align: <span class="hljs-number">-0.15</span>em;
+   fill: currentColor;
+   overflow: hidden;
+}
+&lt;<span class="hljs-regexp">/style&gt;</span></code></pre>
+        <h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
+        <pre><code class="lang-js hljs javascript">&lt;svg <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"icon"</span> aria-hidden=<span class="hljs-string">"true"</span>&gt;<span class="xml"><span class="hljs-tag">
+  &lt;<span class="hljs-name">use</span> <span class="hljs-attr">xlink:href</span>=<span class="hljs-string">"#icon-xxx"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">use</span>&gt;</span>
+</span>&lt;<span class="hljs-regexp">/svg&gt;
+        </span></code></pre>
+    </div>
+</body>
+</html>

+ 294 - 0
static/font/demo_unicode.html

@@ -0,0 +1,294 @@
+
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8"/>
+    <title>IconFont</title>
+    <link rel="stylesheet" href="demo.css">
+
+    <style type="text/css">
+
+        @font-face {font-family: "iconfont";
+          src: url('iconfont.eot'); /* IE9*/
+          src: url('iconfont.eot#iefix') format('embedded-opentype'), /* IE6-IE8 */
+          url('iconfont.woff') format('woff'), /* chrome, firefox */
+          url('iconfont.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
+          url('iconfont.svg#iconfont') format('svg'); /* iOS 4.1- */
+        }
+
+        .iconfont {
+          font-family:"iconfont" !important;
+          font-size:16px;
+          font-style:normal;
+          -webkit-font-smoothing: antialiased;
+          -webkit-text-stroke-width: 0.2px;
+          -moz-osx-font-smoothing: grayscale;
+        }
+
+    </style>
+</head>
+<body>
+    <div class="main markdown">
+        <h1>IconFont 图标</h1>
+        <ul class="icon_lists clear">
+            
+                <li>
+                <i class="icon iconfont">&#xe601;</i>
+                    <div class="name">add</div>
+                    <div class="code">&amp;#xe601;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe604;</i>
+                    <div class="name">gongdan2</div>
+                    <div class="code">&amp;#xe604;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe605;</i>
+                    <div class="name">gongdan</div>
+                    <div class="code">&amp;#xe605;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe606;</i>
+                    <div class="name">home</div>
+                    <div class="code">&amp;#xe606;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe607;</i>
+                    <div class="name">more</div>
+                    <div class="code">&amp;#xe607;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe608;</i>
+                    <div class="name">message</div>
+                    <div class="code">&amp;#xe608;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe60a;</i>
+                    <div class="name">peo2</div>
+                    <div class="code">&amp;#xe60a;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe60c;</i>
+                    <div class="name">people</div>
+                    <div class="code">&amp;#xe60c;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe60d;</i>
+                    <div class="name">peo3</div>
+                    <div class="code">&amp;#xe60d;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe60f;</i>
+                    <div class="name">search</div>
+                    <div class="code">&amp;#xe60f;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe611;</i>
+                    <div class="name">sort1</div>
+                    <div class="code">&amp;#xe611;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe613;</i>
+                    <div class="name">start</div>
+                    <div class="code">&amp;#xe613;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe614;</i>
+                    <div class="name">start 2</div>
+                    <div class="code">&amp;#xe614;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe615;</i>
+                    <div class="name">安全参数</div>
+                    <div class="code">&amp;#xe615;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe619;</i>
+                    <div class="name">当前报警</div>
+                    <div class="code">&amp;#xe619;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe61a;</i>
+                    <div class="name">环境</div>
+                    <div class="code">&amp;#xe61a;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe61b;</i>
+                    <div class="name">环境logo</div>
+                    <div class="code">&amp;#xe61b;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe61d;</i>
+                    <div class="name">会员满意度</div>
+                    <div class="code">&amp;#xe61d;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe620;</i>
+                    <div class="name">监测点</div>
+                    <div class="code">&amp;#xe620;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe622;</i>
+                    <div class="name">冷站logo</div>
+                    <div class="code">&amp;#xe622;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe623;</i>
+                    <div class="name">能源logo</div>
+                    <div class="code">&amp;#xe623;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe624;</i>
+                    <div class="name">评分</div>
+                    <div class="code">&amp;#xe624;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe625;</i>
+                    <div class="name">配电logo</div>
+                    <div class="code">&amp;#xe625;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe626;</i>
+                    <div class="name">趋势</div>
+                    <div class="code">&amp;#xe626;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe627;</i>
+                    <div class="name">强电专业系统</div>
+                    <div class="code">&amp;#xe627;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe629;</i>
+                    <div class="name">生活热水</div>
+                    <div class="code">&amp;#xe629;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe62b;</i>
+                    <div class="name">项目打分表</div>
+                    <div class="code">&amp;#xe62b;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe62d;</i>
+                    <div class="name">空状态icon</div>
+                    <div class="code">&amp;#xe62d;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe62e;</i>
+                    <div class="name">统计分析blue</div>
+                    <div class="code">&amp;#xe62e;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe62f;</i>
+                    <div class="name">预警</div>
+                    <div class="code">&amp;#xe62f;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe631;</i>
+                    <div class="name">总览</div>
+                    <div class="code">&amp;#xe631;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe632;</i>
+                    <div class="name">租赁logo</div>
+                    <div class="code">&amp;#xe632;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe616;</i>
+                    <div class="name">账号</div>
+                    <div class="code">&amp;#xe616;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe617;</i>
+                    <div class="name">close</div>
+                    <div class="code">&amp;#xe617;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe618;</i>
+                    <div class="name">密码</div>
+                    <div class="code">&amp;#xe618;</div>
+                </li>
+            
+                <li>
+                <i class="icon iconfont">&#xe602;</i>
+                    <div class="name">meos</div>
+                    <div class="code">&amp;#xe602;</div>
+                </li>
+            
+        </ul>
+        <h2 id="unicode-">unicode引用</h2>
+        <hr>
+
+        <p>unicode是字体在网页端最原始的应用方式,特点是:</p>
+        <ul>
+        <li>兼容性最好,支持ie6+,及所有现代浏览器。</li>
+        <li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
+        <li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li>
+        </ul>
+        <blockquote>
+        <p>注意:新版iconfont支持多色图标,这些多色图标在unicode模式下将不能使用,如果有需求建议使用symbol的引用方式</p>
+        </blockquote>
+        <p>unicode使用步骤如下:</p>
+        <h3 id="-font-face">第一步:拷贝项目下面生成的font-face</h3>
+        <pre><code class="lang-js hljs javascript">@font-face {
+  font-family: <span class="hljs-string">'iconfont'</span>;
+  src: url(<span class="hljs-string">'iconfont.eot'</span>);
+  src: url(<span class="hljs-string">'iconfont.eot?#iefix'</span>) format(<span class="hljs-string">'embedded-opentype'</span>),
+  url(<span class="hljs-string">'iconfont.woff'</span>) format(<span class="hljs-string">'woff'</span>),
+  url(<span class="hljs-string">'iconfont.ttf'</span>) format(<span class="hljs-string">'truetype'</span>),
+  url(<span class="hljs-string">'iconfont.svg#iconfont'</span>) format(<span class="hljs-string">'svg'</span>);
+}
+</code></pre>
+        <h3 id="-iconfont-">第二步:定义使用iconfont的样式</h3>
+        <pre><code class="lang-js hljs javascript">.iconfont{
+  font-family:<span class="hljs-string">"iconfont"</span> !important;
+  font-size:<span class="hljs-number">16</span>px;font-style:normal;
+  -webkit-font-smoothing: antialiased;
+  -webkit-text-stroke-width: <span class="hljs-number">0.2</span>px;
+  -moz-osx-font-smoothing: grayscale;
+}
+</code></pre>
+        <h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
+        <pre><code class="lang-js hljs javascript">&lt;i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"iconfont"</span>&gt;&amp;#x33;<span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span></span></code></pre>
+
+        <blockquote>
+        <p>"iconfont"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。</p>
+        </blockquote>
+    </div>
+
+
+</body>
+</html>

Fichier diff supprimé car celui-ci est trop grand
+ 89 - 0
static/font/iconfont.css


BIN
static/font/iconfont.eot


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 0
static/font/iconfont.js


Fichier diff supprimé car celui-ci est trop grand
+ 134 - 0
static/font/iconfont.svg


BIN
static/font/iconfont.ttf


BIN
static/font/iconfont.woff


BIN
static/img/QRcode.jpg


BIN
static/img/alarm.png


BIN
static/img/alarmAandS.png


BIN
static/img/auto.png


BIN
static/img/backIcon.jpg


BIN
static/img/bill.png


BIN
static/img/deal.png


BIN
static/img/down.png


BIN
static/img/eleCon.png


BIN
static/img/elePower.png


BIN
static/img/email.png


BIN
static/img/ernomal.png


+ 0 - 0
static/img/event.png


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff