浏览代码

first commit

tremble 5 年之前
当前提交
ec69e7b7eb
共有 100 个文件被更改,包括 70761 次插入0 次删除
  1. 12 0
      .babelrc
  2. 9 0
      .editorconfig
  3. 4 0
      .eslintignore
  4. 29 0
      .eslintrc.js
  5. 14 0
      .gitignore
  6. 10 0
      .postcssrc.js
  7. 21 0
      README.md
  8. 41 0
      build/build.js
  9. 54 0
      build/check-versions.js
  10. 二进制
      build/logo.png
  11. 101 0
      build/utils.js
  12. 22 0
      build/vue-loader.conf.js
  13. 92 0
      build/webpack.base.conf.js
  14. 98 0
      build/webpack.dev.conf.js
  15. 148 0
      build/webpack.prod.conf.js
  16. 7 0
      config/dev.env.js
  17. 76 0
      config/index.js
  18. 4 0
      config/prod.env.js
  19. 17 0
      index.html
  20. 11716 0
      package-lock.json
  21. 83 0
      package.json
  22. 27 0
      src/App.vue
  23. 40 0
      src/assets/font/iconfont.css
  24. 二进制
      src/assets/font/iconfont.eot
  25. 1 0
      src/assets/font/iconfont.js
  26. 32 0
      src/assets/font/iconfont.svg
  27. 二进制
      src/assets/font/iconfont.ttf
  28. 二进制
      src/assets/font/iconfont.woff
  29. 二进制
      src/assets/images/icon_mp3.png
  30. 二进制
      src/assets/images/img_login_banbg.jpg
  31. 二进制
      src/assets/images/index_logo@2x.png
  32. 二进制
      src/assets/images/menu_icon_01@2x.png
  33. 二进制
      src/assets/images/menu_icon_02@2x.png
  34. 二进制
      src/assets/images/menu_icon_03@2x.png
  35. 138 0
      src/assets/style/info.scss
  36. 131 0
      src/assets/style/public.scss
  37. 22 0
      src/assets/style/reset.scss
  38. 87 0
      src/components/crumb/index.vue
  39. 16 0
      src/components/vcenter/index.vue
  40. 25 0
      src/main.js
  41. 881 0
      src/pages/department/index.vue
  42. 0 0
      src/pages/department/style.scss
  43. 102 0
      src/pages/home/index.vue
  44. 0 0
      src/pages/home/style.scss
  45. 223 0
      src/pages/layout/aside.vue
  46. 69 0
      src/pages/layout/header/index.vue
  47. 27 0
      src/pages/layout/header/style.scss
  48. 70 0
      src/pages/layout/index.vue
  49. 212 0
      src/pages/login/index.vue
  50. 485 0
      src/pages/recommended/index.vue
  51. 0 0
      src/pages/recommended/style.scss
  52. 669 0
      src/pages/rental-info/index.vue
  53. 0 0
      src/pages/rental-info/style.scss
  54. 885 0
      src/pages/role/index.vue
  55. 0 0
      src/pages/role/style.scss
  56. 518 0
      src/pages/scene/index.vue
  57. 0 0
      src/pages/scene/style.scss
  58. 671 0
      src/pages/sell-info/index.vue
  59. 0 0
      src/pages/sell-info/style.scss
  60. 671 0
      src/pages/site-decoration/index.vue
  61. 0 0
      src/pages/site-decoration/style.scss
  62. 898 0
      src/pages/user/index.vue
  63. 0 0
      src/pages/user/style.scss
  64. 571 0
      src/pages/z-carousel/index.vue
  65. 0 0
      src/pages/z-carousel/style.scss
  66. 63 0
      src/router/index.js
  67. 156 0
      src/utils/base.js
  68. 86 0
      src/utils/http.js
  69. 0 0
      static/.gitkeep
  70. 二进制
      static/img/favicon.ico
  71. 7 0
      消安-后台原型0225/data/document.js
  72. 115 0
      消安-后台原型0225/data/styles.css
  73. 7 0
      消安-后台原型0225/files/个人中心/data.js
  74. 14 0
      消安-后台原型0225/files/个人中心/styles.css
  75. 7 0
      消安-后台原型0225/files/场景拼接(此页交互待定)/data.js
  76. 1907 0
      消安-后台原型0225/files/场景拼接(此页交互待定)/styles.css
  77. 7 0
      消安-后台原型0225/files/场景管理/data.js
  78. 9507 0
      消安-后台原型0225/files/场景管理/styles.css
  79. 7 0
      消安-后台原型0225/files/我的场景/data.js
  80. 2017 0
      消安-后台原型0225/files/我的场景/styles.css
  81. 7 0
      消安-后台原型0225/files/我的相机/data.js
  82. 2247 0
      消安-后台原型0225/files/我的相机/styles.css
  83. 7 0
      消安-后台原型0225/files/操作日志/data.js
  84. 6574 0
      消安-后台原型0225/files/操作日志/styles.css
  85. 7 0
      消安-后台原型0225/files/数据统计/data.js
  86. 3613 0
      消安-后台原型0225/files/数据统计/styles.css
  87. 7 0
      消安-后台原型0225/files/用户管理/data.js
  88. 5666 0
      消安-后台原型0225/files/用户管理/styles.css
  89. 7 0
      消安-后台原型0225/files/登陆/data.js
  90. 1007 0
      消安-后台原型0225/files/登陆/styles.css
  91. 7 0
      消安-后台原型0225/files/角色权限/data.js
  92. 6634 0
      消安-后台原型0225/files/角色权限/styles.css
  93. 7 0
      消安-后台原型0225/files/部门信息/data.js
  94. 3861 0
      消安-后台原型0225/files/部门信息/styles.css
  95. 7 0
      消安-后台原型0225/files/问题反馈/data.js
  96. 4509 0
      消安-后台原型0225/files/问题反馈/styles.css
  97. 7 0
      消安-后台原型0225/files/首页/data.js
  98. 2658 0
      消安-后台原型0225/files/首页/styles.css
  99. 二进制
      消安-后台原型0225/images/场景拼接(此页交互待定)/u1669.png
  100. 0 0
      消安-后台原型0225/images/场景拼接(此页交互待定)/u1670.png

+ 12 - 0
.babelrc

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

+ 9 - 0
.editorconfig

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

+ 4 - 0
.eslintignore

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

+ 29 - 0
.eslintrc.js

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

+ 14 - 0
.gitignore

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

+ 10 - 0
.postcssrc.js

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

+ 21 - 0
README.md

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

+ 41 - 0
build/build.js

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

+ 54 - 0
build/check-versions.js

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

二进制
build/logo.png


+ 101 - 0
build/utils.js

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

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

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

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

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

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

@@ -0,0 +1,98 @@
+'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.ProvidePlugin({
+      'window.Quill': 'quill'
+    }),
+    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)
+    }
+  })
+})

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

@@ -0,0 +1,148 @@
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const baseWebpackConfig = require('./webpack.base.conf')
+const CopyWebpackPlugin = require('copy-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
+const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
+const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
+
+const env = require('../config/prod.env')
+
+const webpackConfig = merge(baseWebpackConfig, {
+  module: {
+    rules: utils.styleLoaders({
+      sourceMap: config.build.productionSourceMap,
+      extract: true,
+      usePostCSS: true
+    })
+  },
+  devtool: config.build.productionSourceMap ? config.build.devtool : false,
+  output: {
+    path: config.build.assetsRoot,
+    filename: utils.assetsPath('js/[name].[chunkhash].js'),
+    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
+  },
+  plugins: [
+    // http://vuejs.github.io/vue-loader/en/workflow/production.html
+    new webpack.DefinePlugin({
+      'process.env': env
+    }),
+    new webpack.ProvidePlugin({
+      'window.Quill': 'quill'
+    }),
+    new UglifyJsPlugin({
+      uglifyOptions: {
+        compress: {
+          warnings: false
+        }
+      },
+      sourceMap: config.build.productionSourceMap,
+      parallel: true
+    }),
+    // extract css into its own file
+    new ExtractTextPlugin({
+      filename: utils.assetsPath('css/[name].[contenthash].css'),
+      // Setting the following option to `false` will not extract CSS from codesplit chunks.
+      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
+      // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 
+      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
+      allChunks: true,
+    }),
+    // Compress extracted CSS. We are using this plugin so that possible
+    // duplicated CSS from different components can be deduped.
+    new OptimizeCSSPlugin({
+      cssProcessorOptions: config.build.productionSourceMap
+        ? { safe: true, map: { inline: false } }
+        : { safe: true }
+    }),
+    // generate dist index.html with correct asset hash for caching.
+    // you can customize output by editing /index.html
+    // see https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: config.build.index,
+      template: 'index.html',
+      inject: true,
+      minify: {
+        removeComments: true,
+        collapseWhitespace: true,
+        removeAttributeQuotes: true
+        // more options:
+        // https://github.com/kangax/html-minifier#options-quick-reference
+      },
+      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
+      chunksSortMode: 'dependency'
+    }),
+    // keep module.id stable when vendor modules does not change
+    new webpack.HashedModuleIdsPlugin(),
+    // enable scope hoisting
+    new webpack.optimize.ModuleConcatenationPlugin(),
+    // split vendor js into its own file
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'vendor',
+      minChunks (module) {
+        // any required modules inside node_modules are extracted to vendor
+        return (
+          module.resource &&
+          /\.js$/.test(module.resource) &&
+          module.resource.indexOf(
+            path.join(__dirname, '../node_modules')
+          ) === 0
+        )
+      }
+    }),
+    // extract webpack runtime and module manifest to its own file in order to
+    // prevent vendor hash from being updated whenever app bundle is updated
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'manifest',
+      minChunks: Infinity
+    }),
+    // This instance extracts shared chunks from code splitted chunks and bundles them
+    // in a separate chunk, similar to the vendor chunk
+    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'app',
+      async: 'vendor-async',
+      children: true,
+      minChunks: 3
+    }),
+
+    // copy custom static assets
+    new CopyWebpackPlugin([
+      {
+        from: path.resolve(__dirname, '../static'),
+        to: config.build.assetsSubDirectory,
+        ignore: ['.*']
+      }
+    ])
+  ]
+})
+
+if (config.build.productionGzip) {
+  const CompressionWebpackPlugin = require('compression-webpack-plugin')
+
+  webpackConfig.plugins.push(
+    new CompressionWebpackPlugin({
+      asset: '[path].gz[query]',
+      algorithm: 'gzip',
+      test: new RegExp(
+        '\\.(' +
+        config.build.productionGzipExtensions.join('|') +
+        ')$'
+      ),
+      threshold: 10240,
+      minRatio: 0.8
+    })
+  )
+}
+
+if (config.build.bundleAnalyzerReport) {
+  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
+  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
+}
+
+module.exports = webpackConfig

+ 7 - 0
config/dev.env.js

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

+ 76 - 0
config/index.js

@@ -0,0 +1,76 @@
+'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: {},
+
+    // Various Dev Server settings
+    host: 'localhost', // can be overwritten by process.env.HOST
+    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: true,
+    // If true, eslint errors and warnings will also be shown in the error overlay
+    // in the browser.
+    showEslintErrorsInOverlay: false,
+
+    /**
+     * Source Maps
+     */
+
+    // https://webpack.js.org/configuration/devtool/#development
+    devtool: 'cheap-module-eval-source-map',
+
+    // If you have problems debugging vue-files in devtools,
+    // set this to false - it *may* help
+    // https://vue-loader.vuejs.org/en/options.html#cachebusting
+    cacheBusting: true,
+
+    cssSourceMap: true
+  },
+
+  build: {
+    // Template for index.html
+    index: path.resolve(__dirname, '../dist/index.html'),
+
+    // Paths
+    assetsRoot: path.resolve(__dirname, '../dist'),
+    assetsSubDirectory: 'static',
+    assetsPublicPath: './',
+
+    /**
+     * Source Maps
+     */
+
+    productionSourceMap: 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"'
+}

+ 17 - 0
index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta name="renderer" content="webkit">
+    <meta name="force-rendering" content="webkit"/>
+    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
+    <link rel="apple-touch-icon" sizes="180x180" href="static/img/favicon.ico">
+    <link rel="icon" type="image/png" href="static/img/favicon.ico" sizes="192x192">
+    <title>后台管理系统</title>
+  </head>
+  <body>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

文件差异内容过多而无法显示
+ 11716 - 0
package-lock.json


+ 83 - 0
package.json

@@ -0,0 +1,83 @@
+{
+  "name": "house",
+  "version": "1.0.0",
+  "description": "A Vue.js project",
+  "author": "tremble <290487845@qq.com>",
+  "private": true,
+  "scripts": {
+    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+    "start": "npm run dev",
+    "lint": "eslint --ext .js,.vue src",
+    "build": "node build/build.js"
+  },
+  "dependencies": {
+    "axios": "^0.18.0",
+    "element-ui": "^2.4.11",
+    "quill-image-drop-module": "^1.0.3",
+    "quill-image-resize-module": "^3.0.0",
+    "vue": "^2.5.2",
+    "vue-quill-editor": "^3.0.6",
+    "vue-quill-editor-upload": "^1.1.0",
+    "vue-router": "^3.0.1"
+  },
+  "devDependencies": {
+    "autoprefixer": "^7.1.2",
+    "babel-core": "^6.22.1",
+    "babel-eslint": "^8.2.1",
+    "babel-helper-vue-jsx-merge-props": "^2.0.3",
+    "babel-loader": "^7.1.1",
+    "babel-plugin-syntax-jsx": "^6.18.0",
+    "babel-plugin-transform-runtime": "^6.22.0",
+    "babel-plugin-transform-vue-jsx": "^3.5.0",
+    "babel-polyfill": "^6.26.0",
+    "babel-preset-env": "^1.3.2",
+    "babel-preset-stage-2": "^6.22.0",
+    "chalk": "^2.0.1",
+    "copy-webpack-plugin": "^4.0.1",
+    "css-loader": "^0.28.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.7.0",
+    "eslint-plugin-node": "^5.2.0",
+    "eslint-plugin-promise": "^3.4.0",
+    "eslint-plugin-standard": "^3.0.1",
+    "eslint-plugin-vue": "^4.0.0",
+    "extract-text-webpack-plugin": "^3.0.0",
+    "file-loader": "^1.1.4",
+    "friendly-errors-webpack-plugin": "^1.6.1",
+    "html-webpack-plugin": "^2.30.1",
+    "node-notifier": "^5.1.2",
+    "node-sass": "^4.10.0",
+    "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",
+    "rimraf": "^2.6.0",
+    "sass-loader": "^7.1.0",
+    "sass-resources-loader": "^2.0.0",
+    "semver": "^5.3.0",
+    "shelljs": "^0.7.6",
+    "uglifyjs-webpack-plugin": "^1.1.1",
+    "url-loader": "^0.5.8",
+    "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"
+  ]
+}

+ 27 - 0
src/App.vue

@@ -0,0 +1,27 @@
+<template>
+<div id="app">
+  <router-view/>
+</div>
+</template>
+
+<script>
+import '@/assets/style/reset.scss'
+import '@/assets/style/public.scss'
+import '@/assets/font/iconfont.css'
+
+export default {
+  name: 'App',
+  components: {
+
+  },
+  data () {
+    return {
+
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 40 - 0
src/assets/font/iconfont.css

@@ -0,0 +1,40 @@
+@font-face {
+  font-family: 'iconfont';  /* project id 961134 */
+  src: url('//at.alicdn.com/t/font_961134_16afefeun84.eot');
+  src: url('//at.alicdn.com/t/font_961134_16afefeun84.eot?#iefix') format('embedded-opentype'),
+  url('//at.alicdn.com/t/font_961134_16afefeun84.woff2') format('woff2'),
+  url('//at.alicdn.com/t/font_961134_16afefeun84.woff') format('woff'),
+  url('//at.alicdn.com/t/font_961134_16afefeun84.ttf') format('truetype'),
+  url('//at.alicdn.com/t/font_961134_16afefeun84.svg#iconfont') format('svg');
+}
+
+.iconfont {
+  font-family:"iconfont" !important;
+  font-size:16px;
+  font-style:normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  color: #909399;
+}
+
+.icon-arrow:before { content: "\e612";}
+
+.icon-guanggao:before { content: "\e610"; }
+
+.icon-renzheng:before { content: "\e60e"; }
+
+.icon-xinxifabu:before { content: "\e60f"; }
+
+.icon-zhuxiao:before { content: "\e611"; color: #fff;}
+
+.icon-download:before { content: "\e613"; }
+
+.icon-chongzhi:before { content: "\e609"; font-size: 32px; }
+
+.icon-close:before { content: "\e61a"; }
+
+.icon-correct:before { content: "\e687"; }
+
+.icon-plus:before { content: "\e648"; }
+
+.icon-music:before { content: "\e653"; }

二进制
src/assets/font/iconfont.eot


文件差异内容过多而无法显示
+ 1 - 0
src/assets/font/iconfont.js


+ 32 - 0
src/assets/font/iconfont.svg

@@ -0,0 +1,32 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<!--
+2013-9-30: Created.
+-->
+<svg>
+<metadata>
+Created by iconfont
+</metadata>
+<defs>
+
+<font id="iconfont" horiz-adv-x="1024" >
+  <font-face
+    font-family="iconfont"
+    font-weight="500"
+    font-stretch="normal"
+    units-per-em="1024"
+    ascent="896"
+    descent="-128"
+  />
+    <missing-glyph />
+    
+    <glyph glyph-name="arrowt" unicode="&#58902;" d="M490.982 519.763c-12.499 12.499-12.499 32.755 0 45.253v0c12.499 12.499 32.755 12.499 45.253 0l316.781-316.781c12.499-12.499 12.499-32.755 0-45.253v0c-12.499-12.499-32.755-12.499-45.253 0l-316.781 316.781zM216.237 202.982c-12.499-12.499-32.755-12.499-45.253 0v0c-12.499 12.499-12.499 32.755 0 45.253l316.781 316.781c12.499 12.499 32.755 12.499 45.253 0v0c12.499-12.499 12.499-32.755 0-45.253l-316.781-316.781z"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="daohang" unicode="&#58880;" d="M54.32 329.31733299999996H54.314667l391.344-122.358666L927.62 629.406667 554.132 174.36933299999998l418.510667-133.353333L1188.137333 896zM540.924 107.28666699999997V-128l137.770667 194.416-137.770667 40.876z"  horiz-adv-x="1741" />
+
+    
+
+
+  </font>
+</defs></svg>

二进制
src/assets/font/iconfont.ttf


二进制
src/assets/font/iconfont.woff


二进制
src/assets/images/icon_mp3.png


二进制
src/assets/images/img_login_banbg.jpg


二进制
src/assets/images/index_logo@2x.png


二进制
src/assets/images/menu_icon_01@2x.png


二进制
src/assets/images/menu_icon_02@2x.png


二进制
src/assets/images/menu_icon_03@2x.png


+ 138 - 0
src/assets/style/info.scss

@@ -0,0 +1,138 @@
+.con {
+  .d-l{
+    // & /deep/ .el-form-item__content{
+    //   line-height: 30px;
+    //   .el-upload-list__item{
+    //     display: none;
+    //     &:last-child{
+    //       display: inline-block;
+    //     }
+    //   }
+    // }
+    display: inline-block;
+    width:45%;
+  }
+  .d-r{
+    width:45%;
+    float: right;
+    .el-date-editor.el-input, .el-date-editor.el-input__inner{
+      width: 100%;
+    }
+    .c-logo{
+      width: 150px;
+      height: 150px;
+      border: 1px solid #ccc;
+      border-radius: 4px;
+      background-color: #f5fafe;
+      img{
+        width: 100%;
+        height: 100%;
+      }
+    }
+    .c-zizhi{
+      width: 150px;
+      height: 150px;
+      border: 1px solid #ccc;
+      border-radius: 4px;
+      position: relative;
+      background-color: #f5fafe;
+      img{
+        width: 100%;
+        height: 100%;
+      }
+      .c-mask{
+        width: 100%;
+        height: 100%;
+        position: absolute;
+        top: 0;
+        left: 0;
+        background: rgba(0, 0, 0, 0.5);
+        text-align: center;
+        display: table;
+        .icon-download{
+          text-align: center;
+          display: table-cell;
+          vertical-align: middle;
+          color: #fff;
+          font-size: 20px;
+        }
+      }
+    }
+  }
+  .ei-num{
+    .el-input-number{
+      width: 90%;
+    }
+  }
+  .ei-input{
+    width: 100%;
+    max-height: 200px;
+    overflow-y: auto;
+    .input-con{
+      display: inline-block;
+      width: 45%;
+      margin: 2px 5px 2px 0;
+      height: 60px;
+      position: relative;
+      .el-input_err{
+        & /deep/ .el-input__inner{
+          border: 1px solid #f56c6c;
+        }
+      }
+      .el-input_success{
+        & /deep/ .el-input__inner{
+          border: 1px solid #67c23a;
+        }
+      }
+      span {
+        color: #f56c6c;
+        font-size: 12px;
+        line-height: 1;
+        padding-top: 4px;
+        position: absolute;
+        left: 0;
+      }
+    }
+
+  }
+ .h-header {
+    height: 80px;
+    background-color: #fff;
+    padding-left: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+    div{
+      display: inline-block;
+      vertical-align: middle;
+    }
+    .h-input {
+      margin-left: 20px;
+      display: inline-block;
+    }
+    .fix-date{
+      div{
+        display: flex;
+      }
+    }
+  }
+
+  .h-body {
+    width: 100%;
+    margin: 30px 0 0;
+    padding-top: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+    background-color: #fff;
+
+    .o-span {
+      color: #0175dc;
+      cursor: pointer;
+    }
+
+    .p-con {
+      width: 100%;
+      text-align: right;
+      padding: 25px 20px 30px;
+    }
+  }
+}

+ 131 - 0
src/assets/style/public.scss

@@ -0,0 +1,131 @@
+#app, .layout, body, html{
+  width: 100%;
+  height: 100%;
+  color: #333;
+}
+table tr td .cell,table tr th .cell{
+  text-align: center;
+}
+
+::-webkit-scrollbar {
+  width: 5px;
+  height: 16px;
+  background-color: transparent;
+}
+
+::-webkit-scrollbar-track{
+    border-radius: 10px;
+    background-color: transparent;
+}
+
+::-webkit-scrollbar-thumb {
+  border-radius: 10px;
+  -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.2);
+  background-color: #d4d4d4;
+}
+
+.zfb-success{
+  color: #fff;
+  background-color: #67c23a;
+  border: 1px solid #67c23a;
+  padding: 2px 10px;
+  display: inline-block;
+  border-radius: 2px;
+}
+.zfb-shenhe{
+  color: #0175dc;
+  background-color: #fff;
+  border: 1px solid #0175dc;
+  padding: 2px 10px;
+  border-radius: 2px;
+  display: inline-block;
+}
+.zfb-reject{
+  color: #fff;
+  background-color: #e6a23e;
+  border: 1px solid #e6a23e;
+  padding: 2px 10px;
+  display: inline-block;
+  border-radius: 2px;
+}
+
+.zfb-guanbi{
+  color: #fff;
+  background-color: #ccc;
+  border: 1px solid #ccc;
+  padding: 2px 10px;
+  display: inline-block;
+  border-radius: 2px;
+}
+
+
+.zfb-upload{
+  position: relative;
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  width: 164px;
+  height: 164px;
+  line-height: 164px;
+  background-color: #f9fcff;
+  display: inline-block;
+  overflow: hidden;
+  img{
+    width: 162px;
+    height: 162px;
+    border-radius: 6px;
+  }
+  .v-mask{
+    display: none;
+    position: absolute;
+    top: 0;
+    left: 0;
+  }
+  &:hover{
+    border-color: #409eff;
+    .v-mask{
+      display: inline-block;
+      width: 162px;
+      height: 162px;
+      border-radius: 6px;
+      background: rgba(0,0,0,0.5);
+    
+    }
+  }
+  .el-icon-plus {
+    position: relative;
+    top: -15px;
+    font-size: 20px;
+  }
+  .zfb-upload-text{
+    position: absolute;
+    top: 50%;
+    left: 0;
+    width: 100%;
+    line-height: 16px;
+    span{
+      color: #999;
+      font-size: 12px;
+      line-height: 1.5;
+    }
+  }
+}
+
+.el-select{
+  width: 100%;
+}
+
+.c-input-con{
+  position: relative;
+  .hover-tip{
+    position: absolute;
+    right: 10px;
+    top: 0;
+  }
+}
+
+.quill-editor:not(.bubble) .ql-container,
+.quill-editor:not(.bubble) .ql-container .ql-editor {
+    height: 20rem;
+    padding-bottom: 1rem;
+    margin-bottom: 30px;
+  }

+ 22 - 0
src/assets/style/reset.scss

@@ -0,0 +1,22 @@
+/* reset */
+html,body,h1,h2,h3,h4,h5,h6,div,dl,dt,dd,ul,ol,li,p,blockquote,pre,hr,figure,table,caption,th,td,form,fieldset,legend,input,button,textarea,menu{margin:0;padding:0;}
+header,footer,section,article,aside,nav,hgroup,address,figure,figcaption,menu,details{display:block;}
+table{border-collapse:collapse;border-spacing:0;}
+caption,th{text-align:left;font-weight:normal;}
+html,body,fieldset,img,iframe,abbr{border:0;}
+i,cite,em,var,address,dfn{font-style:normal;}
+[hidefocus],summary{outline:0;}
+li{list-style:none;}
+// h1,h2,h3,h4,h5,h6,small{font-size:100%;}
+sup,sub{font-size:83%;}
+pre,code,kbd,samp{font-family:inherit;}
+q:before,q:after{content:none;}
+textarea{overflow:auto;resize:none;}
+label,summary{cursor:default;}
+a,button{cursor:pointer;}
+h1,h2,h3,h4,h5,h6,em,strong,b{font-weight:bold;}
+del,ins,u,s,a,a:hover{text-decoration:none;}
+body,textarea,input,button,select,keygen,legend{font:14px/1.14 'Microsoft YaHei',\5b8b\4f53;outline:0;}
+body{background:#fff;}
+*{box-sizing: border-box}
+a{text-decoration: none;}

+ 87 - 0
src/components/crumb/index.vue

@@ -0,0 +1,87 @@
+<!--  -->
+<template>
+<div class='crumb-con'>
+  <vcenter>
+    <span>{{title}}</span>
+    <div class="fr">
+      <div v-for="(item,i) in data" :key="i">
+        <span style="cursor:pointer">{{item.name}}</span>
+        <span style="padding-right:3px;" v-if="data.length-1!==i">></span>
+      </div>
+    </div>
+  </vcenter>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import vcenter from '@/components/vcenter'
+
+export default {
+// import引入的组件需要注入到对象中才能使用
+  props: {
+    data: {
+      default: () => {
+        return []
+      },
+      type: Array
+    },
+    title: {
+      default: () => {
+        return ''
+      },
+      type: String
+    }
+  },
+  components: {vcenter},
+  data () {
+    // 这里存放数据
+    return {
+
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style lang="scss" scoped>
+.crumb-con{
+  height: 60px;
+  width: 100%;
+  background-color: #fff;
+  box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+  font-size: 18px;
+  padding: 0 25px;
+  .fr{
+    color: #999;
+    float: right;
+    div{
+      display: inline-block;
+      font-size: 14px;
+    }
+  }
+}
+
+</style>

+ 16 - 0
src/components/vcenter/index.vue

@@ -0,0 +1,16 @@
+<template>
+  <table>
+    <tr>
+      <td>
+        <slot />
+      </td>
+    </tr>
+  </table>
+</template>
+
+<style scoped>
+table {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 25 - 0
src/main.js

@@ -0,0 +1,25 @@
+// The Vue build version to load with the `import` command
+// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
+import 'babel-polyfill'
+import Vue from 'vue'
+import App from './App'
+import router from './router'
+import ElementUI from 'element-ui'
+import 'element-ui/lib/theme-chalk/index.css'
+import {axios} from './utils/http'
+import {base} from './utils/base'
+
+Vue.config.productionTip = false
+
+Vue.prototype.$http = axios
+Vue.prototype.$base = base
+Vue.prototype.$bus = new Vue()
+
+Vue.use(ElementUI)
+/* eslint-disable no-new */
+new Vue({
+  el: '#app',
+  router,
+  components: { App },
+  template: '<App/>'
+})

+ 881 - 0
src/pages/department/index.vue

@@ -0,0 +1,881 @@
+<!--  -->
+<template>
+  <div class="con" v-loading.fullscreen.lock="loading">
+
+    <div class="h-header">
+      <vcenter>
+        <div>
+          关键字:
+        </div>
+        <div class="h-input">
+          <el-input v-model="inpuKey" placeholder="输入部门名称"></el-input>
+        </div>
+        <div>
+          <el-button type="primary" @click="search(inpuKey)">查询</el-button>
+          <el-button>导出</el-button>
+        </div>
+      </vcenter>
+    </div>
+    <div class="h-body">
+      <div style="padding:0 20px;">
+        <el-button type="primary">新增部门</el-button>
+        <el-button>删除</el-button>
+      </div>
+      <el-table height="520" :data="tableData" style="width: 100%;padding:0 20px;">
+        <el-table-column
+          v-for="(item,i) in tableHeader"
+          :key="i"
+          :prop="item.name"
+          :label="item.label"
+        >
+          <template slot-scope="scope">
+            <span
+              @click="view_device(scope.row)"
+              class="o-span"
+              v-if="item.label==='设备数量'"
+            >{{scope['row'].cameraNum}}</span>
+            <div class="logo-add" v-else-if="item.label==='加载界面logo'">
+              <div @click="showLoadingLogo(scope.row,'scene')">
+                <img :src="scope['row'].sceneLogo" alt />
+                <span>+</span>
+              </div>
+            </div>
+            <div class="logo-add" v-else-if="item.label==='加载地面logo'">
+              <div @click="showLoadingLogo(scope.row,'floor')">
+                <img :src="scope['row'].floorLogo" alt />
+                <span>+</span>
+              </div>
+            </div>
+            <div class="logo-add" v-else-if="item.label==='背景音乐'">
+              <div @click="showLoadingLogo(scope.row,'music')">
+                <img :src="scope['row'].bgMusic?require('@/assets/images/icon_mp3.png'):''" alt />
+                <span v-if="!scope['row'].bgMusic">+</span>
+              </div>
+            </div>
+            <span v-else-if="item.label==='子账号数量'">{{scope['row'].subNum+scope['row'].num}}</span>
+            <div
+              class="time-data"
+              v-else-if="item.label==='到期时间'"
+            >
+             <div class="select-data" @click="daoqiDate = scope.row">
+               <el-date-picker
+                v-model="value1"
+                @change="dateChange"
+                value-format="yyyy-MM-dd"
+                type="date"
+                placeholder="选择日期">
+              </el-date-picker>
+             </div>
+            <span>{{scope.row[item.name]?$base.dateFormat('yyyy-MM-dd', new Date(scope.row[item.name])):'暂无到期时间'}}</span></div>
+            <span v-else>{{scope.row[item.name]}}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="p-con">
+        <el-pagination
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          :current-page.sync="currentPage"
+          :page-size="size"
+          layout="prev, pager, next, jumper"
+          :total="total"
+        ></el-pagination>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import vcenter from '@/components/vcenter'
+import { serverName } from '@/utils/http'
+
+const tableHeader = [
+  {
+    name: 'daihao',
+    label: '部门代号'
+  },
+  {
+    name: 'name',
+    label: '部门名称'
+  },
+  {
+    name: 'sceneLogo',
+    label: '创建人'
+  },
+  {
+    name: 'floorLogo',
+    label: '创建时间'
+  }
+]
+
+let saveTypes = {
+  scene: '加载界面logo',
+  floor: '加载地面logo',
+  music: '背景音乐'
+}
+
+let sceneTypeArr = {
+  scene: 'sceneLogo',
+  floor: 'floorLogo',
+  music: 'bgMusic'
+}
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    vcenter
+  },
+  data () {
+    // 这里存放数据
+    let dropdownActives = [{
+      text: '企业账号',
+      id: 'account'
+    },
+    {
+      text: '设备ID',
+      id: 'childName'
+    }]
+
+    let placeholder = {
+      account: '输入企业账号查询',
+      childName: '输入设备ID查询'
+    }
+    return {
+      dropdownActives,
+      dropdown_active: {
+        text: '企业账号',
+        id: 'account'
+      },
+      placeholder,
+      fileList: [],
+      currentlogo_id: '',
+      homepic: '',
+      saveTypes,
+      saveType: 'scene',
+      isAdd: false,
+      serverName,
+      c_num: '',
+      tableData: [],
+      tableHeader,
+      dialogFormVisible: false,
+      chargeVisible: false,
+      deviceFormVisible: false,
+      loadinglogoVisible: false,
+      currentPage: 1,
+      num: 1,
+      loading: false,
+      formLabelWidth: '100px',
+      errMsg: '该ID不可用',
+      userName: '',
+      recharge_id: '',
+      daoqiDate: '',
+      form_charge: {
+        userName: '',
+        point: '',
+        recharge: ''
+      },
+      form: {
+        name: '',
+        region: '',
+        date1: '',
+        date2: '',
+        delivery: false,
+        type: [],
+        resource: '',
+        desc: ''
+      },
+      form_device: {
+        d_userName: '',
+        d_name: '',
+        d_device: []
+      },
+      size: 10,
+      total: 0,
+      c_id: null,
+      c_subNum: '',
+      c_userName: '',
+      c_name: '',
+      addDevies: [
+        {
+          value: '',
+          isAvailable: false,
+          hasCheck: false
+        }
+      ],
+      inpuKey: '',
+      value1: ''
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {
+    token () {
+      return window.localStorage.getItem('zfb_token')
+    }
+  },
+  // 监控data中的数据变化
+  watch: {
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    },
+    num (newVal, oldVal) {
+      if (newVal > oldVal) {
+        this.addDevies.push({
+          value: '',
+          isAvailable: false,
+          hasCheck: false
+        })
+      } else {
+        this.addDevies.pop()
+      }
+    }
+  },
+  // 方法集合
+  methods: {
+    unbind (item) {
+      this.$confirm('此操作将解除该设备的绑定, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http({
+          method: 'post',
+          data: {
+            childName: item.childName
+          },
+          url: '/company/unbindDevice',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('解除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.deviceFormVisible = false
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.message
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    dropClick (item) {
+      this.inpuKey = ''
+      this.userName = ''
+      this.dropdown_active = item
+    },
+    beforeAvatarUpload (file) {
+      const isLt5M = file.size / 1024 / 1024 < 5
+      const isMp3 =
+        file.type === 'audio/mp3' ||
+        file.type === 'audio/x-ms-wma' ||
+        file.type === 'audio/wav'
+
+      if (this.saveType === 'music') {
+        if (!isMp3) {
+          this.$message.error('暂不支持该音频格式')
+          return false
+        }
+      }
+      if (!isLt5M) {
+        this.$message.error('上传文件大小不能超过 5MB')
+        return false
+      }
+      return true
+    },
+    handleChange (file, fileList) {
+      if (fileList.length > 1) {
+        this.fileList = fileList.slice(-1)
+      }
+    },
+    dateChange (data) {
+      // let data1 = new Date(data)
+      this.$confirm('此操作将会更新该企业账号的到期时间, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        console.log(data)
+        this.$http({
+          method: 'post',
+          data: {
+            id: this.daoqiDate.id,
+            expirationDate: data
+          },
+          url: '/company/updateExpirationTime',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('更新成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.message
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消'
+        })
+      })
+    },
+    upload_success (data) {
+      this.homepic = data.message
+    },
+    upload_fail (data) {
+      this.$notify.error({
+        title: '上传失败',
+        message: data.message
+      })
+    },
+    handleSizeChange (val) {
+      console.log(`每页 ${val} 条`)
+    },
+    handleCurrentChange (val) {
+      console.log(`当前页: ${val}`)
+    },
+    _checkInput: function (e) {
+      this.form_charge.recharge += ''
+      this.form_charge.recharge = this.form_charge.recharge.replace(
+        /[^\d]/g,
+        ''
+      )
+      if (
+        Number(this.form_charge.recharge) &&
+        this.form_charge.recharge > 999999999
+      ) {
+        this.form_charge.recharge = 999999999
+      }
+    },
+    saveLoadingLogo () {
+      if (!this.homepic && this.saveType !== 'music') {
+        this.$notify.error({
+          title: '保存失败',
+          message: '请上传图片'
+        })
+      } else {
+        let params
+        if (this.saveType === 'scene') {
+          params = {
+            id: this.currentlogo_id,
+            sceneLogo: this.homepic || null
+          }
+        } else if (this.saveType === 'music') {
+          params = {
+            id: this.currentlogo_id,
+            bgMusic: this.homepic || ''
+          }
+        } else {
+          params = {
+            id: this.currentlogo_id,
+            floorLogo: this.homepic || null
+          }
+        }
+        this.$http({
+          method: 'post',
+          data: params,
+          url: '/company/updateCompany',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('保存成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.loadinglogoVisible = false
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '保存失败',
+              message: res.message
+            })
+          }
+        })
+      }
+    },
+    refresh () {
+      this.loading = true
+      this.getData()
+      this.loading = false
+    },
+    search (item) {
+      this.userName = item
+      this.refresh()
+    },
+    save_reCharge () {
+      this.$confirm('此操作将对该账号进行充值, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          this.loading = true
+          let params = {
+            id: this.recharge_id,
+            point: Number(this.form_charge.recharge)
+          }
+          this.$http({
+            method: 'post',
+            data: params,
+            url: '/company/addPoint',
+            headers: {
+              token: window.localStorage.getItem('zfb_token')
+            }
+          }).then(res => {
+            if (res.code === 200) {
+              this.$alert('充值成功', '提示', {
+                confirmButtonText: '确定',
+                callback: action => {
+                  this.clearInfo()
+                }
+              })
+            } else {
+              this.loading = false
+              this.$notify.error({
+                title: '充值失败',
+                message: res.message
+              })
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消充值'
+          })
+        })
+    },
+    async show_reCharge (item) {
+      this.chargeVisible = true
+      this.recharge_id = item.id
+      this.form_charge = {
+        userName: item.userName,
+        point: item.point,
+        recharge: ''
+      }
+    },
+
+    async showLoadingLogo (item, type) {
+      console.log(item)
+      this.saveType = type
+      this.homepic = item[sceneTypeArr[type]] || ''
+      this.currentlogo_id = item.id
+      this.loadinglogoVisible = true
+    },
+    async view_device (item, search = false) {
+      this.deviceFormVisible = true
+      // this.d_subNum = item.subNum
+      this.form_device.d_userName = item.userName
+      this.form_device.d_name = item.name
+      let params = {
+        userName: item.userName
+      }
+      this.form_device.d_device = (await this.$http({
+        method: 'post',
+        data: params,
+        url: '/company/selectCompanyDevice',
+        headers: {
+          token: window.localStorage.getItem('zfb_token')
+        }
+      })).message
+      setTimeout(() => {
+        let items = Array.from(this.$refs.dcon.querySelectorAll('.d-body'))
+        let offTop = 0
+        items.forEach(item => {
+          item.style.background = '#fff'
+          let txt = item.querySelectorAll('span')[1].innerText
+          if (txt === this.userName.trim() && search) {
+            offTop = item.offsetTop - 311
+            item.style.background = '#ccc'
+          }
+        })
+        document.querySelector('#dcon').scrollTop = offTop
+      }, 0)
+    },
+    add (item) {
+      this.dialogFormVisible = true
+      this.c_subNum = item.subNum
+      this.c_num = item.num
+      this.c_userName = item.userName
+      this.c_name = item.name
+      this.c_id = item.id
+    },
+    clearInfo () {
+      this.num = 1
+      this.addDevies = [
+        {
+          value: '',
+          isAvailable: false,
+          hasCheck: false
+        }
+      ]
+      this.dialogFormVisible = false
+      this.chargeVisible = false
+      this.recharge_id = ''
+      this.form_charge = {
+        userName: '',
+        point: '',
+        recharge: ''
+      }
+      this.refresh()
+    },
+    canIsave () {
+      let temp = []
+      for (let i = 0; i < this.addDevies.length; i++) {
+        if (this.addDevies[i].isAvailable === true) {
+          temp.push(this.addDevies[i].value)
+        } else {
+          temp = []
+          return false
+        }
+      }
+      return temp.join(';')
+    },
+    save (userName) {
+      let params = {
+        childName: this.canIsave() || null,
+        userName: userName || null,
+        id: this.c_id || null,
+        subNum: this.c_subNum || null
+      }
+      this.loading = true
+      this.$http({
+        method: 'post',
+        data: params,
+        url: '/company/addDevice',
+        headers: {
+          token: window.localStorage.getItem('zfb_token')
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.$alert('添加成功', '提示', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.clearInfo()
+            }
+          })
+        } else {
+          this.loading = false
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    checkLegal (item) {
+      if (item.value) {
+        let params = {
+          childName: item.value
+        }
+        this.$http({
+          method: 'post',
+          data: params,
+          url: '/company/checkDevice',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            item.isAvailable = true
+          } else {
+            item.isAvailable = false
+            this.errMsg = '该ID不可用'
+          }
+          item.hasCheck = true
+        })
+      } else {
+        item.isAvailable = false
+        item.hasCheck = true
+        this.errMsg = 'ID不能为空'
+      }
+    },
+    async getData () {
+      let params = {
+        userName: this.userName || ''
+      }
+      let result
+      if (this.dropdown_active.id === 'childName' && this.userName) {
+        result = await this.$http({
+          method: 'post',
+          data: {
+            childName: this.userName
+          },
+          url: '/company/findCompanyDevice',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        })
+        let {message, code} = result
+        if (message && code === 200) {
+          this.view_device(message, true)
+        } else {
+          this.$notify.error({
+            title: '无法找到对应设备'
+          })
+        }
+      } else {
+        result = await this.$http({
+          method: 'post',
+          data: params,
+          url: '/company/selectCompanyNum',
+          headers: {
+            token: window.localStorage.getItem('zfb_token'),
+            pageNum: this.currentPage,
+            pageSize: this.size
+          }
+        })
+        this.tableData = result.message.list
+        this.total = result.message.total
+        this.currentPage = result.message.pageNum
+      }
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {},
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+    console.log('mounted')
+    this.refresh()
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+
+<style lang="scss" scoped>
+.con {
+  .time-data{
+    position: relative;
+    .select-data{
+      position: absolute;
+      left: 0;
+      top: 0;
+      opacity: 0;
+      cursor: pointer;
+    }
+    >span{
+      color: #0175dc;
+    }
+  }
+  .ei-num {
+    .el-input-number {
+      width: 90%;
+    }
+  }
+  .clear-music {
+    position: relative;
+    text-align: right;
+    top: -30px;
+    color: #999;
+    cursor: pointer;
+  }
+  .musicIcon {
+    width: 100%;
+    height: 100%;
+    line-height: 1;
+    margin-top: 35px;
+    img {
+      width: 50px;
+      height: auto;
+    }
+    p {
+      font-weight: bold;
+      font-size: 14px;
+      color: #000;
+      line-height: 20px;
+      height: 20px;
+      margin-top: 20px;
+    }
+  }
+  .icon-plus {
+    margin-left: 15px;
+    width: 40px;
+    height: 38px;
+    line-height: 38px;
+    text-align: center;
+    background: #f5f7fa;
+    color: #999;
+    cursor: pointer;
+    font-size: 13px;
+    display: inline-block;
+    border: 1px solid #dcdfe6;
+    border-radius: 4px;
+    &:hover {
+      border: 1px solid #c0c4cc;
+    }
+  }
+  .add-num {
+    margin-left: 15px;
+    width: 250px;
+    .icon-close,
+    .icon-correct {
+      line-height: 1;
+      color: #999;
+    }
+    input[type="number"]::-webkit-inner-spin-button,
+    input[type="number"]::-webkit-outer-spin-button {
+      -webkit-appearance: none;
+      margin: 0;
+    }
+  }
+
+  .ei-input {
+    width: 100%;
+    max-height: 200px;
+    overflow-y: auto;
+    .input-con {
+      display: inline-block;
+      width: 45%;
+      margin: 2px 5px 2px 0;
+      height: 60px;
+      position: relative;
+      .el-input_err {
+        & /deep/ .el-input__inner {
+          border: 1px solid #f56c6c;
+        }
+      }
+      .el-input_success {
+        & /deep/ .el-input__inner {
+          border: 1px solid #67c23a;
+        }
+      }
+      span {
+        color: #f56c6c;
+        font-size: 12px;
+        line-height: 1;
+        padding-top: 4px;
+        position: absolute;
+        left: 0;
+      }
+    }
+  }
+  .h-header {
+    height: 80px;
+    background-color: #fff;
+    padding-left: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+
+    div {
+      display: inline-block;
+    }
+
+    .h-input {
+      width: 220px;
+    }
+  }
+
+  .h-body {
+    width: 100%;
+    margin: 30px 0 0;
+    padding-top: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+    background-color: #fff;
+
+    .logo-add {
+      div {
+        cursor: pointer;
+        line-height: 40px;
+        border: 1px dotted #dcdfe6;
+        border-radius: 4px;
+        font-weight: bold;
+        font-size: 18px;
+        display: inline-block;
+        width: 40px;
+        height: 40px;
+        background: #f5f7fa;
+        position: relative;
+        img {
+          width: 100%;
+          height: 100%;
+          position: absolute;
+          top: 0;
+          left: 0;
+        }
+        span {
+          position: absolute;
+          z-index: 100;
+          left: 0;
+          top: 0;
+          width: 100%;
+          height: 100%;
+        }
+      }
+    }
+
+    .o-span {
+      color: #0175dc;
+      cursor: pointer;
+    }
+
+    .p-con {
+      width: 100%;
+      text-align: right;
+      padding: 25px 20px 30px;
+    }
+  }
+
+  .d-table {
+    border: 1px solid #ccc;
+    .d-con {
+      max-height: 200px;
+      overflow-y: scroll;
+    }
+    .d-header {
+      font-weight: bold;
+    }
+    .d-header,
+    .d-body {
+      height: 40px;
+      line-height: 40px;
+      width: 100%;
+      border-bottom: 1px solid #ccc;
+      &:last-child {
+        border: none;
+      }
+      span {
+        text-align: center;
+        display: inline-block;
+        width: 24%;
+
+      }
+      .unbind{
+        cursor: pointer;
+      }
+    }
+  }
+}
+</style>

+ 0 - 0
src/pages/department/style.scss


+ 102 - 0
src/pages/home/index.vue

@@ -0,0 +1,102 @@
+<!--  -->
+<template>
+  <div class="con" v-loading.fullscreen.lock="loading">
+    <div class="h-body">
+      <ul>
+        <li v-for="(item, i) in lists" :key="i">
+          <img :src="require('@/assets/images/icon_mp3.png')" alt="">
+          <div>{{item.name}}</div>
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import vcenter from '@/components/vcenter'
+
+const lists = [
+  {
+    name: '我的场景',
+    link: '/',
+    img: '',
+    id: ''
+  },
+  {
+    name: '问题反馈',
+    link: '/',
+    img: '',
+    id: ''
+  },
+  {
+    name: '数据统计',
+    link: '/',
+    img: '',
+    id: ''
+  },
+  {
+    name: '场景管理',
+    link: '/',
+    img: '',
+    id: ''
+  },
+  {
+    name: '我的相机',
+    link: '/',
+    img: '',
+    id: ''
+  },
+  {
+    name: '操作日志',
+    link: '/',
+    img: '',
+    id: ''
+  }
+]
+
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    vcenter
+  },
+  data () {
+    return {
+      lists,
+      loading: false
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.con {
+  .h-body {
+    width: 100%;
+    padding: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+    background-color: #fff;
+
+    ul{
+      width: 100%;
+      display: flex;
+      flex-wrap: wrap;
+      justify-content: space-between;
+      text-align: center;
+      padding: 2% 5%;
+      li{
+        width: 30%;
+        margin-bottom: 6%;
+        img{
+          width: 50%;
+        }
+        div{
+          margin-top: 10px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 0 - 0
src/pages/home/style.scss


+ 223 - 0
src/pages/layout/aside.vue

@@ -0,0 +1,223 @@
+<template>
+<div class='aside'>
+  <div class="nav-menu">
+    <div class="navigator_menu">
+      <vcenter>
+        <span>导航面板</span>
+      </vcenter>
+    </div>
+    <ul class="aside-ul">
+      <li class="aside-li" v-for="(item,i) in aside" :key="i">
+        <div @click="clickNav(item)" :class="{'aside-li-div':true,'active':item.id&&item.id===activeIdx}" >
+          <vcenter>
+            <i class="iconfont" :class="item.icon" style="float:left;width:27px;"></i>
+            <span style="vertical-align: middle;">{{item.name}}</span>
+            <i v-if="item.subItem" style="font-size:12px;vertical-align: middle;position:relative;top:2px;" :class="{'iconfont':true, 'icon-arrow':true,'fr':true,rotate:item.isShow}"></i>
+          </vcenter>
+        </div>
+        <ul class="li-ul" v-if="item.subItem" :style="{maxHeight:item.isShow?'260px':'0'}">
+          <li @click="navigate(sub)" v-for="(sub, idx) in item.subItem" :class="{'active':sub.id&&sub.id===activeIdx}" :key="idx">
+            <vcenter>
+              <span>{{sub.name}}</span>
+              <span v-if="sub.id==='1-2' && a_tips" class="aside-tip">{{a_tips}}</span>
+            </vcenter>
+          </li>
+        </ul>
+      </li>
+    </ul>
+  </div>
+</div>
+</template>
+
+<script>
+import vcenter from '@/components/vcenter'
+
+const aside = [{
+  name: '首页',
+  id: '1',
+  icon: 'icon-renzheng',
+  isShow: true,
+  url: '/'
+},
+{
+  name: '部门管理',
+  id: '2',
+  icon: 'icon-renzheng',
+  isShow: false,
+  url: '/department'
+},
+{
+  name: '用户管理',
+  id: '3',
+  icon: 'icon-renzheng',
+  isShow: false,
+  url: '/user'
+}, {
+  name: '角色权限',
+  id: '4',
+  icon: 'icon-renzheng',
+  isShow: true,
+  url: '/role'
+
+}, {
+  name: '场景管理',
+  id: '5',
+  icon: 'icon-renzheng',
+  isShow: true,
+  url: '/scene'
+}, {
+  name: '数据统计',
+  id: '',
+  icon: 'icon-renzheng',
+  isShow: true
+}, {
+  name: '操作日志',
+  id: '',
+  icon: 'icon-renzheng',
+  isShow: true
+}, {
+  name: '系统管理',
+  id: '',
+  icon: 'icon-xinxifabu',
+  isShow: false,
+  subItem: [{
+    name: '账号信息',
+    id: '2-1',
+    url: '/rental-info'
+  }, {
+    name: '我的场景',
+    id: '2-2',
+    url: '/sell-info'
+  }, {
+    name: '我的相机',
+    id: '2-3',
+    url: '/site-decoration'
+  }, {
+    name: '问题反馈',
+    id: '2-4',
+    url: '/site-decoration'
+  }]
+}]
+export default {
+  name: 'm-aside',
+  components: {vcenter},
+  data () {
+    return {
+      aside,
+      a_tips: 0
+    }
+  },
+  computed: {
+    activeIdx: {
+      get: function () {
+        return this.$route.meta.index
+      },
+      set: function () {
+      }
+    },
+    token () {
+      return window.localStorage.getItem('zfb_token')
+    }
+  },
+  mounted () {
+    this.$bus.$on('refresh', data => {
+      if (data) {
+        this._getTipsNum()
+      }
+    })
+    this._getTipsNum()
+  },
+  methods: {
+    clickNav (item) {
+      if (item.id) {
+        this.activeIdx = item.id
+        this.$router.push(item.url)
+      } else {
+        item.isShow = !item.isShow
+      }
+    },
+    navigate (item) {
+      this._getTipsNum()
+      this.activeIdx = item.id
+      this.$router.push(item.url)
+    },
+    async _getTipsNum () {
+      let result = await this.$http({
+        method: 'post',
+        url: '/company/selectAuditNum',
+        headers: {
+          token: this.token
+        }
+      })
+      this.a_tips = result.message
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.aside {
+  width: 100%;
+  .navigator_menu{
+    height: 56px;
+    span{
+      padding-left: 20px;
+      font-size: 12px;
+      color: #999;
+    }
+  }
+  .aside-ul{
+    color: #999;
+    .aside-li{
+      cursor: pointer;
+      font-size: 14px;
+      .aside-li-div{
+        padding: 0 20px;
+        height: 56px;
+        .fr{
+          float: right;
+          transition: transform 0.3s ease;
+        }
+        .rotate{
+          transform: rotate(180deg);
+        }
+        &:hover{
+          background-color: #f5f5f5;
+        }
+      }
+      .active{
+        background-color: #f5f5f5;
+        color: #333;
+        .iconfont{
+          color: #333;
+        }
+      }
+      .li-ul{
+        max-height: 200px;
+        transition: max-height 0.3s ease;
+        overflow: hidden;
+        li{
+          height: 56px;
+          padding: 0 47px;
+          .aside-tip{
+            background: #ff0000;
+            color: #fff;
+            border-radius: 10px;
+            display: inline-block;
+            width: 16px;
+            height: 16px;
+            text-align: center;
+            font-size: 12px;
+            line-height: 16px;
+            margin-left: 4px;
+          }
+          &:hover{
+            background-color: #f5f5f5;
+          }
+        }
+      }
+    }
+  }
+}
+
+</style>

+ 69 - 0
src/pages/layout/header/index.vue

@@ -0,0 +1,69 @@
+<!--  -->
+<template>
+<div class='con'>
+  <div class="logo">
+    <vcenter>
+      <img :src="require('@/assets/images/index_logo@2x.png')" alt="">
+    </vcenter>
+  </div>
+  <div class="setting">
+    <vcenter>
+      <div>
+        <i class="iconfont icon-zhuxiao"></i>
+         <span @click="logout">注销</span>
+      </div>
+    </vcenter>
+  </div>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import vcenter from '@/components/vcenter'
+export default {
+// import引入的组件需要注入到对象中才能使用
+  components: {vcenter},
+  data () {
+    // 这里存放数据
+    return {
+
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+    logout () {
+      window.localStorage.setItem('zfb_token', '')
+      this.$token = ''
+      this.$alert('退出成功', '提示', {
+        confirmButtonText: '确定',
+        callback: action => {
+          this.$router.push('/login')
+        }
+      })
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style lang="scss" scoped>
+@import './style.scss';
+</style>

+ 27 - 0
src/pages/layout/header/style.scss

@@ -0,0 +1,27 @@
+.con{
+  background: #0175dc;
+  // background: -webkit-gradient(linear, left top, left bottom, from(#4491fa), to(#5653e4));
+  height: 70px;
+  display: inline-block;
+  width: 100%;
+  color: #fff;
+  padding: 0 30px;
+  .logo{
+    height: 100%;
+    display: inline-block;
+    img{
+      width: 100px;
+    }
+  }
+  .setting{
+    height: 100%;
+    float: right;
+    
+    div{
+      cursor: pointer;
+      .iconfont{
+        padding-right:5px; 
+      }
+    }
+  }
+}

+ 70 - 0
src/pages/layout/index.vue

@@ -0,0 +1,70 @@
+<template>
+<div class="layout">
+  <iheader />
+  <div class="main">
+    <div class="aside-con">
+      <iaside />
+    </div>
+    <div class="r-view">
+      <crumb :title="$route.name"/>
+      <router-view class="r-main" />
+    </div>
+  </div>
+</div>
+</template>
+
+<script>
+import header from '@/pages/layout/header'
+import aside from '@/pages/layout/aside'
+import crumb from '@/components/crumb'
+
+export default {
+  components: {
+    iheader: header,
+    iaside: aside,
+    crumb
+  },
+  data () {
+    return {
+
+    }
+  },
+  computed: {
+    userId () {
+      return window.localStorage.getItem('zfb_token')
+    }
+  },
+  mounted () {
+    if (!this.userId) {
+      this.$router.push('/login')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.main {
+  width: 100%;
+  height: calc(100% - 72px);
+  background: #f2f2f2;
+  .aside-con {
+    border-right: 1px solid #ebeef5;
+    background: #fff;
+    position: fixed;
+    height: 100%;
+    width: 235px;
+    z-index: 1;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, .1);
+  }
+  .r-view {
+    height: 100%;
+    padding-left: 235px;
+    overflow: hidden;
+    .r-main{
+      padding: 30px;
+      height: calc(100% - 65px);
+      overflow: auto;
+    }
+  }
+}
+</style>

+ 212 - 0
src/pages/login/index.vue

@@ -0,0 +1,212 @@
+<template>
+<div class="l-con">
+  <div class="l-top">
+    <h1>指房宝后台管理系统</h1>
+  </div>
+  <div class="l_center">
+    <vcenter>
+      <div class="lc-l">
+        <img :src="logoImg" alt="">
+        <div class="text_01">10分钟搞定实景VR</div>
+        <div class="text_02">自助720度实景VR发布管理</div>
+        <div class="text_03">自助、简单、安全、高效</div>
+      </div>
+      <div class="lc-r">
+        <div class="lc-title">
+          <span>后台登录</span>
+        </div>
+        <div class="lc-form">
+           <el-form label-position="top" :model="ruleForm2" status-icon :rules="rules2" ref="ruleForm2" label-width="100px" class="demo-ruleForm">
+              <el-form-item prop="username">
+                <el-input type="username" placeholder="账号" v-model="ruleForm2.username" auto-complete="off"></el-input>
+              </el-form-item>
+              <el-form-item prop="pass" id='no-bottom'>
+                <el-input type="password" placeholder="密码" @keyup.enter.native="submitForm('ruleForm2')" v-model="ruleForm2.pass" auto-complete="off"></el-input>
+              </el-form-item>
+              <el-form-item>
+                <el-checkbox  v-model="checked">记住密码(在公共场所电脑请勿勾选)</el-checkbox>
+              </el-form-item>
+            </el-form>
+            <div class="lc-btn">
+              <el-button type="primary" v-loading.fullscreen.lock="fullscreenLoading" @click="submitForm('ruleForm2')">登录</el-button>
+            </div>
+        </div>
+      </div>
+    </vcenter>
+  </div>
+  <div class="l_footer">
+    <div>杭州天门科技有限公司  版权所有 © 2018 Inc.  浙ICP备18054719号-1</div>
+    <div class="sub">Design by TianMen Technology Co.Ltd.</div>
+  </div>
+</div>
+</template>
+
+<script>
+import vcenter from '@/components/vcenter'
+export default {
+  name: 'login',
+  components: {
+    vcenter
+  },
+  data () {
+    var validateUser = (rule, value, callback) => {
+      if (!value) {
+        return callback(new Error('用户名不能为空'))
+      } else if (value.length < 3) {
+        callback(new Error('用户名不合法'))
+      } else {
+        callback()
+      }
+    }
+
+    var validatePass = (rule, value, callback) => {
+      if (value === '') {
+        return callback(new Error('请输入密码'))
+      } else if (value.length < 4) {
+        callback(new Error('密码不能小于4位'))
+      } else {
+        callback()
+      }
+    }
+
+    return {
+      fullscreenLoading: false,
+      checked: true,
+      logoImg: require('@/assets/images/index_logo@2x.png'),
+      ruleForm2: {
+        username: '',
+        pass: ''
+      },
+      rules2: {
+        username: [{
+          validator: validateUser,
+          trigger: 'blur'
+        }],
+        pass: [{
+          validator: validatePass,
+          trigger: 'blur'
+        }]
+      }
+    }
+  },
+
+  mounted () {
+    this.ruleForm2.username = window.localStorage.getItem('zfb_username') || ''
+    this.ruleForm2.pass = window.localStorage.getItem('zfb_pass') || ''
+  },
+  methods: {
+    login () {
+      this.$http.post('loginBackground', {
+        userName: this.ruleForm2.username,
+        userPassword: this.ruleForm2.pass
+      }).then(res => {
+        this.fullscreenLoading = true
+        if (res.code === 200) {
+          window.localStorage.setItem('zfb_token', String(res.message.token))
+          if (this.checked) {
+            window.localStorage.setItem('zfb_username', this.ruleForm2.username)
+            window.localStorage.setItem('zfb_pass', this.ruleForm2.pass)
+          } else {
+            window.localStorage.setItem('zfb_username', '')
+            window.localStorage.setItem('zfb_pass', '')
+          }
+          this.$router.push('/')
+        } else {
+          this.fullscreenLoading = false
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    submitForm (formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.login()
+        } else {
+          this.$alert('请填写正确信息', '提示', {
+            confirmButtonText: '确定',
+            callback: action => {}
+          })
+          return false
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.l-con{
+  width: 100%;
+  .l-top{
+    color: #333;
+    text-align: center;
+    padding: 50px 0;
+  }
+  .l_center {
+    height: 600px;
+    width: 100%;
+    padding: 0 10% 0 20%;
+    background: url('~@/assets/images/img_login_banbg.jpg') center center no-repeat;
+    .lc-l{
+      display: inline-block;
+      color: #fff;
+      img{
+        width: 150px;
+      }
+
+      .text_01{
+        font-size: 60px;
+        font-weight: bold;
+        margin-top: 70px;
+      }
+      .text_02{
+        font-size: 40px;
+        margin: 30px 0;
+      }
+      .text_03{
+        font-size: 20px;
+      }
+
+    }
+    .lc-r{
+      float: right;
+      width: 345px;
+      height: 370px;
+      background-color: #fff;
+      padding: 28px 30px;
+      .lc-title{
+        text-align: center;
+        border-bottom: 2px solid #0175dc;
+        padding-bottom: 20px;
+        span{
+          color: #333;
+          font-size: 16px;
+        }
+      }
+      .lc-form{
+        margin-top: 40px;
+        .lc-btn{
+          width: 100%;
+          .el-button--primary{
+            width: 100%;
+          }
+        }
+      }
+    }
+  }
+  .l_footer{
+    font-size: 14px;
+    text-align: center;
+    margin-top: 45px;
+    line-height: 1.5;
+    .sub{
+      font-size: 12px;
+      color: #999;
+      margin-top: 10px;
+    }
+  }
+}
+</style>

+ 485 - 0
src/pages/recommended/index.vue

@@ -0,0 +1,485 @@
+<!--  -->
+<template>
+<div class='con' v-loading.fullscreen.lock="loading">
+  <el-dialog title="轮播资讯" width="495px" :visible.sync="dialogFormVisible">
+    <el-form :model="form" :label-position="'left'" :label-width="formLabelWidth">
+      <div style="padding:0 10px;">
+        <div class="d-l">
+          <el-form-item label="封面">
+            <el-upload :action="serverName+'/house/upload'" :headers="{token}" :show-file-list="true" :on-change="handleChange" :file-list="fileList" :before-upload="beforeAvatarUpload" :on-success="upload_success" :on-error="upload_fail">
+              <div class="zfb-upload">
+                <img  v-if="image" :src="image" style="width:auto;height:128px;">
+                <div v-else>
+                  <i class="el-icon-plus"></i>
+                  <div class="zfb-upload-text">
+                    <span v-html="$base.defaultTxt.upload_tips"></span>
+                  </div>
+                </div>
+                <div class="v-mask">
+                  <i class="iconfont icon-chongzhi"></i>
+                </div>
+              </div>
+            </el-upload>
+          </el-form-item>
+          <el-form-item label="标题">
+            <el-input v-model="form.title"></el-input>
+          </el-form-item>
+          <el-form-item label="链接ID">
+            <el-input v-model="form.connectId"></el-input>
+          </el-form-item>
+          <el-form-item label="推荐排序">
+            <el-input v-model="form.orderNum"></el-input>
+          </el-form-item>
+        </div>
+      </div>
+    </el-form>
+    <div style="text-align:center" class="dialog-footer">
+      <el-button @click="dialogFormVisible = false">取 消</el-button>
+      <el-button v-if="isAdd" type="primary" @click="add">保 存</el-button>
+      <el-button v-else type="primary" @click="save">保 存</el-button>
+    </div>
+  </el-dialog>
+  <div class="h-body">
+    <div class="c-header">
+      <div v-for="(item,i) in tag" class="span-tag" :key="i">
+        <span @click="activeTagId=item.id" :class="{'t-span':true,'t-active':activeTagId===item.id}" >{{item.txt}}</span>
+        <span v-if="i!==tag.length-1">/</span>
+      </div>
+      <div style="float:right">
+        <el-button @click="showAdd" type="primary">新增<i class="el-icon-plus el-icon--right"></i></el-button>
+      </div>
+    </div>
+    <div class="c-table">
+      <el-table height="670" v-if="tableData" :data="tableData" style="width: 100%;padding:0 20px;">
+        <el-table-column v-for="(item,i) in tableHeader" :key="i" :prop="item.name" :label="item.label" :width="item.name === 'image'?'300px':'auto'">
+          <template slot-scope="scope">
+            <img v-if="item.name === 'image'" :src="scope.row.image" style="height:200px;" alt="">
+            <span v-else>{{scope.row[item.name]}}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作">
+          <template slot-scope="scope">
+            <span class="o-span" @click="show(scope.row)">编辑</span>
+            <span class="o-span" @click="del(scope.row)" style="color:#f56c6c;padding-left:15px;">删除</span>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+  </div>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import {
+  serverName
+} from '@/utils/http'
+
+const tableHeader = [{
+  name: 'orderNum',
+  label: '序号'
+}, {
+  name: 'image',
+  label: '封面'
+}, {
+  name: 'title',
+  label: '标题'
+}, {
+  name: 'connectId',
+  label: '链接ID'
+}, {
+  name: 'createTime',
+  label: '编辑时间'
+}]
+const tableData = []
+const tag = [{
+  txt: '新上房源',
+  id: 0
+}, {
+  txt: '热门房源',
+  id: 1
+}, {
+  txt: '热门企业',
+  id: 2
+}]
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+
+  },
+  data () {
+    // 这里存放数据
+    return {
+      isAdd: true,
+      fileList: [],
+      loading: false,
+      activeTagId: 0,
+      tag,
+      c_id: '',
+      serverName,
+      tableData,
+      tableHeader,
+      dialogFormVisible: false,
+      currentPage: 1,
+      formLabelWidth: '100px',
+      content: '',
+      form: {
+        title: '',
+        connectId: '',
+        type: '',
+        orderNum: ''
+      },
+      image: '',
+      editorOption: {
+        modules: {
+          toolbar: [
+            [{
+              'size': ['small', false, 'large']
+            }],
+            ['bold', 'italic'],
+            [{
+              'list': 'ordered'
+            }, {
+              'list': 'bullet'
+            }],
+            ['link', 'image']
+          ],
+          history: {
+            delay: 1000,
+            maxStack: 50,
+            userOnly: false
+          },
+          imageDrop: true
+          // imageResize: {
+          //   displayStyles: {
+          //     backgroundColor: 'black',
+          //     border: 'none',
+          //     color: 'white'
+          //   },
+          //   modules: ['Resize', 'DisplaySize', 'Toolbar']
+          // }
+        }
+      }
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {
+    token () {
+      return window.localStorage.getItem('zfb_token')
+    }
+  },
+  // 监控data中的数据变化
+  watch: {
+    activeTagId () {
+      this.refresh()
+    }
+  },
+  // 方法集合
+  methods: {
+    showAdd () {
+      this.clearInfo()
+      this.dialogFormVisible = true
+      this.isAdd = true
+    },
+    del (item) {
+      this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http({
+          method: 'post',
+          data: {
+            id: item.id
+          },
+          url: '/recommend/delete',
+          headers: {
+            token: this.token
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('删除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.message
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    clearInfo () {
+      this.c_id = ''
+      this.form = {
+        title: '',
+        connectId: '',
+        type: '',
+        orderNum: ''
+      }
+      this.image = ''
+    },
+    add () {
+      let params = {
+        title: this.form.title,
+        image: this.image,
+        connectId: this.form.connectId,
+        orderNum: this.form.orderNum,
+        type: this.activeTagId
+      }
+      this.$http({
+        method: 'post',
+        data: params,
+        url: '/recommend/save',
+        headers: {
+          token: this.token
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.$alert('新增成功', '提示', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.dialogFormVisible = false
+              this.clearInfo()
+              this.refresh()
+            }
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    save () {
+      let params = {
+        id: this.c_id,
+        title: this.form.title,
+        image: this.image,
+        connectId: this.form.connectId,
+        orderNum: this.form.orderNum,
+        type: this.form.type
+      }
+      this.$http({
+        method: 'post',
+        data: params,
+        url: '/recommend/update',
+        headers: {
+          token: this.token
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.$alert('修改成功', '提示', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.dialogFormVisible = false
+              this.clearInfo()
+              this.refresh()
+            }
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    async show (item) {
+      this.isAdd = false
+      this.dialogFormVisible = true
+      let result = await this.$http({
+        method: 'post',
+        data: {
+          id: item.id
+        },
+        url: '/recommend/selectById',
+        headers: {
+          token: this.token
+        }
+      })
+      let list = result.message
+      this.c_id = list.id
+      this.form = {
+        title: list.title,
+        type: list.type,
+        connectId: list.connectId,
+        orderNum: list.orderNum
+      }
+      this.image = list.image
+    },
+    beforeAvatarUpload (file) {
+      const isLt5M = file.size / 1024 / 1024 < 5
+      if (!isLt5M) {
+        this.$message.error('上传头像图片大小不能超过 5MB!')
+        return false
+      }
+      return isLt5M
+    },
+    handleChange (file, fileList) {
+      console.log('file', file)
+      console.log('fileList', fileList)
+
+      if (fileList.length > 1) {
+        this.fileList = fileList.slice(-1)
+      }
+    },
+    upload_success (data) {
+      console.log('上传成功')
+
+      this.image = data.message
+    },
+    upload_fail (data) {
+      this.$notify.error({
+        title: '上传失败',
+        message: data.message
+      })
+    },
+    onEditorBlur (quill) {
+      // console.log('editor blur!', quill)
+    },
+    onEditorFocus (quill) {
+      // console.log('editor focus!', quill)
+    },
+    onEditorReady (quill) {
+      // console.log('editor ready!', quill)
+    },
+    onEditorChange ({quill, html, text}) {
+      console.log('editor change!', quill, html, text)
+      this.content = html
+    },
+    handleSizeChange (val) {
+      console.log(`每页 ${val} 条`)
+    },
+    handleCurrentChange (val) {
+      console.log(`当前页: ${val}`)
+    },
+    refresh () {
+      this.loading = true
+      this.getData()
+      this.loading = false
+    },
+    getData () {
+      this.$http({
+        method: 'post',
+        data: {
+          type: this.activeTagId
+        },
+        url: '/recommend/selectByType',
+        headers: {
+          token: this.token
+        }
+      }).then(res => {
+        let result = res
+        for (let i = 0; i < result.message.length; i++) {
+          result.message[i].createTime = this.$base.dateFormat('yyyy-MM-dd hh:mm', new Date(result.message[i].createTime))
+        }
+        this.tableData = result.message
+      })
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+    this.refresh()
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+
+<style lang="scss" scoped>
+.con {
+  .d-l {
+    display: inline-block;
+    width: 100%;
+    .zfb-upload {
+      width: 180px;
+      height: 130px;
+      line-height: 130px;
+      overflow: hidden;
+
+      img {
+        width: 178px;
+        height: 128px;
+        border-radius: 6px;
+      }
+
+      &:hover{
+          border-color: #409eff;
+          .v-mask{
+            display: inline-block;
+            width: 178px;
+            height: 128px;
+            border-radius: 6px;
+            background: rgba(0,0,0,0.5);
+          }
+      }
+
+      .el-icon-plus {
+        position: relative;
+        top: -15px;
+        font-size: 20px;
+      }
+    }
+  }
+
+  .h-body {
+    width: 100%;
+    padding: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+    background-color: #fff;
+
+    .span-tag {
+      display: inline-block;
+      padding-right: 8px;
+      font-size: 18px;
+
+      .t-span {
+        cursor: pointer;
+        padding-right: 3px;
+      }
+
+      .t-active {
+        font-weight: bold;
+      }
+    }
+
+    .c-table {
+      overflow: auto;
+      height: 670px;
+      margin-top: 60px;
+      .o-span {
+        color: #0175dc;
+        cursor: pointer;
+      }
+
+      .p-con {
+        width: 100%;
+        text-align: right;
+        padding: 25px 20px 30px;
+      }
+    }
+  }
+}
+</style>

+ 0 - 0
src/pages/recommended/style.scss


+ 669 - 0
src/pages/rental-info/index.vue

@@ -0,0 +1,669 @@
+<!--  -->
+<template>
+<div class='con' v-loading.fullscreen.lock="loading">
+  <el-dialog title="企业信息" width="45%" :visible.sync="dialogFormVisible">
+    <el-form :model="form" :label-position="'left'" :label-width="formLabelWidth">
+      <div style="padding:0 30px;">
+        <div class="d-l">
+          <el-form-item label="信息标题">
+            <el-input v-model="form.title"></el-input>
+          </el-form-item>
+          <el-form-item label="价格">
+            <div class="c-input-con">
+              <el-input placeholder="请输入价格" maxlength="10" v-model="form.total"></el-input>
+              <span class="hover-tip">元/月</span>
+            </div>
+          </el-form-item>
+          <el-form-item label="建筑面积">
+            <div class="c-input-con">
+              <el-input placeholder="请输入价格" maxlength="10" v-model="form.coveredArea"></el-input>
+              <span class="hover-tip">m²</span>
+            </div>
+          </el-form-item>
+          <el-form-item label="单位朝向">
+             <el-select v-model="form.orientation" placeholder="请选择">
+                <el-option
+                  v-for="item in form.orientations"
+                  :key="item.txt"
+                  :label="item.txt"
+                  v-model="item.txt">
+                </el-option>
+              </el-select>
+          </el-form-item>
+          <el-form-item label="装修情况">
+            <el-select v-model="form.decorate" placeholder="请选择">
+              <el-option
+                v-for="item in form.decorates"
+                :key="item.txt"
+                :label="item.txt"
+                v-model="item.txt">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="封面">
+            <el-upload
+              :action="serverName+'/house/upload'"
+              :headers="{token}"
+              :show-file-list="true"
+              :before-upload="beforeAvatarUpload"
+              :on-change="handleChange"
+              :file-list="fileList"
+              :on-success="upload_success"
+              :on-error="upload_fail">
+              <div class="zfb-upload">
+                <img  v-if="homepic" :src="homepic">
+                <div v-else>
+                  <i class="el-icon-plus"></i>
+                  <div class="zfb-upload-text">
+                    <span v-html="$base.defaultTxt.upload_tips"></span>
+                  </div>
+                </div>
+                <div class="v-mask">
+                  <i class="iconfont icon-chongzhi"></i>
+                </div>
+              </div>
+            </el-upload>
+          </el-form-item>
+        </div>
+        <div class="d-r">
+          <el-form-item label="所在楼层">
+            <el-input v-model="form.floor"></el-input>
+          </el-form-item>
+          <el-form-item label="房间数">
+            <el-input v-model="form.houseNum"></el-input>
+          </el-form-item>
+          <el-form-item label="客厅数">
+            <el-input v-model="form.parlourNum"></el-input>
+          </el-form-item>
+          <el-form-item label="卫生间数">
+            <el-input v-model="form.toiletNum"></el-input>
+          </el-form-item>
+          <el-form-item label="挂牌时间">
+              <el-date-picker
+                v-model="form.startTime"
+                type="date"
+                placeholder="选择日期">
+              </el-date-picker>
+          </el-form-item>
+          <el-form-item label="用途">
+            <el-input v-model="form.purpose"></el-input>
+          </el-form-item>
+          <el-form-item label="电梯">
+            <el-select v-model="form.elevator" placeholder="请选择">
+              <el-option
+                v-for="item in form.elevators"
+                :key="item.val"
+                :label="item.txt"
+                v-model="item.val">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="仅属">
+            <el-input v-model="form.power"></el-input>
+          </el-form-item>
+        </div>
+      </div>
+    </el-form>
+    <div style="text-align:center" class="dialog-footer">
+      <div>
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+        <el-button type="primary" @click="save(c_id)">保 存</el-button>
+      </div>
+    </div>
+  </el-dialog>
+  <div class="h-header">
+    <vcenter>
+      <div>
+        <el-dropdown >
+          <el-button type="primary">
+            {{dropdown_active.text}}
+            <i class="el-icon-arrow-down el-icon--right"></i>
+          </el-button>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item style="padding:0" v-for="(item,i) in dropdown_actives" :key="i"><div style="padding:0 20px;" @click="dropdown_active=item">{{item.text}}</div></el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+      </div>
+      <div class="h-input">
+        <span>时间段:</span>
+      </div>
+      <div class="fix-date">
+        <el-date-picker
+          v-model="value5"
+          type="datetimerange"
+          :picker-options="pickerOptions2"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd hh:mm:ss"
+          align="right">
+        </el-date-picker>
+      </div>
+      <div class="h-input"><span>手机号:</span></div>
+      <div>
+        <el-input v-model="userName" placeholder="输入手机号查询"></el-input>
+      </div>
+      <div>
+        <el-button @click="search" type="primary">搜索</el-button>
+      </div>
+    </vcenter>
+  </div>
+  <div class="h-body">
+    <el-table height="520" :data="tableData" style="width: 100%;padding:0 20px;">
+      <el-table-column v-for="(item,i) in tableHeader" :key="i" :prop="item.name" :label="item.label">
+      </el-table-column>
+      <el-table-column label="状态">
+        <template slot-scope="scope">
+          <el-switch
+            @change='changeState(scope.row)'
+            v-model="scope.row.state.st"
+            active-color="#0175dc"
+            inactive-color="#999">
+          </el-switch>
+          <span :style="{color:scope.row.state.text==='开'?'#0175dc':'#999',paddingLeft:'5px'}">{{scope.row.state.text}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作">
+        <template slot-scope="scope">
+          <span class="o-span" @click="show(scope.row)">编辑</span>
+          <span class="o-span" @click="del(scope.row)" style="color:#f56c6c;padding-left:15px;">删除</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="p-con">
+      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="currentPage" :page-size="size" layout="prev, pager, next, jumper" :total="total">
+      </el-pagination>
+    </div>
+  </div>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import vcenter from '@/components/vcenter'
+import {serverName} from '@/utils/http'
+
+const tableHeader = [{
+  name: 'id',
+  label: 'ID'
+}, {
+  name: 'createTime',
+  label: '发布时间'
+}, {
+  name: 'title',
+  label: '信息标题'
+}, {
+  name: 'userName',
+  label: '发布账号'
+}]
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    vcenter
+  },
+  data () {
+    // 这里存放数据
+    return {
+      fileList: [],
+      homepic: '',
+      serverName,
+      type: 2,
+      dropdown_actives: [
+        {
+          text: '全部',
+          id: ''
+        },
+        {
+          text: '正常',
+          id: 0
+        },
+        {
+          text: '已关闭',
+          id: 1
+        }
+      ],
+      dropdown_active: {
+        text: '全部',
+        id: ''
+      },
+      tableData: [],
+      tableHeader,
+      dialogFormVisible: false,
+      currentPage: 1,
+      value3: true,
+      loading: false,
+      formLabelWidth: '100px',
+      userName: '',
+      form: {
+        total: '',
+        title: '',
+        price: '',
+        coveredArea: '',
+        utilizationArea: '',
+        startTime: '',
+        orientation: '东',
+        orientations: [{
+          txt: '东'
+        }, {
+          txt: '南'
+        }, {
+          txt: '西'
+        }, {
+          txt: '北'
+        }],
+        decorates: [{
+          txt: '精装'
+        }, {
+          txt: '简装'
+        }, {
+          txt: '毛坯'
+        }, {
+          txt: '豪华装修'
+        } ],
+        decorate: '精装',
+        floor: '',
+        houseNum: '',
+        parlourNum: '',
+        toiletNum: '',
+        power: '',
+        elevators: [{
+          txt: '有',
+          val: true
+        }, {
+          txt: '无',
+          val: false
+        }],
+        elevator: true,
+        purpose: ''
+      },
+      size: 10,
+      total: 0,
+      c_id: '',
+      inpuKey: '',
+      pickerOptions2: {
+        shortcuts: [{
+          text: '最近一周',
+          onClick (picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近一个月',
+          onClick (picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近三个月',
+          onClick (picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
+            picker.$emit('pick', [start, end])
+          }
+        }]
+      },
+      value5: [],
+      options: [{
+        value: '选项1',
+        label: '东'
+      }, {
+        value: '选项2',
+        label: '东南'
+      }, {
+        value: '选项3',
+        label: '南'
+      }, {
+        value: '选项4',
+        label: '西南'
+      }, {
+        value: '选项5',
+        label: '西北'
+      }],
+      value: ''
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {
+    token () {
+      return window.localStorage.getItem('zfb_token')
+    }
+  },
+  // 监控data中的数据变化
+  watch: {
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    }
+  },
+  // 方法集合
+  methods: {
+    search () {
+      this.currentPage === 1 ? this.refresh() : this.currentPage = 1
+    },
+    beforeAvatarUpload (file) {
+      const isLt5M = file.size / 1024 / 1024 < 5
+      if (!isLt5M) {
+        this.$message.error('上传头像图片大小不能超过 5MB!')
+        return false
+      }
+      return isLt5M
+    },
+    handleChange (file, fileList) {
+      console.log('file', file)
+      console.log('fileList', fileList)
+
+      if (fileList.length > 1) {
+        this.fileList = fileList.slice(-1)
+      }
+    },
+    upload_success (data) {
+      console.log('上传成功')
+      this.homepic = data.message
+    },
+    upload_fail (data) {
+      this.$notify.error({
+        title: '上传失败',
+        message: data.message
+      })
+    },
+    handleSizeChange (val) {
+      console.log(`每页 ${val} 条`)
+    },
+    handleCurrentChange (val) {
+      console.log(`当前页: ${val}`)
+    },
+    refresh () {
+      this.loading = true
+      this.getData()
+      this.loading = false
+    },
+    clearInfo () {
+      this.dialogFormVisible = false
+      this.form = {
+        total: '',
+        title: '',
+        price: '',
+        coveredArea: '',
+        utilizationArea: '',
+        startTime: '',
+        orientation: '东',
+        orientations: [{
+          txt: '东'
+        }, {
+          txt: '南'
+        }, {
+          txt: '西'
+        }, {
+          txt: '北'
+        }],
+        decorates: [{
+          txt: '精装'
+        }, {
+          txt: '简装'
+        }, {
+          txt: '毛坯'
+        }, {
+          txt: '豪华装修'
+        } ],
+        decorate: '精装',
+        floor: '',
+        houseNum: '',
+        parlourNum: '',
+        toiletNum: '',
+        power: '',
+        elevators: [{
+          txt: '有',
+          val: true
+        }, {
+          txt: '无',
+          val: false
+        }],
+        elevator: true,
+        purpose: ''
+      }
+      this.homepic = ''
+      this.refresh()
+    },
+    async changeState (item) {
+      await this.$http({
+        method: 'post',
+        data: {
+          id: item.id,
+          state: (!item.state.st ? 1 : 0)
+        },
+        url: '/house/updateHouse',
+        headers: {
+          token: this.token
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.refresh()
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    async save (id) {
+      await this.$http({
+        method: 'post',
+        data: {
+          id,
+          title: this.form.title || null,
+          coveredArea: this.form.coveredArea || null,
+          total: this.form.total || null,
+          orientation: this.form.orientation || null,
+          floor: this.form.floor || null,
+          houseNum: this.form.houseNum || null,
+          parlourNum: this.form.parlourNum || null,
+          toiletNum: this.form.toiletNum || null,
+          elevator: this.form.elevator || null,
+          purpose: this.form.purpose || null,
+          power: this.form.power || null,
+          homepic: this.homepic || null,
+          decorate: this.form.decorate || null,
+          startTime: this.form.startTime || null
+
+        },
+        url: '/house/updateHouse',
+        headers: {
+          token: this.token
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.$alert('更新成功!', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.clearInfo()
+            }
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+
+    async getData () {
+      let params = {
+        userName: this.userName || '',
+        startTime: this.value5 ? this.value5[0] : '',
+        endTime: this.value5 ? this.value5[1] : '',
+        state: this.dropdown_active.id !== '' ? this.dropdown_active.id : '',
+        type: this.type
+      }
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        url: '/house/selectHouseByType',
+        headers: {
+          token: this.token,
+          pageNum: this.currentPage,
+          pageSize: this.size
+        }
+      })
+      for (let i = 0; i < result.message.list.length; i++) {
+        result.message.list[i].createTime = this.$base.dateFormat('yyyy-MM-dd hh:mm', new Date(result.message.list[i].createTime))
+        result.message.list[i].state = this.fixState(result.message.list[i].state)
+      }
+      this.tableData = result.message.list
+
+      this.total = result.message.total
+      this.currentPage = result.message.pageNum
+    },
+    del (item) {
+      this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http({
+          method: 'post',
+          data: {
+            id: item.id
+          },
+          url: '/house/deleteHouse',
+          headers: {
+            token: this.token
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('删除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.message
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    async show (item) {
+      this.dialogFormVisible = true
+      let result = await this.$http({
+        method: 'post',
+        data: {
+          id: item.id
+        },
+        url: '/house/selectHouseById',
+        headers: {
+          token: this.token
+        }
+      })
+      let list = result.message
+      this.c_id = list.id
+      this.form = {
+        total: list.total,
+        title: list.title,
+        price: list.price,
+        coveredArea: list.coveredArea,
+        utilizationArea: list.utilizationArea,
+        startTime: list.startTime ? this.$base.dateFormat('yyyy-MM-dd', new Date(list.startTime)) : '',
+        orientation: list.orientation,
+        decorate: list.decorate,
+        floor: list.floor,
+        houseNum: list.houseNum,
+        parlourNum: list.parlourNum,
+        toiletNum: list.toiletNum,
+        power: list.power,
+        elevator: list.elevator,
+        purpose: list.purpose,
+        c_zizhi: list.c_zizhi,
+        c_state: list.c_state,
+        orientations: [{
+          txt: '东'
+        }, {
+          txt: '南'
+        }, {
+          txt: '西'
+        }, {
+          txt: '北'
+        }],
+        decorates: [{
+          txt: '精装'
+        }, {
+          txt: '简装'
+        }, {
+          txt: '毛坯'
+        }, {
+          txt: '豪华装修'
+        } ],
+        elevators: [{
+          txt: '有',
+          val: true
+        }, {
+          txt: '无',
+          val: false
+        }]
+      }
+      this.homepic = list.homepic
+    },
+    fixState (state) {
+      let obj = {}
+      switch (state) {
+        case 0:
+          obj = {
+            status: 0,
+            text: '开',
+            class: 'zfb-success',
+            st: true
+          }
+          break
+
+        case 1:
+          obj = {
+            status: 1,
+            text: '关',
+            class: 'zfb-guanbi',
+            st: false
+          }
+          break
+        default:
+          break
+      }
+      return obj
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+    this.refresh()
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/style/info.scss'
+</style>

+ 0 - 0
src/pages/rental-info/style.scss


+ 885 - 0
src/pages/role/index.vue

@@ -0,0 +1,885 @@
+<!--  -->
+<template>
+  <div class="con" v-loading.fullscreen.lock="loading">
+
+    <div class="h-header">
+      <vcenter>
+        <div>
+          关键字:
+        </div>
+        <div class="h-input">
+          <el-input v-model="inpuKey" placeholder="输入角色名称"></el-input>
+        </div>
+        <div>
+          <el-button type="primary" @click="search(inpuKey)">查询</el-button>
+          <el-button>导出</el-button>
+        </div>
+      </vcenter>
+    </div>
+    <div class="h-body">
+      <div style="padding:0 20px;">
+        <el-button type="primary">新增角色</el-button>
+        <el-button>修改权限</el-button>
+      </div>
+      <el-table height="520" :data="tableData" style="width: 100%;padding:0 20px;">
+        <el-table-column
+          v-for="(item,i) in tableHeader"
+          :key="i"
+          :prop="item.name"
+          :label="item.label"
+        >
+          <template slot-scope="scope">
+            <span
+              @click="view_device(scope.row)"
+              class="o-span"
+              v-if="item.label==='设备数量'"
+            >{{scope['row'].cameraNum}}</span>
+            <div class="logo-add" v-else-if="item.label==='加载界面logo'">
+              <div @click="showLoadingLogo(scope.row,'scene')">
+                <img :src="scope['row'].sceneLogo" alt />
+                <span>+</span>
+              </div>
+            </div>
+            <div class="logo-add" v-else-if="item.label==='加载地面logo'">
+              <div @click="showLoadingLogo(scope.row,'floor')">
+                <img :src="scope['row'].floorLogo" alt />
+                <span>+</span>
+              </div>
+            </div>
+            <div class="logo-add" v-else-if="item.label==='背景音乐'">
+              <div @click="showLoadingLogo(scope.row,'music')">
+                <img :src="scope['row'].bgMusic?require('@/assets/images/icon_mp3.png'):''" alt />
+                <span v-if="!scope['row'].bgMusic">+</span>
+              </div>
+            </div>
+            <span v-else-if="item.label==='子账号数量'">{{scope['row'].subNum+scope['row'].num}}</span>
+            <div
+              class="time-data"
+              v-else-if="item.label==='到期时间'"
+            >
+             <div class="select-data" @click="daoqiDate = scope.row">
+               <el-date-picker
+                v-model="value1"
+                @change="dateChange"
+                value-format="yyyy-MM-dd"
+                type="date"
+                placeholder="选择日期">
+              </el-date-picker>
+             </div>
+            <span>{{scope.row[item.name]?$base.dateFormat('yyyy-MM-dd', new Date(scope.row[item.name])):'暂无到期时间'}}</span></div>
+            <span v-else>{{scope.row[item.name]}}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="p-con">
+        <el-pagination
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          :current-page.sync="currentPage"
+          :page-size="size"
+          layout="prev, pager, next, jumper"
+          :total="total"
+        ></el-pagination>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import vcenter from '@/components/vcenter'
+import { serverName } from '@/utils/http'
+
+const tableHeader = [
+  {
+    name: 'daihao',
+    label: '角色名称'
+  },
+  {
+    name: 'sceneLogo',
+    label: '创建人'
+  },
+  {
+    name: 'floorLogo',
+    label: '创建时间'
+  },
+  {
+    name: 'lasttime',
+    label: '上次修改时间'
+  },
+  {
+    name: 'lasttime',
+    label: '备注'
+  }
+]
+
+let saveTypes = {
+  scene: '加载界面logo',
+  floor: '加载地面logo',
+  music: '背景音乐'
+}
+
+let sceneTypeArr = {
+  scene: 'sceneLogo',
+  floor: 'floorLogo',
+  music: 'bgMusic'
+}
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    vcenter
+  },
+  data () {
+    // 这里存放数据
+    let dropdownActives = [{
+      text: '企业账号',
+      id: 'account'
+    },
+    {
+      text: '设备ID',
+      id: 'childName'
+    }]
+
+    let placeholder = {
+      account: '输入企业账号查询',
+      childName: '输入设备ID查询'
+    }
+    return {
+      dropdownActives,
+      dropdown_active: {
+        text: '企业账号',
+        id: 'account'
+      },
+      placeholder,
+      fileList: [],
+      currentlogo_id: '',
+      homepic: '',
+      saveTypes,
+      saveType: 'scene',
+      isAdd: false,
+      serverName,
+      c_num: '',
+      tableData: [],
+      tableHeader,
+      dialogFormVisible: false,
+      chargeVisible: false,
+      deviceFormVisible: false,
+      loadinglogoVisible: false,
+      currentPage: 1,
+      num: 1,
+      loading: false,
+      formLabelWidth: '100px',
+      errMsg: '该ID不可用',
+      userName: '',
+      recharge_id: '',
+      daoqiDate: '',
+      form_charge: {
+        userName: '',
+        point: '',
+        recharge: ''
+      },
+      form: {
+        name: '',
+        region: '',
+        date1: '',
+        date2: '',
+        delivery: false,
+        type: [],
+        resource: '',
+        desc: ''
+      },
+      form_device: {
+        d_userName: '',
+        d_name: '',
+        d_device: []
+      },
+      size: 10,
+      total: 0,
+      c_id: null,
+      c_subNum: '',
+      c_userName: '',
+      c_name: '',
+      addDevies: [
+        {
+          value: '',
+          isAvailable: false,
+          hasCheck: false
+        }
+      ],
+      inpuKey: '',
+      value1: ''
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {
+    token () {
+      return window.localStorage.getItem('zfb_token')
+    }
+  },
+  // 监控data中的数据变化
+  watch: {
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    },
+    num (newVal, oldVal) {
+      if (newVal > oldVal) {
+        this.addDevies.push({
+          value: '',
+          isAvailable: false,
+          hasCheck: false
+        })
+      } else {
+        this.addDevies.pop()
+      }
+    }
+  },
+  // 方法集合
+  methods: {
+    unbind (item) {
+      this.$confirm('此操作将解除该设备的绑定, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http({
+          method: 'post',
+          data: {
+            childName: item.childName
+          },
+          url: '/company/unbindDevice',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('解除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.deviceFormVisible = false
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.message
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    dropClick (item) {
+      this.inpuKey = ''
+      this.userName = ''
+      this.dropdown_active = item
+    },
+    beforeAvatarUpload (file) {
+      const isLt5M = file.size / 1024 / 1024 < 5
+      const isMp3 =
+        file.type === 'audio/mp3' ||
+        file.type === 'audio/x-ms-wma' ||
+        file.type === 'audio/wav'
+
+      if (this.saveType === 'music') {
+        if (!isMp3) {
+          this.$message.error('暂不支持该音频格式')
+          return false
+        }
+      }
+      if (!isLt5M) {
+        this.$message.error('上传文件大小不能超过 5MB')
+        return false
+      }
+      return true
+    },
+    handleChange (file, fileList) {
+      if (fileList.length > 1) {
+        this.fileList = fileList.slice(-1)
+      }
+    },
+    dateChange (data) {
+      // let data1 = new Date(data)
+      this.$confirm('此操作将会更新该企业账号的到期时间, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        console.log(data)
+        this.$http({
+          method: 'post',
+          data: {
+            id: this.daoqiDate.id,
+            expirationDate: data
+          },
+          url: '/company/updateExpirationTime',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('更新成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.message
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消'
+        })
+      })
+    },
+    upload_success (data) {
+      this.homepic = data.message
+    },
+    upload_fail (data) {
+      this.$notify.error({
+        title: '上传失败',
+        message: data.message
+      })
+    },
+    handleSizeChange (val) {
+      console.log(`每页 ${val} 条`)
+    },
+    handleCurrentChange (val) {
+      console.log(`当前页: ${val}`)
+    },
+    _checkInput: function (e) {
+      this.form_charge.recharge += ''
+      this.form_charge.recharge = this.form_charge.recharge.replace(
+        /[^\d]/g,
+        ''
+      )
+      if (
+        Number(this.form_charge.recharge) &&
+        this.form_charge.recharge > 999999999
+      ) {
+        this.form_charge.recharge = 999999999
+      }
+    },
+    saveLoadingLogo () {
+      if (!this.homepic && this.saveType !== 'music') {
+        this.$notify.error({
+          title: '保存失败',
+          message: '请上传图片'
+        })
+      } else {
+        let params
+        if (this.saveType === 'scene') {
+          params = {
+            id: this.currentlogo_id,
+            sceneLogo: this.homepic || null
+          }
+        } else if (this.saveType === 'music') {
+          params = {
+            id: this.currentlogo_id,
+            bgMusic: this.homepic || ''
+          }
+        } else {
+          params = {
+            id: this.currentlogo_id,
+            floorLogo: this.homepic || null
+          }
+        }
+        this.$http({
+          method: 'post',
+          data: params,
+          url: '/company/updateCompany',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('保存成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.loadinglogoVisible = false
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '保存失败',
+              message: res.message
+            })
+          }
+        })
+      }
+    },
+    refresh () {
+      this.loading = true
+      this.getData()
+      this.loading = false
+    },
+    search (item) {
+      this.userName = item
+      this.refresh()
+    },
+    save_reCharge () {
+      this.$confirm('此操作将对该账号进行充值, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          this.loading = true
+          let params = {
+            id: this.recharge_id,
+            point: Number(this.form_charge.recharge)
+          }
+          this.$http({
+            method: 'post',
+            data: params,
+            url: '/company/addPoint',
+            headers: {
+              token: window.localStorage.getItem('zfb_token')
+            }
+          }).then(res => {
+            if (res.code === 200) {
+              this.$alert('充值成功', '提示', {
+                confirmButtonText: '确定',
+                callback: action => {
+                  this.clearInfo()
+                }
+              })
+            } else {
+              this.loading = false
+              this.$notify.error({
+                title: '充值失败',
+                message: res.message
+              })
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消充值'
+          })
+        })
+    },
+    async show_reCharge (item) {
+      this.chargeVisible = true
+      this.recharge_id = item.id
+      this.form_charge = {
+        userName: item.userName,
+        point: item.point,
+        recharge: ''
+      }
+    },
+
+    async showLoadingLogo (item, type) {
+      console.log(item)
+      this.saveType = type
+      this.homepic = item[sceneTypeArr[type]] || ''
+      this.currentlogo_id = item.id
+      this.loadinglogoVisible = true
+    },
+    async view_device (item, search = false) {
+      this.deviceFormVisible = true
+      // this.d_subNum = item.subNum
+      this.form_device.d_userName = item.userName
+      this.form_device.d_name = item.name
+      let params = {
+        userName: item.userName
+      }
+      this.form_device.d_device = (await this.$http({
+        method: 'post',
+        data: params,
+        url: '/company/selectCompanyDevice',
+        headers: {
+          token: window.localStorage.getItem('zfb_token')
+        }
+      })).message
+      setTimeout(() => {
+        let items = Array.from(this.$refs.dcon.querySelectorAll('.d-body'))
+        let offTop = 0
+        items.forEach(item => {
+          item.style.background = '#fff'
+          let txt = item.querySelectorAll('span')[1].innerText
+          if (txt === this.userName.trim() && search) {
+            offTop = item.offsetTop - 311
+            item.style.background = '#ccc'
+          }
+        })
+        document.querySelector('#dcon').scrollTop = offTop
+      }, 0)
+    },
+    add (item) {
+      this.dialogFormVisible = true
+      this.c_subNum = item.subNum
+      this.c_num = item.num
+      this.c_userName = item.userName
+      this.c_name = item.name
+      this.c_id = item.id
+    },
+    clearInfo () {
+      this.num = 1
+      this.addDevies = [
+        {
+          value: '',
+          isAvailable: false,
+          hasCheck: false
+        }
+      ]
+      this.dialogFormVisible = false
+      this.chargeVisible = false
+      this.recharge_id = ''
+      this.form_charge = {
+        userName: '',
+        point: '',
+        recharge: ''
+      }
+      this.refresh()
+    },
+    canIsave () {
+      let temp = []
+      for (let i = 0; i < this.addDevies.length; i++) {
+        if (this.addDevies[i].isAvailable === true) {
+          temp.push(this.addDevies[i].value)
+        } else {
+          temp = []
+          return false
+        }
+      }
+      return temp.join(';')
+    },
+    save (userName) {
+      let params = {
+        childName: this.canIsave() || null,
+        userName: userName || null,
+        id: this.c_id || null,
+        subNum: this.c_subNum || null
+      }
+      this.loading = true
+      this.$http({
+        method: 'post',
+        data: params,
+        url: '/company/addDevice',
+        headers: {
+          token: window.localStorage.getItem('zfb_token')
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.$alert('添加成功', '提示', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.clearInfo()
+            }
+          })
+        } else {
+          this.loading = false
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    checkLegal (item) {
+      if (item.value) {
+        let params = {
+          childName: item.value
+        }
+        this.$http({
+          method: 'post',
+          data: params,
+          url: '/company/checkDevice',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            item.isAvailable = true
+          } else {
+            item.isAvailable = false
+            this.errMsg = '该ID不可用'
+          }
+          item.hasCheck = true
+        })
+      } else {
+        item.isAvailable = false
+        item.hasCheck = true
+        this.errMsg = 'ID不能为空'
+      }
+    },
+    async getData () {
+      let params = {
+        userName: this.userName || ''
+      }
+      let result
+      if (this.dropdown_active.id === 'childName' && this.userName) {
+        result = await this.$http({
+          method: 'post',
+          data: {
+            childName: this.userName
+          },
+          url: '/company/findCompanyDevice',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        })
+        let {message, code} = result
+        if (message && code === 200) {
+          this.view_device(message, true)
+        } else {
+          this.$notify.error({
+            title: '无法找到对应设备'
+          })
+        }
+      } else {
+        result = await this.$http({
+          method: 'post',
+          data: params,
+          url: '/company/selectCompanyNum',
+          headers: {
+            token: window.localStorage.getItem('zfb_token'),
+            pageNum: this.currentPage,
+            pageSize: this.size
+          }
+        })
+        this.tableData = result.message.list
+        this.total = result.message.total
+        this.currentPage = result.message.pageNum
+      }
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {},
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+    console.log('mounted')
+    this.refresh()
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+
+<style lang="scss" scoped>
+.con {
+  .time-data{
+    position: relative;
+    .select-data{
+      position: absolute;
+      left: 0;
+      top: 0;
+      opacity: 0;
+      cursor: pointer;
+    }
+    >span{
+      color: #0175dc;
+    }
+  }
+  .ei-num {
+    .el-input-number {
+      width: 90%;
+    }
+  }
+  .clear-music {
+    position: relative;
+    text-align: right;
+    top: -30px;
+    color: #999;
+    cursor: pointer;
+  }
+  .musicIcon {
+    width: 100%;
+    height: 100%;
+    line-height: 1;
+    margin-top: 35px;
+    img {
+      width: 50px;
+      height: auto;
+    }
+    p {
+      font-weight: bold;
+      font-size: 14px;
+      color: #000;
+      line-height: 20px;
+      height: 20px;
+      margin-top: 20px;
+    }
+  }
+  .icon-plus {
+    margin-left: 15px;
+    width: 40px;
+    height: 38px;
+    line-height: 38px;
+    text-align: center;
+    background: #f5f7fa;
+    color: #999;
+    cursor: pointer;
+    font-size: 13px;
+    display: inline-block;
+    border: 1px solid #dcdfe6;
+    border-radius: 4px;
+    &:hover {
+      border: 1px solid #c0c4cc;
+    }
+  }
+  .add-num {
+    margin-left: 15px;
+    width: 250px;
+    .icon-close,
+    .icon-correct {
+      line-height: 1;
+      color: #999;
+    }
+    input[type="number"]::-webkit-inner-spin-button,
+    input[type="number"]::-webkit-outer-spin-button {
+      -webkit-appearance: none;
+      margin: 0;
+    }
+  }
+
+  .ei-input {
+    width: 100%;
+    max-height: 200px;
+    overflow-y: auto;
+    .input-con {
+      display: inline-block;
+      width: 45%;
+      margin: 2px 5px 2px 0;
+      height: 60px;
+      position: relative;
+      .el-input_err {
+        & /deep/ .el-input__inner {
+          border: 1px solid #f56c6c;
+        }
+      }
+      .el-input_success {
+        & /deep/ .el-input__inner {
+          border: 1px solid #67c23a;
+        }
+      }
+      span {
+        color: #f56c6c;
+        font-size: 12px;
+        line-height: 1;
+        padding-top: 4px;
+        position: absolute;
+        left: 0;
+      }
+    }
+  }
+  .h-header {
+    height: 80px;
+    background-color: #fff;
+    padding-left: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+
+    div {
+      display: inline-block;
+    }
+
+    .h-input {
+      width: 220px;
+    }
+  }
+
+  .h-body {
+    width: 100%;
+    margin: 30px 0 0;
+    padding-top: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+    background-color: #fff;
+
+    .logo-add {
+      div {
+        cursor: pointer;
+        line-height: 40px;
+        border: 1px dotted #dcdfe6;
+        border-radius: 4px;
+        font-weight: bold;
+        font-size: 18px;
+        display: inline-block;
+        width: 40px;
+        height: 40px;
+        background: #f5f7fa;
+        position: relative;
+        img {
+          width: 100%;
+          height: 100%;
+          position: absolute;
+          top: 0;
+          left: 0;
+        }
+        span {
+          position: absolute;
+          z-index: 100;
+          left: 0;
+          top: 0;
+          width: 100%;
+          height: 100%;
+        }
+      }
+    }
+
+    .o-span {
+      color: #0175dc;
+      cursor: pointer;
+    }
+
+    .p-con {
+      width: 100%;
+      text-align: right;
+      padding: 25px 20px 30px;
+    }
+  }
+
+  .d-table {
+    border: 1px solid #ccc;
+    .d-con {
+      max-height: 200px;
+      overflow-y: scroll;
+    }
+    .d-header {
+      font-weight: bold;
+    }
+    .d-header,
+    .d-body {
+      height: 40px;
+      line-height: 40px;
+      width: 100%;
+      border-bottom: 1px solid #ccc;
+      &:last-child {
+        border: none;
+      }
+      span {
+        text-align: center;
+        display: inline-block;
+        width: 24%;
+
+      }
+      .unbind{
+        cursor: pointer;
+      }
+    }
+  }
+}
+</style>

+ 0 - 0
src/pages/role/style.scss


+ 518 - 0
src/pages/scene/index.vue

@@ -0,0 +1,518 @@
+<!--  -->
+<template>
+<div class='con' v-loading.fullscreen.lock="loading">
+  <el-dialog title="企业信息" width="45%" :visible.sync="dialogFormVisible">
+    <el-form :model="form" :label-position="'left'" :label-width="formLabelWidth">
+      <div class="con-main">
+        <div class="d-l">
+          <el-form-item label="信息标题:">
+            <span>{{c_title}}</span>
+          </el-form-item>
+          <el-form-item label="联系人:">
+            <span>{{c_user}}</span>
+          </el-form-item>
+          <el-form-item label="手机号:">
+            <span>{{c_phone}}</span>
+          </el-form-item>
+          <el-form-item label="所属区域:">
+            <span>{{c_area}}</span>
+          </el-form-item>
+          <el-form-item label="详细地址:">
+            <span>{{c_address}}</span>
+          </el-form-item>
+          <el-form-item label="企业官网:">
+            <span style="color:#0055f2;cursor:pointer" @click="fix_website(c_website)">{{c_website}}</span>
+          </el-form-item>
+        </div>
+        <div class="d-r">
+          <el-form-item label="企业LOGO:">
+            <div class="c-logo"><img :src="c_logo" alt=""></div>
+          </el-form-item>
+          <el-form-item label="企业资质:">
+            <div class="c-zizhi">
+              <img :src="c_zizhi" alt="">
+              <a v-if="$base.isImg(c_zizhi)" :href="c_zizhi" download="download" class="c-mask">
+                <i class="iconfont icon-download"></i>
+              </a>
+              <div v-else class="c-mask">
+                <i class="iconfont icon-download"></i>
+              </div>
+            </div>
+          </el-form-item>
+        </div>
+        <el-form-item label="企业简介:">
+            <div style="word-break: break-all">{{c_introduce}}</div>
+        </el-form-item>
+      </div>
+    </el-form>
+    <div style="text-align:center" class="dialog-footer">
+      <div v-if="c_state === 0">
+        <el-button type="danger" @click="save(c_id,2)">拒 绝</el-button>
+        <el-button type="primary" @click="save(c_id,1)">通 过</el-button>
+      </div>
+      <el-button type="info" v-else>{{c_state===1?'已通过':'已拒绝'}}</el-button>
+    </div>
+  </el-dialog>
+  <div class="h-header">
+    <vcenter>
+      <div>
+        <el-dropdown>
+          <el-button type="primary">
+            {{dropdown_active.text}}
+            <i class="el-icon-arrow-down el-icon--right"></i>
+          </el-button>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item style="padding:0" v-for="(item,i) in dropdown_actives" :key="i">
+              <div style="padding:0 20px;" @click="dropdown_active=item">{{item.text}}</div>
+            </el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+      </div>
+      <div class="h-input">
+        <span>时间段:</span>
+      </div>
+      <div class="fix-date">
+        <el-date-picker v-model="value5" type="datetimerange" :picker-options="pickerOptions2" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" value-format="yyyy-MM-dd hh:mm:ss" align="right">
+        </el-date-picker>
+      </div>
+      <div class="h-input"><span>手机号:</span></div>
+      <div>
+        <el-input v-model="userName" placeholder="输入手机号查询"></el-input>
+      </div>
+      <div>
+        <el-button @click="refresh" type="primary">搜索</el-button>
+      </div>
+    </vcenter>
+  </div>
+  <div class="h-body">
+    <el-table height="520" :data="tableData" style="width: 100%;padding:0 20px;">
+      <el-table-column v-for="(item,i) in tableHeader" :key="i" :prop="item.name" :label="item.label">
+      </el-table-column>
+      <el-table-column label="状态">
+        <template slot-scope="scope">
+          <span :class="scope.row.state.class">{{scope.row.state.text}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作">
+        <template slot-scope="scope">
+          <span class="o-span" @click="show(scope.row)">详细信息</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="p-con">
+      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="currentPage" :page-size="size" layout="prev, pager, next, jumper" :total="total">
+      </el-pagination>
+    </div>
+  </div>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import vcenter from '@/components/vcenter'
+const tableHeader = [{
+  name: 'createTime',
+  label: '提交日期'
+}, {
+  name: 'name',
+  label: '企业名称'
+}, {
+  name: 'userName',
+  label: '手机号'
+}]
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    vcenter
+  },
+  data () {
+    // 这里存放数据
+    return {
+      dropdown_actives: [{
+        text: '全部',
+        id: ''
+      },
+      {
+        text: '已通过',
+        id: 1
+      },
+      {
+        text: '审核中',
+        id: 0
+      },
+      {
+        text: '已拒绝',
+        id: 2
+      }
+      ],
+      dropdown_active: {
+        text: '全部',
+        id: ''
+      },
+      tableData: [],
+      tableHeader,
+      dialogFormVisible: false,
+      currentPage: 1,
+      value3: true,
+      loading: false,
+      formLabelWidth: '100px',
+      userName: '',
+      form: {},
+      size: 10,
+      total: 0,
+      c_id: '',
+      c_title: '',
+      c_user: '',
+      c_phone: '',
+      c_area: '',
+      c_address: '',
+      c_website: '',
+      c_introduce: '',
+      c_logo: '',
+      c_zizhi: '',
+      c_state: '',
+      inpuKey: '',
+      pickerOptions2: {
+        shortcuts: [{
+          text: '最近一周',
+          onClick (picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近一个月',
+          onClick (picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近三个月',
+          onClick (picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
+            picker.$emit('pick', [start, end])
+          }
+        }]
+      },
+      value5: []
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    }
+  },
+  // 方法集合
+  methods: {
+    fix_website (value) {
+      if (this.$base.isContain(value, 'http://') || this.$base.isContain(value, 'https://')) {
+        window.open(value, '_blank')
+      } else {
+        window.open('http://' + value, '_blank')
+      }
+    },
+    handleSizeChange (val) {
+      console.log(`每页 ${val} 条`)
+    },
+    handleCurrentChange (val) {
+      console.log(`当前页: ${val}`)
+    },
+    refresh () {
+      this.loading = true
+      this.getData()
+      this.loading = false
+    },
+    clearInfo () {
+      this.dialogFormVisible = false
+      this.$bus.$emit('refresh', true)
+      this.refresh()
+    },
+
+    async save (id = '', state = '') {
+      await this.$http({
+        method: 'post',
+        data: {
+          id,
+          state
+        },
+        url: '/company/auditCompany',
+        headers: {
+          token: window.localStorage.getItem('zfb_token')
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.$alert('审核成功!', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.clearInfo()
+            }
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+
+    async getData () {
+      let params = {
+        userName: this.userName || '',
+        startTime: this.value5 ? this.value5[0] : '',
+        endTime: this.value5 ? this.value5[1] : '',
+        state: this.dropdown_active.id !== '' ? this.dropdown_active.id : ''
+      }
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        url: '/company/selectCompanyByType',
+        headers: {
+          token: window.localStorage.getItem('zfb_token'),
+          pageNum: this.currentPage,
+          pageSize: this.size
+        }
+      })
+      for (let i = 0; i < result.message.list.length; i++) {
+        result.message.list[i].createTime = this.$base.dateFormat('yyyy-MM-dd hh:mm', new Date(result.message.list[i].createTime))
+        result.message.list[i].state = this.fixState(result.message.list[i].state)
+      }
+      this.tableData = result.message.list
+
+      this.total = result.message.total
+      this.currentPage = result.message.pageNum
+    },
+    async show (item) {
+      this.dialogFormVisible = true
+      let result = await this.$http({
+        method: 'post',
+        data: {
+          id: item.id
+        },
+        url: '/company/selectCompanyById',
+        headers: {
+          token: window.localStorage.getItem('zfb_token')
+        }
+      })
+      let list = result.message
+      this.c_id = list.id || ''
+      this.c_title = list.name || ''
+      this.c_user = list.contacts || ''
+      this.c_phone = list.phone || ''
+      this.c_area = list.area || ''
+      this.c_address = list.address || ''
+      this.c_website = list.website || ''
+      this.c_logo = list.logo || ''
+      this.c_zizhi = list.qualification || ''
+      this.c_introduce = list.introduce || ''
+      this.c_state = list.state
+    },
+    fixState (state) {
+      let obj = {}
+      switch (state) {
+        case 0:
+          obj = {
+            status: 0,
+            text: '审核中',
+            class: 'zfb-shenhe'
+          }
+          break
+
+        case 1:
+          obj = {
+            status: 1,
+            text: '已通过',
+            class: 'zfb-success'
+          }
+          break
+
+        case 2:
+          obj = {
+            status: 2,
+            text: '已拒绝',
+            class: 'zfb-reject'
+          }
+          break
+
+        default:
+          break
+      }
+      return obj
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+    this.refresh()
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+
+<style lang="scss" scoped>
+.con {
+  .con-main {
+    padding: 0 30px;
+    .d-l {
+      display: inline-block
+    }
+
+    .d-r {
+      float: right;
+
+      .c-logo {
+        width: 150px;
+        height: 150px;
+        border: 1px solid #ccc;
+        border-radius: 4px;
+        background-color: #f5fafe;
+
+        img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+
+      .c-zizhi {
+        width: 150px;
+        height: 150px;
+        border: 1px solid #ccc;
+        border-radius: 4px;
+        position: relative;
+        background-color: #f5fafe;
+
+        img {
+          width: 100%;
+          height: 100%;
+        }
+
+        .c-mask {
+          width: 100%;
+          height: 100%;
+          position: absolute;
+          top: 0;
+          left: 0;
+          background: rgba(0, 0, 0, 0.5);
+          text-align: center;
+          display: table;
+
+          .icon-download {
+            text-align: center;
+            display: table-cell;
+            vertical-align: middle;
+            color: #fff;
+            font-size: 20px;
+          }
+        }
+      }
+    }
+  }
+
+  .ei-num {
+    .el-input-number {
+      width: 90%;
+    }
+  }
+
+  .ei-input {
+    width: 100%;
+    max-height: 200px;
+    overflow-y: auto;
+
+    .input-con {
+      display: inline-block;
+      width: 45%;
+      margin: 2px 5px 2px 0;
+      height: 60px;
+      position: relative;
+
+      .el-input_err {
+        & /deep/ .el-input__inner {
+          border: 1px solid #f56c6c;
+        }
+      }
+
+      .el-input_success {
+        & /deep/ .el-input__inner {
+          border: 1px solid #67c23a;
+        }
+      }
+
+      span {
+        color: #f56c6c;
+        font-size: 12px;
+        line-height: 1;
+        padding-top: 4px;
+        position: absolute;
+        left: 0;
+      }
+    }
+
+  }
+
+  .h-header {
+    height: 80px;
+    background-color: #fff;
+    padding-left: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+
+    div {
+      display: inline-block;
+      vertical-align: middle;
+    }
+
+    .h-input {
+      margin-left: 20px;
+      display: inline-block;
+    }
+
+    .fix-date {
+      div {
+        display: flex;
+      }
+    }
+  }
+
+  .h-body {
+    width: 100%;
+    margin: 30px 0 0;
+    padding-top: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+    background-color: #fff;
+
+    .o-span {
+      color: #0175dc;
+      cursor: pointer;
+    }
+
+    .p-con {
+      width: 100%;
+      text-align: right;
+      padding: 25px 20px 30px;
+    }
+  }
+}
+</style>

+ 0 - 0
src/pages/scene/style.scss


+ 671 - 0
src/pages/sell-info/index.vue

@@ -0,0 +1,671 @@
+<!--  -->
+<template>
+<div class='con' v-loading.fullscreen.lock="loading">
+  <el-dialog title="企业信息" width="45%" :visible.sync="dialogFormVisible">
+    <el-form :model="form" :label-position="'left'" :label-width="formLabelWidth">
+      <div style="padding:0 30px;">
+        <div class="d-l">
+          <el-form-item label="信息标题">
+            <el-input v-model="form.title"></el-input>
+          </el-form-item>
+          <el-form-item label="价格">
+            <div class="c-input-con">
+              <el-input placeholder="请输入价格" maxlength="10" v-model="form.total"></el-input>
+              <span class="hover-tip"></span>
+            </div>
+          </el-form-item>
+          <el-form-item label="建筑面积">
+            <div class="c-input-con">
+              <el-input placeholder="请输入价格" maxlength="10" v-model="form.coveredArea"></el-input>
+              <span class="hover-tip">m²</span>
+            </div>
+          </el-form-item>
+          <el-form-item label="单位朝向">
+             <el-select v-model="form.orientation" placeholder="请选择">
+                <el-option
+                  v-for="item in form.orientations"
+                  :key="item.txt"
+                  :label="item.txt"
+                  v-model="item.txt">
+                </el-option>
+              </el-select>
+          </el-form-item>
+          <el-form-item label="装修情况">
+            <el-select v-model="form.decorate" placeholder="请选择">
+              <el-option
+                v-for="item in form.decorates"
+                :key="item.txt"
+                :label="item.txt"
+                v-model="item.txt">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="封面">
+            <el-upload
+              :action="serverName+'/house/upload'"
+              :headers="{token}"
+              :show-file-list="true"
+              :before-upload="beforeAvatarUpload"
+              :on-change="handleChange"
+              :file-list="fileList"
+              :on-success="upload_success"
+              :on-error="upload_fail">
+              <div class="zfb-upload">
+                <img  v-if="homepic" :src="homepic">
+                <div v-else>
+                  <i class="el-icon-plus"></i>
+                  <div class="zfb-upload-text">
+                    <span v-html="$base.defaultTxt.upload_tips"></span>
+                  </div>
+                </div>
+                <div class="v-mask">
+                  <i class="iconfont icon-chongzhi"></i>
+                </div>
+              </div>
+            </el-upload>
+          </el-form-item>
+        </div>
+        <div class="d-r">
+          <el-form-item label="所在楼层">
+            <el-input v-model="form.floor"></el-input>
+          </el-form-item>
+          <el-form-item label="房间数">
+            <el-input v-model="form.houseNum"></el-input>
+          </el-form-item>
+          <el-form-item label="客厅数">
+            <el-input v-model="form.parlourNum"></el-input>
+          </el-form-item>
+          <el-form-item label="卫生间数">
+            <el-input v-model="form.toiletNum"></el-input>
+          </el-form-item>
+          <el-form-item label="挂牌时间">
+              <el-date-picker
+                v-model="form.startTime"
+                type="date"
+                placeholder="选择日期">
+              </el-date-picker>
+          </el-form-item>
+          <el-form-item label="用途">
+            <el-input v-model="form.purpose"></el-input>
+          </el-form-item>
+          <el-form-item label="电梯">
+            <el-select v-model="form.elevator" placeholder="请选择">
+              <el-option
+                v-for="item in form.elevators"
+                :key="item.val"
+                :label="item.txt"
+                v-model="item.val">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="仅属">
+            <el-input v-model="form.power"></el-input>
+          </el-form-item>
+        </div>
+      </div>
+    </el-form>
+    <div style="text-align:center" class="dialog-footer">
+      <div>
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+        <el-button type="primary" @click="save(c_id)">保 存</el-button>
+      </div>
+    </div>
+  </el-dialog>
+  <div class="h-header">
+    <vcenter>
+      <div>
+        <el-dropdown >
+          <el-button type="primary">
+            {{dropdown_active.text}}
+            <i class="el-icon-arrow-down el-icon--right"></i>
+          </el-button>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item style="padding:0" v-for="(item,i) in dropdown_actives" :key="i"><div style="padding:0 20px;" @click="dropdown_active=item">{{item.text}}</div></el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+      </div>
+      <div class="h-input">
+        <span>时间段:</span>
+      </div>
+      <div class="fix-date">
+        <el-date-picker
+          v-model="value5"
+          type="datetimerange"
+          :picker-options="pickerOptions2"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd hh:mm:ss"
+          align="right">
+        </el-date-picker>
+      </div>
+      <div class="h-input"><span>手机号:</span></div>
+      <div>
+        <el-input v-model="userName" placeholder="输入手机号查询"></el-input>
+      </div>
+      <div>
+        <el-button @click="search" type="primary">搜索</el-button>
+      </div>
+    </vcenter>
+  </div>
+  <div class="h-body">
+    <el-table height="520" :data="tableData" style="width: 100%;padding:0 20px;">
+      <el-table-column v-for="(item,i) in tableHeader" :key="i" :prop="item.name" :label="item.label">
+      </el-table-column>
+      <el-table-column label="状态">
+        <template slot-scope="scope">
+          <el-switch
+            @change='changeState(scope.row)'
+            v-model="scope.row.state.st"
+            active-color="#0175dc"
+            inactive-color="#999">
+          </el-switch>
+          <span :style="{color:scope.row.state.text==='开'?'#0175dc':'#999',paddingLeft:'5px'}">{{scope.row.state.text}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作">
+        <template slot-scope="scope">
+          <span class="o-span" @click="show(scope.row)">编辑</span>
+          <span class="o-span" @click="del(scope.row)" style="color:#f56c6c;padding-left:15px;">删除</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="p-con">
+      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="currentPage" :page-size="size" layout="prev, pager, next, jumper" :total="total">
+      </el-pagination>
+    </div>
+  </div>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import vcenter from '@/components/vcenter'
+import {serverName} from '@/utils/http'
+
+const tableHeader = [{
+  name: 'id',
+  label: 'ID'
+}, {
+  name: 'createTime',
+  label: '发布时间'
+}, {
+  name: 'title',
+  label: '信息标题'
+}, {
+  name: 'userName',
+  label: '发布账号'
+}]
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    vcenter
+  },
+  data () {
+    // 这里存放数据
+    return {
+      fileList: [],
+      homepic: '',
+      serverName,
+      type: 1,
+      dropdown_actives: [
+        {
+          text: '全部',
+          id: ''
+        },
+        {
+          text: '正常',
+          id: 0
+        },
+        {
+          text: '已关闭',
+          id: 1
+        }
+      ],
+      dropdown_active: {
+        text: '全部',
+        id: ''
+      },
+      tableData: [],
+      tableHeader,
+      dialogFormVisible: false,
+      currentPage: 1,
+      value3: true,
+      loading: false,
+      formLabelWidth: '100px',
+      userName: '',
+      form: {
+        total: '',
+        title: '',
+        price: '',
+        coveredArea: '',
+        utilizationArea: '',
+        startTime: '',
+        orientation: '东',
+        orientations: [{
+          txt: '东'
+        }, {
+          txt: '南'
+        }, {
+          txt: '西'
+        }, {
+          txt: '北'
+        }],
+        decorates: [{
+          txt: '精装'
+        }, {
+          txt: '简装'
+        }, {
+          txt: '毛坯'
+        }, {
+          txt: '豪华装修'
+        } ],
+        decorate: '精装',
+        floor: '',
+        houseNum: '',
+        parlourNum: '',
+        toiletNum: '',
+        power: '',
+        elevators: [{
+          txt: '有',
+          val: true
+        }, {
+          txt: '无',
+          val: false
+        }],
+        elevator: true,
+        purpose: ''
+      },
+      size: 10,
+      total: 0,
+      c_id: '',
+      inpuKey: '',
+      pickerOptions2: {
+        shortcuts: [{
+          text: '最近一周',
+          onClick (picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近一个月',
+          onClick (picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近三个月',
+          onClick (picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
+            picker.$emit('pick', [start, end])
+          }
+        }]
+      },
+      value5: [],
+      options: [{
+        value: '选项1',
+        label: '东'
+      }, {
+        value: '选项2',
+        label: '东南'
+      }, {
+        value: '选项3',
+        label: '南'
+      }, {
+        value: '选项4',
+        label: '西南'
+      }, {
+        value: '选项5',
+        label: '西北'
+      }],
+      value: ''
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {
+    token () {
+      return window.localStorage.getItem('zfb_token')
+    }
+
+  },
+  // 监控data中的数据变化
+  watch: {
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    }
+  },
+  // 方法集合
+  methods: {
+    search () {
+      this.currentPage === 1 ? this.refresh() : this.currentPage = 1
+    },
+    beforeAvatarUpload (file) {
+      const isLt5M = file.size / 1024 / 1024 < 5
+      if (!isLt5M) {
+        this.$message.error('上传头像图片大小不能超过 5MB!')
+        return false
+      }
+      return isLt5M
+    },
+    handleChange (file, fileList) {
+      console.log('file', file)
+      console.log('fileList', fileList)
+
+      if (fileList.length > 1) {
+        this.fileList = fileList.slice(-1)
+      }
+    },
+    upload_success (data) {
+      console.log('上传成功')
+
+      this.homepic = data.message
+    },
+    upload_fail (data) {
+      this.$notify.error({
+        title: '上传失败',
+        message: data.message
+      })
+    },
+    handleSizeChange (val) {
+      console.log(`每页 ${val} 条`)
+    },
+    handleCurrentChange (val) {
+      console.log(`当前页: ${val}`)
+    },
+    refresh () {
+      this.loading = true
+      this.getData()
+      this.loading = false
+    },
+    clearInfo () {
+      this.dialogFormVisible = false
+      this.form = {
+        total: '',
+        title: '',
+        price: '',
+        coveredArea: '',
+        utilizationArea: '',
+        startTime: '',
+        orientation: '东',
+        orientations: [{
+          txt: '东'
+        }, {
+          txt: '南'
+        }, {
+          txt: '西'
+        }, {
+          txt: '北'
+        }],
+        decorates: [{
+          txt: '精装'
+        }, {
+          txt: '简装'
+        }, {
+          txt: '毛坯'
+        }, {
+          txt: '豪华装修'
+        } ],
+        decorate: '精装',
+        floor: '',
+        houseNum: '',
+        parlourNum: '',
+        toiletNum: '',
+        power: '',
+        elevators: [{
+          txt: '有',
+          val: true
+        }, {
+          txt: '无',
+          val: false
+        }],
+        elevator: true,
+        purpose: ''
+      }
+      this.homepic = ''
+      this.refresh()
+    },
+    async changeState (item) {
+      await this.$http({
+        method: 'post',
+        data: {
+          id: item.id,
+          state: (!item.state.st ? 1 : 0)
+        },
+        url: '/house/updateHouse',
+        headers: {
+          token: this.token
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.refresh()
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    async save (id) {
+      await this.$http({
+        method: 'post',
+        data: {
+          id,
+          title: this.form.title || null,
+          coveredArea: this.form.coveredArea || null,
+          total: this.form.total || null,
+          orientation: this.form.orientation || null,
+          floor: this.form.floor || null,
+          houseNum: this.form.houseNum || null,
+          parlourNum: this.form.parlourNum || null,
+          toiletNum: this.form.toiletNum || null,
+          elevator: this.form.elevator || null,
+          purpose: this.form.purpose || null,
+          power: this.form.power || null,
+          homepic: this.homepic || null,
+          decorate: this.form.decorate || null,
+          startTime: this.form.startTime || null
+
+        },
+        url: '/house/updateHouse',
+        headers: {
+          token: this.token
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.$alert('更新成功!', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.clearInfo()
+            }
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+
+    async getData () {
+      let params = {
+        userName: this.userName || '',
+        startTime: this.value5 ? this.value5[0] : '',
+        endTime: this.value5 ? this.value5[1] : '',
+        state: this.dropdown_active.id !== '' ? this.dropdown_active.id : '',
+        type: this.type
+      }
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        url: '/house/selectHouseByType',
+        headers: {
+          token: this.token,
+          pageNum: this.currentPage,
+          pageSize: this.size
+        }
+      })
+      for (let i = 0; i < result.message.list.length; i++) {
+        result.message.list[i].createTime = this.$base.dateFormat('yyyy-MM-dd hh:mm', new Date(result.message.list[i].createTime))
+        result.message.list[i].state = this.fixState(result.message.list[i].state)
+      }
+      this.tableData = result.message.list
+
+      this.total = result.message.total
+      this.currentPage = result.message.pageNum
+    },
+    del (item) {
+      this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http({
+          method: 'post',
+          data: {
+            id: item.id
+          },
+          url: '/house/deleteHouse',
+          headers: {
+            token: this.token
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('删除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.message
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    async show (item) {
+      this.dialogFormVisible = true
+      let result = await this.$http({
+        method: 'post',
+        data: {
+          id: item.id
+        },
+        url: '/house/selectHouseById',
+        headers: {
+          token: this.token
+        }
+      })
+      let list = result.message
+      this.c_id = list.id
+      this.form = {
+        total: list.total,
+        title: list.title,
+        price: list.price,
+        coveredArea: list.coveredArea,
+        utilizationArea: list.utilizationArea,
+        startTime: list.startTime ? this.$base.dateFormat('yyyy-MM-dd', new Date(list.startTime)) : '',
+        orientation: list.orientation,
+        decorate: list.decorate,
+        floor: list.floor,
+        houseNum: list.houseNum,
+        parlourNum: list.parlourNum,
+        toiletNum: list.toiletNum,
+        power: list.power,
+        elevator: list.elevator,
+        purpose: list.purpose,
+        c_zizhi: list.c_zizhi,
+        c_state: list.c_state,
+        orientations: [{
+          txt: '东'
+        }, {
+          txt: '南'
+        }, {
+          txt: '西'
+        }, {
+          txt: '北'
+        }],
+        decorates: [{
+          txt: '精装'
+        }, {
+          txt: '简装'
+        }, {
+          txt: '毛坯'
+        }, {
+          txt: '豪华装修'
+        } ],
+        elevators: [{
+          txt: '有',
+          val: true
+        }, {
+          txt: '无',
+          val: false
+        }]
+      }
+      this.homepic = list.homepic
+    },
+    fixState (state) {
+      let obj = {}
+      switch (state) {
+        case 0:
+          obj = {
+            status: 0,
+            text: '开',
+            class: 'zfb-success',
+            st: true
+          }
+          break
+
+        case 1:
+          obj = {
+            status: 1,
+            text: '关',
+            class: 'zfb-guanbi',
+            st: false
+          }
+          break
+        default:
+          break
+      }
+      return obj
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+    this.refresh()
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/style/info.scss'
+</style>

+ 0 - 0
src/pages/sell-info/style.scss


+ 671 - 0
src/pages/site-decoration/index.vue

@@ -0,0 +1,671 @@
+<!--  -->
+<template>
+<div class='con' v-loading.fullscreen.lock="loading">
+  <el-dialog title="企业信息" width="45%" :visible.sync="dialogFormVisible">
+    <el-form :model="form" :label-position="'left'" :label-width="formLabelWidth">
+      <div style="padding:0 30px;">
+        <div class="d-l">
+          <el-form-item label="信息标题">
+            <el-input v-model="form.title"></el-input>
+          </el-form-item>
+          <el-form-item label="价格">
+            <div class="c-input-con">
+              <el-input placeholder="请输入价格" maxlength="10" v-model="form.total"></el-input>
+              <span class="hover-tip"></span>
+            </div>
+          </el-form-item>
+          <el-form-item label="建筑面积">
+            <div class="c-input-con">
+              <el-input placeholder="请输入价格" maxlength="10" v-model="form.coveredArea"></el-input>
+              <span class="hover-tip">m²</span>
+            </div>
+          </el-form-item>
+          <el-form-item label="单位朝向">
+             <el-select v-model="form.orientation" placeholder="请选择">
+                <el-option
+                  v-for="item in form.orientations"
+                  :key="item.txt"
+                  :label="item.txt"
+                  v-model="item.txt">
+                </el-option>
+              </el-select>
+          </el-form-item>
+          <el-form-item label="装修情况">
+            <el-select v-model="form.decorate" placeholder="请选择">
+              <el-option
+                v-for="item in form.decorates"
+                :key="item.txt"
+                :label="item.txt"
+                v-model="item.txt">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="封面">
+            <el-upload
+              :action="serverName+'/house/upload'"
+              :headers="{token}"
+              :show-file-list="true"
+              :before-upload="beforeAvatarUpload"
+              :on-change="handleChange"
+              :file-list="fileList"
+              :on-success="upload_success"
+              :on-error="upload_fail">
+              <div class="zfb-upload">
+                <img  v-if="homepic" :src="homepic">
+                <div v-else>
+                  <i class="el-icon-plus"></i>
+                  <div class="zfb-upload-text">
+                    <span v-html="$base.defaultTxt.upload_tips"></span>
+                  </div>
+                </div>
+                <div class="v-mask">
+                  <i class="iconfont icon-chongzhi"></i>
+                </div>
+              </div>
+            </el-upload>
+          </el-form-item>
+        </div>
+        <div class="d-r">
+          <el-form-item label="所在楼层">
+            <el-input v-model="form.floor"></el-input>
+          </el-form-item>
+          <el-form-item label="房间数">
+            <el-input v-model="form.houseNum"></el-input>
+          </el-form-item>
+          <el-form-item label="客厅数">
+            <el-input v-model="form.parlourNum"></el-input>
+          </el-form-item>
+          <el-form-item label="卫生间数">
+            <el-input v-model="form.toiletNum"></el-input>
+          </el-form-item>
+          <el-form-item label="挂牌时间">
+              <el-date-picker
+                v-model="form.startTime"
+                type="date"
+                placeholder="选择日期">
+              </el-date-picker>
+          </el-form-item>
+          <el-form-item label="用途">
+            <el-input v-model="form.purpose"></el-input>
+          </el-form-item>
+          <el-form-item label="电梯">
+            <el-select v-model="form.elevator" placeholder="请选择">
+              <el-option
+                v-for="item in form.elevators"
+                :key="item.val"
+                :label="item.txt"
+                v-model="item.val">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="仅属">
+            <el-input v-model="form.power"></el-input>
+          </el-form-item>
+        </div>
+      </div>
+    </el-form>
+    <div style="text-align:center" class="dialog-footer">
+      <div>
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+        <el-button type="primary" @click="save(c_id)">保 存</el-button>
+      </div>
+    </div>
+  </el-dialog>
+  <div class="h-header">
+    <vcenter>
+      <div>
+        <el-dropdown >
+          <el-button type="primary">
+            {{dropdown_active.text}}
+            <i class="el-icon-arrow-down el-icon--right"></i>
+          </el-button>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item style="padding:0" v-for="(item,i) in dropdown_actives" :key="i"><div style="padding:0 20px;" @click="dropdown_active=item">{{item.text}}</div></el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+      </div>
+      <div class="h-input">
+        <span>时间段:</span>
+      </div>
+      <div class="fix-date">
+        <el-date-picker
+          v-model="value5"
+          type="datetimerange"
+          :picker-options="pickerOptions2"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd hh:mm:ss"
+          align="right">
+        </el-date-picker>
+      </div>
+      <div class="h-input"><span>手机号:</span></div>
+      <div>
+        <el-input v-model="userName" placeholder="输入手机号查询"></el-input>
+      </div>
+      <div>
+        <el-button @click="search" type="primary">搜索</el-button>
+      </div>
+    </vcenter>
+  </div>
+  <div class="h-body">
+    <el-table height="520" :data="tableData" style="width: 100%;padding:0 20px;">
+      <el-table-column v-for="(item,i) in tableHeader" :key="i" :prop="item.name" :label="item.label">
+      </el-table-column>
+      <el-table-column label="状态">
+        <template slot-scope="scope">
+          <el-switch
+            @change='changeState(scope.row)'
+            v-model="scope.row.state.st"
+            active-color="#0175dc"
+            inactive-color="#999">
+          </el-switch>
+          <span :style="{color:scope.row.state.text==='开'?'#0175dc':'#999',paddingLeft:'5px'}">{{scope.row.state.text}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作">
+        <template slot-scope="scope">
+          <span class="o-span" @click="show(scope.row)">编辑</span>
+          <span class="o-span" @click="del(scope.row)" style="color:#f56c6c;padding-left:15px;">删除</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="p-con">
+      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="currentPage" :page-size="size" layout="prev, pager, next, jumper" :total="total">
+      </el-pagination>
+    </div>
+  </div>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import vcenter from '@/components/vcenter'
+import {serverName} from '@/utils/http'
+
+const tableHeader = [{
+  name: 'id',
+  label: 'ID'
+}, {
+  name: 'createTime',
+  label: '发布时间'
+}, {
+  name: 'title',
+  label: '信息标题'
+}, {
+  name: 'userName',
+  label: '发布账号'
+}]
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    vcenter
+  },
+  data () {
+    // 这里存放数据
+    return {
+      fileList: [],
+      homepic: '',
+      serverName,
+      type: 0,
+      dropdown_actives: [
+        {
+          text: '全部',
+          id: ''
+        },
+        {
+          text: '正常',
+          id: 0
+        },
+        {
+          text: '已关闭',
+          id: 1
+        }
+      ],
+      dropdown_active: {
+        text: '全部',
+        id: ''
+      },
+      tableData: [],
+      tableHeader,
+      dialogFormVisible: false,
+      currentPage: 1,
+      value3: true,
+      loading: false,
+      formLabelWidth: '100px',
+      userName: '',
+      form: {
+        total: '',
+        title: '',
+        price: '',
+        coveredArea: '',
+        utilizationArea: '',
+        startTime: '',
+        orientation: '东',
+        orientations: [{
+          txt: '东'
+        }, {
+          txt: '南'
+        }, {
+          txt: '西'
+        }, {
+          txt: '北'
+        }],
+        decorates: [{
+          txt: '精装'
+        }, {
+          txt: '简装'
+        }, {
+          txt: '毛坯'
+        }, {
+          txt: '豪华装修'
+        } ],
+        decorate: '精装',
+        floor: '',
+        houseNum: '',
+        parlourNum: '',
+        toiletNum: '',
+        power: '',
+        elevators: [{
+          txt: '有',
+          val: true
+        }, {
+          txt: '无',
+          val: false
+        }],
+        elevator: true,
+        purpose: ''
+      },
+      size: 10,
+      total: 0,
+      c_id: '',
+      inpuKey: '',
+      pickerOptions2: {
+        shortcuts: [{
+          text: '最近一周',
+          onClick (picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近一个月',
+          onClick (picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近三个月',
+          onClick (picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
+            picker.$emit('pick', [start, end])
+          }
+        }]
+      },
+      value5: [],
+      options: [{
+        value: '选项1',
+        label: '东'
+      }, {
+        value: '选项2',
+        label: '东南'
+      }, {
+        value: '选项3',
+        label: '南'
+      }, {
+        value: '选项4',
+        label: '西南'
+      }, {
+        value: '选项5',
+        label: '西北'
+      }],
+      value: ''
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {
+    token () {
+      return window.localStorage.getItem('zfb_token')
+    }
+
+  },
+  // 监控data中的数据变化
+  watch: {
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    }
+  },
+  // 方法集合
+  methods: {
+    search () {
+      this.currentPage === 1 ? this.refresh() : this.currentPage = 1
+    },
+    beforeAvatarUpload (file) {
+      const isLt5M = file.size / 1024 / 1024 < 5
+      if (!isLt5M) {
+        this.$message.error('上传头像图片大小不能超过 5MB!')
+        return false
+      }
+      return isLt5M
+    },
+    handleChange (file, fileList) {
+      console.log('file', file)
+      console.log('fileList', fileList)
+
+      if (fileList.length > 1) {
+        this.fileList = fileList.slice(-1)
+      }
+    },
+    upload_success (data) {
+      console.log('上传成功')
+
+      this.homepic = data.message
+    },
+    upload_fail (data) {
+      this.$notify.error({
+        title: '上传失败',
+        message: data.message
+      })
+    },
+    handleSizeChange (val) {
+      console.log(`每页 ${val} 条`)
+    },
+    handleCurrentChange (val) {
+      console.log(`当前页: ${val}`)
+    },
+    refresh () {
+      this.loading = true
+      this.getData()
+      this.loading = false
+    },
+    clearInfo () {
+      this.dialogFormVisible = false
+      this.form = {
+        total: '',
+        title: '',
+        price: '',
+        coveredArea: '',
+        utilizationArea: '',
+        startTime: '',
+        orientation: '东',
+        orientations: [{
+          txt: '东'
+        }, {
+          txt: '南'
+        }, {
+          txt: '西'
+        }, {
+          txt: '北'
+        }],
+        decorates: [{
+          txt: '精装'
+        }, {
+          txt: '简装'
+        }, {
+          txt: '毛坯'
+        }, {
+          txt: '豪华装修'
+        } ],
+        decorate: '精装',
+        floor: '',
+        houseNum: '',
+        parlourNum: '',
+        toiletNum: '',
+        power: '',
+        elevators: [{
+          txt: '有',
+          val: true
+        }, {
+          txt: '无',
+          val: false
+        }],
+        elevator: true,
+        purpose: ''
+      }
+      this.homepic = ''
+      this.refresh()
+    },
+    async changeState (item) {
+      await this.$http({
+        method: 'post',
+        data: {
+          id: item.id,
+          state: (!item.state.st ? 1 : 0)
+        },
+        url: '/house/updateHouse',
+        headers: {
+          token: this.token
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.refresh()
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    async save (id) {
+      await this.$http({
+        method: 'post',
+        data: {
+          id,
+          title: this.form.title || null,
+          coveredArea: this.form.coveredArea || null,
+          total: this.form.total || null,
+          orientation: this.form.orientation || null,
+          floor: this.form.floor || null,
+          houseNum: this.form.houseNum || null,
+          parlourNum: this.form.parlourNum || null,
+          toiletNum: this.form.toiletNum || null,
+          elevator: this.form.elevator || null,
+          purpose: this.form.purpose || null,
+          power: this.form.power || null,
+          homepic: this.homepic || null,
+          decorate: this.form.decorate || null,
+          startTime: this.form.startTime || null
+
+        },
+        url: '/house/updateHouse',
+        headers: {
+          token: this.token
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.$alert('更新成功!', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.clearInfo()
+            }
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+
+    async getData () {
+      let params = {
+        userName: this.userName || '',
+        startTime: this.value5 ? this.value5[0] : '',
+        endTime: this.value5 ? this.value5[1] : '',
+        state: this.dropdown_active.id !== '' ? this.dropdown_active.id : '',
+        type: this.type
+      }
+      let result = await this.$http({
+        method: 'post',
+        data: params,
+        url: '/house/selectHouseByType',
+        headers: {
+          token: this.token,
+          pageNum: this.currentPage,
+          pageSize: this.size
+        }
+      })
+      for (let i = 0; i < result.message.list.length; i++) {
+        result.message.list[i].createTime = this.$base.dateFormat('yyyy-MM-dd hh:mm', new Date(result.message.list[i].createTime))
+        result.message.list[i].state = this.fixState(result.message.list[i].state)
+      }
+      this.tableData = result.message.list
+
+      this.total = result.message.total
+      this.currentPage = result.message.pageNum
+    },
+    del (item) {
+      this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http({
+          method: 'post',
+          data: {
+            id: item.id
+          },
+          url: '/house/deleteHouse',
+          headers: {
+            token: this.token
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('删除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.message
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    async show (item) {
+      this.dialogFormVisible = true
+      let result = await this.$http({
+        method: 'post',
+        data: {
+          id: item.id
+        },
+        url: '/house/selectHouseById',
+        headers: {
+          token: this.token
+        }
+      })
+      let list = result.message
+      this.c_id = list.id
+      this.form = {
+        total: list.total,
+        title: list.title,
+        price: list.price,
+        coveredArea: list.coveredArea,
+        utilizationArea: list.utilizationArea,
+        startTime: list.startTime ? this.$base.dateFormat('yyyy-MM-dd', new Date(list.startTime)) : '',
+        orientation: list.orientation,
+        decorate: list.decorate,
+        floor: list.floor,
+        houseNum: list.houseNum,
+        parlourNum: list.parlourNum,
+        toiletNum: list.toiletNum,
+        power: list.power,
+        elevator: list.elevator,
+        purpose: list.purpose,
+        c_zizhi: list.c_zizhi,
+        c_state: list.c_state,
+        orientations: [{
+          txt: '东'
+        }, {
+          txt: '南'
+        }, {
+          txt: '西'
+        }, {
+          txt: '北'
+        }],
+        decorates: [{
+          txt: '精装'
+        }, {
+          txt: '简装'
+        }, {
+          txt: '毛坯'
+        }, {
+          txt: '豪华装修'
+        } ],
+        elevators: [{
+          txt: '有',
+          val: true
+        }, {
+          txt: '无',
+          val: false
+        }]
+      }
+      this.homepic = list.homepic
+    },
+    fixState (state) {
+      let obj = {}
+      switch (state) {
+        case 0:
+          obj = {
+            status: 0,
+            text: '开',
+            class: 'zfb-success',
+            st: true
+          }
+          break
+
+        case 1:
+          obj = {
+            status: 1,
+            text: '关',
+            class: 'zfb-guanbi',
+            st: false
+          }
+          break
+        default:
+          break
+      }
+      return obj
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+    this.refresh()
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/style/info.scss'
+</style>

+ 0 - 0
src/pages/site-decoration/style.scss


+ 898 - 0
src/pages/user/index.vue

@@ -0,0 +1,898 @@
+<!--  -->
+<template>
+  <div class="con" v-loading.fullscreen.lock="loading">
+
+    <div class="h-header">
+      <vcenter>
+        <div>
+          关键字:
+        </div>
+        <div class="h-input">
+          <el-input v-model="inpuKey" placeholder="输入用户名/部门/角色"></el-input>
+        </div>
+        <div>
+          <el-button type="primary" @click="search(inpuKey)">查询</el-button>
+          <el-button>导出</el-button>
+        </div>
+      </vcenter>
+    </div>
+    <div class="h-body">
+      <div style="padding:0 20px;">
+        <el-button type="primary">新增用户</el-button>
+        <el-button>修改信息</el-button>
+        <el-button>密码重置</el-button>
+      </div>
+      <el-table height="520" :data="tableData" style="width: 100%;padding:0 20px;">
+        <el-table-column
+          v-for="(item,i) in tableHeader"
+          :key="i"
+          :prop="item.name"
+          :label="item.label"
+        >
+          <template slot-scope="scope">
+            <span
+              @click="view_device(scope.row)"
+              class="o-span"
+              v-if="item.label==='设备数量'"
+            >{{scope['row'].cameraNum}}</span>
+            <div class="logo-add" v-else-if="item.label==='加载界面logo'">
+              <div @click="showLoadingLogo(scope.row,'scene')">
+                <img :src="scope['row'].sceneLogo" alt />
+                <span>+</span>
+              </div>
+            </div>
+            <div class="logo-add" v-else-if="item.label==='加载地面logo'">
+              <div @click="showLoadingLogo(scope.row,'floor')">
+                <img :src="scope['row'].floorLogo" alt />
+                <span>+</span>
+              </div>
+            </div>
+            <div class="logo-add" v-else-if="item.label==='背景音乐'">
+              <div @click="showLoadingLogo(scope.row,'music')">
+                <img :src="scope['row'].bgMusic?require('@/assets/images/icon_mp3.png'):''" alt />
+                <span v-if="!scope['row'].bgMusic">+</span>
+              </div>
+            </div>
+            <span v-else-if="item.label==='子账号数量'">{{scope['row'].subNum+scope['row'].num}}</span>
+            <div
+              class="time-data"
+              v-else-if="item.label==='到期时间'"
+            >
+             <div class="select-data" @click="daoqiDate = scope.row">
+               <el-date-picker
+                v-model="value1"
+                @change="dateChange"
+                value-format="yyyy-MM-dd"
+                type="date"
+                placeholder="选择日期">
+              </el-date-picker>
+             </div>
+            <span>{{scope.row[item.name]?$base.dateFormat('yyyy-MM-dd', new Date(scope.row[item.name])):'暂无到期时间'}}</span></div>
+            <span v-else>{{scope.row[item.name]}}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="p-con">
+        <el-pagination
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          :current-page.sync="currentPage"
+          :page-size="size"
+          layout="prev, pager, next, jumper"
+          :total="total"
+        ></el-pagination>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import vcenter from '@/components/vcenter'
+import { serverName } from '@/utils/http'
+
+const tableHeader = [
+  {
+    name: 'daihao',
+    label: '用户代号'
+  },
+  {
+    name: 'name',
+    label: '用户名'
+  },
+  {
+    name: 'sceneLogo',
+    label: '姓别'
+  },
+  {
+    name: 'number',
+    label: '手机号码'
+  },
+  {
+    name: 'email',
+    label: '邮箱'
+  },
+  {
+    name: 'floorLogo',
+    label: '所属部门'
+  },
+  {
+    name: 'asd',
+    label: '所属角色'
+  },
+  {
+    name: 'time',
+    label: '创建时间'
+  }
+]
+
+let saveTypes = {
+  scene: '加载界面logo',
+  floor: '加载地面logo',
+  music: '背景音乐'
+}
+
+let sceneTypeArr = {
+  scene: 'sceneLogo',
+  floor: 'floorLogo',
+  music: 'bgMusic'
+}
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    vcenter
+  },
+  data () {
+    // 这里存放数据
+    let dropdownActives = [{
+      text: '企业账号',
+      id: 'account'
+    },
+    {
+      text: '设备ID',
+      id: 'childName'
+    }]
+
+    let placeholder = {
+      account: '输入企业账号查询',
+      childName: '输入设备ID查询'
+    }
+    return {
+      dropdownActives,
+      dropdown_active: {
+        text: '企业账号',
+        id: 'account'
+      },
+      placeholder,
+      fileList: [],
+      currentlogo_id: '',
+      homepic: '',
+      saveTypes,
+      saveType: 'scene',
+      isAdd: false,
+      serverName,
+      c_num: '',
+      tableData: [],
+      tableHeader,
+      dialogFormVisible: false,
+      chargeVisible: false,
+      deviceFormVisible: false,
+      loadinglogoVisible: false,
+      currentPage: 1,
+      num: 1,
+      loading: false,
+      formLabelWidth: '100px',
+      errMsg: '该ID不可用',
+      userName: '',
+      recharge_id: '',
+      daoqiDate: '',
+      form_charge: {
+        userName: '',
+        point: '',
+        recharge: ''
+      },
+      form: {
+        name: '',
+        region: '',
+        date1: '',
+        date2: '',
+        delivery: false,
+        type: [],
+        resource: '',
+        desc: ''
+      },
+      form_device: {
+        d_userName: '',
+        d_name: '',
+        d_device: []
+      },
+      size: 10,
+      total: 0,
+      c_id: null,
+      c_subNum: '',
+      c_userName: '',
+      c_name: '',
+      addDevies: [
+        {
+          value: '',
+          isAvailable: false,
+          hasCheck: false
+        }
+      ],
+      inpuKey: '',
+      value1: ''
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {
+    token () {
+      return window.localStorage.getItem('zfb_token')
+    }
+  },
+  // 监控data中的数据变化
+  watch: {
+    currentPage () {
+      this.refresh()
+    },
+    size () {
+      this.refresh()
+    },
+    num (newVal, oldVal) {
+      if (newVal > oldVal) {
+        this.addDevies.push({
+          value: '',
+          isAvailable: false,
+          hasCheck: false
+        })
+      } else {
+        this.addDevies.pop()
+      }
+    }
+  },
+  // 方法集合
+  methods: {
+    unbind (item) {
+      this.$confirm('此操作将解除该设备的绑定, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http({
+          method: 'post',
+          data: {
+            childName: item.childName
+          },
+          url: '/company/unbindDevice',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('解除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.deviceFormVisible = false
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.message
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    dropClick (item) {
+      this.inpuKey = ''
+      this.userName = ''
+      this.dropdown_active = item
+    },
+    beforeAvatarUpload (file) {
+      const isLt5M = file.size / 1024 / 1024 < 5
+      const isMp3 =
+        file.type === 'audio/mp3' ||
+        file.type === 'audio/x-ms-wma' ||
+        file.type === 'audio/wav'
+
+      if (this.saveType === 'music') {
+        if (!isMp3) {
+          this.$message.error('暂不支持该音频格式')
+          return false
+        }
+      }
+      if (!isLt5M) {
+        this.$message.error('上传文件大小不能超过 5MB')
+        return false
+      }
+      return true
+    },
+    handleChange (file, fileList) {
+      if (fileList.length > 1) {
+        this.fileList = fileList.slice(-1)
+      }
+    },
+    dateChange (data) {
+      // let data1 = new Date(data)
+      this.$confirm('此操作将会更新该企业账号的到期时间, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        console.log(data)
+        this.$http({
+          method: 'post',
+          data: {
+            id: this.daoqiDate.id,
+            expirationDate: data
+          },
+          url: '/company/updateExpirationTime',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('更新成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.message
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消'
+        })
+      })
+    },
+    upload_success (data) {
+      this.homepic = data.message
+    },
+    upload_fail (data) {
+      this.$notify.error({
+        title: '上传失败',
+        message: data.message
+      })
+    },
+    handleSizeChange (val) {
+      console.log(`每页 ${val} 条`)
+    },
+    handleCurrentChange (val) {
+      console.log(`当前页: ${val}`)
+    },
+    _checkInput: function (e) {
+      this.form_charge.recharge += ''
+      this.form_charge.recharge = this.form_charge.recharge.replace(
+        /[^\d]/g,
+        ''
+      )
+      if (
+        Number(this.form_charge.recharge) &&
+        this.form_charge.recharge > 999999999
+      ) {
+        this.form_charge.recharge = 999999999
+      }
+    },
+    saveLoadingLogo () {
+      if (!this.homepic && this.saveType !== 'music') {
+        this.$notify.error({
+          title: '保存失败',
+          message: '请上传图片'
+        })
+      } else {
+        let params
+        if (this.saveType === 'scene') {
+          params = {
+            id: this.currentlogo_id,
+            sceneLogo: this.homepic || null
+          }
+        } else if (this.saveType === 'music') {
+          params = {
+            id: this.currentlogo_id,
+            bgMusic: this.homepic || ''
+          }
+        } else {
+          params = {
+            id: this.currentlogo_id,
+            floorLogo: this.homepic || null
+          }
+        }
+        this.$http({
+          method: 'post',
+          data: params,
+          url: '/company/updateCompany',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('保存成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.loadinglogoVisible = false
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '保存失败',
+              message: res.message
+            })
+          }
+        })
+      }
+    },
+    refresh () {
+      this.loading = true
+      this.getData()
+      this.loading = false
+    },
+    search (item) {
+      this.userName = item
+      this.refresh()
+    },
+    save_reCharge () {
+      this.$confirm('此操作将对该账号进行充值, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          this.loading = true
+          let params = {
+            id: this.recharge_id,
+            point: Number(this.form_charge.recharge)
+          }
+          this.$http({
+            method: 'post',
+            data: params,
+            url: '/company/addPoint',
+            headers: {
+              token: window.localStorage.getItem('zfb_token')
+            }
+          }).then(res => {
+            if (res.code === 200) {
+              this.$alert('充值成功', '提示', {
+                confirmButtonText: '确定',
+                callback: action => {
+                  this.clearInfo()
+                }
+              })
+            } else {
+              this.loading = false
+              this.$notify.error({
+                title: '充值失败',
+                message: res.message
+              })
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消充值'
+          })
+        })
+    },
+    async show_reCharge (item) {
+      this.chargeVisible = true
+      this.recharge_id = item.id
+      this.form_charge = {
+        userName: item.userName,
+        point: item.point,
+        recharge: ''
+      }
+    },
+
+    async showLoadingLogo (item, type) {
+      console.log(item)
+      this.saveType = type
+      this.homepic = item[sceneTypeArr[type]] || ''
+      this.currentlogo_id = item.id
+      this.loadinglogoVisible = true
+    },
+    async view_device (item, search = false) {
+      this.deviceFormVisible = true
+      // this.d_subNum = item.subNum
+      this.form_device.d_userName = item.userName
+      this.form_device.d_name = item.name
+      let params = {
+        userName: item.userName
+      }
+      this.form_device.d_device = (await this.$http({
+        method: 'post',
+        data: params,
+        url: '/company/selectCompanyDevice',
+        headers: {
+          token: window.localStorage.getItem('zfb_token')
+        }
+      })).message
+      setTimeout(() => {
+        let items = Array.from(this.$refs.dcon.querySelectorAll('.d-body'))
+        let offTop = 0
+        items.forEach(item => {
+          item.style.background = '#fff'
+          let txt = item.querySelectorAll('span')[1].innerText
+          if (txt === this.userName.trim() && search) {
+            offTop = item.offsetTop - 311
+            item.style.background = '#ccc'
+          }
+        })
+        document.querySelector('#dcon').scrollTop = offTop
+      }, 0)
+    },
+    add (item) {
+      this.dialogFormVisible = true
+      this.c_subNum = item.subNum
+      this.c_num = item.num
+      this.c_userName = item.userName
+      this.c_name = item.name
+      this.c_id = item.id
+    },
+    clearInfo () {
+      this.num = 1
+      this.addDevies = [
+        {
+          value: '',
+          isAvailable: false,
+          hasCheck: false
+        }
+      ]
+      this.dialogFormVisible = false
+      this.chargeVisible = false
+      this.recharge_id = ''
+      this.form_charge = {
+        userName: '',
+        point: '',
+        recharge: ''
+      }
+      this.refresh()
+    },
+    canIsave () {
+      let temp = []
+      for (let i = 0; i < this.addDevies.length; i++) {
+        if (this.addDevies[i].isAvailable === true) {
+          temp.push(this.addDevies[i].value)
+        } else {
+          temp = []
+          return false
+        }
+      }
+      return temp.join(';')
+    },
+    save (userName) {
+      let params = {
+        childName: this.canIsave() || null,
+        userName: userName || null,
+        id: this.c_id || null,
+        subNum: this.c_subNum || null
+      }
+      this.loading = true
+      this.$http({
+        method: 'post',
+        data: params,
+        url: '/company/addDevice',
+        headers: {
+          token: window.localStorage.getItem('zfb_token')
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.$alert('添加成功', '提示', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.clearInfo()
+            }
+          })
+        } else {
+          this.loading = false
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    checkLegal (item) {
+      if (item.value) {
+        let params = {
+          childName: item.value
+        }
+        this.$http({
+          method: 'post',
+          data: params,
+          url: '/company/checkDevice',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            item.isAvailable = true
+          } else {
+            item.isAvailable = false
+            this.errMsg = '该ID不可用'
+          }
+          item.hasCheck = true
+        })
+      } else {
+        item.isAvailable = false
+        item.hasCheck = true
+        this.errMsg = 'ID不能为空'
+      }
+    },
+    async getData () {
+      let params = {
+        userName: this.userName || ''
+      }
+      let result
+      if (this.dropdown_active.id === 'childName' && this.userName) {
+        result = await this.$http({
+          method: 'post',
+          data: {
+            childName: this.userName
+          },
+          url: '/company/findCompanyDevice',
+          headers: {
+            token: window.localStorage.getItem('zfb_token')
+          }
+        })
+        let {message, code} = result
+        if (message && code === 200) {
+          this.view_device(message, true)
+        } else {
+          this.$notify.error({
+            title: '无法找到对应设备'
+          })
+        }
+      } else {
+        result = await this.$http({
+          method: 'post',
+          data: params,
+          url: '/company/selectCompanyNum',
+          headers: {
+            token: window.localStorage.getItem('zfb_token'),
+            pageNum: this.currentPage,
+            pageSize: this.size
+          }
+        })
+        this.tableData = result.message.list
+        this.total = result.message.total
+        this.currentPage = result.message.pageNum
+      }
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {},
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+    console.log('mounted')
+    this.refresh()
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+
+<style lang="scss" scoped>
+.con {
+  .time-data{
+    position: relative;
+    .select-data{
+      position: absolute;
+      left: 0;
+      top: 0;
+      opacity: 0;
+      cursor: pointer;
+    }
+    >span{
+      color: #0175dc;
+    }
+  }
+  .ei-num {
+    .el-input-number {
+      width: 90%;
+    }
+  }
+  .clear-music {
+    position: relative;
+    text-align: right;
+    top: -30px;
+    color: #999;
+    cursor: pointer;
+  }
+  .musicIcon {
+    width: 100%;
+    height: 100%;
+    line-height: 1;
+    margin-top: 35px;
+    img {
+      width: 50px;
+      height: auto;
+    }
+    p {
+      font-weight: bold;
+      font-size: 14px;
+      color: #000;
+      line-height: 20px;
+      height: 20px;
+      margin-top: 20px;
+    }
+  }
+  .icon-plus {
+    margin-left: 15px;
+    width: 40px;
+    height: 38px;
+    line-height: 38px;
+    text-align: center;
+    background: #f5f7fa;
+    color: #999;
+    cursor: pointer;
+    font-size: 13px;
+    display: inline-block;
+    border: 1px solid #dcdfe6;
+    border-radius: 4px;
+    &:hover {
+      border: 1px solid #c0c4cc;
+    }
+  }
+  .add-num {
+    margin-left: 15px;
+    width: 250px;
+    .icon-close,
+    .icon-correct {
+      line-height: 1;
+      color: #999;
+    }
+    input[type="number"]::-webkit-inner-spin-button,
+    input[type="number"]::-webkit-outer-spin-button {
+      -webkit-appearance: none;
+      margin: 0;
+    }
+  }
+
+  .ei-input {
+    width: 100%;
+    max-height: 200px;
+    overflow-y: auto;
+    .input-con {
+      display: inline-block;
+      width: 45%;
+      margin: 2px 5px 2px 0;
+      height: 60px;
+      position: relative;
+      .el-input_err {
+        & /deep/ .el-input__inner {
+          border: 1px solid #f56c6c;
+        }
+      }
+      .el-input_success {
+        & /deep/ .el-input__inner {
+          border: 1px solid #67c23a;
+        }
+      }
+      span {
+        color: #f56c6c;
+        font-size: 12px;
+        line-height: 1;
+        padding-top: 4px;
+        position: absolute;
+        left: 0;
+      }
+    }
+  }
+  .h-header {
+    height: 80px;
+    background-color: #fff;
+    padding-left: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+
+    div {
+      display: inline-block;
+    }
+
+    .h-input {
+      width: 220px;
+    }
+  }
+
+  .h-body {
+    width: 100%;
+    margin: 30px 0 0;
+    padding-top: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+    background-color: #fff;
+
+    .logo-add {
+      div {
+        cursor: pointer;
+        line-height: 40px;
+        border: 1px dotted #dcdfe6;
+        border-radius: 4px;
+        font-weight: bold;
+        font-size: 18px;
+        display: inline-block;
+        width: 40px;
+        height: 40px;
+        background: #f5f7fa;
+        position: relative;
+        img {
+          width: 100%;
+          height: 100%;
+          position: absolute;
+          top: 0;
+          left: 0;
+        }
+        span {
+          position: absolute;
+          z-index: 100;
+          left: 0;
+          top: 0;
+          width: 100%;
+          height: 100%;
+        }
+      }
+    }
+
+    .o-span {
+      color: #0175dc;
+      cursor: pointer;
+    }
+
+    .p-con {
+      width: 100%;
+      text-align: right;
+      padding: 25px 20px 30px;
+    }
+  }
+
+  .d-table {
+    border: 1px solid #ccc;
+    .d-con {
+      max-height: 200px;
+      overflow-y: scroll;
+    }
+    .d-header {
+      font-weight: bold;
+    }
+    .d-header,
+    .d-body {
+      height: 40px;
+      line-height: 40px;
+      width: 100%;
+      border-bottom: 1px solid #ccc;
+      &:last-child {
+        border: none;
+      }
+      span {
+        text-align: center;
+        display: inline-block;
+        width: 24%;
+
+      }
+      .unbind{
+        cursor: pointer;
+      }
+    }
+  }
+}
+</style>

+ 0 - 0
src/pages/user/style.scss


+ 571 - 0
src/pages/z-carousel/index.vue

@@ -0,0 +1,571 @@
+<!--  -->
+<template>
+<div class='con' v-loading.fullscreen.lock="loading">
+  <el-upload
+          class="avatar-uploader"
+          :action="serverName+'house/upload'"
+          :headers="{token}"
+          :show-file-list="false"
+          :on-success="uploadSuccess"
+          :on-error="uploadError"
+          :before-upload="beforeUpload">
+  </el-upload>
+  <el-dialog title="轮播资讯" width="860px" :visible.sync="dialogFormVisible">
+    <el-form :model="form" :label-position="'left'" :label-width="formLabelWidth">
+      <div style="padding:0 30px;">
+        <div class="d-l">
+          <el-form-item label="封面">
+            <el-upload :action="serverName+'/house/upload'" :headers="{token}" :show-file-list="true" :on-change="handleChange" :file-list="fileList" :before-upload="beforeAvatarUpload" :on-success="upload_success" :on-error="upload_fail">
+              <div class="zfb-upload">
+                <img  v-if="image" :src="image" style="width:auto;height:158px;">
+                <div v-else>
+                  <i class="el-icon-plus"></i>
+                  <div class="zfb-upload-text">
+                    <span v-html="$base.defaultTxt.upload_tips"></span>
+                  </div>
+                </div>
+                <div class="v-mask">
+                  <i class="iconfont icon-chongzhi"></i>
+                </div>
+              </div>
+            </el-upload>
+          </el-form-item>
+        </div>
+        <div class="d-r">
+          <el-form-item label="正文标题">
+            <el-input v-model="form.title"></el-input>
+          </el-form-item>
+          <el-form-item label="轮播排序">
+            <el-input v-model="form.orderNum"></el-input>
+          </el-form-item>
+          <el-form-item label="链接">
+            <el-input v-model="form.url"></el-input>
+          </el-form-item>
+        </div>
+      </div>
+      <div style="padding:0 30px;">
+        <el-form-item label="正文内容">
+          <quill-editor v-model="content" ref="myQuillEditor" :options="editorOption"  @change="onEditorChange($event)" @blur="onEditorBlur($event)" @focus="onEditorFocus($event)" @ready="onEditorReady($event)">
+          </quill-editor>
+        </el-form-item>
+      </div>
+    </el-form>
+    <div style="text-align:center" class="dialog-footer">
+      <el-button @click="dialogFormVisible = false">取 消</el-button>
+      <el-button v-if="isAdd" type="primary" @click="add">保 存</el-button>
+      <el-button v-else type="primary" @click="save">保 存</el-button>
+    </div>
+  </el-dialog>
+  <div class="h-body">
+    <div class="c-header">
+      <el-button @click="showAdd" type="primary">新增<i class="el-icon-plus el-icon--right"></i></el-button>
+    </div>
+    <div class="c-table">
+      <el-table v-if="tableData" height="670" :data="tableData" style="width: 100%;padding:0 20px;">
+        <el-table-column v-for="(item,i) in tableHeader" :key="i" :prop="item.name" :label="item.label" :width="item.name === 'image'?'300px':'auto'">
+          <template slot-scope="scope">
+            <img v-if="item.name === 'image'" :src="scope.row.image" style="height:200px;" alt="">
+            <span v-else>{{scope.row[item.name]}}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作">
+          <template slot-scope="scope">
+            <span class="o-span" @click="show(scope.row)">编辑</span>
+            <span class="o-span" @click="del(scope.row)" style="color:#f56c6c;padding-left:15px;">删除</span>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+  </div>
+</div>
+</template>
+
+<script>
+// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
+// 例如:import 《组件名称》 from '《组件路径》';
+import {
+  serverName
+} from '@/utils/http'
+import 'quill/dist/quill.core.css'
+import 'quill/dist/quill.snow.css'
+import 'quill/dist/quill.bubble.css'
+
+import { Quill, quillEditor } from 'vue-quill-editor'
+
+import { ImageDrop } from 'quill-image-drop-module'
+import ImageResize from 'quill-image-resize-module'
+Quill.register('modules/imageDrop', ImageDrop)
+Quill.register('modules/imageResize', ImageResize)
+
+const tableHeader = [{
+  name: 'orderNum',
+  label: '序号'
+}, {
+  name: 'image',
+  label: '封面'
+}, {
+  name: 'title',
+  label: '标题'
+}, {
+  name: 'createTime',
+  label: '编辑时间'
+}]
+const tableData = []
+const toolbarOptions = [
+  [{
+    'size': ['small', false, 'large']
+  }],
+  ['bold', 'italic'],
+  [{
+    'list': 'ordered'
+  }, {
+    'list': 'bullet'
+  }],
+  ['link', 'image']
+]
+export default {
+  // import引入的组件需要注入到对象中才能使用
+  components: {
+    quillEditor
+  },
+  data () {
+    // 这里存放数据
+    return {
+      loading: false,
+      fileList: [],
+      isAdd: true,
+      c_id: '',
+      serverName,
+      tableData,
+      tableHeader,
+      dialogFormVisible: false,
+      currentPage: 1,
+      formLabelWidth: '100px',
+      content: '',
+      form: {
+        title: '',
+        url: '',
+        orderNum: ''
+      },
+      image: '',
+      editorOption: {
+        modules: {
+          toolbar: {
+            container: toolbarOptions,
+            handlers: {
+              'image': function (value) {
+                if (value) {
+                  document.querySelector('.avatar-uploader input').click()
+                } else {
+                  this.quill.format('image', false)
+                }
+              }
+            }
+          },
+          history: {
+            delay: 1000,
+            maxStack: 50,
+            userOnly: false
+          },
+          imageDrop: true,
+          imageResize: {
+            displayStyles: {
+              backgroundColor: 'black',
+              border: 'none',
+              color: 'white'
+            },
+            modules: [ 'Resize', 'DisplaySize', 'Toolbar' ]
+          }
+        }
+      }
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {
+    token () {
+      return window.localStorage.getItem('zfb_token')
+    },
+    editor () {
+      return this.$refs.myQuillEditor.quill
+    }
+  },
+  // 监控data中的数据变化
+  watch: {
+  },
+  // 方法集合
+  methods: {
+    showAdd () {
+      this.clearInfo()
+      this.dialogFormVisible = true
+      this.isAdd = true
+    },
+    del (item) {
+      this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$http({
+          method: 'post',
+          data: {
+            id: item.id
+          },
+          url: '/rotation/delete',
+          headers: {
+            token: this.token
+          }
+        }).then(res => {
+          if (res.code === 200) {
+            this.$alert('删除成功', '提示', {
+              confirmButtonText: '确定',
+              callback: action => {
+                this.refresh()
+              }
+            })
+          } else {
+            this.$notify.error({
+              title: '错误',
+              message: res.message
+            })
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    add () {
+      let params = {
+        title: this.form.title,
+        image: this.image,
+        orderNum: this.form.orderNum,
+        url: this.form.url,
+        content: this.content
+      }
+      this.$http({
+        method: 'post',
+        data: params,
+        url: '/rotation/save',
+        headers: {
+          token: this.token
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.$alert('新增成功', '提示', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.dialogFormVisible = false
+              this.clearInfo()
+              this.refresh()
+            }
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    clearInfo () {
+      this.c_id = ''
+      this.form = {
+        title: '',
+        orderNum: '',
+        url: ''
+      }
+      this.image = ''
+      this.content = ''
+    },
+    save () {
+      let params = {
+        id: this.c_id,
+        title: this.form.title,
+        image: this.image,
+        orderNum: this.form.orderNum,
+        url: this.form.url,
+        content: this.content
+      }
+      this.$http({
+        method: 'post',
+        data: params,
+        url: '/rotation/update',
+        headers: {
+          token: this.token
+        }
+      }).then(res => {
+        if (res.code === 200) {
+          this.$alert('修改成功', '提示', {
+            confirmButtonText: '确定',
+            callback: action => {
+              this.dialogFormVisible = false
+              this.clearInfo()
+              this.refresh()
+            }
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: res.message
+          })
+        }
+      })
+    },
+    async show (item) {
+      this.isAdd = false
+      this.dialogFormVisible = true
+      let result = await this.$http({
+        method: 'post',
+        data: {
+          id: item.id
+        },
+        url: '/rotation/selectById',
+        headers: {
+          token: this.token
+        }
+      })
+      let list = result.message
+      this.c_id = list.id
+      this.form = {
+        title: list.title,
+        orderNum: list.orderNum,
+        url: list.url
+      }
+      this.image = list.image
+      this.content = list.content
+    },
+    beforeAvatarUpload (file) {
+      const isLt5M = file.size / 1024 / 1024 < 5
+      if (!isLt5M) {
+        this.$message.error('上传头像图片大小不能超过 5MB!')
+        return false
+      }
+      return isLt5M
+    },
+    handleChange (file, fileList) {
+      console.log('file', file)
+      console.log('fileList', fileList)
+
+      if (fileList.length > 1) {
+        this.fileList = fileList.slice(-1)
+      }
+    },
+    upload_success (data) {
+      console.log('上传成功')
+      this.image = data.message
+    },
+    upload_fail (data) {
+      this.$notify.error({
+        title: '上传失败',
+        message: data.message
+      })
+    },
+    uploadSuccess (data) {
+      // 如果上传成功
+      if (data.code === 200 && data.message !== null) {
+        // 获取光标所在位置
+        let length = this.editor.getSelection().index
+        // 插入图片  res.info为服务器返回的图片地址
+        this.editor.insertEmbed(length, 'image', data.message)
+        // 调整光标到最后
+        this.editor.setSelection(length + 1)
+      } else {
+        this.$message.error('图片插入失败')
+      }
+      // loading动画消失
+      this.loading = false
+    },
+    uploadError (data) {
+      this.$notify.error({
+        title: '上传失败',
+        message: data.message
+      })
+    },
+    beforeUpload (file) {
+      const isLt5M = file.size / 1024 / 1024 < 5
+      if (!isLt5M) {
+        this.$message.error('上传头像图片大小不能超过 5MB!')
+        return false
+      }
+      this.loading = true
+      return isLt5M
+    },
+    onEditorBlur (quill) {
+      // console.log('editor blur!', quill)
+    },
+    onEditorFocus (quill) {
+      // console.log('editor focus!', quill)
+    },
+    onEditorReady (quill) {
+      // console.log('editor ready!', quill)
+    },
+    onEditorChange ({
+      quill,
+      html,
+      text
+    }) {
+      this.content = html
+    },
+    handleSizeChange (val) {
+      console.log(`每页 ${val} 条`)
+    },
+    handleCurrentChange (val) {
+      console.log(`当前页: ${val}`)
+    },
+    refresh () {
+      this.loading = true
+      this.getData()
+      this.loading = false
+    },
+    getData () {
+      this.$http({
+        method: 'post',
+        data: {},
+        url: '/rotation/selectAll',
+        headers: {
+          token: this.token
+        }
+      }).then(res => {
+        let result = res
+        for (let i = 0; i < result.message.length; i++) {
+          result.message[i].createTime =
+          this.$base.dateFormat('yyyy-MM-dd hh:mm', new Date(result.message[i].createTime))
+        }
+        this.tableData = result.message
+      })
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {
+    this.refresh()
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+
+<style lang="scss" scoped>
+.con {
+  .d-l {
+    display: inline-block;
+    width: 45%;
+
+    .zfb-upload {
+      width: 280px;
+      height: 160px;
+      line-height: 160px;
+      overflow:hidden;
+      img {
+        width: 278px;
+        height: 158px;
+        border-radius: 6px;
+      }
+      &:hover{
+          border-color: #409eff;
+          .v-mask{
+            display: inline-block;
+            width: 278px;
+            height: 158px;
+            border-radius: 6px;
+            background: rgba(0,0,0,0.5);
+          }
+        }
+      .el-icon-plus {
+        position: relative;
+        top: -15px;
+        font-size: 20px;
+      }
+    }
+  }
+
+  .d-r {
+    width: 45%;
+    float: right;
+
+    .el-date-editor.el-input,
+    .el-date-editor.el-input__inner {
+      width: 100%;
+    }
+
+    .c-logo {
+      width: 150px;
+      height: 150px;
+      border: 1px solid #ccc;
+      border-radius: 4px;
+      background-color: #f5fafe;
+
+      img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    .c-zizhi {
+      width: 150px;
+      height: 150px;
+      border: 1px solid #ccc;
+      border-radius: 4px;
+      position: relative;
+      background-color: #f5fafe;
+
+      img {
+        width: 100%;
+        height: 100%;
+      }
+
+      .c-mask {
+        width: 100%;
+        height: 100%;
+        position: absolute;
+        top: 0;
+        left: 0;
+        background: rgba(0, 0, 0, 0.5);
+        text-align: center;
+        display: table;
+
+        .icon-download {
+          text-align: center;
+          display: table-cell;
+          vertical-align: middle;
+          color: #fff;
+          font-size: 20px;
+        }
+      }
+    }
+  }
+
+  .h-body {
+    width: 100%;
+    padding: 20px;
+    box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.1);
+    border-radius: 3px;
+    background-color: #fff;
+
+    .c-table {
+      overflow: auto;
+      height: 670px;
+      margin-top: 60px;
+      .o-span {
+        color: #0175dc;
+        cursor: pointer;
+      }
+
+      .p-con {
+        width: 100%;
+        text-align: right;
+        padding: 25px 20px 30px;
+      }
+    }
+  }
+}
+</style>

+ 0 - 0
src/pages/z-carousel/style.scss


+ 63 - 0
src/router/index.js

@@ -0,0 +1,63 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+Vue.use(Router)
+
+const router = new Router({
+  routes: [
+    {
+      path: '/',
+      component: () => import('@/pages/layout/'),
+      children: [
+        {
+          path: '/',
+          name: '首页',
+          component: () => import('@/pages/home'),
+          meta: {index: '1'}
+        },
+        {
+          path: '/department',
+          name: '部门管理',
+          component: () => import('@/pages/department'),
+          meta: {index: '2'}
+        },
+        {
+          path: '/user',
+          name: '用户管理',
+          component: () => import('@/pages/user'),
+          meta: {index: '3'}
+        },
+        {
+          path: '/role',
+          name: '角色权限',
+          component: () => import('@/pages/role'),
+          meta: {index: '4'}
+        },
+        {
+          path: '/scene',
+          name: '场景管理',
+          component: () => import('@/pages/scene'),
+          meta: {index: '5'}
+        },
+        {
+          path: '/z-carousel',
+          name: '轮播图',
+          component: () => import('@/pages/z-carousel'),
+          meta: {index: '3-1'}
+        },
+        {
+          path: '/recommended',
+          name: '推荐位',
+          component: () => import('@/pages/recommended'),
+          meta: {index: '3-2'}
+        }
+      ]
+    },
+    {
+      path: '/login',
+      name: '登录',
+      component: () => import('@/pages/login')
+    }
+  ]
+})
+
+export default router

+ 156 - 0
src/utils/base.js

@@ -0,0 +1,156 @@
+const base = {
+  weeks: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
+  test: function () {
+    console.log('test')
+  },
+  /**
+   * 删除数组内指定索引的元素
+   * @param {*} delIndex 索引
+   * @param {*} that 数组本身
+   * @return {Array} 删除后的数组
+   */
+  arrDelete: function (delIndex, that) {
+    var temArray = []
+    for (var i = 0; i < that.length; i++) {
+      if (i !== delIndex) {
+        temArray.push(that[i])
+      }
+    }
+    return temArray
+  },
+  /**
+   * 格式化时间
+   * @param {*} fmt 格式 eg:'yyyy-MM-dd'
+   * @param {*} that Date本身
+   * @return {Date} 格式化的时间
+   */
+  dateFormat: function (fmt, that) {
+    var o = {
+      'M+': that.getMonth() + 1, // 月份
+      'd+': that.getDate(), // 日
+      'h+': that.getHours(), // 小时
+      'm+': that.getMinutes(), // 分
+      's+': that.getSeconds(), // 秒
+      'q+': Math.floor((that.getMonth() + 3) / 3), // 季度
+      S: that.getMilliseconds() // 毫秒
+    }
+    if (/(y+)/.test(fmt)) {
+      fmt = fmt.replace(
+        RegExp.$1,
+        (that.getFullYear() + '').substr(4 - RegExp.$1.length)
+      )
+    }
+    for (var k in o) {
+      if (new RegExp('(' + k + ')').test(fmt)) {
+        fmt = fmt.replace(
+          RegExp.$1,
+          RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
+        )
+      }
+    }
+    return fmt
+  },
+  /**
+   * 获取html的纯文本
+   * @param {*} html HTML代码块
+   * @return 纯文本
+   */
+  getSimpleText: function (html) {
+    var re1 = new RegExp('<.+?>', 'g')
+    var msg = html.replace(re1, '')
+    return msg
+  },
+  /**
+   * 获取不包含span标签的html
+   * @param {*} html HTML代码块
+   * @return html
+   */
+  getSpanText: function (html) {
+    var re2 = new RegExp('(<|</)(?!(span)[ >])[^>/]*>', 'g')
+    var msg2 = html.replace(re2, '')
+    console.log(msg2)
+    return msg2
+  },
+  /**
+   * 滚动到锚点
+   * @param {*} dom 锚点
+   */
+  scorllToHref: function (dom) {
+    if (dom) {
+      let anchor = document.querySelector(dom)
+      document.documentElement.scrollTop = anchor.offsetTop > 80 ? anchor.offsetTop - 80 : anchor.offsetTop
+    } else {
+      document.documentElement.scrollTop = 0
+    }
+  },
+  /**
+   * 去除空格
+   * @param {*} str 需要去除的字符串
+   * @param {*} global 正则标准
+   */
+  trim: function (str, global) {
+    var result
+    result = str.replace(/(^\s+)|(\s+$)/g, '')
+    if (global.toLowerCase() === 'g') {
+      result = result.replace(/\s/g, '')
+    }
+    return result
+  },
+  /**
+   * 获取n天前/后的时间
+   * @param {*} day +-天数(+代表后day天,-代表前day天)
+   */
+  getDay: function (day) {
+    var today = new Date()
+
+    var targetdayMilliseconds = today.getTime() + 1000 * 60 * 60 * 24 * day
+
+    today.setTime(targetdayMilliseconds) // 注意,这行是关键代码
+
+    var tYear = today.getFullYear()
+    var tMonth = today.getMonth()
+    var tDate = today.getDate()
+    var tDay = this.weeks[today.getDay()]
+
+    tMonth = this.doHandleMonth(tMonth + 1)
+    tDate = this.doHandleMonth(tDate)
+    return tYear + '-' + tMonth + '-' + tDate + '(' + tDay + ')'
+  },
+  /**
+   * 给个位数月份前添加0
+   * @param {*} month 要格式化的月份
+   */
+  doHandleMonth: function (month) {
+    var m = month
+    if (month.toString().length === 1) {
+      m = '0' + month
+    }
+    return m
+  },
+  isImg: function (url) {
+    var temp = []
+    temp = url.toString().split('.')
+    if (temp[temp.length - 1].toLowerCase() === 'png' || temp[temp.length - 1].toLowerCase() === 'jpg') {
+      return true
+    } else {
+      return false
+    }
+  },
+  isContain: function (value, str) {
+    if (value.indexOf(str) > -1) {
+      return true
+    } else {
+      return false
+    }
+  },
+  reg: {
+    idCard: /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|[xX])$/,
+    phone: /^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$/,
+    email: /^([a-zA-Z0-9]+[_|_|.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|_|.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/
+  },
+  defaultTxt: {
+    upload_tips: '支持jpg/png格式,<5M <br/>推荐分辨率800*800px',
+    upload_bg_tips: '支持mp3、wmv、<br/>wma格式,<5M '
+  }
+}
+export { base }

+ 86 - 0
src/utils/http.js

@@ -0,0 +1,86 @@
+import axios from 'axios'
+import Vue from 'vue'
+import router from '../router'
+
+var isProduction = process.env.NODE_ENV === 'production'
+const serverName = isProduction ? '' : 'http://192.168.0.207:7081/'
+
+// const serverName = isProduction ? '' : 'https://admin.zhifangbao.com/'
+
+const vue = new Vue()
+
+axios.defaults.baseURL = serverName
+axios.defaults.headers['X-Requested-with'] = 'XMLHttpRequest'
+
+// 拦截请求,做登陆,或head处理
+axios.interceptors.request.use(
+  function (config) {
+    if (config.method === 'post') {
+      config.data = {
+        ...config.data,
+        rnd: Math.random()
+      }
+    } else if (config.method === 'get') {
+      config.params = {
+        rnd: Math.random(),
+        ...config.params
+      }
+    }
+    return config
+  }, function (error) {
+    // 对请求错误做些什么
+    return Promise.reject(error)
+  }
+)
+
+// 拦截返回,做错误统一处理
+axios.interceptors.response.use(
+  response => {
+    let data = response.data
+    let code = Number(response.data.code)
+
+    switch (code) {
+      case -1:
+        break
+      case 202:
+        if (window.localStorage.getItem('zfb_token')) {
+          window.localStorage.setItem('zfb_token', '')
+          vue.$alert('登录状态失效,请重新登录', '提示', {
+            confirmButtonText: '确定',
+            callback: function () {
+              router.push('/login')
+            }
+          })
+        }
+        break
+      case 500:
+        vue.$alert(data.message, '提示', {
+          confirmButtonText: '确定',
+          callback: function () {
+          }
+        })
+        break
+      case 0:
+        break
+    }
+    // tryHideFullScreenLoading()
+    return data
+  },
+  error => {
+    if (error.response) {
+      switch (error.response.status) {
+        case 500:
+          vue.$alert(error.response.message, '提示', {
+            confirmButtonText: '确定',
+            callback: action => {
+
+            }
+          })
+          break
+      }
+    }
+    return Promise.reject(error)
+  }
+)
+
+export { serverName, axios }

+ 0 - 0
static/.gitkeep


二进制
static/img/favicon.ico


文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/data/document.js


+ 115 - 0
消安-后台原型0225/data/styles.css

@@ -0,0 +1,115 @@
+.ax_default {
+  font-family:'Arial Normal', 'Arial';
+  font-weight:400;
+  font-style:normal;
+  font-size:13px;
+  color:#333333;
+  text-align:center;
+  line-height:normal;
+}
+.box_1 {
+}
+.box_2 {
+}
+.box_3 {
+}
+.ellipse {
+}
+._图片 {
+}
+.button {
+}
+.primary_button {
+  color:#FFFFFF;
+}
+.link_button {
+  color:#169BD5;
+}
+._一级标题 {
+  font-family:'Arial Normal', 'Arial';
+  font-weight:bold;
+  font-style:normal;
+  font-size:32px;
+  text-align:left;
+}
+._二级标题 {
+  font-family:'Arial Normal', 'Arial';
+  font-weight:bold;
+  font-style:normal;
+  font-size:24px;
+  text-align:left;
+}
+._三级标题 {
+  font-family:'Arial Normal', 'Arial';
+  font-weight:bold;
+  font-style:normal;
+  font-size:18px;
+  text-align:left;
+}
+._四级标题 {
+  font-family:'Arial Normal', 'Arial';
+  font-weight:bold;
+  font-style:normal;
+  font-size:14px;
+  text-align:left;
+}
+._五级标题 {
+  font-family:'Arial Normal', 'Arial';
+  font-weight:bold;
+  font-style:normal;
+  text-align:left;
+}
+._六级标题 {
+  font-family:'Arial Normal', 'Arial';
+  font-weight:bold;
+  font-style:normal;
+  font-size:10px;
+  text-align:left;
+}
+.label {
+  font-size:14px;
+  text-align:left;
+}
+._文本段落 {
+  text-align:left;
+}
+.line {
+}
+.text_field {
+  color:#000000;
+  text-align:left;
+}
+.text_area {
+  color:#000000;
+  text-align:left;
+}
+.droplist {
+  color:#000000;
+  text-align:left;
+}
+.checkbox {
+  text-align:left;
+}
+.radio_button {
+  text-align:left;
+}
+.html_button {
+  text-align:center;
+}
+.tree_node {
+  text-align:left;
+}
+._流程形状 {
+}
+.table_cell {
+}
+.menu_item {
+}
+.marker {
+  color:#FFFFFF;
+}
+._表格 {
+}
+._提交按钮 {
+  color:#000000;
+}

文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/个人中心/data.js


+ 14 - 0
消安-后台原型0225/files/个人中心/styles.css

@@ -0,0 +1,14 @@
+body {
+  margin:0px;
+  background-image:none;
+  position:static;
+  left:auto;
+  width:10px;
+  margin-left:0;
+  margin-right:0;
+  text-align:left;
+}
+#base {
+  position:absolute;
+  z-index:0;
+}

文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/场景拼接(此页交互待定)/data.js


文件差异内容过多而无法显示
+ 1907 - 0
消安-后台原型0225/files/场景拼接(此页交互待定)/styles.css


文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/场景管理/data.js


文件差异内容过多而无法显示
+ 9507 - 0
消安-后台原型0225/files/场景管理/styles.css


文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/我的场景/data.js


文件差异内容过多而无法显示
+ 2017 - 0
消安-后台原型0225/files/我的场景/styles.css


文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/我的相机/data.js


文件差异内容过多而无法显示
+ 2247 - 0
消安-后台原型0225/files/我的相机/styles.css


文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/操作日志/data.js


文件差异内容过多而无法显示
+ 6574 - 0
消安-后台原型0225/files/操作日志/styles.css


文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/数据统计/data.js


文件差异内容过多而无法显示
+ 3613 - 0
消安-后台原型0225/files/数据统计/styles.css


文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/用户管理/data.js


文件差异内容过多而无法显示
+ 5666 - 0
消安-后台原型0225/files/用户管理/styles.css


文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/登陆/data.js


文件差异内容过多而无法显示
+ 1007 - 0
消安-后台原型0225/files/登陆/styles.css


文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/角色权限/data.js


文件差异内容过多而无法显示
+ 6634 - 0
消安-后台原型0225/files/角色权限/styles.css


文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/部门信息/data.js


文件差异内容过多而无法显示
+ 3861 - 0
消安-后台原型0225/files/部门信息/styles.css


文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/问题反馈/data.js


文件差异内容过多而无法显示
+ 4509 - 0
消安-后台原型0225/files/问题反馈/styles.css


文件差异内容过多而无法显示
+ 7 - 0
消安-后台原型0225/files/首页/data.js


文件差异内容过多而无法显示
+ 2658 - 0
消安-后台原型0225/files/首页/styles.css


二进制
消安-后台原型0225/images/场景拼接(此页交互待定)/u1669.png


+ 0 - 0
消安-后台原型0225/images/场景拼接(此页交互待定)/u1670.png


部分文件因为文件数量过多而无法显示